railsbench 0.9.2 → 0.9.8
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.
- data/CHANGELOG +1808 -451
- data/GCPATCH +73 -0
- data/INSTALL +5 -0
- data/Manifest.txt +23 -13
- data/PROBLEMS +0 -0
- data/README +23 -7
- data/Rakefile +1 -2
- data/bin/railsbench +7 -1
- data/config/benchmarking.rb +0 -0
- data/config/benchmarks.rb +3 -2
- data/config/benchmarks.yml +0 -0
- data/images/empty.png +0 -0
- data/images/minus.png +0 -0
- data/images/plus.png +0 -0
- data/install.rb +1 -1
- data/latest_changes.txt +18 -0
- data/lib/benchmark.rb +0 -0
- data/lib/railsbench/benchmark.rb +576 -0
- data/lib/railsbench/benchmark_specs.rb +63 -63
- data/lib/railsbench/gc_info.rb +38 -3
- data/lib/railsbench/perf_info.rb +1 -1
- data/lib/railsbench/perf_utils.rb +202 -179
- data/lib/railsbench/railsbenchmark.rb +213 -55
- data/lib/railsbench/version.rb +9 -9
- data/lib/railsbench/write_headers_only.rb +15 -15
- data/postinstall.rb +0 -0
- data/ruby185gc.patch +56 -29
- data/ruby186gc.patch +564 -0
- data/ruby19gc.patch +2425 -0
- data/script/convert_raw_data_files +49 -49
- data/script/generate_benchmarks +14 -4
- data/script/perf_bench +12 -8
- data/script/perf_comp +1 -1
- data/script/perf_comp_gc +9 -1
- data/script/perf_diff +2 -2
- data/script/perf_diff_gc +2 -2
- data/script/perf_html +1 -1
- data/script/perf_plot +192 -75
- data/script/perf_plot_gc +213 -74
- data/script/perf_prof +29 -10
- data/script/perf_run +2 -2
- data/script/perf_run_gc +2 -2
- data/script/perf_table +2 -2
- data/script/perf_tex +1 -1
- data/script/perf_times +6 -6
- data/script/perf_times_gc +14 -2
- data/script/run_urls +16 -10
- data/setup.rb +0 -0
- data/test/railsbench_test.rb +0 -0
- data/test/test_helper.rb +2 -0
- metadata +77 -55
data/script/perf_plot_gc
CHANGED
@@ -1,104 +1,243 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
|
-
require '
|
4
|
+
require 'optparse'
|
5
|
+
require 'ostruct'
|
5
6
|
|
6
7
|
$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
7
8
|
require 'railsbench/gc_info'
|
8
9
|
|
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
|
10
32
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
labels = %w()
|
16
|
-
perf_data = []
|
17
|
-
graph_type = Gruff::StackedBar
|
18
|
-
graph_width = '1400x1050'
|
19
|
-
font_size = 14
|
20
|
-
ignored_object_types = %w(NODE STRING)
|
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
|
21
37
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
43
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
|
44
86
|
end
|
45
87
|
|
46
|
-
|
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)
|
47
105
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
gcis << GCInfo.new(file)
|
52
|
-
object_types.merge gcis.last.object_types
|
106
|
+
o.gcis = []
|
107
|
+
o.files.each do |file|
|
108
|
+
o.gcis << GCInfo.new(file)
|
53
109
|
file.close
|
54
110
|
end
|
55
111
|
|
56
|
-
object_types =
|
57
|
-
|
58
|
-
|
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
|
59
135
|
|
60
|
-
|
136
|
+
def plot_with_gruff
|
137
|
+
require 'gruff'
|
61
138
|
|
62
|
-
g.
|
63
|
-
g.add_color("#00FF00")
|
64
|
-
g.add_color("#0000FF")
|
139
|
+
g = Gruff::StackedBar.new(o.graph_width)
|
65
140
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
70
149
|
|
71
|
-
g.title = title
|
72
|
-
g.sort = false
|
73
|
-
g.
|
74
|
-
g.
|
75
|
-
g.
|
76
|
-
|
77
|
-
|
78
|
-
g.
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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)
|
90
175
|
end
|
176
|
+
|
177
|
+
g.write(o.output_file)
|
91
178
|
end
|
92
|
-
# puts "#{ot}: #{data.inspect}"
|
93
|
-
g.data(ot, data)
|
94
|
-
end
|
95
179
|
|
96
|
-
|
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
|
97
235
|
|
236
|
+
Plotter.new(o).plot
|
98
237
|
|
99
238
|
__END__
|
100
239
|
|
101
|
-
# Copyright (C) 2005
|
240
|
+
# Copyright (C) 2005-2008 Stefan Kaes
|
102
241
|
#
|
103
242
|
# This program is free software; you can redistribute it and/or modify
|
104
243
|
# it under the terms of the GNU General Public License as published by
|
data/script/perf_prof
CHANGED
@@ -9,6 +9,8 @@ end
|
|
9
9
|
bindir = File.dirname(__FILE__)
|
10
10
|
require "#{bindir}/../lib/railsbench/perf_utils"
|
11
11
|
|
12
|
+
determine_rails_root_or_die!
|
13
|
+
|
12
14
|
perf_data_dir = (ENV['RAILS_PERF_DATA'] ||= ENV['HOME'])
|
13
15
|
|
14
16
|
iterations = ARGV[0]
|
@@ -16,20 +18,32 @@ options = ARGV[1]
|
|
16
18
|
config = ARGV[2]
|
17
19
|
benchmark = ""
|
18
20
|
|
19
|
-
ruby_prof_opts="-ruby_prof=1"
|
21
|
+
ruby_prof_opts="-ruby_prof=0.1/1"
|
20
22
|
warmup="-warmup"
|
21
23
|
|
22
24
|
warmup = "" if options =~ /-warmup/
|
23
25
|
benchmark = $1 if options =~ /-bm=([^ ]+)/
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
if options =~ /(-ruby_prof=[^ ]+)/
|
27
|
+
ruby_prof_opts = $1
|
28
|
+
options = options.sub($1, '')
|
29
|
+
end
|
30
|
+
profile_type = 'graph'
|
31
|
+
if options =~ /(-profile_type=([^ ]+))/
|
32
|
+
profile_type = $2
|
33
|
+
ruby_prof_opts << " " << $1
|
34
|
+
options = options.sub($1, '')
|
35
|
+
end
|
36
|
+
extension = case profile_type
|
37
|
+
when 'grind' then 'dat'
|
38
|
+
when 'flat' then 'txt'
|
39
|
+
else 'html'
|
40
|
+
end
|
27
41
|
date = Time.now.strftime '%m-%d'
|
28
42
|
|
29
43
|
if config
|
30
|
-
benchmark_file="#{perf_data_dir}/#{date}.#{benchmark}.#{config}
|
44
|
+
benchmark_file="#{perf_data_dir}/#{date}.#{benchmark}.#{config}.#{profile_type}.#{extension}"
|
31
45
|
else
|
32
|
-
benchmark_file="#{perf_data_dir}/perf_run.#{benchmark}
|
46
|
+
benchmark_file="#{perf_data_dir}/perf_run.#{benchmark}.#{profile_type}.#{extension}"
|
33
47
|
end
|
34
48
|
ENV['RAILS_BENCHMARK_FILE'] = benchmark_file
|
35
49
|
|
@@ -42,16 +56,21 @@ perf_options="#{iterations} #{options} #{warmup} #{ruby_prof_opts}"
|
|
42
56
|
perf_cmd = "ruby #{bindir}/run_urls #{perf_options} >#{null}"
|
43
57
|
system(perf_cmd) || die("perf_prof: #{perf_cmd} returned #{$?}")
|
44
58
|
|
59
|
+
benchmark_file.sub!('.multi.', '.stack.') if profile_type == 'multi'
|
45
60
|
puts "profile data written to #{benchmark_file}"
|
46
61
|
|
47
|
-
|
48
|
-
|
49
|
-
|
62
|
+
if profile_type == 'grind'
|
63
|
+
system("kcachegrind #{benchmark_file} 2>/dev/null &") unless RUBY_PLATFORM =~ /win32/
|
64
|
+
else
|
65
|
+
case RUBY_PLATFORM
|
66
|
+
when /win32/ then system("start #{benchmark_file.gsub(/\//, '\\')}")
|
67
|
+
when /darwin/ then system("osascript -e 'tell application \"Safari\" to open location \"#{benchmark_file}\"'")
|
68
|
+
end
|
50
69
|
end
|
51
70
|
|
52
71
|
__END__
|
53
72
|
|
54
|
-
# Copyright (C) 2005
|
73
|
+
# Copyright (C) 2005-2008 Stefan Kaes
|
55
74
|
#
|
56
75
|
# This program is free software; you can redistribute it and/or modify
|
57
76
|
# it under the terms of the GNU General Public License as published by
|
data/script/perf_run
CHANGED
@@ -9,7 +9,7 @@ end
|
|
9
9
|
bindir = File.dirname(__FILE__)
|
10
10
|
require "#{bindir}/../lib/railsbench/perf_utils"
|
11
11
|
|
12
|
-
|
12
|
+
determine_rails_root_or_die!
|
13
13
|
|
14
14
|
iterations = ARGV[0]
|
15
15
|
options = ARGV[1]
|
@@ -22,7 +22,7 @@ perf_run("perf_run", iterations, options, benchmark_file)
|
|
22
22
|
|
23
23
|
__END__
|
24
24
|
|
25
|
-
# Copyright (C) 2005
|
25
|
+
# Copyright (C) 2005-2008 Stefan Kaes
|
26
26
|
#
|
27
27
|
# This program is free software; you can redistribute it and/or modify
|
28
28
|
# it under the terms of the GNU General Public License as published by
|
data/script/perf_run_gc
CHANGED
@@ -9,7 +9,7 @@ end
|
|
9
9
|
bindir = File.dirname(__FILE__)
|
10
10
|
require "#{bindir}/../lib/railsbench/perf_utils"
|
11
11
|
|
12
|
-
|
12
|
+
determine_rails_root_or_die!
|
13
13
|
|
14
14
|
iterations = ARGV[0]
|
15
15
|
options = ARGV[1]
|
@@ -23,7 +23,7 @@ perf_run_gc("perf_run_gc", iterations, options, benchmark_file)
|
|
23
23
|
|
24
24
|
__END__
|
25
25
|
|
26
|
-
# Copyright (C) 2005
|
26
|
+
# Copyright (C) 2005-2008 Stefan Kaes
|
27
27
|
#
|
28
28
|
# This program is free software; you can redistribute it and/or modify
|
29
29
|
# it under the terms of the GNU General Public License as published by
|
data/script/perf_table
CHANGED
@@ -67,7 +67,7 @@ perf_data = perf_data.map{|d| d.restrict_to(selection.map{|i| i-1})}
|
|
67
67
|
#puts labels.inspect
|
68
68
|
#puts perf_data.length
|
69
69
|
#puts perf_data.inspect
|
70
|
-
#puts names.inspect
|
70
|
+
#puts names.inspect
|
71
71
|
|
72
72
|
# puts labels.zip(perf_data).inspect
|
73
73
|
puts "<table border=1>"
|
@@ -87,7 +87,7 @@ puts "</table>"
|
|
87
87
|
|
88
88
|
__END__
|
89
89
|
|
90
|
-
# Copyright (C) 2007 Stefan Kaes
|
90
|
+
# Copyright (C) 2007, 2008 Stefan Kaes
|
91
91
|
#
|
92
92
|
# This program is free software; you can redistribute it and/or modify
|
93
93
|
# it under the terms of the GNU General Public License as published by
|
data/script/perf_tex
CHANGED
@@ -41,7 +41,7 @@ end
|
|
41
41
|
|
42
42
|
__END__
|
43
43
|
|
44
|
-
# Copyright (C) 2005
|
44
|
+
# Copyright (C) 2005-2008 Stefan Kaes
|
45
45
|
#
|
46
46
|
# This program is free software; you can redistribute it and/or modify
|
47
47
|
# it under the terms of the GNU General Public License as published by
|