r18455 reverted.
[ruby-svn.git] / benchmark / driver.rb
blob4a1afe360bcd5d26605d22ce29df13ca090bde6b
2 # Ruby Benchmark driver
5 first = true
7 p RUBY_VERSION
9 begin
10   require 'optparse'
11 rescue LoadError
12   if first
13     first = false
14     $:.unshift File.join(File.dirname(__FILE__), '../lib')
15     retry
16   else
17     raise
18   end
19 end
21 require 'benchmark'
22 require 'pp'
24 class BenchmarkDriver
25   def self.benchmark(opt)
26     driver = self.new(opt[:execs], opt[:dir], opt)
27     begin
28       driver.run
29     ensure
30       driver.show_results
31     end
32   end
34   def output *args
35     puts(*args)
36     @output and @output.puts(*args)
37   end
39   def message *args
40     output(*args) if @verbose
41   end
43   def message_print *args
44     if @verbose
45       print(*args)
46       STDOUT.flush
47       @output and @output.print(*args)
48     end
49   end
51   def progress_message *args
52     unless STDOUT.tty?
53       STDERR.print(*args) 
54       STDERR.flush
55     end
56   end
58   def initialize execs, dir, opt = {}
59     @execs = execs.map{|e|
60       e.strip!
61       next if e.empty?
63       if /(.+)::(.+)/ =~ e
64         # ex) ruby-a::/path/to/ruby-a
65         v = $1.strip
66         e = $2
67       else
68         v =  `#{e} -v`.chomp
69         v.sub!(/ patchlevel \d+/, '')
70       end
71       [e, v]
72     }.compact
74     @dir = dir
75     @repeat = opt[:repeat] || 1
76     @repeat = 1 if @repeat < 1
77     @pattern = opt[:pattern] || nil
78     @verbose = opt[:quiet] ? false : (opt[:verbose] || false)
79     @output = opt[:output] ? open(opt[:output], 'w') : nil
80     @loop_wl1 = @loop_wl2 = nil
81     @opt = opt
83     # [[name, [[r-1-1, r-1-2, ...], [r-2-1, r-2-2, ...]]], ...]
84     @results = []
86     if @verbose
87       @start_time = Time.now
88       message @start_time
89       @execs.each_with_index{|(e, v), i|
90         message "target #{i}: #{v}"
91       }
92     end
93   end
95   def show_results
96     output
98     if @verbose
99       message '-----------------------------------------------------------'
100       message 'raw data:'
101       message
102       message PP.pp(@results, "", 79)
103       message
104       message "Elapesed time: #{Time.now - @start_time} (sec)"
105     end
107     output '-----------------------------------------------------------'
108     output 'benchmark results:'
110     if @verbose and @repeat > 1
111       output "minimum results in each #{@repeat} measurements."
112     end
114     output "name\t#{@execs.map{|(e, v)| v}.join("\t")}"
115     @results.each{|v, result|
116       rets = []
117       s = nil
118       result.each_with_index{|e, i|
119         r = e.min
120         case v
121         when /^vm1_/
122           if @loop_wl1
123             r -= @loop_wl1[i]
124             s = '*'
125           end
126         when /^vm2_/
127           if @loop_wl2
128             r -= @loop_wl2[i]
129             s = '*'
130           end
131         end
132         rets << sprintf("%.3f", r)
133       }
134       output "#{v}#{s}\t#{rets.join("\t")}"
135     }
136   end
138   def files
139     flag = {}
140     vm1 = vm2 = wl1 = wl2 = false
141     @files = Dir.glob(File.join(@dir, 'bm*.rb')).map{|file|
142       next if @pattern && /#{@pattern}/ !~ File.basename(file)
143       case file
144       when /bm_(vm[12])_/, /bm_loop_(whileloop2?).rb/
145         flag[$1] = true
146       end
147       file
148     }.compact
150     if flag['vm1'] && !flag['whileloop']
151       @files << File.join(@dir, 'bm_loop_whileloop.rb')
152     elsif flag['vm2'] && !flag['whileloop2']
153       @files << File.join(@dir, 'bm_loop_whileloop2.rb')
154     end
156     @files.sort!
157     progress_message "total: #{@files.size * @repeat} trial(s) (#{@repeat} trial(s) for #{@files.size} benchmark(s))\n"
158     @files
159   end
161   def run
162     files.each_with_index{|file, i|
163       @i = i
164       r = measure_file(file)
166       if /bm_loop_whileloop.rb/ =~ file
167         @loop_wl1 = r[1].map{|e| e.min}
168       elsif /bm_loop_whileloop2.rb/ =~ file
169         @loop_wl2 = r[1].map{|e| e.min}
170       end
171     }
172   end
174   def measure_file file
175     name = File.basename(file, '.rb').sub(/^bm_/, '')
176     prepare_file = File.join(File.dirname(file), "prepare_#{name}.rb")
177     load prepare_file if FileTest.exist?(prepare_file)
179     if @verbose
180       output
181       output '-----------------------------------------------------------'
182       output name
183       output
184       output File.read(file)
185       output
186     end
188     result = [name]
189     result << @execs.map{|(e, v)|
190       (0...@repeat).map{
191         message_print "#{v}\t"
192         progress_message '.'
194         m = measure(e, file)
195         message "#{m}"
196         m
197       }
198     }
199     @results << result
200     result
201   end
203   def measure executable, file
204     cmd = "#{executable} #{file}"
205     m = Benchmark.measure{
206       `#{cmd}`
207     }
209     if $? != 0
210       raise "Benchmark process exited with abnormal status (#{$?})"
211     end
213     m.real
214   end
217 if __FILE__ == $0
218   opt = {
219     :execs => ['ruby'],
220     :dir => './',
221     :repeat => 1,
222     :output => "bmlog-#{Time.now.strftime('%Y%m%d-%H%M%S')}.#{$$}",
223   }
225   parser = OptionParser.new{|o|
226     o.on('-e', '--executables [EXECS]',
227          "Specify benchmark one or more targets. (exec1; exec2; exec3, ...)"){|e|
228       opt[:execs] = e.split(/;/)
229     }
230     o.on('-d', '--directory [DIRECTORY]', "Benchmark suites directory"){|d|
231       opt[:dir] = d
232     }
233     o.on('-p', '--pattern [PATTERN]', "Benchmark name pattern"){|p|
234       opt[:pattern] = p
235     }
236     o.on('-r', '--repeat-count [NUM]', "Repeat count"){|n|
237       opt[:repeat] = n.to_i
238     }
239     o.on('-o', '--output-file [FILE]', "Output file"){|o|
240       opt[:output] = o
241     }
242     o.on('-q', '--quiet', "Run without notify information except result table."){|q|
243       opt[:quiet] = q
244     }
245     o.on('-v', '--verbose'){|v|
246       opt[:verbose] = v
247     }
248   }
250   parser.parse!(ARGV)
251   BenchmarkDriver.benchmark(opt)