bleak_house 3.1 → 3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
metadata.gz.sig ADDED
Binary file
@@ -1,139 +0,0 @@
1
-
2
- require 'rubygems'
3
- require 'fileutils'
4
- require 'base64'
5
-
6
- gem 'gruff', '= 0.2.8'
7
- require 'gruff'
8
-
9
- # require, but make rdoc not whine
10
- load "#{File.dirname(__FILE__)}/gruff_hacks.rb"
11
- load "#{File.dirname(__FILE__)}/support_methods.rb"
12
-
13
- Gruff::Base::LEFT_MARGIN = 200
14
- Gruff::Base::NEGATIVE_TOP_MARGIN = 30
15
- Gruff::Base::MAX_LEGENDS = 28
16
-
17
- class BleakHouse
18
- class Analyze
19
-
20
- DIR = "#{RAILS_ROOT}/log/bleak_house/"
21
-
22
- def initialize(data, increments, name)
23
- @data = data
24
- @increments = increments
25
- @name = name
26
- end
27
-
28
- def draw
29
- g = Gruff::Line.new("1024x768")
30
- g.title = @name
31
- g.x_axis_label = "time"
32
- g.legend_font_size = g.legend_box_size = 14
33
- g.title_font_size = 24
34
- g.marker_font_size = 14
35
-
36
- @data.map do |key, values|
37
- name = if key.to_s == ""
38
- '[Unknown]'
39
- else
40
- # elsif key =~ Regexp.new(@specials.keys.join('|'))
41
- # name = "#{key} (#{values.to_i.max / (2**10)} MB)"
42
- # @specials.each do |regex, scale|
43
- # values.map! {|x| x * scale} if key =~ regex
44
- # end
45
- # else
46
- "#{key.gsub(/.*::/, '')} (#{values.to_i.max})"
47
- end
48
- [name, values]
49
- end.sort_by do |key, values|
50
- 0 - key[/.*?([\d]+)\)$/, 1].to_i
51
- end.each do |key, values|
52
- g.data(key, values.to_i)
53
- end
54
-
55
- labels = {}
56
- mod = (@increments.size / 4.0).ceil
57
- @increments.each_with_index do |increment, index|
58
- labels[index] = increment.split(" ").last if (index % mod).zero?
59
- end
60
- g.labels = labels
61
-
62
- g.minimum_value = 0
63
- # g.maximum_value = @maximum
64
-
65
- g.write(@name.to_filename + ".png")
66
- end
67
-
68
- def self.aggregate(data, selector, namer)
69
- aggregate_data = {}
70
- increments = []
71
- data.each_with_index do |frameset, index|
72
- increments << frameset.time
73
- frameset.data.keys.select do |key|
74
- key =~ selector #or key =~ Regexp.new(specials.keys.join('|'))
75
- end.each do |key|
76
- aggregate_data[key.to_s[namer, 1]] ||= []
77
- aggregate_data[key.to_s[namer, 1]][index] += frameset.data[key].to_i
78
- end
79
- end
80
- [aggregate_data, increments]
81
- end
82
-
83
- def self.build_all(filename)
84
- unless File.exists? filename
85
- puts "No data file found: #{filename}"
86
- exit
87
- end
88
- FileUtils.rm_r(DIR) rescue nil
89
- Dir.mkdir(DIR)
90
-
91
- Dir.chdir(DIR) do
92
-
93
- puts "Parsing data"
94
- data = File.open(filename).readlines.map do |line|
95
- Marshal.load Base64.decode64(line)
96
- end
97
-
98
- # data_maximum = data.flatten.inject(0) do |max, el|
99
- # if el.is_a? Hash
100
- # current_max = el.merge({:"real memory" => 0, :"virtual memory" => 0}).values.to_i.max
101
- # current_max if max < current_max
102
- # end or max
103
- # end
104
- # mem_maximum = data.flatten.inject(0) do |max, el| # only real memory (RSS) for now
105
- # (el["real memory"] if el.is_a?(Hash) and max < el["real memory"]) or max
106
- # end
107
- # mem_scale = data_maximum / mem_maximum.to_f
108
- # scales = {/memory$/ => mem_scale}
109
-
110
- puts "By controller"
111
- controller_data, increments = aggregate(data, //, /^(.*?)($|\/|::::)/)
112
- Analyze.new(controller_data, increments, "objects by controller").draw
113
-
114
- # in each controller, by action
115
- puts "By action"
116
- controller_data.keys.each do |controller|
117
- puts " ...in #{controller} controller"
118
- Dir.descend(controller) do
119
- action_data, increments = aggregate(data, /^#{controller}($|\/|::::)/, /\/(.*?)($|\/|::::)/)
120
- Analyze.new(action_data, increments, "objects by action in /#{controller}").draw
121
-
122
- # in each action, by object class
123
- action_data.keys.each do |action|
124
- action = "unknown" if action.to_s == ""
125
- puts " ...in #{action} action"
126
- Dir.descend(action) do
127
- class_data, increments = aggregate(data, /^#{controller}#{"\/#{action}" unless action == "unknown"}($|\/|::::)/,
128
- /::::(.*)/)
129
- Analyze.new(class_data, increments, "objects by class in /#{controller}/#{action}").draw
130
- end
131
- end
132
-
133
- end
134
- end
135
- end
136
- end
137
-
138
- end
139
- end
@@ -1,33 +0,0 @@
1
-
2
- class BleakHouse
3
- cattr_accessor :last_request_name
4
- cattr_accessor :dispatch_count
5
- cattr_accessor :log_interval
6
-
7
- self.dispatch_count = 0
8
- self.log_interval = (ENV['INTERVAL'] and ENV['INTERVAL'].to_i or 10)
9
-
10
- def self.set_request_name request, other = nil
11
- self.last_request_name = "#{request.parameters['controller']}/#{request.parameters['action']}/#{request.request_method}#{other}"
12
- end
13
-
14
- def self.debug s
15
- s = "#{name.underscore}: #{s}"
16
- ::ActiveRecord::Base.logger.debug s if ::ActiveRecord::Base.logger
17
- end
18
-
19
- def self.warn s
20
- s = "#{name.underscore}: #{s}"
21
- if ::ActiveRecord::Base.logger
22
- ::ActiveRecord::Base.logger.warn s
23
- else
24
- $stderr.puts s
25
- end
26
- end
27
-
28
- LOGFILE = "#{RAILS_ROOT}/log/bleak_house_#{RAILS_ENV}.dump"
29
- if File.exists?(LOGFILE)
30
- File.rename(LOGFILE, "#{LOGFILE}.old")
31
- warn "renamed old logfile"
32
- end
33
- end
@@ -1,23 +0,0 @@
1
-
2
- # crazyness
3
-
4
- class Dispatcher
5
- class << self
6
- def prepare_application_with_bleak_house
7
- prepare_application_without_bleak_house
8
- BleakHouse.dispatch_count += 1
9
- BleakHouse::MemLogger.snapshot('core rails')
10
- end
11
- alias_method_chain :prepare_application, :bleak_house
12
-
13
- def reset_after_dispatch_with_bleak_house
14
- BleakHouse::MemLogger.snapshot(BleakHouse.last_request_name || 'unknown')
15
- if (BleakHouse.dispatch_count % BleakHouse.log_interval).zero?
16
- BleakHouse.warn "wrote frameset (#{BleakHouse.dispatch_count} dispatches)"
17
- BleakHouse::MemLogger.log(BleakHouse::LOGFILE)
18
- end
19
- reset_after_dispatch_without_bleak_house
20
- end
21
- alias_method_chain :reset_after_dispatch, :bleak_house
22
- end
23
- end
@@ -1,56 +0,0 @@
1
-
2
- class Gruff::Base
3
-
4
- def draw_legend
5
- @legend_labels = @data.collect {|item| item[DATA_LABEL_INDEX] }
6
-
7
- legend_square_width = @legend_box_size # small square with color of this item
8
- legend_left = 10
9
-
10
- current_x_offset = legend_left
11
- current_y_offset = TOP_MARGIN + TITLE_MARGIN + @title_caps_height + LEGEND_MARGIN
12
-
13
- debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
14
-
15
- @legend_labels.each_with_index do |legend_label, index|
16
-
17
- next if index > MAX_LEGENDS
18
- legend_label = "Some not shown" if index == MAX_LEGENDS
19
-
20
- # Draw label
21
- @d.fill = @font_color
22
- @d.font = @font if @font
23
- @d.pointsize = scale_fontsize(@legend_font_size)
24
- @d.stroke('transparent')
25
- @d.font_weight = NormalWeight
26
- @d.gravity = WestGravity
27
- @d = @d.annotate_scaled( @base_image,
28
- @raw_columns, 1.0,
29
- current_x_offset + (legend_square_width * 1.7), current_y_offset,
30
- legend_label.to_s, @scale)
31
-
32
- if index < MAX_LEGENDS
33
- # Now draw box with color of this dataset
34
- @d = @d.stroke('transparent')
35
- @d = @d.fill @data[index][DATA_COLOR_INDEX]
36
- @d = @d.rectangle(current_x_offset,
37
- current_y_offset - legend_square_width / 2.0,
38
- current_x_offset + legend_square_width,
39
- current_y_offset + legend_square_width / 2.0)
40
- end
41
-
42
- @d.pointsize = @legend_font_size
43
- metrics = @d.get_type_metrics(@base_image, legend_label.to_s)
44
- current_y_offset += metrics.height * 1.05
45
- end
46
- @color_index = 0
47
- end
48
-
49
- alias :setup_graph_measurements_without_top_margin :setup_graph_measurements
50
- def setup_graph_measurements
51
- setup_graph_measurements_without_top_margin
52
- @graph_height += NEGATIVE_TOP_MARGIN
53
- @graph_top -= NEGATIVE_TOP_MARGIN
54
- end
55
-
56
- end
@@ -1,54 +0,0 @@
1
-
2
- require 'base64'
3
-
4
- class BleakHouse::MemLogger
5
- class << self
6
-
7
- SEEN = {}
8
- CURRENT = {}
9
- TAGS = Hash.new(0)
10
- TIMEFORMAT = '%Y-%m-%d %H:%M:%S'
11
- VSZ = "virtual memory"
12
- RSS = "real memory"
13
-
14
- def log(path, with_mem = false)
15
- File.open(path, 'a+') do |log|
16
- log.sync = true
17
- TAGS[VSZ], TAGS[RSS] = mem_usage if with_mem
18
- log.puts Base64.encode64(Marshal.dump([Time.now.strftime(TIMEFORMAT), TAGS])).gsub("\n", '')
19
- end
20
- GC.start
21
- end
22
-
23
- def snapshot(tag)
24
- # puts "bleak_house: seen: #{SEEN.size}"
25
- CURRENT.clear
26
- ObjectSpace.each_object do |obj|
27
- CURRENT[obj_id = obj._bleak_house_object_id] = true
28
- unless SEEN[obj_id]
29
- # symbols will rapidly stabilize; don't worry
30
- SEEN[obj_id] = "#{tag}::::#{obj._bleak_house_class}".to_sym
31
- TAGS[SEEN[obj_id]] += 1
32
- end
33
- end
34
- # puts "bleak_house: current: #{CURRENT.size}"
35
- SEEN.keys.each do |obj_id|
36
- TAGS[SEEN.delete(obj_id)] -= 1 unless CURRENT[obj_id]
37
- end
38
- # puts "bleak_house: done"
39
- CURRENT.clear
40
- GC.start
41
- end
42
-
43
- def mem_usage
44
- `ps -x -o 'rss vsz' -p #{Process.pid}`.split(/\s+/)[-2..-1].map{|el| el.to_i}
45
- end
46
-
47
- end
48
- end
49
-
50
- class Object
51
- alias :_bleak_house_object_id :object_id
52
- alias :_bleak_house_class :class
53
- end
54
-
@@ -1,13 +0,0 @@
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
-