bleak_house 7.1 → 7.2
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +1 -0
- data/CHANGELOG +52 -12
- data/Manifest +20 -20
- data/README +84 -31
- data/Rakefile +10 -83
- data/TODO +10 -0
- data/bin/bleak +13 -0
- data/bleak_house.gemspec +36 -0
- data/ext/build_ruby.rb +114 -0
- data/ext/build_snapshot.rb +5 -0
- data/ext/extconf.rb +26 -0
- data/ext/snapshot.c +153 -0
- data/ext/snapshot.h +59 -0
- data/lib/bleak_house.rb +17 -12
- data/lib/bleak_house/analyzer.rb +54 -0
- data/lib/bleak_house/hook.rb +24 -0
- data/ruby/ruby-1.8.7-p174.tar.bz2 +0 -0
- data/ruby/ruby-1.8.7.patch +483 -0
- data/test/benchmark/bench.rb +16 -0
- data/test/test_helper.rb +6 -0
- data/test/unit/test_bleak_house.rb +44 -19
- metadata +100 -104
- metadata.gz.sig +2 -0
- data/init.rb +0 -2
- data/install.rb +0 -7
- data/lib/bleak_house/action_controller.rb +0 -17
- data/lib/bleak_house/analyze.rb +0 -196
- data/lib/bleak_house/bleak_house.rb +0 -47
- data/lib/bleak_house/c.rb +0 -230
- data/lib/bleak_house/dispatcher.rb +0 -19
- data/lib/bleak_house/gruff_hacks.rb +0 -62
- data/lib/bleak_house/rake_task_redefine_task.rb +0 -25
- data/lib/bleak_house/support_methods.rb +0 -50
- data/patches/gc.c.patch +0 -30
- data/tasks/bleak_house_tasks.rake +0 -16
- data/test/misc/direct.rb +0 -13
@@ -1,47 +0,0 @@
|
|
1
|
-
|
2
|
-
class BleakHouse
|
3
|
-
cattr_accessor :last_request_name
|
4
|
-
|
5
|
-
# Avoid making four more strings on each request.
|
6
|
-
CONTROLLER_KEY = 'controller'
|
7
|
-
ACTION_KEY = 'action'
|
8
|
-
GSUB_SEARCH = '/'
|
9
|
-
GSUB_REPLACEMENT = '__'
|
10
|
-
|
11
|
-
# Sets the request name on the BleakHouse object to match this Rails request. Called from <tt>ActionController::Base.process</tt>. Assign to <tt>last_request_name</tt> yourself if you are not using BleakHouse within Rails.
|
12
|
-
def self.set_request_name request, other = nil
|
13
|
-
self.last_request_name = "#{
|
14
|
-
request.parameters[CONTROLLER_KEY].gsub(GSUB_SEARCH, GSUB_REPLACEMENT) # mangle namespaced controller names
|
15
|
-
}/#{
|
16
|
-
request.parameters[ACTION_KEY]
|
17
|
-
}/#{
|
18
|
-
request.request_method
|
19
|
-
}#{
|
20
|
-
other
|
21
|
-
}"
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.debug s #:nodoc:
|
25
|
-
s = "** #{name.underscore}: #{s}"
|
26
|
-
RAILS_DEFAULT_LOGGER.debug s if RAILS_DEFAULT_LOGGER
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.warn s #:nodoc:
|
30
|
-
s = "** #{name.underscore}: #{s}"
|
31
|
-
if RAILS_DEFAULT_LOGGER
|
32
|
-
RAILS_DEFAULT_LOGGER.warn s
|
33
|
-
else
|
34
|
-
$stderr.puts s
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
LOGFILE = "#{RAILS_ROOT}/log/bleak_house_#{RAILS_ENV}.yaml.log"
|
39
|
-
if File.exists?(LOGFILE)
|
40
|
-
File.rename(LOGFILE, "#{LOGFILE}.old")
|
41
|
-
warn "renamed old logfile"
|
42
|
-
end
|
43
|
-
|
44
|
-
WITH_SPECIALS = false
|
45
|
-
|
46
|
-
MEMLOGGER = CLogger.new
|
47
|
-
end
|
data/lib/bleak_house/c.rb
DELETED
@@ -1,230 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rubygems'
|
3
|
-
require 'inline'
|
4
|
-
|
5
|
-
class BleakHouse
|
6
|
-
|
7
|
-
=begin rdoc
|
8
|
-
This class performs the actual object logging of BleakHouse. To use it directly, you need to make calls to BleakHouse::CLogger#snapshot.
|
9
|
-
|
10
|
-
== Example
|
11
|
-
|
12
|
-
At the start of your app, put:
|
13
|
-
require 'rubygems'
|
14
|
-
require 'bleak_house/c'
|
15
|
-
$memlogger = BleakHouse::CLogger.new
|
16
|
-
File.delete($logfile = "/path/to/logfile") rescue nil
|
17
|
-
|
18
|
-
(This assumes you are using the gem version.)
|
19
|
-
|
20
|
-
Now, at the points of interest, put:
|
21
|
-
$memlogger.snapshot($logfile, "tag/subtag", false)
|
22
|
-
|
23
|
-
Run your app. Once you are done, analyze your data:
|
24
|
-
ruby -r rubygems -e 'require "bleak_house/analyze"; BleakHouse::Analyze.build_all("/path/to/logfile")'
|
25
|
-
|
26
|
-
You will get a <tt>bleak_house/</tt> folder in the same folder as your logfile.
|
27
|
-
|
28
|
-
=end
|
29
|
-
|
30
|
-
class CLogger
|
31
|
-
|
32
|
-
MAX_UNIQ_TAGS = 1536 # per frame
|
33
|
-
MAX_TAG_LENGTH = 192 # tag plus fully namespaced classname
|
34
|
-
|
35
|
-
# Returns an array of the running process's real and virtual memory usage, in kilobytes.
|
36
|
-
def mem_usage
|
37
|
-
a = `ps -o vsz,rss -p #{Process.pid}`.split(/\s+/)[-2..-1].map{|el| el.to_i}
|
38
|
-
[a.first - a.last, a.last]
|
39
|
-
end
|
40
|
-
|
41
|
-
inline do |builder|
|
42
|
-
builder.include '"node.h"' # struct RNode
|
43
|
-
builder.include '"st.h"' # struct st_table
|
44
|
-
builder.include '"re.h"' # struct RRegexp
|
45
|
-
builder.include '"env.h"' # various structs
|
46
|
-
|
47
|
-
builder.prefix <<-EOC
|
48
|
-
typedef struct RVALUE {
|
49
|
-
union {
|
50
|
-
struct {
|
51
|
-
unsigned long flags; /* always 0 for freed obj */
|
52
|
-
struct RVALUE *next;
|
53
|
-
} free;
|
54
|
-
struct RBasic basic;
|
55
|
-
struct RObject object;
|
56
|
-
struct RClass klass;
|
57
|
-
struct RFloat flonum;
|
58
|
-
struct RString string;
|
59
|
-
struct RArray array;
|
60
|
-
struct RRegexp regexp;
|
61
|
-
struct RHash hash;
|
62
|
-
struct RData data;
|
63
|
-
struct RStruct rstruct;
|
64
|
-
struct RBignum bignum;
|
65
|
-
struct RFile file;
|
66
|
-
struct RNode node;
|
67
|
-
struct RMatch match;
|
68
|
-
struct RVarmap varmap;
|
69
|
-
struct SCOPE scope;
|
70
|
-
} as;
|
71
|
-
} RVALUE;
|
72
|
-
|
73
|
-
struct heaps_slot {
|
74
|
-
void *membase;
|
75
|
-
RVALUE *slot;
|
76
|
-
int limit;
|
77
|
-
};
|
78
|
-
|
79
|
-
struct heaps_slot * rb_gc_heap_slots();
|
80
|
-
int rb_gc_heaps_used();
|
81
|
-
int rb_gc_heaps_length();
|
82
|
-
EOC
|
83
|
-
|
84
|
-
# number of struct heaps_slots used
|
85
|
-
builder.c <<-EOC
|
86
|
-
static int
|
87
|
-
heaps_used() {
|
88
|
-
return rb_gc_heaps_used();
|
89
|
-
}
|
90
|
-
EOC
|
91
|
-
|
92
|
-
# length of the struct heaps_slots allocated
|
93
|
-
builder.c <<-EOC
|
94
|
-
static int
|
95
|
-
heaps_length() {
|
96
|
-
return rb_gc_heaps_length();
|
97
|
-
}
|
98
|
-
EOC
|
99
|
-
|
100
|
-
OBJ_TYPES = ["T_NIL",
|
101
|
-
"T_OBJECT",
|
102
|
-
"T_CLASS",
|
103
|
-
"T_ICLASS",
|
104
|
-
"T_MODULE",
|
105
|
-
"T_FLOAT",
|
106
|
-
"T_STRING",
|
107
|
-
"T_REGEXP",
|
108
|
-
"T_ARRAY",
|
109
|
-
"T_FIXNUM",
|
110
|
-
"T_HASH",
|
111
|
-
"T_STRUCT",
|
112
|
-
"T_BIGNUM",
|
113
|
-
"T_FILE",
|
114
|
-
"T_TRUE",
|
115
|
-
"T_FALSE",
|
116
|
-
"T_DATA",
|
117
|
-
"T_SYMBOL",
|
118
|
-
"T_MATCH"]
|
119
|
-
|
120
|
-
RAW_TYPES = ["T_NONE",
|
121
|
-
"T_BLKTAG",
|
122
|
-
"T_UNDEF",
|
123
|
-
"T_VARMAP",
|
124
|
-
"T_SCOPE",
|
125
|
-
"T_NODE"]
|
126
|
-
|
127
|
-
# Counts the live objects on the heap and writes a single tagged YAML frame to the logfile. Set <tt>specials = true</tt> if you also want to count AST nodes and var scopes; otherwise, use <tt>false</tt>.
|
128
|
-
def snapshot(logfile, tag, specials)
|
129
|
-
# RDoc stub
|
130
|
-
end
|
131
|
-
|
132
|
-
builder.c <<-EOC
|
133
|
-
static void
|
134
|
-
VALUE snapshot(VALUE logfile, VALUE tag, VALUE _specials) {
|
135
|
-
Check_Type(logfile, T_STRING);
|
136
|
-
Check_Type(tag, T_STRING);
|
137
|
-
|
138
|
-
RVALUE *p, *pend;
|
139
|
-
struct heaps_slot * heaps = rb_gc_heap_slots();
|
140
|
-
|
141
|
-
int specials = RTEST(_specials);
|
142
|
-
|
143
|
-
FILE *obj_log = fopen(StringValueCStr(logfile), "r");
|
144
|
-
int is_new;
|
145
|
-
if (!(is_new = (obj_log == NULL)))
|
146
|
-
fclose(obj_log);
|
147
|
-
|
148
|
-
if ((obj_log = fopen(StringValueCStr(logfile), "a+")) == NULL)
|
149
|
-
rb_raise(rb_eRuntimeError, "couldn't open snapshot file");
|
150
|
-
|
151
|
-
if (is_new)
|
152
|
-
fprintf(obj_log, \"---\\n");
|
153
|
-
fprintf(obj_log, \"- - %i\\n", time(0));
|
154
|
-
VALUE mem = rb_funcall(self, rb_intern("mem_usage"), 0);
|
155
|
-
fprintf(obj_log, \" - :\\"memory usage/swap\\": %i\\n", NUM2INT(RARRAY_PTR(mem)[0]));
|
156
|
-
fprintf(obj_log, \" :\\"memory usage/real\\": %i\\n", NUM2INT(RARRAY_PTR(mem)[1]));
|
157
|
-
|
158
|
-
/* haha */
|
159
|
-
char tags[#{MAX_UNIQ_TAGS}][#{MAX_TAG_LENGTH}];
|
160
|
-
char current_tag[2048];
|
161
|
-
int counts[#{MAX_UNIQ_TAGS}];
|
162
|
-
int current_pos = 0;
|
163
|
-
|
164
|
-
int filled_slots = 0;
|
165
|
-
int free_slots = 0;
|
166
|
-
|
167
|
-
int i, j;
|
168
|
-
for (i = 0; i < rb_gc_heaps_used(); i++) {
|
169
|
-
p = heaps[i].slot;
|
170
|
-
pend = p + heaps[i].limit;
|
171
|
-
for (; p < pend; p++) {
|
172
|
-
if (p->as.basic.flags) { /* always 0 for freed objects */
|
173
|
-
filled_slots ++;
|
174
|
-
sprintf(current_tag, "");
|
175
|
-
switch (TYPE(p)) {
|
176
|
-
#{RAW_TYPES.map do |type|
|
177
|
-
"case #{type}:
|
178
|
-
if (specials)
|
179
|
-
sprintf(current_tag , \"%s::::_#{type[2..-1].downcase}\", StringValueCStr(tag));
|
180
|
-
break;
|
181
|
-
"
|
182
|
-
end.flatten.join}
|
183
|
-
default:
|
184
|
-
if (!p->as.basic.klass) {
|
185
|
-
sprintf(current_tag , "%s::::_unknown", StringValueCStr(tag));
|
186
|
-
} else {
|
187
|
-
sprintf(current_tag , "%s::::%s", StringValueCStr(tag), rb_obj_classname((VALUE)p));
|
188
|
-
}
|
189
|
-
}
|
190
|
-
if (strlen(current_tag) > #{MAX_TAG_LENGTH})
|
191
|
-
rb_raise(rb_eRuntimeError, "tag + classname too big; increase MAX_TAG_LENGTH (#{MAX_TAG_LENGTH})");
|
192
|
-
if (strcmp(current_tag, "")) {
|
193
|
-
for (j = 0; j < current_pos; j++) {
|
194
|
-
if (!strcmp(tags[j], current_tag)) {
|
195
|
-
counts[j] ++;
|
196
|
-
break;
|
197
|
-
}
|
198
|
-
}
|
199
|
-
if (j == current_pos) {
|
200
|
-
/* found a new one */
|
201
|
-
if (current_pos == #{MAX_UNIQ_TAGS})
|
202
|
-
rb_raise(rb_eRuntimeError, "exhausted tag array; increase MAX_UNIQ_TAGS (#{MAX_UNIQ_TAGS})");
|
203
|
-
sprintf(tags[current_pos], current_tag);
|
204
|
-
counts[current_pos] = 1;
|
205
|
-
current_pos ++;
|
206
|
-
}
|
207
|
-
}
|
208
|
-
} else {
|
209
|
-
free_slots ++;
|
210
|
-
}
|
211
|
-
}
|
212
|
-
}
|
213
|
-
fprintf(obj_log, \" :\\"heap usage/filled slots\\": %i\\n", filled_slots);
|
214
|
-
fprintf(obj_log, \" :\\"heap usage/free slots\\": %i\\n", free_slots);
|
215
|
-
for (j = 0; j < current_pos; j++) {
|
216
|
-
fprintf(obj_log, " :\\"%s\\": %i\\n", tags[j], counts[j]);
|
217
|
-
}
|
218
|
-
fclose(obj_log);
|
219
|
-
|
220
|
-
/* request GC run */
|
221
|
-
rb_funcall(rb_mGC, rb_intern("start"), 0);
|
222
|
-
/* to get a custom module: rb_const_get(parentModule, "ModuleName")
|
223
|
-
parent module can be something like rb_mKernel for the toplevel */
|
224
|
-
return Qtrue;
|
225
|
-
}
|
226
|
-
EOC
|
227
|
-
end
|
228
|
-
|
229
|
-
end
|
230
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
|
2
|
-
# Override Dispatcher#prepare and Dispatcher#reset_after_dispatch so that each request makes before-and-after usage snapshots.
|
3
|
-
class Dispatcher
|
4
|
-
class << self
|
5
|
-
|
6
|
-
def prepare_application_with_bleak_house
|
7
|
-
prepare_application_without_bleak_house
|
8
|
-
BleakHouse::MEMLOGGER.snapshot(BleakHouse::LOGFILE, 'core rails', BleakHouse::WITH_SPECIALS)
|
9
|
-
end
|
10
|
-
alias_method_chain :prepare_application, :bleak_house
|
11
|
-
|
12
|
-
def reset_after_dispatch_with_bleak_house
|
13
|
-
BleakHouse::MEMLOGGER.snapshot(BleakHouse::LOGFILE, BleakHouse.last_request_name || 'unknown', BleakHouse::WITH_SPECIALS)
|
14
|
-
reset_after_dispatch_without_bleak_house
|
15
|
-
end
|
16
|
-
alias_method_chain :reset_after_dispatch, :bleak_house
|
17
|
-
|
18
|
-
end
|
19
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
|
2
|
-
class Gruff::Base
|
3
|
-
|
4
|
-
def draw_legend
|
5
|
-
@legend_labels = @data.collect {|item| item[DATA_LABEL_INDEX] }
|
6
|
-
|
7
|
-
legend_square_width = @legend_box_size # small square with color of this item
|
8
|
-
legend_left = 10
|
9
|
-
|
10
|
-
current_x_offset = legend_left
|
11
|
-
current_y_offset = TOP_MARGIN + TITLE_MARGIN + @title_caps_height + LEGEND_MARGIN
|
12
|
-
|
13
|
-
debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
|
14
|
-
|
15
|
-
@legend_labels.each_with_index do |legend_label, index|
|
16
|
-
|
17
|
-
next if index > MAX_LEGENDS
|
18
|
-
legend_label = "some not shown" if index == MAX_LEGENDS
|
19
|
-
|
20
|
-
# Draw label
|
21
|
-
@d.fill = @font_color
|
22
|
-
@d.font = @font if @font
|
23
|
-
@d.pointsize = scale_fontsize(@legend_font_size)
|
24
|
-
@d.stroke('transparent')
|
25
|
-
@d.font_weight = NormalWeight
|
26
|
-
@d.gravity = WestGravity
|
27
|
-
@d = @d.annotate_scaled( @base_image,
|
28
|
-
@raw_columns, 1.0,
|
29
|
-
current_x_offset + (legend_square_width * 1.7), current_y_offset,
|
30
|
-
legend_label.to_s, @scale)
|
31
|
-
|
32
|
-
if index < MAX_LEGENDS
|
33
|
-
# Now draw box with color of this dataset
|
34
|
-
@d = @d.stroke('transparent')
|
35
|
-
@d = @d.fill @data[index][DATA_COLOR_INDEX]
|
36
|
-
@d = @d.rectangle(current_x_offset,
|
37
|
-
current_y_offset - legend_square_width / 2.0,
|
38
|
-
current_x_offset + legend_square_width,
|
39
|
-
current_y_offset + legend_square_width / 2.0)
|
40
|
-
end
|
41
|
-
|
42
|
-
@d.pointsize = @legend_font_size
|
43
|
-
metrics = @d.get_type_metrics(@base_image, legend_label.to_s)
|
44
|
-
current_y_offset += metrics.height * 1.05
|
45
|
-
end
|
46
|
-
@color_index = 0
|
47
|
-
end
|
48
|
-
|
49
|
-
alias :setup_graph_measurements_without_top_margin :setup_graph_measurements
|
50
|
-
def setup_graph_measurements
|
51
|
-
setup_graph_measurements_without_top_margin
|
52
|
-
@graph_height += NEGATIVE_TOP_MARGIN
|
53
|
-
@graph_top -= NEGATIVE_TOP_MARGIN
|
54
|
-
end
|
55
|
-
|
56
|
-
alias :clip_value_if_greater_than_without_size_hacks :clip_value_if_greater_than
|
57
|
-
def clip_value_if_greater_than(arg1, arg2)
|
58
|
-
arg2 = arg2 / 2 if arg1 == @columns / (@norm_data.first[1].size * 2.5)
|
59
|
-
clip_value_if_greater_than_without_size_hacks(arg1, arg2)
|
60
|
-
end
|
61
|
-
|
62
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
|
2
|
-
# http://www.bigbold.com/snippets/posts/show/2032
|
3
|
-
module Rake
|
4
|
-
module TaskManager
|
5
|
-
def redefine_task(task_class, args, &block)
|
6
|
-
task_name, deps = resolve_args(args)
|
7
|
-
task_name = task_class.scope_name(@scope, task_name)
|
8
|
-
deps = [deps] unless deps.respond_to?(:to_ary)
|
9
|
-
deps = deps.collect {|d| d.to_s }
|
10
|
-
task = @tasks[task_name.to_s] = task_class.new(task_name, self)
|
11
|
-
task.application = self
|
12
|
-
task.add_comment(@last_comment)
|
13
|
-
@last_comment = nil
|
14
|
-
task.enhance(deps, &block)
|
15
|
-
task
|
16
|
-
end
|
17
|
-
end
|
18
|
-
class Task
|
19
|
-
class << self
|
20
|
-
def redefine_task(args, &block)
|
21
|
-
Rake.application.redefine_task(self, args, &block)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
|
2
|
-
class Array
|
3
|
-
alias :time :first
|
4
|
-
alias :data :last
|
5
|
-
|
6
|
-
def sum
|
7
|
-
inject(0) {|s, x| x + s}
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_i
|
11
|
-
self.map{|s| s.to_i}
|
12
|
-
end
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
class Dir
|
17
|
-
def self.descend path, &block
|
18
|
-
path = path.split("/") unless path.is_a? Array
|
19
|
-
top = (path.shift or ".")
|
20
|
-
Dir.mkdir(top) unless File.exists? top
|
21
|
-
Dir.chdir(top) do
|
22
|
-
if path.any?
|
23
|
-
descend path, &block
|
24
|
-
else
|
25
|
-
block.call
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class String
|
32
|
-
def to_filename
|
33
|
-
self.downcase.gsub(/[^\w\d\-]/, '_')
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
class NilClass
|
38
|
-
def +(op)
|
39
|
-
self.to_i + op
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
class Symbol
|
44
|
-
def =~ regex
|
45
|
-
self.to_s =~ regex
|
46
|
-
end
|
47
|
-
def [](*args)
|
48
|
-
self.to_s[*args]
|
49
|
-
end
|
50
|
-
end
|
data/patches/gc.c.patch
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
Index: gc.c
|
2
|
-
===================================================================
|
3
|
-
RCS file: /src/ruby/gc.c,v
|
4
|
-
retrieving revision 1.168.2.45
|
5
|
-
diff -p -u -r1.168.2.45 gc.c
|
6
|
-
--- gc.c 25 Aug 2006 08:12:46 -0000 1.168.2.45
|
7
|
-
+++ gc.c 31 Aug 2006 18:47:55 -0000
|
8
|
-
@@ -323,6 +323,22 @@ static struct heaps_slot {
|
9
|
-
static int heaps_length = 0;
|
10
|
-
static int heaps_used = 0;
|
11
|
-
|
12
|
-
+struct heaps_slot *
|
13
|
-
+rb_gc_heap_slots()
|
14
|
-
+{
|
15
|
-
+ return heaps;
|
16
|
-
+}
|
17
|
-
+
|
18
|
-
+int
|
19
|
-
+rb_gc_heaps_used() {
|
20
|
-
+ return heaps_used;
|
21
|
-
+}
|
22
|
-
+
|
23
|
-
+int
|
24
|
-
+rb_gc_heaps_length() {
|
25
|
-
+ return heaps_length;
|
26
|
-
+}
|
27
|
-
+
|
28
|
-
#define HEAP_MIN_SLOTS 10000
|
29
|
-
static int heap_slots = HEAP_MIN_SLOTS;
|
30
|
-
|