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.
Files changed (51) hide show
  1. data/CHANGELOG +1808 -451
  2. data/GCPATCH +73 -0
  3. data/INSTALL +5 -0
  4. data/Manifest.txt +23 -13
  5. data/PROBLEMS +0 -0
  6. data/README +23 -7
  7. data/Rakefile +1 -2
  8. data/bin/railsbench +7 -1
  9. data/config/benchmarking.rb +0 -0
  10. data/config/benchmarks.rb +3 -2
  11. data/config/benchmarks.yml +0 -0
  12. data/images/empty.png +0 -0
  13. data/images/minus.png +0 -0
  14. data/images/plus.png +0 -0
  15. data/install.rb +1 -1
  16. data/latest_changes.txt +18 -0
  17. data/lib/benchmark.rb +0 -0
  18. data/lib/railsbench/benchmark.rb +576 -0
  19. data/lib/railsbench/benchmark_specs.rb +63 -63
  20. data/lib/railsbench/gc_info.rb +38 -3
  21. data/lib/railsbench/perf_info.rb +1 -1
  22. data/lib/railsbench/perf_utils.rb +202 -179
  23. data/lib/railsbench/railsbenchmark.rb +213 -55
  24. data/lib/railsbench/version.rb +9 -9
  25. data/lib/railsbench/write_headers_only.rb +15 -15
  26. data/postinstall.rb +0 -0
  27. data/ruby185gc.patch +56 -29
  28. data/ruby186gc.patch +564 -0
  29. data/ruby19gc.patch +2425 -0
  30. data/script/convert_raw_data_files +49 -49
  31. data/script/generate_benchmarks +14 -4
  32. data/script/perf_bench +12 -8
  33. data/script/perf_comp +1 -1
  34. data/script/perf_comp_gc +9 -1
  35. data/script/perf_diff +2 -2
  36. data/script/perf_diff_gc +2 -2
  37. data/script/perf_html +1 -1
  38. data/script/perf_plot +192 -75
  39. data/script/perf_plot_gc +213 -74
  40. data/script/perf_prof +29 -10
  41. data/script/perf_run +2 -2
  42. data/script/perf_run_gc +2 -2
  43. data/script/perf_table +2 -2
  44. data/script/perf_tex +1 -1
  45. data/script/perf_times +6 -6
  46. data/script/perf_times_gc +14 -2
  47. data/script/run_urls +16 -10
  48. data/setup.rb +0 -0
  49. data/test/railsbench_test.rb +0 -0
  50. data/test/test_helper.rb +2 -0
  51. metadata +77 -55
@@ -1,63 +1,63 @@
1
- require 'delegate'
2
- require 'yaml'
3
- require 'erb'
4
-
5
- class BenchmarkSpec < DelegateClass(Hash)
6
- attr_accessor :name
7
-
8
- READERS = %w(uri method post_data query_string new_session action controller session_data)
9
- READERS.each do |method|
10
- define_method(method) { self[method] }
11
- end
12
-
13
- def initialize(name, hash)
14
- super(hash)
15
- @name = name
16
- end
17
-
18
- def inspect
19
- "BenchmarkSpec(#{name},#{super})"
20
- end
21
-
22
- class << self
23
- def load(name, file_name = nil)
24
- unless file_name
25
- file_name = ENV['RAILS_ROOT'] + "/config/benchmarks.yml"
26
- end
27
- @@specs = YAML::load(ERB.new(IO.read(file_name)).result)
28
- raise "There is no benchmark named '#{name}'" unless @@specs[name]
29
- parse(@@specs, name)
30
- end
31
-
32
- def parse(specs, name)
33
- spec = specs[name]
34
- if spec.is_a?(String)
35
- spec.split(/, */).collect!{ |n| parse(specs, n) }.flatten
36
- elsif spec.is_a?(Hash)
37
- [ BenchmarkSpec.new(name,spec) ]
38
- elsif spec.is_a?(Array)
39
- spec.collect{|n| parse(specs, n)}.flatten
40
- else
41
- raise "oops: unknown entry type in benchmark specification"
42
- end
43
- end
44
- end
45
- end
46
-
47
- __END__
48
-
49
- # Copyright (C) 2007 Stefan Kaes
50
- #
51
- # This program is free software; you can redistribute it and/or modify
52
- # it under the terms of the GNU General Public License as published by
53
- # the Free Software Foundation; either version 2 of the License, or
54
- # (at your option) any later version.
55
- #
56
- # This program is distributed in the hope that it will be useful,
57
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
58
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59
- # GNU General Public License for more details.
60
- #
61
- # You should have received a copy of the GNU General Public License
62
- # along with this program; if not, write to the Free Software
63
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1
+ require 'delegate'
2
+ require 'yaml'
3
+ require 'erb'
4
+
5
+ class BenchmarkSpec < DelegateClass(Hash)
6
+ attr_accessor :name
7
+
8
+ READERS = %w(uri method post_data query_string new_session action controller session_data xhr raw_data)
9
+ READERS.each do |method|
10
+ define_method(method) { self[method] }
11
+ end
12
+
13
+ def initialize(name, hash)
14
+ super(hash)
15
+ @name = name
16
+ end
17
+
18
+ def inspect
19
+ "BenchmarkSpec(#{name},#{super})"
20
+ end
21
+
22
+ class << self
23
+ def load(name, file_name = nil)
24
+ unless file_name
25
+ file_name = ENV['RAILS_ROOT'] + "/config/benchmarks.yml"
26
+ end
27
+ @@specs = YAML::load(ERB.new(IO.read(file_name)).result)
28
+ raise "There is no benchmark named '#{name}'" unless @@specs[name]
29
+ parse(@@specs, name)
30
+ end
31
+
32
+ def parse(specs, name)
33
+ spec = specs[name]
34
+ if spec.is_a?(String)
35
+ spec.split(/, */).collect!{ |n| parse(specs, n) }.flatten
36
+ elsif spec.is_a?(Hash)
37
+ [ BenchmarkSpec.new(name,spec) ]
38
+ elsif spec.is_a?(Array)
39
+ spec.collect{|n| parse(specs, n)}.flatten
40
+ else
41
+ raise "oops: unknown entry type in benchmark specification"
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ __END__
48
+
49
+ # Copyright (C) 2007, 2008 Stefan Kaes
50
+ #
51
+ # This program is free software; you can redistribute it and/or modify
52
+ # it under the terms of the GNU General Public License as published by
53
+ # the Free Software Foundation; either version 2 of the License, or
54
+ # (at your option) any later version.
55
+ #
56
+ # This program is distributed in the hope that it will be useful,
57
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
58
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59
+ # GNU General Public License for more details.
60
+ #
61
+ # You should have received a copy of the GNU General Public License
62
+ # along with this program; if not, write to the Free Software
63
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -25,6 +25,15 @@ require "set"
25
25
  # kept 0173634 / freed 0002389 objects of type NODE
26
26
  # GC time: 47 msec
27
27
 
28
+ # Sentinel:
29
+ # HEAP[ 0]: size= 300000
30
+ # HEAP[ 1]: size= 600000
31
+ # ...
32
+ # number of requests processed: 1000
33
+ # 128334 nodes malloced for 17345 KB
34
+ # 396 leaks for 10464 total leaked bytes.
35
+
36
+
28
37
  GCAttributes = [:processed, :live, :freelist, :freed, :time]
29
38
  GCSummaries = [:min, :max, :mean, :stddev, :stddev_percentage]
30
39
 
@@ -41,7 +50,8 @@ class GCInfo
41
50
 
42
51
  attr_reader(*GCAttributes)
43
52
  attr_reader :entries, :num_requests, :collections, :garbage_produced, :time_total, :topology
44
- attr_reader :live_objects, :freed_objects, :object_types
53
+ attr_reader :live_objects, :freed_objects, :object_types, :garbage_totals
54
+ attr_reader :mallocs, :malloced, :leaks, :leaked
45
55
 
46
56
  GCAttributes.each do |attr|
47
57
  GCSummaries.each do |method|
@@ -54,6 +64,7 @@ class GCInfo
54
64
  @num_requests = 0
55
65
  @topology = []
56
66
  @object_types = Set.new
67
+ @mallocs = @malloced = @leaks = @leaked = 0
57
68
 
58
69
  file.each_line do |line|
59
70
  case line
@@ -72,11 +83,18 @@ class GCInfo
72
83
  when /^number of requests processed: (\d+)$/
73
84
  @num_requests = $1.to_i
74
85
  when /^HEAP\[\s*(\d+)\]: size=\s*(\d+)$/
86
+ @topology = [] if $1.to_i == 0
75
87
  @topology << $2.to_i
76
88
  when /^kept (\d+) \/ freed (\d+) objects of type ([a-zA-Z]+)/
77
89
  @object_types.add($3)
78
90
  @entries.last.live_objects[$3] = $1.to_i
79
91
  @entries.last.freed_objects[$3] = $2.to_i
92
+ when /^(\d+) nodes malloced for (\d+) KB$/
93
+ @mallocs = $1.to_i
94
+ @malloced = $2.to_i * 1024
95
+ when /^(\d+) leaks for (\d+) total leaked bytes.$/
96
+ @leaks = $1.to_i
97
+ @leaked = $2.to_i
80
98
  end
81
99
  end
82
100
 
@@ -85,10 +103,18 @@ class GCInfo
85
103
  @garbage_produced = @entries.map{|e| e.freed}.sum
86
104
  @live_objects = @entries.map{|e| e.live_objects}
87
105
  @freed_objects = @entries.map{|e| e.freed_objects}
106
+ @freelist = @entries.map{|e| e.freelist}
107
+ @garbage_totals = @freed_objects.inject(Hash.new(0)) do |totals, freed|
108
+ freed.each do |object_type, count|
109
+ totals[object_type] += freed[object_type] || 0
110
+ end
111
+ totals
112
+ end
88
113
 
89
114
  GCAttributes.each do |attr|
90
115
  a = @entries.map{|e| e.send attr}
91
- a.pop
116
+ # we need to pop the last entry, as the freelist is not empty when doing the last forced GC
117
+ a.pop if :freelist == attr.to_sym
92
118
 
93
119
  [:min, :max, :mean].each do |method|
94
120
  instance_variable_set "@#{attr}_#{method}", (a.send method)
@@ -99,6 +125,15 @@ class GCInfo
99
125
  end
100
126
  end
101
127
 
128
+ OBJECT_TYPES = %w(NODE STRING ARRAY HASH SCOPE VARMAP CLASS ICLASS REGEXP FLOAT MATCH FILE DATA MODULE OBJECT)
129
+
130
+ class << self
131
+ def object_types(list_of_gc_infos)
132
+ list_of_gc_infos.inject(OBJECT_TYPES) do |object_types, gci|
133
+ (object_types + gci.object_types.to_a).uniq
134
+ end
135
+ end
136
+ end
102
137
  end
103
138
 
104
139
 
@@ -106,7 +141,7 @@ end
106
141
  ### mode:ruby ***
107
142
  ### End: ***
108
143
 
109
- # Copyright (C) 2006, 2007 Stefan Kaes
144
+ # Copyright (C) 2006, 2007, 2008 Stefan Kaes
110
145
  #
111
146
  # This program is free software; you can redistribute it and/or modify
112
147
  # it under the terms of the GNU General Public License as published by
@@ -129,7 +129,7 @@ end
129
129
  ### mode:ruby ***
130
130
  ### End: ***
131
131
 
132
- # Copyright (C) 2006, 2007 Stefan Kaes
132
+ # Copyright (C) 2006, 2007, 2008 Stefan Kaes
133
133
  #
134
134
  # This program is free software; you can redistribute it and/or modify
135
135
  # it under the terms of the GNU General Public License as published by
@@ -1,179 +1,202 @@
1
- # some utility methods
2
-
3
- class Array
4
- def index_map
5
- res = {}
6
- each_with_index{|element, index| res[index] = element}
7
- res
8
- end
9
-
10
- def restrict_to(index_set)
11
- res = []
12
- each_with_index{|e,i| res << e if index_set.include?(i)}
13
- res
14
- end
15
-
16
- def sum
17
- inject(0.0){|r,v| r += v }
18
- end
19
-
20
- def mean
21
- sum/length
22
- end
23
-
24
- def stddev(mean=nil)
25
- mean ||= self.mean
26
- r = inject(0.0){|r,v| r += (v-mean)*(v-mean) }
27
- Math.sqrt(r/(length-1))
28
- end
29
- end
30
-
31
- def stddev_percentage(stddev, mean)
32
- stddev.zero? ? 0.0 : (stddev/mean)*100
33
- end
34
-
35
- def die(msg, error_code=1)
36
- $stderr.puts msg
37
- exit error_code
38
- end
39
-
40
- class File
41
- def self.open_or_die(filename, &block)
42
- filename = filename.sub(/^\/([cdefgh])(\/)/, '\1:\2') if RUBY_PLATFORM =~ /win32/
43
- begin
44
- if stat(filename).readable?
45
- open(filename, &block)
46
- else
47
- die "file #{filename} is unreadable"
48
- end
49
- rescue
50
- die "file #{filename} does not exist"
51
- end
52
- end
53
- end
54
-
55
- def truncate(text, length = 32, truncate_string = "...")
56
- if text.nil? then return "" end
57
- l = truncate_string.length + 1
58
-
59
- if $KCODE == "NONE"
60
- text.length > length ? text[0..(length - l)] + truncate_string : text
61
- else
62
- chars = text.split(//)
63
- chars.length > length ? chars[0..(length - l)].join + truncate_string : text
64
- end
65
- end
66
-
67
- RAILSBENCH_BINDIR = File.expand_path(File.dirname(__FILE__) + "/../../script")
68
-
69
- def enable_gc_stats(file)
70
- ENV['RUBY_GC_STATS'] = "1"
71
- ENV['RUBY_GC_DATA_FILE'] = file
72
- end
73
-
74
- def disable_gc_stats
75
- ENV.delete 'RUBY_GC_STATS'
76
- ENV.delete 'RUBY_GC_DATA_FILE'
77
- end
78
-
79
- def unset_gc_variables
80
- %w(RUBY_HEAP_MIN_SLOTS RUBY_GC_MALLOC_LIMIT RUBY_HEAP_FREE_MIN).each{|v| ENV.delete v}
81
- end
82
-
83
- def load_gc_variables(gc_spec)
84
- File.open_or_die("#{ENV['RAILS_ROOT']}/config/#{gc_spec}.gc").each_line do |line|
85
- ENV[$1] = $2 if line =~ /^(.*)=(.*)$/
86
- end
87
- end
88
-
89
- def set_gc_variables(argv)
90
- gc_spec = nil
91
- argv.each{|arg| gc_spec=$1 if arg =~ /-gc=([^ ]*)/}
92
-
93
- if gc_spec
94
- load_gc_variables(gc_spec)
95
- else
96
- unset_gc_variables
97
- end
98
- end
99
-
100
- def benchmark_file_name(benchmark, config_name, prefix=nil, suffix=nil)
101
- perf_data_dir = (ENV['RAILS_PERF_DATA'] ||= ENV['HOME'])
102
- date = Time.now.strftime '%m-%d'
103
- suffix = ".#{suffix}" if suffix
104
- ENV['RAILS_BENCHMARK_FILE'] =
105
- if config_name
106
- "#{perf_data_dir}/#{date}.#{benchmark}.#{config_name}#{suffix}.txt"
107
- else
108
- "#{perf_data_dir}/perf_run#{prefix}.#{benchmark}#{suffix}.txt"
109
- end
110
- end
111
-
112
- def quote_arguments(argv)
113
- argv.map{|a| a.include?(' ') ? "'#{a}'" : a.to_s}.join(' ')
114
- end
115
-
116
- def perf_run(script, iterations, options, raw_data_file)
117
- perf_runs = (ENV['RAILS_PERF_RUNS'] ||= "3").to_i
118
-
119
- disable_gc_stats
120
- set_gc_variables([iterations, options])
121
-
122
- perf_options = "#{iterations} #{options}"
123
- null = (RUBY_PLATFORM =~ /win32/i) ? 'nul' : '/dev/null'
124
-
125
- perf_cmd = "ruby #{RAILSBENCH_BINDIR}/perf_bench #{perf_options}"
126
- print_cmd = "ruby #{RAILSBENCH_BINDIR}/perf_times #{raw_data_file}"
127
-
128
- puts "benchmarking #{perf_runs} runs with options #{perf_options}"
129
-
130
- File.open(raw_data_file, "w"){ |f| f.puts perf_cmd }
131
- perf_runs.times do
132
- system("#{perf_cmd} >#{null}") || die("#{script}: #{perf_cmd} returned #{$?}")
133
- end
134
- File.open(raw_data_file, "a" ){|f| f.puts }
135
-
136
- unset_gc_variables
137
- system(print_cmd) || die("#{script}: #{print_cmd} returned #{$?}")
138
- end
139
-
140
- def perf_run_gc(script, iterations, options, raw_data_file)
141
- warmup = "-warmup"
142
- warmup = "" if options =~ /-warmup/
143
-
144
- enable_gc_stats(raw_data_file)
145
- set_gc_variables([options])
146
-
147
- perf_options = "#{iterations} #{warmup} #{options}"
148
- null = (RUBY_PLATFORM =~ /win32/) ? 'nul' : '/dev/null'
149
-
150
- perf_cmd = "ruby #{RAILSBENCH_BINDIR}/run_urls #{perf_options} >#{null}"
151
- print_cmd = "ruby #{RAILSBENCH_BINDIR}/perf_times_gc #{raw_data_file}"
152
-
153
- puts "benchmarking GC performance with options #{perf_options}"
154
- puts
155
-
156
- system(perf_cmd) || die("#{script}: #{perf_cmd} returned #{$?}")
157
-
158
- disable_gc_stats
159
- unset_gc_variables
160
- system(print_cmd) || die("#{script}: #{print_cmd} returned #{$?}")
161
- end
162
-
163
- __END__
164
-
165
- # Copyright (C) 2005, 2006, 2007 Stefan Kaes
166
- #
167
- # This program is free software; you can redistribute it and/or modify
168
- # it under the terms of the GNU General Public License as published by
169
- # the Free Software Foundation; either version 2 of the License, or
170
- # (at your option) any later version.
171
- #
172
- # This program is distributed in the hope that it will be useful,
173
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
174
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
175
- # GNU General Public License for more details.
176
- #
177
- # You should have received a copy of the GNU General Public License
178
- # along with this program; if not, write to the Free Software
179
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1
+ # some utility methods
2
+
3
+ class Array
4
+ def index_map
5
+ res = {}
6
+ each_with_index{|element, index| res[index] = element}
7
+ res
8
+ end
9
+
10
+ def restrict_to(index_set)
11
+ res = []
12
+ each_with_index{|e,i| res << e if index_set.include?(i)}
13
+ res
14
+ end
15
+
16
+ def sum
17
+ inject(0.0){|r,v| r += v }
18
+ end
19
+
20
+ def mean
21
+ sum/length
22
+ end
23
+
24
+ def stddev(mean=nil)
25
+ mean ||= self.mean
26
+ r = inject(0.0){|r,v| r += (v-mean)*(v-mean) }
27
+ Math.sqrt(r/(length-1))
28
+ end
29
+ end
30
+
31
+ def stddev_percentage(stddev, mean)
32
+ stddev.zero? ? 0.0 : (stddev/mean)*100
33
+ end
34
+
35
+ def determine_rails_root_or_die!(msg=nil)
36
+ unless ENV['RAILS_ROOT']
37
+ if File.directory?("config") && File.exists?("config/environment.rb")
38
+ ENV['RAILS_ROOT'] = File.expand_path(".")
39
+ else
40
+ die(msg || "#{File.basename $PROGRAM_NAME}: $RAILS_ROOT not set and could not be configured automatically")
41
+ end
42
+ end
43
+ end
44
+
45
+ def die(msg, error_code=1)
46
+ $stderr.puts msg
47
+ exit error_code
48
+ end
49
+
50
+ class File
51
+ def self.open_or_die(filename, &block)
52
+ filename = filename.sub(/^\/([cdefgh])(\/)/, '\1:\2') if RUBY_PLATFORM =~ /win32/
53
+ begin
54
+ if stat(filename).readable?
55
+ open(filename, &block)
56
+ else
57
+ die "file #{filename} is unreadable"
58
+ end
59
+ rescue
60
+ die "file #{filename} does not exist"
61
+ end
62
+ end
63
+ end
64
+
65
+ def truncate(text, length = 32, truncate_string = "...")
66
+ if text.nil? then return "" end
67
+ l = truncate_string.length + 1
68
+
69
+ if RUBY_VERSION !~ /1.9/ && $KCODE == "NONE"
70
+ text.length > length ? text[0..(length - l)] + truncate_string : text
71
+ else
72
+ chars = text.split(//)
73
+ chars.length > length ? chars[0..(length - l)].join + truncate_string : text
74
+ end
75
+ end
76
+
77
+ RAILSBENCH_BINDIR = File.expand_path(File.dirname(__FILE__) + "/../../script")
78
+
79
+ def enable_gc_stats(file)
80
+ ENV['RUBY_GC_STATS'] = "1"
81
+ ENV['RUBY_GC_DATA_FILE'] = file
82
+ end
83
+
84
+ def disable_gc_stats
85
+ ENV.delete 'RUBY_GC_STATS'
86
+ ENV.delete 'RUBY_GC_DATA_FILE'
87
+ end
88
+
89
+ def unset_gc_variables
90
+ %w(RUBY_HEAP_MIN_SLOTS RUBY_GC_MALLOC_LIMIT RUBY_HEAP_FREE_MIN).each{|v| ENV.delete v}
91
+ end
92
+
93
+ def load_gc_variables(gc_spec)
94
+ File.open_or_die("#{ENV['RAILS_ROOT']}/config/#{gc_spec}.gc").each_line do |line|
95
+ ENV[$1] = $2 if line =~ /^(?:export )?(.*)=(.*)$/
96
+ end
97
+ end
98
+
99
+ def set_gc_variables(argv)
100
+ gc_spec = nil
101
+ argv.each{|arg| gc_spec=$1 if arg =~ /-gc=([^ ]*)/}
102
+
103
+ if gc_spec
104
+ load_gc_variables(gc_spec)
105
+ else
106
+ unset_gc_variables
107
+ end
108
+ end
109
+
110
+ def benchmark_file_name(benchmark, config_name, prefix=nil, suffix=nil)
111
+ perf_data_dir = (ENV['RAILS_PERF_DATA'] ||= ENV['HOME'])
112
+ date = Time.now.strftime '%m-%d'
113
+ suffix = ".#{suffix}" if suffix
114
+ ENV['RAILS_BENCHMARK_FILE'] =
115
+ if config_name
116
+ "#{perf_data_dir}/#{date}.#{benchmark}.#{config_name}#{suffix}.txt"
117
+ else
118
+ "#{perf_data_dir}/perf_run#{prefix}.#{benchmark}#{suffix}.txt"
119
+ end
120
+ end
121
+
122
+ def quote_arguments(argv)
123
+ argv.map{|a| a.include?(' ') ? "'#{a}'" : a.to_s}.join(' ')
124
+ end
125
+
126
+ def ruby
127
+ ENV['RUBY'] || "ruby"
128
+ end
129
+
130
+ def perf_run(script, iterations, options, raw_data_file)
131
+ perf_runs = (ENV['RAILS_PERF_RUNS'] ||= "3").to_i
132
+
133
+ disable_gc_stats
134
+ set_gc_variables([iterations, options])
135
+
136
+ perf_options = "#{iterations} #{options}"
137
+ null = (RUBY_PLATFORM =~ /win32/i) ? 'nul' : '/dev/null'
138
+
139
+ perf_cmd = "#{ruby} #{RAILSBENCH_BINDIR}/perf_bench #{perf_options}"
140
+ print_cmd = "#{ruby} #{RAILSBENCH_BINDIR}/perf_times #{raw_data_file}"
141
+
142
+ puts "benchmarking #{perf_runs} runs with options #{perf_options}"
143
+
144
+ File.open(raw_data_file, "w"){ |f| f.puts perf_cmd }
145
+ perf_runs.times do
146
+ system("#{perf_cmd} >#{null}") || die("#{script}: #{perf_cmd} returned #{$?}")
147
+ end
148
+ File.open(raw_data_file, "a" ){|f| f.puts }
149
+
150
+ unset_gc_variables
151
+ system(print_cmd) || die("#{script}: #{print_cmd} returned #{$?}")
152
+ end
153
+
154
+ def perf_run_gc(script, iterations, options, raw_data_file)
155
+ warmup = "-warmup"
156
+ warmup = "" if options =~ /-warmup/
157
+
158
+ enable_gc_stats(raw_data_file)
159
+ set_gc_variables([options])
160
+
161
+ perf_options = "#{iterations} #{warmup} #{options}"
162
+ null = (RUBY_PLATFORM =~ /win32/) ? 'nul' : '/dev/null'
163
+
164
+ perf_cmd = "#{ruby} #{RAILSBENCH_BINDIR}/run_urls #{perf_options} >#{null}"
165
+ print_cmd = "#{ruby} #{RAILSBENCH_BINDIR}/perf_times_gc #{raw_data_file}"
166
+
167
+ if options =~ /-leaks/
168
+ if RUBY_PLATFORM =~ /darwin9/
169
+ puts "enabling MallocStackLogging"
170
+ perf_cmd.insert(0, "MallocStackLogging=1 ")
171
+ else
172
+ die "leak debugging not supported on #{RUBY_PLATFORM}"
173
+ end
174
+ end
175
+
176
+ puts "benchmarking GC performance with options #{perf_options}"
177
+ puts
178
+
179
+ system(perf_cmd) || die("#{script}: #{perf_cmd} returned #{$?}")
180
+
181
+ disable_gc_stats
182
+ unset_gc_variables
183
+ system(print_cmd) || die("#{script}: #{print_cmd} returned #{$?}")
184
+ end
185
+
186
+ __END__
187
+
188
+ # Copyright (C) 2005-2008 Stefan Kaes
189
+ #
190
+ # This program is free software; you can redistribute it and/or modify
191
+ # it under the terms of the GNU General Public License as published by
192
+ # the Free Software Foundation; either version 2 of the License, or
193
+ # (at your option) any later version.
194
+ #
195
+ # This program is distributed in the hope that it will be useful,
196
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
197
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
198
+ # GNU General Public License for more details.
199
+ #
200
+ # You should have received a copy of the GNU General Public License
201
+ # along with this program; if not, write to the Free Software
202
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA