bleak_house 3.7.1 → 4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +2 -0
  3. data/Manifest +12 -66
  4. data/README +57 -20
  5. data/TODO +2 -2
  6. data/bin/bleak +1 -14
  7. data/bleak_house.gemspec +10 -16
  8. data/ext/{bleak_house/logger/build_ruby.rb → build_ruby.rb} +17 -7
  9. data/ext/build_snapshot.rb +4 -0
  10. data/ext/{bleak_house/logger/extconf.rb → extconf.rb} +1 -1
  11. data/ext/snapshot.c +157 -0
  12. data/ext/{bleak_house/logger/snapshot.h → snapshot.h} +2 -45
  13. data/lib/bleak_house.rb +5 -5
  14. data/lib/bleak_house/analyzer.rb +24 -2
  15. data/lib/bleak_house/hook.rb +25 -0
  16. data/ruby/bleak_house.patch +358 -0
  17. data/ruby/configure.patch +242 -0
  18. data/ruby/gc.patch +116 -0
  19. data/ruby/ruby-1.8.6-p114.tar.bz2 +0 -0
  20. data/ruby/valgrind.patch +136 -0
  21. data/test/benchmark/bench.rb +16 -0
  22. data/test/unit/test_bleak_house.rb +26 -27
  23. metadata +22 -86
  24. metadata.gz.sig +0 -0
  25. data/ext/bleak_house/logger/build_logger.rb +0 -3
  26. data/ext/bleak_house/logger/snapshot.c +0 -204
  27. data/init.rb +0 -3
  28. data/install.rb +0 -2
  29. data/lib/bleak_house/analyzer/analyzer.rb +0 -358
  30. data/lib/bleak_house/logger.rb +0 -2
  31. data/lib/bleak_house/logger/source.rb +0 -21
  32. data/lib/bleak_house/rails.rb +0 -6
  33. data/lib/bleak_house/rails/action_controller.rb +0 -17
  34. data/lib/bleak_house/rails/bleak_house.rb +0 -62
  35. data/lib/bleak_house/rails/dispatcher.rb +0 -36
  36. data/lib/bleak_house/support/core_extensions.rb +0 -61
  37. data/ruby/gc.c.patch +0 -27
  38. data/ruby/parse.y.patch +0 -16
  39. data/ruby/ruby-1.8.6-p110.tar.bz2 +0 -0
  40. data/test/integration/app/README +0 -203
  41. data/test/integration/app/Rakefile +0 -10
  42. data/test/integration/app/app/controllers/application.rb +0 -12
  43. data/test/integration/app/app/controllers/items_controller.rb +0 -6
  44. data/test/integration/app/app/helpers/application_helper.rb +0 -3
  45. data/test/integration/app/app/helpers/items_helper.rb +0 -2
  46. data/test/integration/app/app/views/items/index.rhtml +0 -2
  47. data/test/integration/app/config/boot.rb +0 -109
  48. data/test/integration/app/config/database.yml +0 -19
  49. data/test/integration/app/config/environment.rb +0 -15
  50. data/test/integration/app/config/environments/development.rb +0 -18
  51. data/test/integration/app/config/environments/production.rb +0 -19
  52. data/test/integration/app/config/environments/test.rb +0 -22
  53. data/test/integration/app/config/initializers/inflections.rb +0 -10
  54. data/test/integration/app/config/initializers/mime_types.rb +0 -5
  55. data/test/integration/app/config/routes.rb +0 -35
  56. data/test/integration/app/doc/README_FOR_APP +0 -2
  57. data/test/integration/app/public/404.html +0 -30
  58. data/test/integration/app/public/422.html +0 -30
  59. data/test/integration/app/public/500.html +0 -30
  60. data/test/integration/app/public/dispatch.cgi +0 -10
  61. data/test/integration/app/public/dispatch.fcgi +0 -24
  62. data/test/integration/app/public/dispatch.rb +0 -10
  63. data/test/integration/app/public/favicon.ico +0 -0
  64. data/test/integration/app/public/images/rails.png +0 -0
  65. data/test/integration/app/public/javascripts/application.js +0 -2
  66. data/test/integration/app/public/javascripts/controls.js +0 -963
  67. data/test/integration/app/public/javascripts/dragdrop.js +0 -972
  68. data/test/integration/app/public/javascripts/effects.js +0 -1120
  69. data/test/integration/app/public/javascripts/prototype.js +0 -4225
  70. data/test/integration/app/public/robots.txt +0 -5
  71. data/test/integration/app/script/about +0 -3
  72. data/test/integration/app/script/console +0 -3
  73. data/test/integration/app/script/destroy +0 -3
  74. data/test/integration/app/script/generate +0 -3
  75. data/test/integration/app/script/performance/benchmarker +0 -3
  76. data/test/integration/app/script/performance/profiler +0 -3
  77. data/test/integration/app/script/performance/request +0 -3
  78. data/test/integration/app/script/plugin +0 -3
  79. data/test/integration/app/script/process/inspector +0 -3
  80. data/test/integration/app/script/process/reaper +0 -3
  81. data/test/integration/app/script/process/spawner +0 -3
  82. data/test/integration/app/script/runner +0 -3
  83. data/test/integration/app/script/server +0 -3
  84. data/test/integration/app/test/functional/items_controller_test.rb +0 -8
  85. data/test/integration/app/test/test_helper.rb +0 -38
  86. data/test/integration/server_test.rb +0 -93
  87. data/test/misc/direct.rb +0 -13
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,4 +1,6 @@
1
1
 
2
+ v4.0. Track spawn points live instead of sampling.
3
+
2
4
  v3.7.1. Fix some nil issues with corrupted dumps (cody caughlan).
3
5
 
4
6
  v3.7. Sample object contents. Restore Rails 1.2.x compatibility.
data/Manifest CHANGED
@@ -1,77 +1,23 @@
1
1
  bin/bleak
2
2
  CHANGELOG
3
- ext/bleak_house/logger/build_logger.rb
4
- ext/bleak_house/logger/build_ruby.rb
5
- ext/bleak_house/logger/extconf.rb
6
- ext/bleak_house/logger/snapshot.c
7
- ext/bleak_house/logger/snapshot.h
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/logger/source.rb
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/gc.c.patch
25
- ruby/parse.y.patch
26
- ruby/ruby-1.8.6-p110.tar.bz2
27
- test/integration/app/app/controllers/application.rb
28
- test/integration/app/app/controllers/items_controller.rb
29
- test/integration/app/app/helpers/application_helper.rb
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
- * tracks all objects and symbols
18
- * inspection of sample leaked objects (optional)
19
- * easy Rails integration
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
- == Profiling a Rails app
38
+ == Usage
39
39
 
40
- To setup a Rails app for profiling, just <tt>require 'bleak_house'</tt> in <tt>config/environment.rb</tt>.
40
+ We will profile a Rails app as an example. Note that BleakHouse works equally well in any Ruby program.
41
41
 
42
- Then, to engage the logger (ideally, in a live deployment situation), start a server instance as so:
43
- RAILS_ENV=production BLEAK_HOUSE=true ruby-bleak-house ./script/server
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
- Browse around manually, thrash your entire app with a script, target troublesome controllers/actions, etc. The BleakHouse logger will dump a huge amount of data to <tt>log/bleak_house_production.dump</tt>--keep an eye on your disk space. I usually aim for a 3GB dump.
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
- Then, to analyze the dump:
48
- bleak path/to/log/bleak_house_production.dump
49
-
50
- Be patient; it's quite slow.
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
- == Sampling object contents
53
+ ** BleakHouse: working...
54
+ ** BleakHouse: complete
55
+ ** Bleakhouse: run 'bleak /tmp/bleak.5979.0.dump' to analyze.
53
56
 
54
- BleakHouse can sample object contents, which might help you figure out the source of the leak. Just add <tt>SAMPLE_RATE=0.1</tt> to the environment string when you start your server.
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
- Note that there is a chance this could _introduce_ leaks if you override <tt>inspect</tt> in leaky ways. Unfortunately, the samping is of dubious usefulness and really increases the memory usage of the analyze task. That's why it's off by default.
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
- == Using BleakHouse outside of Rails
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
- Just instantiate a BleakHouse::Logger object, and make calls to <tt>snapshot</tt> at appropriate times, with tags to identify their context.
84
+ == Tips
63
85
 
64
- == Troubleshooting
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
- If you see the error <tt>Symbol not found: _rb_gc_heaps_used</tt>, it means you installed the patched binary, but tried to profile the server with the regular Ruby binary.
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
- * Better docs on what the tags mean
3
- * Use per-frame file storage to avoid out-of-memory problems
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
@@ -1,33 +1,31 @@
1
1
 
2
- # Gem::Specification for Bleak_house-3.7.1
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 = "3.7.1"
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-03-30}
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/bleak_house/logger/extconf.rb"]
19
- s.extra_rdoc_files = ["CHANGELOG", "ext/bleak_house/logger/snapshot.c", "lib/bleak_house/analyzer/analyzer.rb", "lib/bleak_house/analyzer.rb", "lib/bleak_house/logger/source.rb", "lib/bleak_house/logger.rb", "lib/bleak_house/rails/bleak_house.rb", "LICENSE", "LICENSE_BSD", "README", "TODO"]
20
- s.files = ["bin/bleak", "CHANGELOG", "ext/bleak_house/logger/build_logger.rb", "ext/bleak_house/logger/build_ruby.rb", "ext/bleak_house/logger/extconf.rb", "ext/bleak_house/logger/snapshot.c", "ext/bleak_house/logger/snapshot.h", "init.rb", "install.rb", "lib/bleak_house/analyzer/analyzer.rb", "lib/bleak_house/analyzer.rb", "lib/bleak_house/logger/source.rb", "lib/bleak_house/logger.rb", "lib/bleak_house/rails/action_controller.rb", "lib/bleak_house/rails/bleak_house.rb", "lib/bleak_house/rails/dispatcher.rb", "lib/bleak_house/rails.rb", "lib/bleak_house/support/core_extensions.rb", "lib/bleak_house.rb", "LICENSE", "LICENSE_BSD", "Manifest", "README", "ruby/gc.c.patch", "ruby/parse.y.patch", "ruby/ruby-1.8.6-p110.tar.bz2", "test/integration/app/app/controllers/application.rb", "test/integration/app/app/controllers/items_controller.rb", "test/integration/app/app/helpers/application_helper.rb", "test/integration/app/app/helpers/items_helper.rb", "test/integration/app/app/views/items/index.rhtml", "test/integration/app/config/boot.rb", "test/integration/app/config/database.yml", "test/integration/app/config/environment.rb", "test/integration/app/config/environments/development.rb", "test/integration/app/config/environments/production.rb", "test/integration/app/config/environments/test.rb", "test/integration/app/config/initializers/inflections.rb", "test/integration/app/config/initializers/mime_types.rb", "test/integration/app/config/routes.rb", "test/integration/app/doc/README_FOR_APP", "test/integration/app/public/404.html", "test/integration/app/public/422.html", "test/integration/app/public/500.html", "test/integration/app/public/dispatch.cgi", "test/integration/app/public/dispatch.fcgi", "test/integration/app/public/dispatch.rb", "test/integration/app/public/favicon.ico", "test/integration/app/public/images/rails.png", "test/integration/app/public/javascripts/application.js", "test/integration/app/public/javascripts/controls.js", "test/integration/app/public/javascripts/dragdrop.js", "test/integration/app/public/javascripts/effects.js", "test/integration/app/public/javascripts/prototype.js", "test/integration/app/public/robots.txt", "test/integration/app/Rakefile", "test/integration/app/README", "test/integration/app/script/about", "test/integration/app/script/console", "test/integration/app/script/destroy", "test/integration/app/script/generate", "test/integration/app/script/performance/benchmarker", "test/integration/app/script/performance/profiler", "test/integration/app/script/performance/request", "test/integration/app/script/plugin", "test/integration/app/script/process/inspector", "test/integration/app/script/process/reaper", "test/integration/app/script/process/spawner", "test/integration/app/script/runner", "test/integration/app/script/server", "test/integration/app/test/functional/items_controller_test.rb", "test/integration/app/test/test_helper.rb", "test/integration/server_test.rb", "test/misc/direct.rb", "test/test_helper.rb", "test/unit/test_bleak_house.rb", "TODO", "bleak_house.gemspec"]
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.1}
26
+ s.rubygems_version = %q{1.1.0}
27
27
  s.summary = %q{A library for finding memory leaks.}
28
- s.test_files = ["test/integration/server_test.rb", "test/unit/test_bleak_house.rb"]
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.dependencies = ['ccsv >=0.1'] # 'memory >=0.0.2'
46
- # p.require_signed = true
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__)) + "/../../../ruby"
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
- unless which('ruby-bleak-house')
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-p110.tar.bz2"
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-p110") do
53
+ Dir.chdir("ruby-1.8.6-p114") do
46
54
 
47
55
  # Patch, configure, and build
48
- system("patch -p0 < \'#{source_dir}/gc.c.patch\' > ../gc.c.patch.log 2>&1")
49
- system("patch -p0 < \'#{source_dir}/parse.y.patch\' > ../parse.y.patch.log 2>&1")
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
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+ $CFLAGS = ENV['CFLAGS']
3
+ dir_config('snapshot')
4
+ create_makefile('snapshot')
@@ -1,3 +1,3 @@
1
1
 
2
2
  system('ruby build_ruby.rb &> /dev/null')
3
- exec('ruby-bleak-house build_logger.rb')
3
+ exec('ruby-bleak-house build_snapshot.rb')
@@ -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
+ }