|
1 | 1 | #!/usr/bin/env ruby |
2 | 2 |
|
3 | | -require 'optparse' |
4 | | -require 'ostruct' |
5 | 3 | require 'pathname' |
6 | 4 | require 'fileutils' |
7 | | -require 'shellwords' |
8 | 5 | require 'csv' |
9 | 6 | require 'json' |
| 7 | +require 'shellwords' |
10 | 8 | require 'rbconfig' |
11 | 9 | require 'etc' |
12 | 10 | require 'yaml' |
|
15 | 13 | require_relative 'lib/benchmark_runner' |
16 | 14 | require_relative 'lib/table_formatter' |
17 | 15 | require_relative 'lib/benchmark_filter' |
18 | | - |
19 | | -def have_yjit?(ruby) |
20 | | - ruby_version = `#{ruby} -v --yjit 2> #{File::NULL}`.strip |
21 | | - ruby_version.downcase.include?("yjit") |
22 | | -end |
| 16 | +require_relative 'lib/argument_parser' |
23 | 17 |
|
24 | 18 | def mean(values) |
25 | 19 | Stats.new(values).mean |
@@ -158,145 +152,7 @@ def run_benchmarks(ruby:, ruby_description:, categories:, name_filters:, out_pat |
158 | 152 | [bench_data, bench_failures] |
159 | 153 | end |
160 | 154 |
|
161 | | -# Default values for command-line arguments |
162 | | -args = OpenStruct.new({ |
163 | | - executables: {}, |
164 | | - out_path: File.expand_path("./data"), |
165 | | - out_override: nil, |
166 | | - harness: "harness", |
167 | | - yjit_opts: "", |
168 | | - categories: [], |
169 | | - name_filters: [], |
170 | | - rss: false, |
171 | | - graph: false, |
172 | | - no_pinning: false, |
173 | | - turbo: false, |
174 | | - skip_yjit: false, |
175 | | -}) |
176 | | - |
177 | | -OptionParser.new do |opts| |
178 | | - opts.on("-e=NAME::RUBY_PATH OPTIONS", "ruby executable and options to be benchmarked (default: interp, yjit)") do |v| |
179 | | - v.split(";").each do |name_executable| |
180 | | - name, executable = name_executable.split("::", 2) |
181 | | - if executable.nil? |
182 | | - executable = name # allow skipping `NAME::` |
183 | | - end |
184 | | - args.executables[name] = executable.shellsplit |
185 | | - end |
186 | | - end |
187 | | - |
188 | | - opts.on("--chruby=NAME::VERSION OPTIONS", "ruby version under chruby and options to be benchmarked") do |v| |
189 | | - v.split(";").each do |name_version| |
190 | | - name, version = name_version.split("::", 2) |
191 | | - # Convert `ruby --yjit` to `ruby::ruby --yjit` |
192 | | - if version.nil? |
193 | | - version = name |
194 | | - name = name.shellsplit.first |
195 | | - end |
196 | | - version, *options = version.shellsplit |
197 | | - rubies_dir = ENV["RUBIES_DIR"] || "#{ENV["HOME"]}/.rubies" |
198 | | - unless executable = ["/opt/rubies/#{version}/bin/ruby", "#{rubies_dir}/#{version}/bin/ruby"].find { |path| File.executable?(path) } |
199 | | - abort "Cannot find '#{version}' in /opt/rubies or #{rubies_dir}" |
200 | | - end |
201 | | - args.executables[name] = [executable, *options] |
202 | | - end |
203 | | - end |
204 | | - |
205 | | - opts.on("--out_path=OUT_PATH", "directory where to store output data files") do |v| |
206 | | - args.out_path = v |
207 | | - end |
208 | | - |
209 | | - opts.on("--out-name=OUT_FILE", "write exactly this output file plus file extension, ignoring directories, overwriting if necessary") do |v| |
210 | | - args.out_override = v |
211 | | - end |
212 | | - |
213 | | - opts.on("--category=headline,other,micro,ractor", "when given, only benchmarks with specified categories will run") do |v| |
214 | | - args.categories += v.split(",") |
215 | | - if args.categories == ["ractor"] |
216 | | - args.harness = "harness-ractor" |
217 | | - end |
218 | | - end |
219 | | - |
220 | | - opts.on("--headline", "when given, headline benchmarks will be run") do |
221 | | - args.categories += ["headline"] |
222 | | - end |
223 | | - |
224 | | - opts.on("--name_filters=x,y,z", Array, "when given, only benchmarks with names that contain one of these strings will run") do |list| |
225 | | - args.name_filters = list |
226 | | - end |
227 | | - |
228 | | - opts.on("--skip-yjit", "Don't run with yjit after interpreter") do |
229 | | - args.skip_yjit = true |
230 | | - end |
231 | | - |
232 | | - opts.on("--harness=HARNESS_DIR", "which harness to use") do |v| |
233 | | - v = "harness-#{v}" unless v.start_with?('harness') |
234 | | - args.harness = v |
235 | | - end |
236 | | - |
237 | | - opts.on("--warmup=N", "the number of warmup iterations for the default harness (default: 15)") do |n| |
238 | | - ENV["WARMUP_ITRS"] = n |
239 | | - end |
240 | | - |
241 | | - opts.on("--bench=N", "the number of benchmark iterations for the default harness (default: 10). Also defaults MIN_BENCH_TIME to 0.") do |n| |
242 | | - ENV["MIN_BENCH_ITRS"] = n |
243 | | - ENV["MIN_BENCH_TIME"] ||= "0" |
244 | | - end |
245 | | - |
246 | | - opts.on("--once", "benchmarks only 1 iteration with no warmup for the default harness") do |
247 | | - ENV["WARMUP_ITRS"] = "0" |
248 | | - ENV["MIN_BENCH_ITRS"] = "1" |
249 | | - ENV["MIN_BENCH_TIME"] = "0" |
250 | | - end |
251 | | - |
252 | | - opts.on("--yjit-stats=STATS", "print YJIT stats at each iteration for the default harness") do |str| |
253 | | - ENV["YJIT_BENCH_STATS"] = str |
254 | | - end |
255 | | - |
256 | | - opts.on("--zjit-stats=STATS", "print ZJIT stats at each iteration for the default harness") do |str| |
257 | | - ENV["ZJIT_BENCH_STATS"] = str |
258 | | - end |
259 | | - |
260 | | - opts.on("--yjit_opts=OPT_STRING", "string of command-line options to run YJIT with (ignored if you use -e)") do |str| |
261 | | - args.yjit_opts=str |
262 | | - end |
263 | | - |
264 | | - opts.on("--with_pre-init=PRE_INIT_FILE", |
265 | | - "a file to require before each benchmark run, so settings can be tuned (eg. enable/disable GC compaction)") do |str| |
266 | | - args.with_pre_init = str |
267 | | - end |
268 | | - |
269 | | - opts.on("--rss", "show RSS in the output (measured after benchmark iterations)") do |
270 | | - args.rss = true |
271 | | - end |
272 | | - |
273 | | - opts.on("--graph", "generate a graph image of benchmark results") do |
274 | | - args.graph = true |
275 | | - end |
276 | | - |
277 | | - opts.on("--no-pinning", "don't pin ruby to a specific CPU core") do |
278 | | - args.no_pinning = true |
279 | | - end |
280 | | - |
281 | | - opts.on("--turbo", "don't disable CPU turbo boost") do |
282 | | - args.turbo = true |
283 | | - end |
284 | | -end.parse! |
285 | | - |
286 | | -# Remaining arguments are treated as benchmark name filters |
287 | | -if ARGV.length > 0 |
288 | | - args.name_filters += ARGV |
289 | | -end |
290 | | - |
291 | | -# If -e is not specified, benchmark the current Ruby. Compare it with YJIT if available. |
292 | | -if args.executables.empty? |
293 | | - if have_yjit?(RbConfig.ruby) && !args.skip_yjit |
294 | | - args.executables["interp"] = [RbConfig.ruby] |
295 | | - args.executables["yjit"] = [RbConfig.ruby, "--yjit", *args.yjit_opts.shellsplit] |
296 | | - else |
297 | | - args.executables["ruby"] = [RbConfig.ruby] |
298 | | - end |
299 | | -end |
| 155 | +args = ArgumentParser.parse(ARGV) |
300 | 156 |
|
301 | 157 | CPUConfig.configure_for_benchmarking(turbo: args.turbo) |
302 | 158 |
|
|
0 commit comments