bleak_house 3.0.1 → 3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -26
- data/Manifest +18 -30
- data/README +13 -66
- data/Rakefile +56 -63
- data/init.rb +1 -2
- data/install.rb +1 -2
- data/lib/bleak_house/{rails/action_controller.rb → action_controller.rb} +2 -3
- data/lib/bleak_house/analyze.rb +139 -0
- data/lib/bleak_house/bleak_house.rb +33 -0
- data/lib/bleak_house/dispatcher.rb +23 -0
- data/lib/bleak_house/gruff_hacks.rb +56 -0
- data/lib/bleak_house/mem_logger.rb +54 -0
- data/lib/bleak_house/{support/rake.rb → rake_task_redefine_task.rb} +0 -0
- data/lib/bleak_house/{support/core_extensions.rb → support_methods.rb} +0 -23
- data/lib/bleak_house.rb +10 -4
- data/tasks/bleak_house_tasks.rake +13 -0
- metadata +50 -77
- data/LICENSE_BSD +0 -10
- data/LICENSE_RUBY +0 -53
- data/TODO +0 -2
- data/bin/bleak +0 -10
- data/ext/bleak_house/logger/extconf.rb +0 -4
- data/ext/bleak_house/logger/snapshot.c +0 -153
- data/ext/bleak_house/logger/snapshot.h +0 -99
- data/lib/bleak_house/analyzer/analyzer.rb +0 -143
- data/lib/bleak_house/analyzer.rb +0 -5
- data/lib/bleak_house/logger/mem_usage.rb +0 -13
- data/lib/bleak_house/logger.rb +0 -3
- data/lib/bleak_house/rails/bleak_house.rb +0 -58
- data/lib/bleak_house/rails/dispatcher.rb +0 -19
- data/lib/bleak_house/rails.rb +0 -6
- data/lib/vendor/lightcsv.rb +0 -168
- data/patches/gc.c.patch +0 -27
- data/patches/parse.y.patch +0 -16
- data/test/misc/direct.rb +0 -13
- data/test/unit/test_bleak_house.rb +0 -34
- data.tar.gz.sig +0 -3
- metadata.gz.sig +0 -0
data/lib/bleak_house.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
if ENV['BLEAK_HOUSE']
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
require 'dispatcher' # rails
|
5
|
+
|
6
|
+
require 'bleak_house/bleak_house'
|
7
|
+
require 'bleak_house/mem_logger'
|
8
|
+
require 'bleak_house/dispatcher'
|
9
|
+
require 'bleak_house/action_controller'
|
10
|
+
|
11
|
+
BleakHouse.warn "enabled (log/#{RAILS_ENV}_bleak_house.log) (#{BleakHouse.log_interval} requests per frame)"
|
12
|
+
|
7
13
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
namespace :bleak_house do
|
3
|
+
desc 'Analyze and chart all data'
|
4
|
+
task :analyze do
|
5
|
+
begin
|
6
|
+
require "#{File.dirname(__FILE__)}/../lib/bleak_house/analyze"
|
7
|
+
rescue LoadError
|
8
|
+
require 'bleak_house/analyze'
|
9
|
+
end
|
10
|
+
BleakHouse::Analyze.build_all("#{RAILS_ROOT}/log/bleak_house_#{RAILS_ENV}.dump")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
metadata
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.
|
2
|
+
rubygems_version: 0.9.2
|
3
3
|
specification_version: 1
|
4
4
|
name: bleak_house
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 3.
|
7
|
-
date: 2007-
|
8
|
-
summary:
|
6
|
+
version: "3.1"
|
7
|
+
date: 2007-05-01 00:00:00 -04:00
|
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
|
11
|
-
|
12
|
-
|
13
|
-
homepage: http://blog.evanweaver.com/files/doc/fauna/bleak_house/
|
11
|
+
email: evan at cloudbur dot st
|
12
|
+
homepage: http://blog.evanweaver.com
|
14
13
|
rubyforge_project: fauna
|
15
|
-
description:
|
14
|
+
description: 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.
|
16
15
|
autorequire:
|
17
16
|
default_executable:
|
18
17
|
bindir: bin
|
@@ -26,81 +25,55 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
26
25
|
platform: ruby
|
27
26
|
signing_key:
|
28
27
|
cert_chain:
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
hIPfLqCyxsn/YgOGvo6iwyQTWyTswamaAC3HRWZxIS1sfn/Ssqa7E7oQMkv5FAXr
|
47
|
-
x5rKePfXINf8XTJczkl9OBEYdE9aNdJsJpXD0asLgGVwBICS5Bjohp6mizJcDC1+
|
48
|
-
yZ0=
|
49
|
-
-----END CERTIFICATE-----
|
50
|
-
|
51
|
-
post_install_message:
|
28
|
+
post_install_message: |+
|
29
|
+
|
30
|
+
Thanks for installing Bleak House 3.1.
|
31
|
+
|
32
|
+
For each Rails app you want to profile, you will need to add the following
|
33
|
+
rake task in RAILS_ROOT/lib/tasks/bleak_house_tasks.rake to be able to run
|
34
|
+
the analyzer:
|
35
|
+
|
36
|
+
namespace :bleak_house do
|
37
|
+
desc 'Analyze and chart all data'
|
38
|
+
task :analyze do
|
39
|
+
require 'bleak_house/analyze'
|
40
|
+
BleakHouse::Analyze.build_all("#{RAILS_ROOT}/log/bleak_house_#{RAILS_ENV}.dump")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
52
45
|
authors:
|
53
46
|
- Evan Weaver
|
54
47
|
files:
|
55
|
-
-
|
56
|
-
-
|
57
|
-
-
|
58
|
-
- README
|
59
|
-
- Rakefile
|
60
|
-
-
|
61
|
-
-
|
62
|
-
-
|
63
|
-
-
|
64
|
-
-
|
65
|
-
-
|
66
|
-
- lib/
|
67
|
-
- lib/bleak_house.rb
|
68
|
-
- lib/bleak_house/
|
69
|
-
- lib/bleak_house/
|
70
|
-
- lib/bleak_house/
|
71
|
-
- lib/bleak_house
|
72
|
-
-
|
73
|
-
|
74
|
-
|
75
|
-
- lib/bleak_house/logger/mem_usage.rb
|
76
|
-
- lib/bleak_house/analyzer.rb
|
77
|
-
- lib/bleak_house/analyzer/analyzer.rb
|
78
|
-
- install.rb
|
79
|
-
- init.rb
|
80
|
-
- ext/bleak_house/logger/snapshot.h
|
81
|
-
- ext/bleak_house/logger/snapshot.c
|
82
|
-
- ext/bleak_house/logger/extconf.rb
|
83
|
-
- CHANGELOG
|
84
|
-
- bin/bleak
|
85
|
-
test_files:
|
86
|
-
- test/unit/test_bleak_house.rb
|
48
|
+
- ./CHANGELOG
|
49
|
+
- ./LICENSE
|
50
|
+
- ./Manifest
|
51
|
+
- ./README
|
52
|
+
- ./Rakefile
|
53
|
+
- ./init.rb
|
54
|
+
- ./install.rb
|
55
|
+
- ./lib/bleak_house
|
56
|
+
- ./lib/bleak_house/action_controller.rb
|
57
|
+
- ./lib/bleak_house/analyze.rb
|
58
|
+
- ./lib/bleak_house/bleak_house.rb
|
59
|
+
- ./lib/bleak_house/dispatcher.rb
|
60
|
+
- ./lib/bleak_house/gruff_hacks.rb
|
61
|
+
- ./lib/bleak_house/mem_logger.rb
|
62
|
+
- ./lib/bleak_house/rake_task_redefine_task.rb
|
63
|
+
- ./lib/bleak_house/support_methods.rb
|
64
|
+
- ./lib/bleak_house.rb
|
65
|
+
- ./tasks/bleak_house_tasks.rake
|
66
|
+
test_files: []
|
67
|
+
|
87
68
|
rdoc_options: []
|
88
69
|
|
89
70
|
extra_rdoc_files: []
|
90
71
|
|
91
|
-
executables:
|
92
|
-
|
93
|
-
extensions:
|
94
|
-
|
72
|
+
executables: []
|
73
|
+
|
74
|
+
extensions: []
|
75
|
+
|
95
76
|
requirements: []
|
96
77
|
|
97
|
-
dependencies:
|
98
|
-
|
99
|
-
name: rake
|
100
|
-
version_requirement:
|
101
|
-
version_requirements: !ruby/object:Gem::Version::Requirement
|
102
|
-
requirements:
|
103
|
-
- - ">"
|
104
|
-
- !ruby/object:Gem::Version
|
105
|
-
version: 0.0.0
|
106
|
-
version:
|
78
|
+
dependencies: []
|
79
|
+
|
data/LICENSE_BSD
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
|
2
|
-
Copyright 2006, Eric Hodel. All rights reserved.
|
3
|
-
|
4
|
-
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
5
|
-
|
6
|
-
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
7
|
-
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
8
|
-
3. Neither the names of the authors nor the names of their contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
9
|
-
|
10
|
-
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS?? AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/LICENSE_RUBY
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
$BK\%W%m%0%i%`$O%U%j!<%=%U%H%&%'%"$G$9!%(BGPL(the GNU General
|
2
|
-
Public License)$B$^$?$O0J2<$K<($9>r7o$GK\%W%m%0%i%`$r:FG[I[$G(B
|
3
|
-
$B$-$^$9!%(BGPL$B$K$D$$$F$O(BCOPYING.txt$B%U%!%$%k$r;2>H$7$F2<$5$$!%(B
|
4
|
-
|
5
|
-
1. $BJ#@=$O@)8B$J$/<+M3$G$9!%(B
|
6
|
-
|
7
|
-
2. $B0J2<$N>r7o$N$$$:$l$+$rK~$?$9;~$KK\%W%m%0%i%`$N%=!<%9$r(B
|
8
|
-
$B<+M3$KJQ99$G$-$^$9!%(B
|
9
|
-
|
10
|
-
(a) $B%M%C%H%K%e!<%:$K%]%9%H$7$?$j!$:n<T$KJQ99$rAwIU$9$k(B
|
11
|
-
$B$J$I$NJ}K!$G!$JQ99$r8x3+$9$k!%(B
|
12
|
-
|
13
|
-
(b) $BJQ99$7$?K\%W%m%0%i%`$r<+J,$N=jB0$9$kAH?%FbIt$@$1$G(B
|
14
|
-
$B;H$&!%(B
|
15
|
-
|
16
|
-
(c) $BJQ99E@$rL@<($7$?$&$(!$%=%U%H%&%'%"$NL>A0$rJQ99$9$k!%(B
|
17
|
-
$B$=$N%=%U%H%&%'%"$rG[I[$9$k;~$K$OJQ99A0$NK\%W%m%0%i(B
|
18
|
-
$B%`$bF1;~$KG[I[$9$k!%$^$?$OJQ99A0$NK\%W%m%0%i%`$N%=!<(B
|
19
|
-
$B%9$NF~<jK!$rL@<($9$k!%(B
|
20
|
-
|
21
|
-
(d) $B$=$NB>$NJQ99>r7o$r:n<T$H9g0U$9$k!%(B
|
22
|
-
|
23
|
-
3. $B0J2<$N>r7o$N$$$:$l$+$rK~$?$9;~$KK\%W%m%0%i%`$r%3%s%Q%$(B
|
24
|
-
$B%k$7$?%*%V%8%'%/%H%3!<%I$d<B9T7A<0$G$bG[I[$G$-$^$9!%(B
|
25
|
-
|
26
|
-
(a) $B%P%$%J%j$r<u$1<h$C$??M$,%=!<%9$rF~<j$G$-$k$h$&$K!$(B
|
27
|
-
$B%=!<%9$NF~<jK!$rL@<($9$k!%(B
|
28
|
-
|
29
|
-
(b) $B5!3#2DFI$J%=!<%9%3!<%I$rE:IU$9$k!%(B
|
30
|
-
|
31
|
-
(c) $BJQ99$r9T$C$?%P%$%J%j$OL>A0$rJQ99$7$?$&$(!$%*%j%8%J(B
|
32
|
-
$B%k$N%=!<%9%3!<%I$NF~<jK!$rL@<($9$k!%(B
|
33
|
-
|
34
|
-
(d) $B$=$NB>$NG[I[>r7o$r:n<T$H9g0U$9$k!%(B
|
35
|
-
|
36
|
-
4. $BB>$N%W%m%0%i%`$X$N0zMQ$O$$$+$J$kL\E*$G$"$l<+M3$G$9!%$?(B
|
37
|
-
$B$@$7!$K\%W%m%0%i%`$K4^$^$l$kB>$N:n<T$K$h$k%3!<%I$O!$$=(B
|
38
|
-
$B$l$>$l$N:n<T$N0U8~$K$h$k@)8B$,2C$($i$k>l9g$,$"$j$^$9!%(B
|
39
|
-
|
40
|
-
$B6qBNE*$K$O(Bgc.c($B0lIt(B)$B!$(Butil.c($B0lIt(B)$B!$(Bst.[ch]$B!$(Bregex.[ch]
|
41
|
-
$B$*$h$S(B ./missing$B%G%#%l%/%H%j2<$N%U%!%$%k72$,3:Ev$7$^$9!%(B
|
42
|
-
$B$=$l$>$l$NG[I[>r7o$J$I$KIU$$$F$O3F%U%!%$%k$r;2>H$7$F$/(B
|
43
|
-
$B$@$5$$!%(B
|
44
|
-
|
45
|
-
5. $BK\%W%m%0%i%`$X$NF~NO$H$J$k%9%/%j%W%H$*$h$S!$K\%W%m%0%i(B
|
46
|
-
$B%`$+$i$N=PNO$N8"Mx$OK\%W%m%0%i%`$N:n<T$G$O$J$/!$$=$l$>(B
|
47
|
-
$B$l$NF~=PNO$r@8@.$7$??M$KB0$7$^$9!%$^$?!$K\%W%m%0%i%`$K(B
|
48
|
-
$BAH$_9~$^$l$k$?$a$N3HD%%i%$%V%i%j$K$D$$$F$bF1MM$G$9!%(B
|
49
|
-
|
50
|
-
6. $BK\%W%m%0%i%`$OL5J]>Z$G$9!%:n<T$OK\%W%m%0%i%`$r%5%]!<%H(B
|
51
|
-
$B$9$k0U;V$O$"$j$^$9$,!$%W%m%0%i%`<+?H$N%P%0$"$k$$$OK\%W(B
|
52
|
-
$B%m%0%i%`$N<B9T$J$I$+$iH/@8$9$k$$$+$J$kB;32$KBP$7$F$b@U(B
|
53
|
-
$BG$$r;}$A$^$;$s!%(B
|
data/TODO
DELETED
data/bin/bleak
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
|
2
|
-
#include "snapshot.h"
|
3
|
-
|
4
|
-
static VALUE rb_mBleakHouse;
|
5
|
-
static VALUE rb_cC;
|
6
|
-
|
7
|
-
/* Number of struct heaps_slots used */
|
8
|
-
static VALUE heaps_used(VALUE self) {
|
9
|
-
return INT2FIX(rb_gc_heaps_used());
|
10
|
-
}
|
11
|
-
|
12
|
-
/* Length of the struct heaps_slots allocated */
|
13
|
-
static VALUE heaps_length(VALUE self) {
|
14
|
-
return INT2FIX(rb_gc_heaps_length());
|
15
|
-
}
|
16
|
-
|
17
|
-
/* Count the live objects on the heap and in the symbol table and write a CSV frame to <tt>_logfile</tt>. Set <tt>_specials = true</tt> if you also want to count AST nodes and var scopes; otherwise, use <tt>false</tt>. Note that common classes in the CSV output are hashed to small integers in order to save space.*/
|
18
|
-
static VALUE snapshot(VALUE self, VALUE _logfile, VALUE tag, VALUE _specials) {
|
19
|
-
Check_Type(_logfile, T_STRING);
|
20
|
-
Check_Type(tag, T_STRING);
|
21
|
-
|
22
|
-
RVALUE *obj, *obj_end;
|
23
|
-
st_table_entry *sym, *sym_end;
|
24
|
-
|
25
|
-
struct heaps_slot * heaps = rb_gc_heap_slots();
|
26
|
-
struct st_table * sym_tbl = rb_parse_sym_tbl();
|
27
|
-
|
28
|
-
int specials = RTEST(_specials);
|
29
|
-
int hashed;
|
30
|
-
|
31
|
-
/* see if the logfile exists already */
|
32
|
-
FILE *logfile = fopen(StringValueCStr(_logfile), "r");
|
33
|
-
int is_new;
|
34
|
-
if (!(is_new = (logfile == NULL)))
|
35
|
-
fclose(logfile);
|
36
|
-
|
37
|
-
/* reopen for writing */
|
38
|
-
if ((logfile = fopen(StringValueCStr(_logfile), "a+")) == NULL)
|
39
|
-
rb_raise(rb_eRuntimeError, "couldn't open snapshot file");
|
40
|
-
|
41
|
-
/* write the time */
|
42
|
-
fprintf(logfile, "-1,%i\n", time(0));
|
43
|
-
|
44
|
-
/* get and write the memory usage */
|
45
|
-
VALUE mem = rb_funcall(self, rb_intern("mem_usage"), 0);
|
46
|
-
fprintf(logfile, "-2,%i\n", NUM2INT(RARRAY_PTR(mem)[0]));
|
47
|
-
fprintf(logfile, "-3,%i\n", NUM2INT(RARRAY_PTR(mem)[1]));
|
48
|
-
|
49
|
-
int current_pos = 0;
|
50
|
-
int filled_slots = 0;
|
51
|
-
int free_slots = 0;
|
52
|
-
|
53
|
-
/* write the tag header */
|
54
|
-
fprintf(logfile, "-4,%s\n", StringValueCStr(tag));
|
55
|
-
|
56
|
-
int i, j;
|
57
|
-
|
58
|
-
/* walk the heap */
|
59
|
-
for (i = 0; i < rb_gc_heaps_used(); i++) {
|
60
|
-
obj = heaps[i].slot;
|
61
|
-
obj_end = obj + heaps[i].limit;
|
62
|
-
for (; obj < obj_end; obj++) {
|
63
|
-
if (obj->as.basic.flags) { /* always 0 for freed objects */
|
64
|
-
filled_slots ++;
|
65
|
-
switch (TYPE(obj)) {
|
66
|
-
case T_NONE:
|
67
|
-
hashed = BUILTINS_SIZE + 0; break;
|
68
|
-
case T_BLKTAG:
|
69
|
-
hashed = BUILTINS_SIZE + 1; break;
|
70
|
-
case T_UNDEF:
|
71
|
-
hashed = BUILTINS_SIZE + 2; break;
|
72
|
-
case T_VARMAP:
|
73
|
-
hashed = BUILTINS_SIZE + 3; break;
|
74
|
-
case T_SCOPE:
|
75
|
-
hashed = BUILTINS_SIZE + 4; break;
|
76
|
-
case T_NODE:
|
77
|
-
hashed = BUILTINS_SIZE + 5; break;
|
78
|
-
default:
|
79
|
-
if (!obj->as.basic.klass) {
|
80
|
-
hashed = BUILTINS_SIZE + 6;
|
81
|
-
} else {
|
82
|
-
hashed = lookup_builtin(rb_obj_classname((VALUE)obj));
|
83
|
-
}
|
84
|
-
}
|
85
|
-
/* write to log */
|
86
|
-
if (hashed < 0) {
|
87
|
-
/* regular classname */
|
88
|
-
fprintf(logfile, "%s,%lu\n", rb_obj_classname((VALUE)obj), FIX2ULONG(rb_obj_id((VALUE)obj)));
|
89
|
-
} else {
|
90
|
-
/* builtins key */
|
91
|
-
if (specials || hashed < BUILTINS_SIZE) {
|
92
|
-
/* 0 is not used for 'hashed' because Ruby's to_i turns any String into 0 */
|
93
|
-
fprintf(logfile, "%i,%lu\n", hashed + 1, FIX2ULONG(rb_obj_id((VALUE)obj)));
|
94
|
-
}
|
95
|
-
}
|
96
|
-
} else {
|
97
|
-
free_slots ++;
|
98
|
-
}
|
99
|
-
}
|
100
|
-
}
|
101
|
-
|
102
|
-
/* walk the symbol table */
|
103
|
-
hashed = lookup_builtin("Symbol");
|
104
|
-
for (i = 0; i < sym_tbl->num_bins; i++) {
|
105
|
-
for (sym = sym_tbl->bins[i]; sym != 0; sym = sym->next) {
|
106
|
-
fprintf(logfile, "%i,%lu\n", hashed + 1, sym->record);
|
107
|
-
}
|
108
|
-
}
|
109
|
-
|
110
|
-
fprintf(logfile, "-5,%i\n", filled_slots);
|
111
|
-
fprintf(logfile, "-6,%i\n", free_slots);
|
112
|
-
fclose(logfile);
|
113
|
-
|
114
|
-
rb_funcall(rb_mGC, rb_intern("start"), 0); /* request GC run */
|
115
|
-
return Qtrue;
|
116
|
-
}
|
117
|
-
|
118
|
-
int lookup_builtin(char * name) {
|
119
|
-
int i;
|
120
|
-
for (i = 0; i < BUILTINS_SIZE; i++) {
|
121
|
-
if (!strcmp(builtins[i], name)) return i;
|
122
|
-
}
|
123
|
-
return -1;
|
124
|
-
}
|
125
|
-
|
126
|
-
/*
|
127
|
-
|
128
|
-
This class performs the actual object logging of BleakHouse. To use it directly, you need to make calls to BleakHouse::Logger#snapshot.
|
129
|
-
|
130
|
-
== Example
|
131
|
-
|
132
|
-
At the start of your app, put:
|
133
|
-
require 'rubygems'
|
134
|
-
require 'bleak_house'
|
135
|
-
$memlogger = BleakHouse::Logger.new
|
136
|
-
File.delete($logfile = "/path/to/logfile") rescue nil
|
137
|
-
|
138
|
-
Now, at the points of interest, put:
|
139
|
-
$memlogger.snapshot($logfile, "tag/subtag", false)
|
140
|
-
|
141
|
-
Run your app. Once you are done, analyze your data:
|
142
|
-
bleak /path/to/logfile
|
143
|
-
|
144
|
-
*/
|
145
|
-
void
|
146
|
-
Init_snapshot()
|
147
|
-
{
|
148
|
-
rb_mBleakHouse = rb_define_module("BleakHouse");
|
149
|
-
rb_cC = rb_define_class_under(rb_mBleakHouse, "Logger", rb_cObject);
|
150
|
-
rb_define_method(rb_cC, "snapshot", snapshot, 3);
|
151
|
-
rb_define_method(rb_cC, "heaps_used", heaps_used, 0);
|
152
|
-
rb_define_method(rb_cC, "heaps_length", heaps_length, 0);
|
153
|
-
}
|
@@ -1,99 +0,0 @@
|
|
1
|
-
#include "ruby.h"
|
2
|
-
#include "env.h"
|
3
|
-
#include "node.h"
|
4
|
-
#include "st.h"
|
5
|
-
#include "re.h"
|
6
|
-
#include "util.h"
|
7
|
-
#include "intern.h"
|
8
|
-
#include "string.h"
|
9
|
-
|
10
|
-
/* Histogram of most common Rails classes */
|
11
|
-
static char * builtins[] = {
|
12
|
-
"String",
|
13
|
-
"Array",
|
14
|
-
"Hash",
|
15
|
-
"Class",
|
16
|
-
"Regexp",
|
17
|
-
"Proc",
|
18
|
-
"ActionController::Routing::DividerSegment",
|
19
|
-
"Gem::Version",
|
20
|
-
"Gem::Version::Requirement",
|
21
|
-
"Bignum",
|
22
|
-
"Symbol",
|
23
|
-
"Time",
|
24
|
-
"MatchData",
|
25
|
-
"Gem::Specification",
|
26
|
-
"ActionController::Routing::StaticSegment",
|
27
|
-
"Gem::Dependency",
|
28
|
-
"Module",
|
29
|
-
"ActionController::Routing::DynamicSegment",
|
30
|
-
"Range",
|
31
|
-
"ActionController::Routing::Route",
|
32
|
-
"Float",
|
33
|
-
"HashWithIndifferentAccess",
|
34
|
-
"Method",
|
35
|
-
"Enumerable",
|
36
|
-
"Comparable",
|
37
|
-
"Set",
|
38
|
-
"File",
|
39
|
-
"Object",
|
40
|
-
"NameError",
|
41
|
-
"Thread",
|
42
|
-
"_node",
|
43
|
-
"_none",
|
44
|
-
"_blktag",
|
45
|
-
"_undef",
|
46
|
-
"_varmap",
|
47
|
-
"_scope",
|
48
|
-
"_unknown"
|
49
|
-
};
|
50
|
-
|
51
|
-
#define BUILTINS_SIZE 30
|
52
|
-
#define SPECIALS_SIZE 7
|
53
|
-
|
54
|
-
typedef struct RVALUE {
|
55
|
-
union {
|
56
|
-
struct {
|
57
|
-
unsigned long flags; /* always 0 for freed obj */
|
58
|
-
struct RVALUE *next;
|
59
|
-
} free;
|
60
|
-
struct RBasic basic;
|
61
|
-
struct RObject object;
|
62
|
-
struct RClass klass;
|
63
|
-
struct RFloat flonum;
|
64
|
-
struct RString string;
|
65
|
-
struct RArray array;
|
66
|
-
struct RRegexp regexp;
|
67
|
-
struct RHash hash;
|
68
|
-
struct RData data;
|
69
|
-
struct RStruct rstruct;
|
70
|
-
struct RBignum bignum;
|
71
|
-
struct RFile file;
|
72
|
-
struct RNode node;
|
73
|
-
struct RMatch match;
|
74
|
-
struct RVarmap varmap;
|
75
|
-
struct SCOPE scope;
|
76
|
-
} as;
|
77
|
-
} RVALUE;
|
78
|
-
|
79
|
-
struct heaps_slot {
|
80
|
-
void *membase;
|
81
|
-
RVALUE *slot;
|
82
|
-
int limit;
|
83
|
-
};
|
84
|
-
|
85
|
-
typedef struct st_table_entry st_table_entry;
|
86
|
-
|
87
|
-
struct st_table_entry {
|
88
|
-
unsigned int hash;
|
89
|
-
st_data_t key;
|
90
|
-
st_data_t record;
|
91
|
-
st_table_entry *next;
|
92
|
-
};
|
93
|
-
|
94
|
-
struct st_table * rb_parse_sym_tbl();
|
95
|
-
struct heaps_slot * rb_gc_heap_slots();
|
96
|
-
int rb_gc_heaps_used();
|
97
|
-
int rb_gc_heaps_length();
|
98
|
-
|
99
|
-
int lookup_builtin(char *);
|
@@ -1,143 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rubygems'
|
3
|
-
require 'fileutils'
|
4
|
-
require 'yaml'
|
5
|
-
require 'pp'
|
6
|
-
require 'ruby-debug'
|
7
|
-
|
8
|
-
module BleakHouse
|
9
|
-
|
10
|
-
class Analyzer
|
11
|
-
|
12
|
-
MAGIC_KEYS = {
|
13
|
-
-1 => 'timestamp',
|
14
|
-
-2 => 'mem usage/swap',
|
15
|
-
-3 => 'mem usage/real',
|
16
|
-
-4 => 'tag',
|
17
|
-
-5 => 'heap/filled',
|
18
|
-
-6 => 'heap/free'
|
19
|
-
}
|
20
|
-
|
21
|
-
CLASS_KEYS = eval('[nil, ' + # skip 0
|
22
|
-
open(
|
23
|
-
File.dirname(__FILE__) + '/../../../ext/bleak_house/logger/snapshot.h'
|
24
|
-
).read[/\{(.*?)\}/m, 1] + ']')
|
25
|
-
|
26
|
-
# Parses and correlates a BleakHouse::Logger output file.
|
27
|
-
def self.run(logfile)
|
28
|
-
unless File.exists? logfile
|
29
|
-
puts "No data file found: #{logfile}"
|
30
|
-
exit
|
31
|
-
end
|
32
|
-
|
33
|
-
frames = []
|
34
|
-
last_population = []
|
35
|
-
frame = nil
|
36
|
-
ix = nil
|
37
|
-
|
38
|
-
puts "Examining objects"
|
39
|
-
|
40
|
-
LightCsv.foreach(logfile) do |row|
|
41
|
-
|
42
|
-
# Stupid is fast
|
43
|
-
row[0] = row[0].to_i if row[0].to_i != 0
|
44
|
-
row[1] = row[1].to_i if row[1].to_i != 0
|
45
|
-
|
46
|
-
if row[0].to_i < 0
|
47
|
-
# Get frame meta-information
|
48
|
-
if MAGIC_KEYS[row[0]] == 'timestamp'
|
49
|
-
|
50
|
-
# The frame has ended; process the last one
|
51
|
-
if frame
|
52
|
-
population = frame['objects'].keys
|
53
|
-
births = population - last_population
|
54
|
-
deaths = last_population - population
|
55
|
-
last_population = population
|
56
|
-
|
57
|
-
# assign births
|
58
|
-
frame['births'] = frame['objects'].slice(births)
|
59
|
-
|
60
|
-
if final = frames[-2]
|
61
|
-
final['deaths'] = final['objects'].slice(deaths)
|
62
|
-
bsize = final['births'].size
|
63
|
-
dsize = final['deaths'].size
|
64
|
-
final['velocity'] = bsize * 100 / dsize / 100.0
|
65
|
-
puts " Frame #{frames.size - 1} (#{final['meta']['tag]}) finalized: #{bsize} births, #{dsize} deaths, velocity #{final['velocity']}, population #{final['objects'].size}"
|
66
|
-
final.delete 'objects'
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Set up a new frame
|
71
|
-
frame = {}
|
72
|
-
frames << frame
|
73
|
-
frame['objects'] ||= {}
|
74
|
-
frame['meta'] ||= {}
|
75
|
-
|
76
|
-
#puts " Frame #{frames.size} opened"
|
77
|
-
end
|
78
|
-
|
79
|
-
frame['meta'][MAGIC_KEYS[row[0]]] = row[1]
|
80
|
-
else
|
81
|
-
# Assign live objects
|
82
|
-
frame['objects'][row[1]] = row[0]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# See what objects are still laying around
|
87
|
-
population = frames.last['objects'].reject do |key, value|
|
88
|
-
frames.first['births'][key] == value
|
89
|
-
end
|
90
|
-
|
91
|
-
# Remove bogus frames
|
92
|
-
frames = frames[1..-3]
|
93
|
-
|
94
|
-
total_births = frames.inject(0) do |births, frame|
|
95
|
-
births + frame['births'].size
|
96
|
-
end
|
97
|
-
total_deaths = frames.inject(0) do |deaths, frame|
|
98
|
-
deaths + frame['deaths'].size
|
99
|
-
end
|
100
|
-
|
101
|
-
puts "#{total_births} total meaningful births, #{total_deaths} total meaningful deaths.\n\n"
|
102
|
-
|
103
|
-
leakers = {}
|
104
|
-
|
105
|
-
# Find the sources of the leftover objects in the final population
|
106
|
-
population.each do |id, klass|
|
107
|
-
leaker = frames.detect do |frame|
|
108
|
-
frame['births'][id] == klass
|
109
|
-
end
|
110
|
-
if leaker
|
111
|
-
tag = leaker['meta']['tag']
|
112
|
-
klass = CLASS_KEYS[klass] if klass.is_a? Fixnum
|
113
|
-
leakers[tag] ||= Hash.new(0)
|
114
|
-
leakers[tag][klass] += 1
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# Sort
|
119
|
-
leakers = leakers.map do |tag, value|
|
120
|
-
[tag, value.sort_by do |klass, count|
|
121
|
-
-count
|
122
|
-
end]
|
123
|
-
end.sort_by do |tag, value|
|
124
|
-
Hash[*value.flatten].values.inject(0) {|i, v| i - v}
|
125
|
-
end
|
126
|
-
|
127
|
-
puts "Here are your leaks:"
|
128
|
-
leakers.each do |tag, value|
|
129
|
-
puts " #{tag} leaked per request:"
|
130
|
-
requests = frames.select do |frame|
|
131
|
-
frame['meta']['tag'] == tag
|
132
|
-
end.size
|
133
|
-
value.each do |klass, count|
|
134
|
-
count = count/requests
|
135
|
-
puts " #{count} #{klass}" if count > 0
|
136
|
-
end
|
137
|
-
end
|
138
|
-
puts "\nBye"
|
139
|
-
|
140
|
-
end
|
141
|
-
|
142
|
-
end
|
143
|
-
end
|
data/lib/bleak_house/analyzer.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
|
2
|
-
module BleakHouse
|
3
|
-
|
4
|
-
class Logger
|
5
|
-
|
6
|
-
# Returns an array of the running process's real and virtual memory usage, in kilobytes.
|
7
|
-
def mem_usage
|
8
|
-
a = `ps -o vsz,rss -p #{Process.pid}`.split(/\s+/)[-2..-1].map{|el| el.to_i}
|
9
|
-
[a.first - a.last, a.last]
|
10
|
-
end
|
11
|
-
|
12
|
-
end
|
13
|
-
end
|