bleak_house 5.3 → 6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/Manifest +0 -2
- data/README +6 -2
- data/lib/bleak_house.rb +6 -2
- data/lib/bleak_house/analyze.rb +25 -11
- data/lib/bleak_house/bleak_house.rb +2 -12
- data/lib/bleak_house/c.rb +19 -6
- metadata +3 -5
- data/lib/bleak_house/mem_logger.rb +0 -15
- data/lib/bleak_house/ruby.rb +0 -46
data/CHANGELOG
CHANGED
data/Manifest
CHANGED
@@ -12,9 +12,7 @@
|
|
12
12
|
./lib/bleak_house/c.rb
|
13
13
|
./lib/bleak_house/dispatcher.rb
|
14
14
|
./lib/bleak_house/gruff_hacks.rb
|
15
|
-
./lib/bleak_house/mem_logger.rb
|
16
15
|
./lib/bleak_house/rake_task_redefine_task.rb
|
17
|
-
./lib/bleak_house/ruby.rb
|
18
16
|
./lib/bleak_house/support_methods.rb
|
19
17
|
./lib/bleak_house.rb
|
20
18
|
./patches/gc.c.patch
|
data/README
CHANGED
@@ -7,8 +7,8 @@ A *nix operating system. Windows is not supported.
|
|
7
7
|
|
8
8
|
Gems: 'gruff', 'rmagick', 'active_support', 'RubyInline'
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
You need to compile the bleak_house patched Ruby build. In the
|
11
|
+
plugin directory:
|
12
12
|
rake ruby:build
|
13
13
|
|
14
14
|
USAGE
|
@@ -35,6 +35,10 @@ alongside a different verson of Ruby. You could try to patch your local
|
|
35
35
|
version of Ruby instead, or you could just upgrade to 1.8.6, which has
|
36
36
|
a good trackrecord of stability anyway.
|
37
37
|
|
38
|
+
FURTHER READING
|
39
|
+
|
40
|
+
Please visit: http://blog.evanweaver.com/pages/code#bleak_house
|
41
|
+
|
38
42
|
COPYRIGHT AND LICENSING
|
39
43
|
|
40
44
|
Copyright (c) 2007 Cloudburst, LLC. See the included LICENSE_AFL
|
data/lib/bleak_house.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
|
2
2
|
if ENV['BLEAK_HOUSE']
|
3
3
|
|
4
|
-
|
4
|
+
# rails
|
5
|
+
require 'dispatcher'
|
5
6
|
|
7
|
+
# logger
|
8
|
+
require 'bleak_house/c'
|
6
9
|
require 'bleak_house/bleak_house'
|
7
|
-
|
10
|
+
|
11
|
+
# overrides
|
8
12
|
require 'bleak_house/dispatcher'
|
9
13
|
require 'bleak_house/action_controller'
|
10
14
|
|
data/lib/bleak_house/analyze.rb
CHANGED
@@ -20,6 +20,7 @@ class BleakHouse
|
|
20
20
|
|
21
21
|
SMOOTHNESS = ENV['SMOOTHNESS'].to_i.zero? ? 1 : ENV['SMOOTHNESS'].to_i
|
22
22
|
MEM_KEY = "memory usage"
|
23
|
+
HEAP_KEY = "heap usage"
|
23
24
|
DIR = "#{RAILS_ROOT}/log/bleak_house/"
|
24
25
|
|
25
26
|
def initialize(data, increments, name)
|
@@ -41,7 +42,12 @@ class BleakHouse
|
|
41
42
|
g.marker_font_size = 14
|
42
43
|
|
43
44
|
@data.map do |key, values|
|
44
|
-
["#{(key.to_s.empty? ? '[Unknown]' : key).gsub(/.*::/, '')} (#{
|
45
|
+
["#{(key.to_s.empty? ? '[Unknown]' : key).gsub(/.*::/, '')} (#{ if
|
46
|
+
[MEM_KEY, HEAP_KEY].include?(key)
|
47
|
+
'relative'
|
48
|
+
else
|
49
|
+
values.to_i.max
|
50
|
+
end })", values] # hax
|
45
51
|
end.sort_by do |key, values|
|
46
52
|
0 - key[/.*?([\d]+)\)$/, 1].to_i
|
47
53
|
end.each do |key, values|
|
@@ -120,22 +126,30 @@ class BleakHouse
|
|
120
126
|
|
121
127
|
# generate initial controller graph
|
122
128
|
puts "entire app"
|
129
|
+
|
123
130
|
controller_data, increments = aggregate(data, //, /^(.*?)($|\/|::::)/)
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
131
|
+
controller_data_without_specials = controller_data.dup
|
132
|
+
controller_data_without_specials.delete(MEM_KEY)
|
133
|
+
controller_data_without_specials.delete(HEAP_KEY)
|
134
|
+
[HEAP_KEY, MEM_KEY].each do |key|
|
135
|
+
# next unless controller_data[key]
|
136
|
+
scale_factor = controller_data_without_specials.values.flatten.to_i.max / controller_data[key].max.to_f * 0.8 rescue 1
|
137
|
+
controller_data[key] = controller_data[key].map{|x| (x * scale_factor).to_i }
|
129
138
|
end
|
130
139
|
Analyze.new(controller_data, increments, "objects by controller").draw
|
131
|
-
|
140
|
+
|
132
141
|
# in each controller, by action
|
133
142
|
controller_data.keys.each do |controller|
|
134
|
-
|
135
|
-
|
143
|
+
# next unless controller == HEAP_KEY
|
144
|
+
@special = [MEM_KEY, HEAP_KEY].include? controller
|
145
|
+
puts(@special ? " #{controller}" : " action for #{controller} controller")
|
136
146
|
Dir.descend(controller) do
|
137
147
|
action_data, increments = aggregate(data, /^#{controller}($|\/|::::)/, /\/(.*?)($|\/|::::)/)
|
138
|
-
Analyze.new(action_data, increments,
|
148
|
+
Analyze.new(action_data, increments, case controller
|
149
|
+
when MEM_KEY then "#{controller} in kilobytes"
|
150
|
+
when HEAP_KEY then "#{controller} in slots"
|
151
|
+
else "objects by action in /#{controller}_controller"
|
152
|
+
end).draw
|
139
153
|
|
140
154
|
# in each action, by object class
|
141
155
|
action_data.keys.each do |action|
|
@@ -146,7 +160,7 @@ class BleakHouse
|
|
146
160
|
/::::(.*)/)
|
147
161
|
Analyze.new(class_data, increments, "objects by class in /#{controller}/#{action}").draw
|
148
162
|
end
|
149
|
-
end unless @
|
163
|
+
end unless @special
|
150
164
|
|
151
165
|
end
|
152
166
|
end
|
@@ -29,16 +29,6 @@ class BleakHouse
|
|
29
29
|
WITH_SPECIALS = false
|
30
30
|
GC = true
|
31
31
|
|
32
|
-
MEMLOGGER =
|
33
|
-
|
34
|
-
require 'bleak_house/c'
|
35
|
-
warn "using C instrumentation"
|
36
|
-
CLogger.new
|
37
|
-
else
|
38
|
-
require 'bleak_house/ruby'
|
39
|
-
warn "using pure Ruby instrumentation"
|
40
|
-
warn "(build the patched binary for speed and accuracy improvements)"
|
41
|
-
RubyLogger.new
|
42
|
-
end
|
43
|
-
|
32
|
+
MEMLOGGER = CLogger.new
|
33
|
+
|
44
34
|
end
|
data/lib/bleak_house/c.rb
CHANGED
@@ -3,11 +3,16 @@ require 'rubygems'
|
|
3
3
|
require 'inline'
|
4
4
|
|
5
5
|
class BleakHouse
|
6
|
-
class CLogger
|
6
|
+
class CLogger
|
7
7
|
|
8
8
|
MAX_UNIQ_TAGS = 1536 # per frame
|
9
9
|
MAX_TAG_LENGTH = 192 # tag plus fully namespaced classname
|
10
10
|
|
11
|
+
def mem_usage
|
12
|
+
a = `ps -o vsz,rss -p #{Process.pid}`.split(/\s+/)[-2..-1].map{|el| el.to_i}
|
13
|
+
[a.first - a.last, a.last]
|
14
|
+
end
|
15
|
+
|
11
16
|
inline do |builder|
|
12
17
|
builder.include '"node.h"' # struct RNode
|
13
18
|
builder.include '"st.h"' # struct st_table
|
@@ -97,8 +102,8 @@ class BleakHouse
|
|
97
102
|
# writes a frame to a file
|
98
103
|
builder.c <<-EOC
|
99
104
|
static void
|
100
|
-
VALUE snapshot(VALUE
|
101
|
-
Check_Type(
|
105
|
+
VALUE snapshot(VALUE logfile, VALUE tag, VALUE _specials) {
|
106
|
+
Check_Type(logfile, T_STRING);
|
102
107
|
Check_Type(tag, T_STRING);
|
103
108
|
|
104
109
|
RVALUE *p, *pend;
|
@@ -106,12 +111,12 @@ class BleakHouse
|
|
106
111
|
|
107
112
|
int specials = RTEST(_specials);
|
108
113
|
|
109
|
-
FILE *obj_log = fopen(StringValueCStr(
|
114
|
+
FILE *obj_log = fopen(StringValueCStr(logfile), "r");
|
110
115
|
int is_new;
|
111
116
|
if (!(is_new = (obj_log == NULL)))
|
112
117
|
fclose(obj_log);
|
113
118
|
|
114
|
-
if ((obj_log = fopen(StringValueCStr(
|
119
|
+
if ((obj_log = fopen(StringValueCStr(logfile), "a+")) == NULL)
|
115
120
|
rb_raise(rb_eRuntimeError, "couldn't open snapshot file");
|
116
121
|
|
117
122
|
if (is_new)
|
@@ -126,6 +131,9 @@ class BleakHouse
|
|
126
131
|
char current_tag[2048];
|
127
132
|
int counts[#{MAX_UNIQ_TAGS}];
|
128
133
|
int current_pos = 0;
|
134
|
+
|
135
|
+
int filled_slots = 0;
|
136
|
+
int free_slots = 0;
|
129
137
|
|
130
138
|
int i, j;
|
131
139
|
for (i = 0; i < rb_gc_heaps_used(); i++) {
|
@@ -133,6 +141,7 @@ class BleakHouse
|
|
133
141
|
pend = p + heaps[i].limit;
|
134
142
|
for (; p < pend; p++) {
|
135
143
|
if (p->as.basic.flags) { /* always 0 for freed objects */
|
144
|
+
filled_slots ++;
|
136
145
|
sprintf(current_tag, "");
|
137
146
|
switch (TYPE(p)) {
|
138
147
|
#{RAW_TYPES.map do |type|
|
@@ -167,10 +176,14 @@ class BleakHouse
|
|
167
176
|
current_pos ++;
|
168
177
|
}
|
169
178
|
}
|
179
|
+
} else {
|
180
|
+
free_slots ++;
|
170
181
|
}
|
171
182
|
}
|
172
183
|
}
|
173
|
-
|
184
|
+
/* fprintf(obj_log, \" :\\"heap usage/ruby heaps\\": %i\\n", rb_gc_heaps_used()); */
|
185
|
+
fprintf(obj_log, \" :\\"heap usage/filled slots\\": %i\\n", filled_slots);
|
186
|
+
fprintf(obj_log, \" :\\"heap usage/free slots\\": %i\\n", free_slots);
|
174
187
|
for (j = 0; j < current_pos; j++) {
|
175
188
|
fprintf(obj_log, " :\\"%s\\": %i\\n", tags[j], counts[j]);
|
176
189
|
}
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: bleak_house
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "
|
7
|
-
date: 2007-05-
|
6
|
+
version: "6"
|
7
|
+
date: 2007-05-12 00:00:00 -04:00
|
8
8
|
summary: BleakHouse is a Rails plugin for finding memory leaks. It tracks ObjectSpace for your entire app, and produces charts of references by controller, by action, and by object class.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -27,7 +27,7 @@ signing_key:
|
|
27
27
|
cert_chain:
|
28
28
|
post_install_message: |+
|
29
29
|
|
30
|
-
Thanks for installing Bleak House
|
30
|
+
Thanks for installing Bleak House 6.
|
31
31
|
|
32
32
|
For each Rails app you want to profile, you will need to add the following
|
33
33
|
rake task in RAILS_ROOT/lib/tasks/bleak_house_tasks.rake to be able to run
|
@@ -60,9 +60,7 @@ files:
|
|
60
60
|
- ./lib/bleak_house/c.rb
|
61
61
|
- ./lib/bleak_house/dispatcher.rb
|
62
62
|
- ./lib/bleak_house/gruff_hacks.rb
|
63
|
-
- ./lib/bleak_house/mem_logger.rb
|
64
63
|
- ./lib/bleak_house/rake_task_redefine_task.rb
|
65
|
-
- ./lib/bleak_house/ruby.rb
|
66
64
|
- ./lib/bleak_house/support_methods.rb
|
67
65
|
- ./lib/bleak_house.rb
|
68
66
|
- ./patches/gc.c.patch
|
@@ -1,15 +0,0 @@
|
|
1
|
-
|
2
|
-
class BleakHouse
|
3
|
-
class MemLogger
|
4
|
-
def snapshot
|
5
|
-
raise "abstract method; please require 'ruby' or 'c'"
|
6
|
-
end
|
7
|
-
|
8
|
-
def mem_usage
|
9
|
-
a = `ps -o vsz,rss -p #{Process.pid}`.split(/\s+/)[-2..-1].map{|el| el.to_i}
|
10
|
-
[a.first - a.last, a.last]
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
data/lib/bleak_house/ruby.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'yaml'
|
3
|
-
|
4
|
-
class BleakHouse
|
5
|
-
class RubyLogger < MemLogger
|
6
|
-
SWAP = :"memory usage/swap"
|
7
|
-
RSS = :"memory usage/real"
|
8
|
-
SEEN = {}
|
9
|
-
CURRENT = {}
|
10
|
-
TAGS = Hash.new(0)
|
11
|
-
|
12
|
-
def snapshot(path, tag, _specials)
|
13
|
-
CURRENT.clear
|
14
|
-
ObjectSpace.each_object do |obj|
|
15
|
-
CURRENT[obj_id = obj._bleak_house_object_id] = true
|
16
|
-
unless SEEN[obj_id]
|
17
|
-
# symbols will rapidly stabilize
|
18
|
-
SEEN[obj_id] = "#{tag}::::#{obj._bleak_house_class}".to_sym
|
19
|
-
TAGS[SEEN[obj_id]] += 1
|
20
|
-
end
|
21
|
-
end
|
22
|
-
SEEN.keys.each do |obj_id|
|
23
|
-
TAGS[SEEN.delete(obj_id)] -= 1 unless CURRENT[obj_id]
|
24
|
-
end
|
25
|
-
CURRENT.clear
|
26
|
-
|
27
|
-
TAGS[SWAP], TAGS[RSS] = mem_usage
|
28
|
-
|
29
|
-
write(path)
|
30
|
-
end
|
31
|
-
|
32
|
-
def write(path)
|
33
|
-
exists = File.exist? path
|
34
|
-
File.open(path, 'a+') do |log|
|
35
|
-
dump = YAML.dump([[Time.now.to_i, TAGS]])
|
36
|
-
log.write(exists ? dump[5..-1] : dump)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
class Object
|
44
|
-
alias :_bleak_house_object_id :object_id
|
45
|
-
alias :_bleak_house_class :class
|
46
|
-
end
|