bleak_house 5.3 → 6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,6 +1,7 @@
1
1
 
2
2
  BleakHouse Changelog
3
3
 
4
+ 6. log heap usage, remove pure-ruby profiler
4
5
  5.3. subtract rails core counts from action counts and convolve
5
6
  5.2. change smoothing algorithm to be more intuitive and so mem usage is correct
6
7
  5.1. close file properly
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
- It is highly recommended that you compile the bleak_house patched
11
- Ruby build. In the plugin directory:
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
@@ -1,10 +1,14 @@
1
1
 
2
2
  if ENV['BLEAK_HOUSE']
3
3
 
4
- require 'dispatcher' # rails
4
+ # rails
5
+ require 'dispatcher'
5
6
 
7
+ # logger
8
+ require 'bleak_house/c'
6
9
  require 'bleak_house/bleak_house'
7
- require 'bleak_house/mem_logger'
10
+
11
+ # overrides
8
12
  require 'bleak_house/dispatcher'
9
13
  require 'bleak_house/action_controller'
10
14
 
@@ -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(/.*::/, '')} (#{key == MEM_KEY ? "relative" : values.to_i.max})", values] # hax
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
- if controller_data.has_key? MEM_KEY
125
- controller_data_without_memory = controller_data.dup
126
- controller_data_without_memory.delete(MEM_KEY)
127
- scale_factor = controller_data_without_memory.values.flatten.to_i.max / controller_data[MEM_KEY].max.to_f * 0.8 rescue 1
128
- controller_data[MEM_KEY] = controller_data[MEM_KEY].map{|x| (x * scale_factor).to_i }
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
- @mem = (controller == MEM_KEY)
135
- puts(@mem ? " #{controller}" : " action for #{controller} controller")
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, @mem ? "#{controller} in kilobytes" : "objects by action in /#{controller}_controller").draw
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 @mem
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 = if ENV['MEMLOGGER'] !~ /ruby/i and (ENV['MEMLOGGER'] =~ /c/i or
33
- `which ruby-bleak-house` !~ /no ruby_bleak_house/)
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
@@ -3,11 +3,16 @@ require 'rubygems'
3
3
  require 'inline'
4
4
 
5
5
  class BleakHouse
6
- class CLogger < MemLogger
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 path, VALUE tag, VALUE _specials) {
101
- Check_Type(path, T_STRING);
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(path), "r");
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(path), "a+")) == NULL)
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: "5.3"
7
- date: 2007-05-08 00:00:00 -04:00
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 5.3.
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
-
@@ -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