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