kamal-railsbench 0.9.9.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/BUGS +2 -0
  2. data/CHANGELOG +2124 -0
  3. data/GCPATCH +73 -0
  4. data/INSTALL +75 -0
  5. data/LICENSE +222 -0
  6. data/Manifest.txt +53 -0
  7. data/PROBLEMS +56 -0
  8. data/README +337 -0
  9. data/Rakefile +51 -0
  10. data/bin/railsbench +80 -0
  11. data/config/benchmarking.rb +21 -0
  12. data/config/benchmarks.rb +21 -0
  13. data/config/benchmarks.yml +2 -0
  14. data/images/empty.png +0 -0
  15. data/images/minus.png +0 -0
  16. data/images/plus.png +0 -0
  17. data/install.rb +70 -0
  18. data/latest_changes.txt +18 -0
  19. data/lib/benchmark.rb +576 -0
  20. data/lib/railsbench/benchmark.rb +576 -0
  21. data/lib/railsbench/benchmark_specs.rb +63 -0
  22. data/lib/railsbench/gc_info.rb +158 -0
  23. data/lib/railsbench/perf_info.rb +146 -0
  24. data/lib/railsbench/perf_utils.rb +202 -0
  25. data/lib/railsbench/railsbenchmark.rb +640 -0
  26. data/lib/railsbench/version.rb +9 -0
  27. data/lib/railsbench/write_headers_only.rb +15 -0
  28. data/postinstall.rb +12 -0
  29. data/ruby184gc.patch +516 -0
  30. data/ruby185gc.patch +562 -0
  31. data/ruby186gc.patch +564 -0
  32. data/ruby19gc.patch +2425 -0
  33. data/script/convert_raw_data_files +49 -0
  34. data/script/generate_benchmarks +171 -0
  35. data/script/perf_bench +74 -0
  36. data/script/perf_comp +151 -0
  37. data/script/perf_comp_gc +113 -0
  38. data/script/perf_diff +48 -0
  39. data/script/perf_diff_gc +53 -0
  40. data/script/perf_html +103 -0
  41. data/script/perf_plot +225 -0
  42. data/script/perf_plot_gc +254 -0
  43. data/script/perf_prof +87 -0
  44. data/script/perf_run +39 -0
  45. data/script/perf_run_gc +40 -0
  46. data/script/perf_table +104 -0
  47. data/script/perf_tex +58 -0
  48. data/script/perf_times +66 -0
  49. data/script/perf_times_gc +94 -0
  50. data/script/run_urls +57 -0
  51. data/setup.rb +1585 -0
  52. data/test/railsbench_test.rb +11 -0
  53. data/test/test_helper.rb +2 -0
  54. metadata +133 -0
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.length < 4 || ARGV.first == 'help'
4
+ $stderr.puts 'usage: perf_diff iterations common-options options1 options4 [conf-name1] [conf-name2]'
5
+ $stderr.puts 'example: perf_diff 100 "-bm=all" "-log" "-nocache" c1 c2'
6
+ exit 1
7
+ end
8
+
9
+ bindir = File.dirname(__FILE__)
10
+ require "#{bindir}/../lib/railsbench/perf_utils"
11
+
12
+ determine_rails_root_or_die!
13
+
14
+ iterations = ARGV[0]
15
+ common = ARGV[1]
16
+ options1 = ARGV[2]
17
+ options2 = ARGV[3]
18
+
19
+ benchmark = "default"
20
+ benchmark = $1 if common =~ /-bm=([^ ]+)/
21
+
22
+ file1 = benchmark_file_name(benchmark, ARGV[4], 1)
23
+ perf_run("perf_diff", iterations, "#{common} #{options1}", file1)
24
+ puts;puts
25
+
26
+ file2 = benchmark_file_name(benchmark, ARGV[5], 2)
27
+ perf_run("perf_diff", iterations, "#{common} #{options2}", file2)
28
+ puts;puts
29
+
30
+ system("ruby #{bindir}/perf_comp #{file1} #{file2}")
31
+
32
+ __END__
33
+
34
+ # Copyright (C) 2005-2008 Stefan Kaes
35
+ #
36
+ # This program is free software; you can redistribute it and/or modify
37
+ # it under the terms of the GNU General Public License as published by
38
+ # the Free Software Foundation; either version 2 of the License, or
39
+ # (at your option) any later version.
40
+ #
41
+ # This program is distributed in the hope that it will be useful,
42
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
43
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44
+ # GNU General Public License for more details.
45
+ #
46
+ # You should have received a copy of the GNU General Public License
47
+ # along with this program; if not, write to the Free Software
48
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.length < 4 || ARGV.first == 'help'
4
+ $stderr.puts 'usage: perf_diff_gc iterations options1 options2 [conf-name1] [conf-name2]'
5
+ $stderr.puts 'example: perf_diff_gc 100 "-bm=default" "-log" "-nocache" c1 c2'
6
+ exit 1
7
+ end
8
+
9
+ bindir = File.dirname(__FILE__)
10
+ require "#{bindir}/../lib/railsbench/perf_utils"
11
+
12
+ determine_rails_root_or_die!
13
+
14
+ iterations = ARGV[0]
15
+ common = ARGV[1]
16
+ options1 = ARGV[2]
17
+ options2 = ARGV[3]
18
+
19
+ benchmark = "default"
20
+ benchmark = $1 if common =~ /-bm=([^ ]+)/
21
+
22
+ file1 = benchmark_file_name(benchmark, ARGV[4], 1, :gc)
23
+ perf_run_gc("perf_run_gc", iterations, "#{common} #{options1}", file1)
24
+
25
+ puts;puts
26
+
27
+ file2 = benchmark_file_name(benchmark, ARGV[5], 2, :gc)
28
+ perf_run_gc("perf_run_gc", iterations, "#{common} #{options2}", file2)
29
+
30
+ puts;puts
31
+
32
+ puts "benchmark comparison data"
33
+ puts
34
+
35
+ system("ruby #{bindir}/perf_comp_gc #{file1} #{file2}")
36
+
37
+ __END__
38
+
39
+ # Copyright (C) 2005-2008 Stefan Kaes
40
+ #
41
+ # This program is free software; you can redistribute it and/or modify
42
+ # it under the terms of the GNU General Public License as published by
43
+ # the Free Software Foundation; either version 2 of the License, or
44
+ # (at your option) any later version.
45
+ #
46
+ # This program is distributed in the hope that it will be useful,
47
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
48
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49
+ # GNU General Public License for more details.
50
+ #
51
+ # You should have received a copy of the GNU General Public License
52
+ # along with this program; if not, write to the Free Software
53
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ unless ARGV.include?('-nocss')
4
+ puts <<'END'
5
+ <style type="text/css">
6
+ <!--
7
+ .perf_header, .perf_data, .perf_name { font-size:70%; padding-left:5px; padding-right:5px; }
8
+ .perf_header { text-align:center; vertical-align:top; font-weight:bold;}
9
+ .i { font-style:italic; }
10
+ .b { font-weight:bold; }
11
+ .c1 { background:#fff3df; }
12
+ .c2 { background:#dfedff; }
13
+ .factor { background:#efe0ef; }
14
+ .factor_red_alert { background:#CC303B; }
15
+ .factor_red { background:#FF6060; }
16
+ .factor_reddish { background:#FFA766; }
17
+ .factor_green_alert { background:#0B8900; }
18
+ .factor_green { background:#6AB788; }
19
+ .factor_greenish { background:#7FFFB0; }
20
+ .name { background:#dfdfdf; }
21
+ .perf_name { text-align:left; }
22
+ .perf_data { text-align:right; }
23
+ -->
24
+ </style>
25
+ END
26
+ end
27
+
28
+ def factor_class(v)
29
+ return 'factor' unless ARGV.include?('-colorize')
30
+ if v <= 0.85
31
+ 'factor_red_alert'
32
+ elsif v <= 0.90
33
+ 'factor_red'
34
+ elsif v <= 0.95
35
+ 'factor_reddish'
36
+ elsif v >= 1.15
37
+ 'factor_green_alert'
38
+ elsif v >= 1.10
39
+ 'factor_green'
40
+ elsif v >= 1.05
41
+ 'factor_greenish'
42
+ else
43
+ 'factor'
44
+ end
45
+ end
46
+
47
+ unless ARGV.include?('-notable')
48
+ puts "<table cellspacing=1px>"
49
+ $stdin.each_line do |l|
50
+ case l
51
+ when /^garbage collection/
52
+ unless ARGV.include?('-gc')
53
+ puts "</table>"
54
+ exit
55
+ end
56
+ puts "<tr></tr><tr></tr>"
57
+ puts "<tr>"
58
+ puts "<th class='perf_header name' style='text-align:left'>GC statistics</th>"
59
+ puts "<th class='perf_header c1'>c1 total</th><th class='perf_header c2'>c2 total</th>"
60
+ puts "<th class='perf_header c1'>c1 #gc</th><th class='perf_header c2'>c2 #gc</th>"
61
+ puts "<th class='perf_header c1'>c1 gc%</th><th class='perf_header c2'>c2 #gc%</th>"
62
+ puts "<th class='perf_header factor'>c1/c2</th>"
63
+ puts "</tr>"
64
+ when /^page/
65
+ puts "<tr>"
66
+ puts "<th class='perf_header name' style='text-align:left;'>page</th>"
67
+ puts "<th class='perf_header c1'>c1 total</th><th class='perf_header c2'>c2 total</th>"
68
+ puts "<th class='perf_header c1'>c1 r/s</th><th class='perf_header c2'>c2 r/s</th>"
69
+ puts "<th class='perf_header c1'>c1 ms/r</th><th class='perf_header c2'>c2 ms/r</th>"
70
+ puts "<th class='perf_header factor'>c1/c2</th>"
71
+ puts "</tr>"
72
+ end
73
+ case l
74
+ when %r{^([A-Za-z0-9./?=_ ]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+$}
75
+ puts "<tr>"
76
+ puts "<td class='perf_name name#{" i" if $1.strip == "all requests"}'>#{$1}</td>"
77
+ puts "<td class='perf_data c1'>#{$2}</td><td class='perf_data c2'>#{$3}</td>"
78
+ puts "<td class='perf_data c1'>#{$4}</td><td class='perf_data c2'>#{$5}</td>"
79
+ puts "<td class='perf_data c1'>#{$6}</td><td class='perf_data c2'>#{$7}</td>"
80
+ puts "<td class='perf_data #{factor_class($8.to_f)}'>#{$8}</td>"
81
+ puts "</tr>"
82
+ end
83
+ end
84
+ puts "</table>"
85
+ end
86
+
87
+ __END__
88
+
89
+ # Copyright (C) 2005-2008 Stefan Kaes
90
+ #
91
+ # This program is free software; you can redistribute it and/or modify
92
+ # it under the terms of the GNU General Public License as published by
93
+ # the Free Software Foundation; either version 2 of the License, or
94
+ # (at your option) any later version.
95
+ #
96
+ # This program is distributed in the hope that it will be useful,
97
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
98
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
99
+ # GNU General Public License for more details.
100
+ #
101
+ # You should have received a copy of the GNU General Public License
102
+ # along with this program; if not, write to the Free Software
103
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ require 'optparse'
6
+ require 'ostruct'
7
+
8
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
9
+ require 'railsbench/perf_info'
10
+
11
+ # parse options
12
+ o = OpenStruct.new
13
+ o.selection = []
14
+ o.title = "Performance Graph"
15
+ o.files = []
16
+ o.names = []
17
+ o.labels = []
18
+ o.graph_type = :line
19
+ o.graph_width = '800x600'
20
+ o.font_size = 14
21
+ o.output_file = nil
22
+ o.colors = nil
23
+ o.theme = nil
24
+ o.engine = :gruff
25
+
26
+ parser = OptionParser.new do |opts|
27
+ opts.banner = "Usage: perf_plot [options] file1 file2 ..."
28
+
29
+ opts.separator ""
30
+ opts.separator "Options:"
31
+
32
+ opts.on("-t", "--title T",
33
+ "Specify the title for your plot") do |t|
34
+ o.title = t
35
+ end
36
+
37
+ opts.on("--only LIST", Array,
38
+ "Restrict plot to a subset of the benchmarks") do |t|
39
+ o.selection = t.map{|s| s.to_i}
40
+ end
41
+
42
+ opts.on("--line",
43
+ "Plot a line graph") do |t|
44
+ o.graph_type = :line
45
+ end
46
+
47
+ opts.on("--bar",
48
+ "Plot a bar graph") do |t|
49
+ o.graph_type = :bar
50
+ end
51
+
52
+ opts.on("-w", "--width W", Integer,
53
+ "Width of the plot (pixels)") do |w|
54
+ o.graph_width = w
55
+ end
56
+
57
+ opts.on("-g", "--geometry WxH", /\d+x\d+/,
58
+ "Specify plot dimensions (pixels)") do |d|
59
+ o.graph_width = d
60
+ end
61
+
62
+ opts.on("-c", "--colors LIST", Array,
63
+ "Use specified colors for lines/bars") do |t|
64
+ o.colors = t
65
+ end
66
+
67
+ opts.on("--theme NAME",
68
+ "Use specified theme") do |t|
69
+ o.theme = t
70
+ end
71
+
72
+ opts.on("-e", "--engine ENGINE", [:gruff, :gnuplot],
73
+ "Select plotting engine: (gruff, gnuplot)") do |e|
74
+ o.engine = e
75
+ end
76
+
77
+ opts.on("-n", "--names LIST", Array,
78
+ "Use specified names for the legend") do |t|
79
+ o.names = t
80
+ end
81
+
82
+ opts.on("-l", "--labels LIST", Array,
83
+ "Use specified labels instead of benchmark names") do |t|
84
+ o.labels = t
85
+ end
86
+
87
+ opts.on("-o", "--out FILE",
88
+ "Specify output file") do |f|
89
+ o.output_file = f
90
+ end
91
+
92
+ opts.on("-f", "--font-size N", Integer,
93
+ "Overall font size to use in the plot (points)") do |n|
94
+ o.font_size = n
95
+ end
96
+
97
+ opts.on_tail("-h", "--help", "Show this message") do
98
+ puts opts
99
+ exit
100
+ end
101
+ end
102
+
103
+ # option compatibility with older versions
104
+ args=[]
105
+ ARGV.each do |arg|
106
+ arg = arg.sub("font_size", "font-size") if arg =~ /^-font_size/
107
+ arg = "-" + arg if arg =~ /^-(title|width|out|geometry|font-size|names|labels|colors|line|bar|only)/
108
+ args << arg
109
+ end
110
+
111
+ parser.parse!(args)
112
+
113
+ o.output_file ||= o.engine == :gruff ? "graph.png" : "graph.pdf"
114
+
115
+ args.each do |arg|
116
+ o.files << File.open_or_die(arg)
117
+ o.names[o.files.length-1] ||= File.basename(arg).sub(/\.txt$/, '').sub(/^\d\d-\d\d\.[^\.]+./, '')
118
+ end
119
+
120
+ o.files.length > 0 or die(parser.banner)
121
+
122
+ class Plotter
123
+ attr_reader :o
124
+ def initialize(options)
125
+ @o = options
126
+ setup
127
+ end
128
+
129
+ def setup
130
+ pi = nil
131
+ @perf_data = []
132
+ o.files.each do |file|
133
+ pi = PerfInfo.new(file)
134
+ iter = pi.iterations
135
+ urls = pi.requests_per_key
136
+ @perf_data << pi.keys.map{ |key| iter*urls/pi.timings_mean(key) }
137
+ file.close
138
+ end
139
+ o.selection = (1..(@perf_data.last.length)).to_a if o.selection.empty?
140
+ if o.labels.empty?
141
+ o.labels = pi.keys.restrict_to(o.selection.map{|i| i-1})
142
+ end
143
+ @perf_data = @perf_data.map{|d| d.restrict_to(o.selection.map{|i| i-1})}
144
+ end
145
+
146
+ def plot_with_gruff
147
+ require 'gruff'
148
+
149
+ g = o.graph_type == :line ? Gruff::Line.new(o.graph_width) : Gruff::Bar.new(o.graph_width)
150
+ g.send "theme_#{o.theme}" if o.theme
151
+
152
+ # on OS X, ImagMagick can't find it's default font (arial) sometimes, so specify some font
153
+ #g.font = 'Arial-Normal' if RUBY_PLATFORM =~ /darwin/
154
+ g.font = 'Helvetica' if RUBY_PLATFORM =~ /darwin/
155
+
156
+ g.replace_colors(o.colors) if o.colors
157
+ g.title = o.title
158
+ g.sort = false
159
+ g.legend_font_size = o.font_size
160
+ g.legend_box_size = o.font_size
161
+ g.marker_font_size = o.font_size
162
+ g.minimum_value = 0
163
+ g.maximum_value = @perf_data.flatten.max.ceil
164
+ g.labels = o.labels.index_map
165
+ @perf_data.each_with_index{|d,i| g.data(o.names[i], d)}
166
+ g.write(o.output_file)
167
+ end
168
+
169
+ def plot_with_gnuplot
170
+ require 'gnuplot'
171
+ Gnuplot.open(false) do |gnuplot|
172
+ Gnuplot::Plot.new(gnuplot) do |plot|
173
+ plot.terminal "pdf noenhanced color fname 'Helvetica' fsize 5"
174
+ plot.output o.output_file
175
+ plot.xlabel "Benchmarks"
176
+ plot.ylabel "Requests per second"
177
+ plot.yrange "[0:*]"
178
+ plot.title o.title
179
+ plot.style "fill solid 1.0 noborder"
180
+ plot.style "data #{o.graph_type == :line ? "linespoints" : "histogram"}"
181
+ plot.style "histogram cluster gap 1"
182
+ plot.xtics "nomirror rotate by -45"
183
+ label_specs = []
184
+ o.labels.each_with_index{ |l,i| label_specs << "\"#{l}\" #{i}" }
185
+ plot.xtics "(#{label_specs.join(', ')})"
186
+ plot.key "outside reverse"
187
+ #plot.boxwidth "0.95"
188
+ plot.grid "nopolar"
189
+ plot.grid "noxtics nomxtics ytics nomytics noztics nomztics nox2tics nomx2tics noy2tics nomy2tics nocbtics nomcbtics"
190
+ plot.grid "back linetype 0 linewidth 0.7"
191
+
192
+ @perf_data.each_with_index do |d,i|
193
+ plot.data << Gnuplot::DataSet.new([[o.names[i]] + d]) do |ds|
194
+ ds.using = "1 title 1"
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ def plot
202
+ send "plot_with_#{o.engine}"
203
+ end
204
+ end
205
+
206
+ Plotter.new(o).plot
207
+
208
+
209
+ __END__
210
+
211
+ # Copyright (C) 2005-2008 Stefan Kaes
212
+ #
213
+ # This program is free software; you can redistribute it and/or modify
214
+ # it under the terms of the GNU General Public License as published by
215
+ # the Free Software Foundation; either version 2 of the License, or
216
+ # (at your option) any later version.
217
+ #
218
+ # This program is distributed in the hope that it will be useful,
219
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
220
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
221
+ # GNU General Public License for more details.
222
+ #
223
+ # You should have received a copy of the GNU General Public License
224
+ # along with this program; if not, write to the Free Software
225
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'ostruct'
6
+
7
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
8
+ require 'railsbench/gc_info'
9
+
10
+ # parse options
11
+ o = OpenStruct.new
12
+ o.title = "GC Data Plot"
13
+ o.graph_width = '1400x1050'
14
+ o.font_size = 10
15
+ o.ignored_object_types = []
16
+ o.output_file = nil
17
+ o.plot_live = true
18
+ o.plot_freed = true
19
+ o.plot_type = :both
20
+ o.engine = :gruff
21
+
22
+ parser = OptionParser.new do |opts|
23
+ opts.banner = "Usage: perf_plot_gc [options] file1 file2 ..."
24
+
25
+ opts.separator ""
26
+ opts.separator "Options:"
27
+
28
+ opts.on("-t", "--title T",
29
+ "Specify the title for your plot") do |t|
30
+ o.title = t
31
+ end
32
+
33
+ opts.on("-i", "--ignore LIST", Array,
34
+ "Specify the object types to ignore") do |i|
35
+ o.ignored_object_types = i.map{|t| t.upcase}
36
+ end
37
+
38
+ opts.on("-d", "--type TYPE", [:freed, :live, :both],
39
+ "Select data points to plot: (live, freed, both)") do |dp|
40
+ o.plot_type = dp
41
+ o.plot_freed = o.plot_live = false
42
+ case dp
43
+ when :live then o.plot_live = true
44
+ when :freed then o.plot_freed = true
45
+ when :both then o.plot_freed = true; o.plot_live = true
46
+ end
47
+ end
48
+
49
+ opts.on("-e", "--engine ENGINE", [:gruff, :gnuplot],
50
+ "Select plotting engine: (gruff, gnuplot)") do |e|
51
+ o.engine = e
52
+ end
53
+
54
+ opts.on("-f", "--font-size N", Integer,
55
+ "Overall font size to use in the plot (points)") do |n|
56
+ o.font_size = n
57
+ end
58
+
59
+ opts.on("-w", "--width W", Integer,
60
+ "Width of the plot (pixels)") do |w|
61
+ o.graph_width = w
62
+ end
63
+
64
+ opts.on("-g", "--geometry WxH", /\d+x\d+/,
65
+ "Specify plot dimensions (pixels)") do |d|
66
+ o.graph_width = d
67
+ end
68
+
69
+ opts.on("-o", "--out FILE",
70
+ "Specify output file") do |f|
71
+ o.output_file = f
72
+ end
73
+
74
+ opts.on_tail("-h", "--help", "Show this message") do
75
+ puts opts
76
+ exit
77
+ end
78
+ end
79
+
80
+ # option compatibility with older versions
81
+ args=[]
82
+ ARGV.each do |arg|
83
+ arg = arg.sub("font_size", "font-size") if arg =~ /^-font_size/
84
+ arg = "-" + arg if arg =~ /^-(title|width|out|geometry|font-size|ignore)/
85
+ args << arg
86
+ end
87
+
88
+ parser.parse!(args)
89
+
90
+ o.output_file ||= if o.engine == :gruff
91
+ "graph.png"
92
+ elsif RUBY_PLATFORM =~ /darwin/
93
+ "graph.pdf"
94
+ else
95
+ "graph.ps"
96
+ end
97
+ o.files = []
98
+ o.names = []
99
+ args.each do |arg|
100
+ o.files << File.open_or_die(arg)
101
+ o.names[o.files.length-1] ||= File.basename(arg)
102
+ end
103
+
104
+ o.files.length > 0 or die(parser.banner)
105
+
106
+ o.gcis = []
107
+ o.files.each do |file|
108
+ o.gcis << GCInfo.new(file)
109
+ file.close
110
+ end
111
+
112
+ # o.object_types = %w(NODE STRING ARRAY HASH SCOPE VARMAP CLASS ICLASS REGEXP FLOAT MATCH FILE DATA MODULE OBJECT)
113
+ o.colors = %w(ff0000 00c000 0080ff c000ff 00eeee c04000 ee0000 2020c0 ffc020 008040 a080ff 804000 ff80ff 00c060 006080 c06080 008000 40ff80 306080 806000).map{|c| "#" + c}
114
+ o.object_types = GCInfo.object_types(o.gcis)
115
+ o.gc_count_max = o.gcis.map{|gci| gci.collections}.max
116
+ o.gc_max_processed = o.gcis.map{|gci| gci.processed_max}.max
117
+ o.gc_max_freed = o.gcis.map{|gci| gci.freed_max}.max
118
+ o.gc_max_live = o.gcis.map{|gci| gci.live_max}.max
119
+
120
+ o.title << " ["
121
+ o.title << "freed" if o.plot_freed
122
+ o.title << "," if o.plot_freed && o.plot_live
123
+ o.title << "live" if o.plot_live
124
+ o.title << "]"
125
+ o.title << " (ignoring #{o.ignored_object_types.join(', ')})" unless o.ignored_object_types.empty?
126
+
127
+ # for very large logs, we need to ignore some entries
128
+ N = o.gc_count_max < 100 ? 1 : o.gc_count_max / 99
129
+
130
+ class Plotter
131
+ attr_reader :o
132
+ def initialize(options)
133
+ @o = options
134
+ end
135
+
136
+ def plot_with_gruff
137
+ require 'gruff'
138
+
139
+ g = Gruff::StackedBar.new(o.graph_width)
140
+
141
+ # on OS X, ImageMagick can't find it's default font (arial) sometimes, so specify some font
142
+ # g.font = 'Arial-Normal' if RUBY_PLATFORM =~ /darwin/
143
+ g.font = 'Helvetica-Narrow' if RUBY_PLATFORM =~ /darwin/
144
+
145
+ %w(#FF0000 #00FF00 #0000FF #D2FF77 #FF68C0 #D1FDFF #FFF0BD #15FFDC
146
+ ).each do |color|
147
+ g.add_color(color)
148
+ end
149
+
150
+ g.title = o.title
151
+ g.sort = false
152
+ g.title_font_size = o.font_size+2
153
+ g.legend_font_size = o.font_size-2
154
+ g.legend_box_size = o.font_size-2
155
+ g.marker_font_size = o.font_size-2
156
+ if o.ignored_object_types.empty?
157
+ g.minimum_value = 0
158
+ maximums = []
159
+ maximums << o.gc_max_live if o.plot_live
160
+ maximums << o.gc_max_freed if o.plot_freed
161
+ g.maximum_value = maximums.max
162
+ end
163
+ label_step = 0
164
+ label_step += 1 if o.plot_live
165
+ label_step += 1 if o.plot_freed
166
+ g.labels = Hash[* (0...o.gc_count_max).map{|i| [label_step*i*o.files.length, i.to_s]}.flatten ]
167
+ # puts g.labels.inspect
168
+ # puts object_types.inspect
169
+ puts "ignoring #{o.ignored_object_types.join(', ')}" unless o.ignored_object_types.empty?
170
+
171
+ (o.object_types + %w(FREELIST)).each do |ot|
172
+ data = prepare_data(ot)
173
+ # puts "#{ot}: #{data.inspect}"
174
+ g.data(ot, data)
175
+ end
176
+
177
+ g.write(o.output_file)
178
+ end
179
+
180
+ def prepare_data(ot)
181
+ return if o.ignored_object_types.include?(ot)
182
+ data = []
183
+ o.gc_count_max.times do |gc_index|
184
+ next unless 0 == gc_index.modulo(N)
185
+ for gci in o.gcis
186
+ map_at_this_gc = gci.freed_objects[gc_index].merge('FREELIST' => gci.freelist[gc_index])
187
+ data << ((map_at_this_gc && map_at_this_gc[ot]) || 0) if o.plot_freed
188
+ map_at_this_gc = gci.live_objects[gc_index]
189
+ data << ((map_at_this_gc && map_at_this_gc[ot]) || 0) if o.plot_live
190
+ end
191
+ end
192
+ data
193
+ end
194
+
195
+ def plot_with_gnuplot
196
+ require 'gnuplot'
197
+ # there's a separate gnuplot binary which can read from stdin, but the gem doesn't know this
198
+ ENV['RB_GNUPLOT'] ||= 'pgnuplot.exe' if RUBY_PLATFORM =~ /mswin/
199
+ plot = Gnuplot::Plot.new
200
+ if o.output_file =~ /\.pdf$/
201
+ plot.terminal "pdf enhanced color font 'Helvetica,4'"
202
+ else
203
+ plot.terminal "postscript enhanced color font 'Helvetica,4'"
204
+ end
205
+ plot.output o.output_file
206
+ plot.xlabel "Collections"
207
+ plot.ylabel "Objects"
208
+ plot.title o.title
209
+ plot.style "fill solid 1.0 noborder"
210
+ plot.style "data histogram"
211
+ plot.style "histogram rowstacked"
212
+ plot.xtics "out nomirror"
213
+ plot.xrange "[-1:#{(o.gc_count_max/N)*((o.plot_type == :both) ? 2 : 1)}]"
214
+ plot.key "outside invert reverse"
215
+ plot.boxwidth "0.8"
216
+ plot.grid "nopolar"
217
+ plot.grid "noxtics nomxtics ytics nomytics noztics nomztics nox2tics nomx2tics noy2tics nomy2tics nocbtics nomcbtics"
218
+ plot.grid "back linetype 0 linewidth 0.7"
219
+
220
+ (o.object_types + %w(FREELIST)).each_with_index do |ot, i|
221
+ next unless data = prepare_data(ot)
222
+ plot.data << Gnuplot::DataSet.new([[ot.downcase] + data]) do |ds|
223
+ ds.using = "1 title 1 lc rgb '#{ot == 'FREELIST' ? '#666666' : o.colors[i]}'"
224
+ end
225
+ end
226
+
227
+ cmds = plot.to_gplot # puts cmds
228
+ Gnuplot.open(false){|gnuplot| gnuplot << cmds}
229
+ end
230
+
231
+ def plot
232
+ send "plot_with_#{o.engine}"
233
+ end
234
+ end
235
+
236
+ Plotter.new(o).plot
237
+
238
+ __END__
239
+
240
+ # Copyright (C) 2005-2008 Stefan Kaes
241
+ #
242
+ # This program is free software; you can redistribute it and/or modify
243
+ # it under the terms of the GNU General Public License as published by
244
+ # the Free Software Foundation; either version 2 of the License, or
245
+ # (at your option) any later version.
246
+ #
247
+ # This program is distributed in the hope that it will be useful,
248
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
249
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
250
+ # GNU General Public License for more details.
251
+ #
252
+ # You should have received a copy of the GNU General Public License
253
+ # along with this program; if not, write to the Free Software
254
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA