bleak_house 3.7.1 → 4.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +2 -0
- data/Manifest +12 -66
- data/README +57 -20
- data/TODO +2 -2
- data/bin/bleak +1 -14
- data/bleak_house.gemspec +10 -16
- data/ext/{bleak_house/logger/build_ruby.rb → build_ruby.rb} +17 -7
- data/ext/build_snapshot.rb +4 -0
- data/ext/{bleak_house/logger/extconf.rb → extconf.rb} +1 -1
- data/ext/snapshot.c +157 -0
- data/ext/{bleak_house/logger/snapshot.h → snapshot.h} +2 -45
- data/lib/bleak_house.rb +5 -5
- data/lib/bleak_house/analyzer.rb +24 -2
- data/lib/bleak_house/hook.rb +25 -0
- data/ruby/bleak_house.patch +358 -0
- data/ruby/configure.patch +242 -0
- data/ruby/gc.patch +116 -0
- data/ruby/ruby-1.8.6-p114.tar.bz2 +0 -0
- data/ruby/valgrind.patch +136 -0
- data/test/benchmark/bench.rb +16 -0
- data/test/unit/test_bleak_house.rb +26 -27
- metadata +22 -86
- metadata.gz.sig +0 -0
- data/ext/bleak_house/logger/build_logger.rb +0 -3
- data/ext/bleak_house/logger/snapshot.c +0 -204
- data/init.rb +0 -3
- data/install.rb +0 -2
- data/lib/bleak_house/analyzer/analyzer.rb +0 -358
- data/lib/bleak_house/logger.rb +0 -2
- data/lib/bleak_house/logger/source.rb +0 -21
- data/lib/bleak_house/rails.rb +0 -6
- data/lib/bleak_house/rails/action_controller.rb +0 -17
- data/lib/bleak_house/rails/bleak_house.rb +0 -62
- data/lib/bleak_house/rails/dispatcher.rb +0 -36
- data/lib/bleak_house/support/core_extensions.rb +0 -61
- data/ruby/gc.c.patch +0 -27
- data/ruby/parse.y.patch +0 -16
- data/ruby/ruby-1.8.6-p110.tar.bz2 +0 -0
- data/test/integration/app/README +0 -203
- data/test/integration/app/Rakefile +0 -10
- data/test/integration/app/app/controllers/application.rb +0 -12
- data/test/integration/app/app/controllers/items_controller.rb +0 -6
- data/test/integration/app/app/helpers/application_helper.rb +0 -3
- data/test/integration/app/app/helpers/items_helper.rb +0 -2
- data/test/integration/app/app/views/items/index.rhtml +0 -2
- data/test/integration/app/config/boot.rb +0 -109
- data/test/integration/app/config/database.yml +0 -19
- data/test/integration/app/config/environment.rb +0 -15
- data/test/integration/app/config/environments/development.rb +0 -18
- data/test/integration/app/config/environments/production.rb +0 -19
- data/test/integration/app/config/environments/test.rb +0 -22
- data/test/integration/app/config/initializers/inflections.rb +0 -10
- data/test/integration/app/config/initializers/mime_types.rb +0 -5
- data/test/integration/app/config/routes.rb +0 -35
- data/test/integration/app/doc/README_FOR_APP +0 -2
- data/test/integration/app/public/404.html +0 -30
- data/test/integration/app/public/422.html +0 -30
- data/test/integration/app/public/500.html +0 -30
- data/test/integration/app/public/dispatch.cgi +0 -10
- data/test/integration/app/public/dispatch.fcgi +0 -24
- data/test/integration/app/public/dispatch.rb +0 -10
- data/test/integration/app/public/favicon.ico +0 -0
- data/test/integration/app/public/images/rails.png +0 -0
- data/test/integration/app/public/javascripts/application.js +0 -2
- data/test/integration/app/public/javascripts/controls.js +0 -963
- data/test/integration/app/public/javascripts/dragdrop.js +0 -972
- data/test/integration/app/public/javascripts/effects.js +0 -1120
- data/test/integration/app/public/javascripts/prototype.js +0 -4225
- data/test/integration/app/public/robots.txt +0 -5
- data/test/integration/app/script/about +0 -3
- data/test/integration/app/script/console +0 -3
- data/test/integration/app/script/destroy +0 -3
- data/test/integration/app/script/generate +0 -3
- data/test/integration/app/script/performance/benchmarker +0 -3
- data/test/integration/app/script/performance/profiler +0 -3
- data/test/integration/app/script/performance/request +0 -3
- data/test/integration/app/script/plugin +0 -3
- data/test/integration/app/script/process/inspector +0 -3
- data/test/integration/app/script/process/reaper +0 -3
- data/test/integration/app/script/process/spawner +0 -3
- data/test/integration/app/script/runner +0 -3
- data/test/integration/app/script/server +0 -3
- data/test/integration/app/test/functional/items_controller_test.rb +0 -8
- data/test/integration/app/test/test_helper.rb +0 -38
- data/test/integration/server_test.rb +0 -93
- data/test/misc/direct.rb +0 -13
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG
CHANGED
data/Manifest
CHANGED
@@ -1,77 +1,23 @@
|
|
1
1
|
bin/bleak
|
2
2
|
CHANGELOG
|
3
|
-
ext/
|
4
|
-
ext/
|
5
|
-
ext/
|
6
|
-
ext/
|
7
|
-
ext/
|
8
|
-
init.rb
|
9
|
-
install.rb
|
10
|
-
lib/bleak_house/analyzer/analyzer.rb
|
3
|
+
ext/build_ruby.rb
|
4
|
+
ext/build_snapshot.rb
|
5
|
+
ext/extconf.rb
|
6
|
+
ext/snapshot.c
|
7
|
+
ext/snapshot.h
|
11
8
|
lib/bleak_house/analyzer.rb
|
12
|
-
lib/bleak_house/
|
13
|
-
lib/bleak_house/logger.rb
|
14
|
-
lib/bleak_house/rails/action_controller.rb
|
15
|
-
lib/bleak_house/rails/bleak_house.rb
|
16
|
-
lib/bleak_house/rails/dispatcher.rb
|
17
|
-
lib/bleak_house/rails.rb
|
18
|
-
lib/bleak_house/support/core_extensions.rb
|
9
|
+
lib/bleak_house/hook.rb
|
19
10
|
lib/bleak_house.rb
|
20
11
|
LICENSE
|
21
12
|
LICENSE_BSD
|
22
13
|
Manifest
|
23
14
|
README
|
24
|
-
ruby/
|
25
|
-
ruby/
|
26
|
-
ruby/
|
27
|
-
|
28
|
-
|
29
|
-
test/
|
30
|
-
test/integration/app/app/helpers/items_helper.rb
|
31
|
-
test/integration/app/app/views/items/index.rhtml
|
32
|
-
test/integration/app/config/boot.rb
|
33
|
-
test/integration/app/config/database.yml
|
34
|
-
test/integration/app/config/environment.rb
|
35
|
-
test/integration/app/config/environments/development.rb
|
36
|
-
test/integration/app/config/environments/production.rb
|
37
|
-
test/integration/app/config/environments/test.rb
|
38
|
-
test/integration/app/config/initializers/inflections.rb
|
39
|
-
test/integration/app/config/initializers/mime_types.rb
|
40
|
-
test/integration/app/config/routes.rb
|
41
|
-
test/integration/app/doc/README_FOR_APP
|
42
|
-
test/integration/app/public/404.html
|
43
|
-
test/integration/app/public/422.html
|
44
|
-
test/integration/app/public/500.html
|
45
|
-
test/integration/app/public/dispatch.cgi
|
46
|
-
test/integration/app/public/dispatch.fcgi
|
47
|
-
test/integration/app/public/dispatch.rb
|
48
|
-
test/integration/app/public/favicon.ico
|
49
|
-
test/integration/app/public/images/rails.png
|
50
|
-
test/integration/app/public/javascripts/application.js
|
51
|
-
test/integration/app/public/javascripts/controls.js
|
52
|
-
test/integration/app/public/javascripts/dragdrop.js
|
53
|
-
test/integration/app/public/javascripts/effects.js
|
54
|
-
test/integration/app/public/javascripts/prototype.js
|
55
|
-
test/integration/app/public/robots.txt
|
56
|
-
test/integration/app/Rakefile
|
57
|
-
test/integration/app/README
|
58
|
-
test/integration/app/script/about
|
59
|
-
test/integration/app/script/console
|
60
|
-
test/integration/app/script/destroy
|
61
|
-
test/integration/app/script/generate
|
62
|
-
test/integration/app/script/performance/benchmarker
|
63
|
-
test/integration/app/script/performance/profiler
|
64
|
-
test/integration/app/script/performance/request
|
65
|
-
test/integration/app/script/plugin
|
66
|
-
test/integration/app/script/process/inspector
|
67
|
-
test/integration/app/script/process/reaper
|
68
|
-
test/integration/app/script/process/spawner
|
69
|
-
test/integration/app/script/runner
|
70
|
-
test/integration/app/script/server
|
71
|
-
test/integration/app/test/functional/items_controller_test.rb
|
72
|
-
test/integration/app/test/test_helper.rb
|
73
|
-
test/integration/server_test.rb
|
74
|
-
test/misc/direct.rb
|
15
|
+
ruby/bleak_house.patch
|
16
|
+
ruby/configure.patch
|
17
|
+
ruby/gc.patch
|
18
|
+
ruby/ruby-1.8.6-p114.tar.bz2
|
19
|
+
ruby/valgrind.patch
|
20
|
+
test/benchmark/bench.rb
|
75
21
|
test/test_helper.rb
|
76
22
|
test/unit/test_bleak_house.rb
|
77
23
|
TODO
|
data/README
CHANGED
@@ -14,15 +14,15 @@ If you use this software, please {make a donation}[http://blog.evanweaver.com/do
|
|
14
14
|
== Features
|
15
15
|
|
16
16
|
* leak-proof C instrumentation
|
17
|
-
*
|
18
|
-
*
|
19
|
-
*
|
17
|
+
* minimal impact on runtime performance
|
18
|
+
* fast analysis step
|
19
|
+
* tracks all objects allocated on the heap, including internal types like <tt>T_NODE</tt>
|
20
|
+
* easy integration in any program, not just Rails
|
20
21
|
|
21
22
|
== Requirements
|
22
23
|
|
23
24
|
* A unix-like operating system
|
24
25
|
* Ruby 1.8.6
|
25
|
-
* Rails 1.2.x or 2.0.x
|
26
26
|
|
27
27
|
= Usage
|
28
28
|
|
@@ -35,38 +35,74 @@ The installation takes a long time because it compiles a patched Ruby binary for
|
|
35
35
|
|
36
36
|
Please see the forum ( http://rubyforge.org/forum/forum.php?forum_id=13983 ) if you have installation problems.
|
37
37
|
|
38
|
-
==
|
38
|
+
== Usage
|
39
39
|
|
40
|
-
|
40
|
+
We will profile a Rails app as an example. Note that BleakHouse works equally well in any Ruby program.
|
41
41
|
|
42
|
-
|
43
|
-
|
42
|
+
First, to setup the app for profiling, add the following at the bottom of <tt>config/environment.rb</tt>:
|
43
|
+
require 'bleak_house' if ENV['BLEAK_HOUSE']
|
44
44
|
|
45
|
-
|
45
|
+
Then, to engage the logger (possibly in a live deployment situation), start a server instance as so:
|
46
|
+
RAILS_ENV=production BLEAK_HOUSE=1 ruby-bleak-house ./script/server
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
Look for the message:
|
49
|
+
** Bleakhouse: installed
|
50
|
+
|
51
|
+
Browse around manually, thrash your entire app with a script, target troublesome controllers/actions, etc. After a couple hundred requests, hit CTRL-C. The server will stop and BleakHouse will produce a dumpfile in <tt>/tmp</tt>:
|
51
52
|
|
52
|
-
|
53
|
+
** BleakHouse: working...
|
54
|
+
** BleakHouse: complete
|
55
|
+
** Bleakhouse: run 'bleak /tmp/bleak.5979.0.dump' to analyze.
|
53
56
|
|
54
|
-
|
57
|
+
To analyse it, just run the listed command. The top 20 leakiest lines will be listed:
|
58
|
+
|
59
|
+
191691 total objects
|
60
|
+
Final heap size 191691 filled, 220961 free
|
61
|
+
Displaying top 20 most common line/class pairs
|
62
|
+
89513 __null__:__null__:__node__
|
63
|
+
41438 __null__:__null__:String
|
64
|
+
2348 /opt/local//lib/ruby/site_ruby/1.8/rubygems/specification.rb:557:Array
|
65
|
+
1508 /opt/local//lib/ruby/gems/1.8/specifications/gettext-1.90.0.gemspec:14:String
|
66
|
+
1021 /opt/local//lib/ruby/gems/1.8/specifications/heel-0.2.0.gemspec:14:String
|
67
|
+
951 /opt/local//lib/ruby/site_ruby/1.8/rubygems/version.rb:111:String
|
68
|
+
935 /opt/local//lib/ruby/site_ruby/1.8/rubygems/specification.rb:557:String
|
69
|
+
834 /opt/local//lib/ruby/site_ruby/1.8/rubygems/version.rb:146:Array
|
70
|
+
...
|
71
|
+
|
72
|
+
You can pass an integer as the second parameter to <tt>bleak</tt> if you want to see more lines than the default.
|
55
73
|
|
56
|
-
|
74
|
+
The underscored types are special Ruby internal structs, but can be real leaks just as easily as fullblown classes.
|
75
|
+
|
76
|
+
Do not try to detect Rails leaks in <tt>development</tt> mode. Make a separate <tt>benchmark</tt> environment if you need to, and make sure all your production caching is turned on.
|
57
77
|
|
58
78
|
= Extras
|
59
79
|
|
60
|
-
==
|
80
|
+
== Injecting a signal
|
81
|
+
|
82
|
+
You can send <tt>SIGUSR2</tt> to a BleakHouse-instrumented program to snag a dump at any time. Once the dump completes, the program will continue to run. Dumps are named based on the host process id, and sequential dumps are numbered in ascending order.
|
61
83
|
|
62
|
-
|
84
|
+
== Tips
|
63
85
|
|
64
|
-
|
86
|
+
It is normal to see lots of <tt>null:null</tt> references, especially for nodes. Using <tt>eval()</tt> too much can be a cause of node leaks. You can track <tt>eval()</tt> by using sourceline macros in your code:
|
65
87
|
|
66
|
-
|
88
|
+
eval("CODE", nil, __FILE__, __LINE__)
|
67
89
|
|
68
90
|
You may get library require errors if you install <tt>ruby-bleak-house</tt> 1.8.6 alongside a different verson of Ruby. You could try to patch your local version of Ruby instead, or you could just upgrade to 1.8.6, which has a good trackrecord of stability.
|
69
91
|
|
92
|
+
It is not recommended that you use <tt>ruby-bleak-house</tt> as your production Ruby binary, since it will be slightly slower and use slightly more memory. It is unlikely, however, to affect stability.
|
93
|
+
|
94
|
+
If BleakHouse doesn't report any heap growth but you still have memory growth, you might have a broken C extension, or have encounted a {real leak in the interpreter}[http://groups.google.com/group/god-rb/browse_thread/thread/1cca2b7c4]. Try using Valgrind[http://blog.evanweaver.com/articles/2008/02/05/valgrind-and-ruby/] instead.
|
95
|
+
|
96
|
+
== Methods
|
97
|
+
|
98
|
+
The easiest way to fix a leak is to make it repeatable.
|
99
|
+
|
100
|
+
First, write a script that exercises your app in a deterministic way. Run it for a small number of loops; then run <tt>bleak</tt>. Then run it for a larger number of loops, and run <tt>bleak</tt> again. The lines that grow significantly between runs are your leaks for that codepath.
|
101
|
+
|
102
|
+
Now, look at those lines in the source and try to figure out what references them. Where do the return values go? Add some breakpoints or output backtraces to <tt>STDERR</tt> as you go. Eventually you should find a point where it is relatively clear that a reference is getting maintained.
|
103
|
+
|
104
|
+
Try to remove that reference, run your script again, and see if the object counts have dropped.
|
105
|
+
|
70
106
|
== Reporting problems
|
71
107
|
|
72
108
|
The support forum is here[http://rubyforge.org/forum/forum.php?forum_id=13983].
|
@@ -75,6 +111,7 @@ Patches and contributions are very welcome. Please note that contributors are re
|
|
75
111
|
|
76
112
|
== Further resources
|
77
113
|
|
114
|
+
* http://blog.evanweaver.com/articles/2008/02/05/valgrind-and-ruby/
|
78
115
|
* http://blog.evanweaver.com/articles/2007/05/12/let-me-hit-you-with-some-knowledge
|
79
116
|
* http://blog.evanweaver.com/articles/2007/05/06/leak-proof-direct-heap-instrumentation-for-bleak_house
|
80
117
|
* http://blog.evanweaver.com/articles/2007/04/28/bleak_house
|
data/TODO
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
|
2
|
-
*
|
3
|
-
*
|
2
|
+
* Add some kind of delta support
|
3
|
+
* Log several levels of the backtrace instead of just the current node's information
|
data/bin/bleak
CHANGED
@@ -8,19 +8,6 @@ if !ARGV[0]
|
|
8
8
|
else
|
9
9
|
$LOAD_PATH << "#{File.dirname(__FILE__)}/../lib/"
|
10
10
|
require 'bleak_house/analyzer'
|
11
|
-
|
12
11
|
require 'ruby-debug' if ENV['DEBUG']
|
13
|
-
|
14
|
-
if ENV['WATCH_MEM']
|
15
|
-
Thread.new do
|
16
|
-
while sleep(10)
|
17
|
-
free = `free -m`.split("\n")[2].split(" ")[3].to_i
|
18
|
-
if free < 20
|
19
|
-
exit!
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
BleakHouse::Analyzer.run(ARGV[0])
|
12
|
+
BleakHouse::Analyzer.run(ARGV[0], ARGV[1] || 20)
|
26
13
|
end
|
data/bleak_house.gemspec
CHANGED
@@ -1,33 +1,31 @@
|
|
1
1
|
|
2
|
-
# Gem::Specification for Bleak_house-
|
2
|
+
# Gem::Specification for Bleak_house-4.0
|
3
3
|
# Originally generated by Echoe
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = %q{bleak_house}
|
7
|
-
s.version = "
|
7
|
+
s.version = "4.0"
|
8
8
|
|
9
9
|
s.specification_version = 2 if s.respond_to? :specification_version=
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.authors = ["Evan Weaver"]
|
13
|
-
s.date = %q{2008-
|
13
|
+
s.date = %q{2008-04-06}
|
14
14
|
s.default_executable = %q{bleak}
|
15
15
|
s.description = %q{A library for finding memory leaks.}
|
16
16
|
s.email = %q{}
|
17
17
|
s.executables = ["bleak"]
|
18
|
-
s.extensions = ["ext/
|
19
|
-
s.extra_rdoc_files = ["CHANGELOG", "ext/
|
20
|
-
s.files = ["bin/bleak", "CHANGELOG", "ext/
|
18
|
+
s.extensions = ["ext/extconf.rb"]
|
19
|
+
s.extra_rdoc_files = ["CHANGELOG", "ext/snapshot.c", "lib/bleak_house/analyzer.rb", "lib/bleak_house/hook.rb", "lib/bleak_house.rb", "LICENSE", "LICENSE_BSD", "README", "TODO"]
|
20
|
+
s.files = ["bin/bleak", "CHANGELOG", "ext/build_ruby.rb", "ext/build_snapshot.rb", "ext/extconf.rb", "ext/snapshot.c", "ext/snapshot.h", "lib/bleak_house/analyzer.rb", "lib/bleak_house/hook.rb", "lib/bleak_house.rb", "LICENSE", "LICENSE_BSD", "Manifest", "README", "ruby/bleak_house.patch", "ruby/configure.patch", "ruby/gc.patch", "ruby/ruby-1.8.6-p114.tar.bz2", "ruby/valgrind.patch", "test/benchmark/bench.rb", "test/test_helper.rb", "test/unit/test_bleak_house.rb", "TODO", "bleak_house.gemspec"]
|
21
21
|
s.has_rdoc = true
|
22
22
|
s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/bleak_house/}
|
23
23
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Bleak_house", "--main", "README"]
|
24
24
|
s.require_paths = ["lib", "ext"]
|
25
25
|
s.rubyforge_project = %q{fauna}
|
26
|
-
s.rubygems_version = %q{1.0
|
26
|
+
s.rubygems_version = %q{1.1.0}
|
27
27
|
s.summary = %q{A library for finding memory leaks.}
|
28
|
-
s.test_files = ["test/
|
29
|
-
|
30
|
-
s.add_dependency(%q<ccsv>, [">= 0.1"])
|
28
|
+
s.test_files = ["test/test_helper.rb", "test/unit/test_bleak_house.rb"]
|
31
29
|
end
|
32
30
|
|
33
31
|
|
@@ -42,10 +40,6 @@ end
|
|
42
40
|
# p.summary = "A library for finding memory leaks."
|
43
41
|
# p.url = "http://blog.evanweaver.com/files/doc/fauna/bleak_house/"
|
44
42
|
# p.docs_host = 'blog.evanweaver.com:~/www/bax/public/files/doc/'
|
45
|
-
# p.
|
46
|
-
# p.
|
47
|
-
#
|
48
|
-
# p.rdoc_pattern = /^ext.*\.c|lib.*logger.*rb|analyzer|rails\/bleak_house|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
|
49
|
-
# p.test_pattern = ["test/integration/*.rb", "test/unit/*.rb"]
|
50
|
-
# p.clean_pattern << "**/bleak_house*dump*"
|
43
|
+
# p.require_signed = true
|
44
|
+
# p.rdoc_pattern = /^ext.*\.c|lib.*|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
|
51
45
|
# end
|
@@ -9,7 +9,7 @@ unless RUBY_VERSION == '1.8.6'
|
|
9
9
|
raise "Wrong Ruby version, you're at '#{RUBY_VERSION}', need 1.8.6"
|
10
10
|
end
|
11
11
|
|
12
|
-
source_dir = File.expand_path(File.dirname(__FILE__)) + "
|
12
|
+
source_dir = File.expand_path(File.dirname(__FILE__)) + "/../ruby"
|
13
13
|
tmp = "/tmp/"
|
14
14
|
|
15
15
|
require 'fileutils'
|
@@ -23,30 +23,40 @@ def which(basename)
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
if which('ruby-bleak-house') and
|
27
|
+
`ruby-bleak-house -e "puts RUBY_PATCHLEVEL"`.to_i > 900
|
28
|
+
# OK
|
29
|
+
else
|
30
|
+
# Build
|
28
31
|
Dir.chdir(tmp) do
|
29
32
|
build_dir = "bleak_house"
|
30
33
|
binary_dir = File.dirname(`which ruby`)
|
34
|
+
|
31
35
|
FileUtils.rm_rf(build_dir) rescue nil
|
36
|
+
if File.exist? build_dir
|
37
|
+
raise "Could not delete previous build dir #{Dir.pwd}/#{build_dir}"
|
38
|
+
end
|
39
|
+
|
32
40
|
Dir.mkdir(build_dir)
|
33
41
|
|
34
42
|
begin
|
35
43
|
Dir.chdir(build_dir) do
|
36
44
|
|
37
45
|
# Copy Ruby source
|
38
|
-
bz2 = "ruby-1.8.6-
|
46
|
+
bz2 = "ruby-1.8.6-p114.tar.bz2"
|
39
47
|
FileUtils.copy "#{source_dir}/#{bz2}", bz2
|
40
48
|
|
41
49
|
# Extract
|
42
50
|
system("tar xjf #{bz2} > tar.log 2>&1")
|
43
51
|
File.delete bz2
|
44
52
|
|
45
|
-
Dir.chdir("ruby-1.8.6-
|
53
|
+
Dir.chdir("ruby-1.8.6-p114") do
|
46
54
|
|
47
55
|
# Patch, configure, and build
|
48
|
-
|
49
|
-
|
56
|
+
["valgrind", "configure", "gc"].each do |patch|
|
57
|
+
system("patch -p0 < \'#{source_dir}/#{patch}.patch\' > ../#{patch}_patch.log 2>&1")
|
58
|
+
end
|
59
|
+
|
50
60
|
system("./configure --prefix=#{binary_dir[0..-5]} > ../configure.log 2>&1") # --with-static-linked-ext
|
51
61
|
|
52
62
|
# Patch the makefile for arch/sitedir
|
data/ext/snapshot.c
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
#include <time.h>
|
2
|
+
#include "snapshot.h"
|
3
|
+
|
4
|
+
static VALUE rb_mB;
|
5
|
+
static VALUE rb_cC;
|
6
|
+
|
7
|
+
/* Number of filled <tt>heaps_slots</tt> */
|
8
|
+
static VALUE heaps_used(VALUE self) {
|
9
|
+
return INT2FIX(rb_gc_heaps_used());
|
10
|
+
}
|
11
|
+
|
12
|
+
/* Number of allocated <tt>heaps_slots</tt> */
|
13
|
+
static VALUE heaps_length(VALUE self) {
|
14
|
+
return INT2FIX(rb_gc_heaps_length());
|
15
|
+
}
|
16
|
+
|
17
|
+
/* Walk the live, instrumented objects on the heap and write them to <tt>_logfile</tt>. */
|
18
|
+
static VALUE snapshot(VALUE self, VALUE _logfile) {
|
19
|
+
Check_Type(_logfile, T_STRING);
|
20
|
+
|
21
|
+
RVALUE *obj, *obj_end;
|
22
|
+
st_table_entry *sym;
|
23
|
+
|
24
|
+
struct heaps_slot * heaps = rb_gc_heap_slots();
|
25
|
+
struct st_table * sym_tbl = rb_parse_sym_tbl();
|
26
|
+
|
27
|
+
/* see if the logfile exists already */
|
28
|
+
FILE *logfile = fopen(StringValueCStr(_logfile), "r");
|
29
|
+
int is_new;
|
30
|
+
if (!(is_new = (logfile == NULL)))
|
31
|
+
fclose(logfile);
|
32
|
+
|
33
|
+
/* reopen for writing */
|
34
|
+
if ((logfile = fopen(StringValueCStr(_logfile), "w")) == NULL)
|
35
|
+
rb_raise(rb_eRuntimeError, "couldn't open snapshot file");
|
36
|
+
|
37
|
+
int filled_slots = 0;
|
38
|
+
int free_slots = 0;
|
39
|
+
|
40
|
+
int i;
|
41
|
+
char * chr;
|
42
|
+
|
43
|
+
for (i = 0; i < 3; i++) {
|
44
|
+
/* request GC run */
|
45
|
+
rb_funcall(rb_mGC, rb_intern("start"), 0);
|
46
|
+
rb_thread_schedule();
|
47
|
+
}
|
48
|
+
|
49
|
+
/* walk the heap */
|
50
|
+
for (i = 0; i < rb_gc_heaps_used(); i++) {
|
51
|
+
obj = heaps[i].slot;
|
52
|
+
obj_end = obj + heaps[i].limit;
|
53
|
+
for (; obj < obj_end; obj++) {
|
54
|
+
if (obj->as.basic.flags) { /* always 0 for freed objects */
|
55
|
+
filled_slots ++;
|
56
|
+
|
57
|
+
/* write the source file*/
|
58
|
+
if (obj->file) {
|
59
|
+
chr = obj->file;
|
60
|
+
if (*chr != '\0') {
|
61
|
+
/* replace unprintable characters */
|
62
|
+
for (; *chr; chr++) {
|
63
|
+
if ((*chr < 33) || (*chr > 126)) {
|
64
|
+
fputc('_', logfile);
|
65
|
+
} else {
|
66
|
+
fputc(*chr, logfile);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
} else {
|
70
|
+
fprintf(logfile, "__empty__");
|
71
|
+
}
|
72
|
+
} else {
|
73
|
+
fprintf(logfile, "__null__");
|
74
|
+
}
|
75
|
+
|
76
|
+
/* write the source line */
|
77
|
+
fprintf(logfile, ":");
|
78
|
+
if (obj->line) {
|
79
|
+
fprintf(logfile, "%i", obj->line);
|
80
|
+
} else {
|
81
|
+
fprintf(logfile, "__null__");
|
82
|
+
}
|
83
|
+
|
84
|
+
/* write the class */
|
85
|
+
fprintf(logfile, ":");
|
86
|
+
switch (TYPE(obj)) {
|
87
|
+
case T_NONE:
|
88
|
+
fprintf(logfile, "__none__"); break;
|
89
|
+
case T_BLKTAG:
|
90
|
+
fprintf(logfile, "__blktag__"); break;
|
91
|
+
case T_UNDEF:
|
92
|
+
fprintf(logfile, "__undef__"); break;
|
93
|
+
case T_VARMAP:
|
94
|
+
fprintf(logfile, "__varmap__"); break;
|
95
|
+
case T_SCOPE:
|
96
|
+
fprintf(logfile, "__scope__"); break;
|
97
|
+
case T_NODE:
|
98
|
+
fprintf(logfile, "__node__"); break;
|
99
|
+
default:
|
100
|
+
if (!obj->as.basic.klass) {
|
101
|
+
fprintf(logfile, "__unknown__");
|
102
|
+
} else {
|
103
|
+
fprintf(logfile, rb_obj_classname((VALUE)obj));
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
/* write newline */
|
108
|
+
fprintf(logfile, "\n");
|
109
|
+
} else {
|
110
|
+
free_slots ++;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
/* walk the symbol table */
|
116
|
+
/* hashed = lookup_builtin("Symbol");
|
117
|
+
for (i = 0; i < sym_tbl->num_bins; i++) {
|
118
|
+
for (sym = sym_tbl->bins[i]; sym != 0; sym = sym->next) {
|
119
|
+
fprintf(logfile, "%i,%lu\n", hashed + 1, sym->record);
|
120
|
+
}
|
121
|
+
} */
|
122
|
+
|
123
|
+
fprintf(logfile, "%i filled\n", filled_slots);
|
124
|
+
fprintf(logfile, "%i free\n", free_slots);
|
125
|
+
fclose(logfile);
|
126
|
+
|
127
|
+
return Qnil;
|
128
|
+
}
|
129
|
+
|
130
|
+
|
131
|
+
/*
|
132
|
+
|
133
|
+
This class performs the actual object logging of BleakHouse. To use it directly, you need to make calls to BleakHouse.snapshot.
|
134
|
+
|
135
|
+
By default, BleakHouse records a snapshot on exit. You can disable this by setting the environment variable <tt>NO_EXIT_HANDLER</tt> before startup.
|
136
|
+
|
137
|
+
It is also possible to externally trigger the snapshot at any time by sending <tt>SIGUSR2</tt> to the process.
|
138
|
+
|
139
|
+
== Example
|
140
|
+
|
141
|
+
At the start of your app, put:
|
142
|
+
require 'rubygems'
|
143
|
+
require 'bleak_house'
|
144
|
+
$logfile = "/path/to/logfile"
|
145
|
+
|
146
|
+
Run your app. Once it exits, analyze your data:
|
147
|
+
bleak /path/to/logfile
|
148
|
+
|
149
|
+
*/
|
150
|
+
void
|
151
|
+
Init_snapshot()
|
152
|
+
{
|
153
|
+
rb_mB = rb_define_module("BleakHouse");
|
154
|
+
rb_define_singleton_method(rb_mB, "snapshot", snapshot, 1);
|
155
|
+
rb_define_singleton_method(rb_mB, "heaps_used", heaps_used, 0);
|
156
|
+
rb_define_singleton_method(rb_mB, "heaps_length", heaps_length, 0);
|
157
|
+
}
|