Skip to content

Commit eccdfb4

Browse files
committed
Improve the run_once script to better handle Ruby options and harness selection
So we don't need to deal with the `-r` ruby argument directly for selecting harnesses.
1 parent fa0bd4f commit eccdfb4

File tree

8 files changed

+370
-44
lines changed

8 files changed

+370
-44
lines changed

README.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,14 @@ To run one or more specific benchmarks and record the data:
9393

9494
### Running a single benchmark
9595

96-
This is the easiest way to run a single benchmark.
97-
It requires no setup at all and assumes nothing about the Ruby you are benchmarking.
98-
It's also convenient for profiling, debugging, etc, especially since all benchmarked code runs in that process.
96+
The easiest way to run a single benchmark once is using the `run_once.rb` script:
9997

10098
```
101-
ruby benchmarks/some_benchmark.rb
99+
./run_once.rb benchmarks/some_benchmark.rb
102100
```
103101

102+
This automatically sets the environment to run the benchmark once (no warmup iterations).
103+
104104
## Ractor Benchmarks
105105

106106
ruby-bench supports Ractor-specific benchmarking with dedicated categories and benchmark directories.
@@ -198,23 +198,29 @@ You can find several test harnesses in the `harness/` directory:
198198
* `chain` - a harness to chain multiple harnesses together
199199
* `mplr` - a harness for multiple iterations with time limits
200200

201-
To use a specific harness, run a benchmark script directly with `-r` to require the harness:
201+
To use a specific harness, use the `run_once.rb` script:
202202

203203
```
204-
# Use default harness (loads harness/default.rb automatically)
205-
ruby benchmarks/railsbench/benchmark.rb
204+
# Use default harness
205+
./run_once.rb benchmarks/railsbench/benchmark.rb
206206
207207
# Use the 'once' harness
208-
ruby -r./harness/once benchmarks/railsbench/benchmark.rb
208+
./run_once.rb --harness=once benchmarks/railsbench/benchmark.rb
209209
210210
# Use the 'perf' harness
211-
ruby -r./harness/perf benchmarks/railsbench/benchmark.rb
211+
./run_once.rb --harness=perf benchmarks/railsbench/benchmark.rb
212212
213213
# Use the 'stackprof' harness
214-
ruby -r./harness/stackprof benchmarks/railsbench/benchmark.rb
214+
./run_once.rb --harness=stackprof benchmarks/railsbench/benchmark.rb
215215
216216
# Use the 'vernier' harness
217-
ruby -r./harness/vernier benchmarks/railsbench/benchmark.rb
217+
./run_once.rb --harness=vernier benchmarks/railsbench/benchmark.rb
218+
219+
# Pass Ruby options like --yjit (use -- separator)
220+
./run_once.rb -- --yjit benchmarks/railsbench/benchmark.rb
221+
222+
# Combine harness option with Ruby options
223+
./run_once.rb --harness=default -- --yjit-stats benchmarks/railsbench/benchmark.rb
218224
```
219225

220226
When using `run_benchmarks.rb`, you can specify a harness with the `--harness` option:
@@ -245,12 +251,11 @@ You can also use `--warmup`, `--bench`, or `--once` to set these environment var
245251
./run_benchmarks.rb railsbench --once
246252
```
247253

248-
There is also a handy script for running benchmarks just once using
249-
`WARMUP_ITRS=0 MIN_BENCH_ITRS=1 MIN_BENCH_TIME=0`, for example
254+
You can also use the `run_once.rb` script to run benchmarks just once, for example
250255
with the `--yjit-stats` command-line option:
251256

252257
```
253-
./run_once.sh --yjit-stats benchmarks/railsbench/benchmark.rb
258+
./run_once.rb -- --yjit-stats benchmarks/railsbench/benchmark.rb
254259
```
255260

256261
### Using perf
@@ -260,10 +265,10 @@ If `PERF` environment variable is present, it starts the perf subcommand after w
260265

261266
```sh
262267
# Use `perf record` for both warmup and benchmark
263-
perf record ruby --yjit-perf=map -r./harness/perf benchmarks/railsbench/benchmark.rb
268+
perf record ./run_once.rb --harness=perf -- --yjit-perf=map benchmarks/railsbench/benchmark.rb
264269

265270
# Use `perf record` only for benchmark
266-
PERF=record ruby --yjit-perf=map -r./harness/perf benchmarks/railsbench/benchmark.rb
271+
PERF=record ./run_once.rb --harness=perf -- --yjit-perf=map benchmarks/railsbench/benchmark.rb
267272
```
268273

269274
This is the only harness that uses `run_benchmark`'s argument, `num_itrs_hint`.

harness/perf.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# This is a relatively minimal harness meant for use with Linux perf(1).
44
# Example usage:
55
#
6-
# $ PERF='record -e cycles' ruby -r./harness/perf benchmarks/fib.rb
6+
# $ PERF='record -e cycles' ./run_once.rb --harness=perf benchmarks/fib.rb
77
#
88
# When recording with perf(1), make sure the benchmark runs long enough; you
99
# can tweak the MIN_BENCH_ITRS environment variable to lengthen the run. A race

harness/stackprof.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
# Profile the benchmark (ignoring initialization code) with stackprof.
44
# Customize stackprof options with an env var of STACKPROF_OPTS='key:value,...'.
55
# Usage:
6-
# STACKPROF_OPTS='mode:object' MIN_BENCH_TIME=0 MIN_BENCH_ITRS=1 ruby -v -r./harness/stackprof benchmarks/.../benchmark.rb
7-
# STACKPROF_OPTS='mode:cpu,interval:10' MIN_BENCH_TIME=1 MIN_BENCH_ITRS=10 ruby -v -r./harness/stackprof benchmarks/.../benchmark.rb
6+
# STACKPROF_OPTS='mode:object' ./run_once.rb --harness=stackprof benchmarks/.../benchmark.rb
7+
# STACKPROF_OPTS='mode:cpu,interval:10' MIN_BENCH_ITRS=10 ./run_once.rb --harness=stackprof benchmarks/.../benchmark.rb
88

99
require_relative "../lib/harness"
1010
require_relative "../lib/harness/extra"

harness/vernier.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
# Profile the benchmark (ignoring initialization code) using vernier and display the profile.
44
# Set NO_VIERWER=1 to disable automatically opening the profile in a browser.
55
# Usage:
6-
# MIN_BENCH_TIME=1 MIN_BENCH_ITRS=1 ruby -v -r./harness/vernier benchmarks/...
7-
# NO_VIEWER=1 MIN_BENCH_TIME=1 MIN_BENCH_ITRS=1 ruby -v -r./harness/vernier benchmarks/...
6+
# ./run_once.rb --harness=vernier benchmarks/...
7+
# NO_VIEWER=1 ./run_once.rb --harness=vernier benchmarks/...
88

99
require_relative "../lib/harness"
1010
require_relative "../lib/harness/extra"

lib/harness/loader.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
# Use harness/default.rb by default. You can change it with -r option.
2-
# The -r option should be specified BEFORE requiring loader.
1+
# Use harness/default.rb by default. You can change it with the --harness option in run_once.rb
2+
# or with -r option when calling Ruby directly.
33
# Examples:
4-
# ruby benchmarks/railsbench/benchmark.rb # uses harness/default.rb
5-
# ruby -r./harness/once benchmarks/railsbench/benchmark.rb # uses harness/once.rb
6-
# ruby -r./harness/ractor benchmarks/railsbench/benchmark.rb # uses harness/ractor.rb
4+
# ./run_once.rb benchmarks/railsbench/benchmark.rb # uses harness/default.rb
5+
# ./run_once.rb --harness=once benchmarks/railsbench/benchmark.rb # uses harness/once.rb
6+
# ./run_once.rb --harness=ractor benchmarks/railsbench/benchmark.rb # uses harness/ractor.rb
77

88
# Only load the default harness if no other harness has defined run_benchmark
99
unless defined?(run_benchmark)

run_once.rb

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
# Script to run a single benchmark once
5+
# Provides a clean interface for running benchmarks with different harnesses.
6+
# Examples:
7+
# ./run_once.rb benchmarks/railsbench/benchmark.rb
8+
# ./run_once.rb --harness=once benchmarks/fib.rb
9+
# ./run_once.rb --harness=stackprof benchmarks/fib.rb
10+
# ./run_once.rb -- --yjit-stats benchmarks/railsbench/benchmark.rb
11+
# ./run_once.rb --harness=default -- --yjit benchmarks/fib.rb
12+
13+
require 'optparse'
14+
require 'shellwords'
15+
16+
# Parse options
17+
harness = nil
18+
ruby_args = []
19+
benchmark_file = nil
20+
21+
parser = OptionParser.new do |opts|
22+
opts.banner = "Usage: #{$0} [options] [--] [ruby-options] BENCHMARK_FILE"
23+
24+
opts.on("--harness=HARNESS", "Harness to use (default: default, options: once, bips, perf, ractor, stackprof, vernier, warmup, stats, continuous, chain, mplr)") do |h|
25+
harness = h
26+
end
27+
28+
opts.on("-h", "--help", "Show this help message") do
29+
puts opts
30+
exit
31+
end
32+
end
33+
34+
# Parse our options - this will stop at '--' or first non-option argument
35+
begin
36+
parser.parse!
37+
rescue OptionParser::InvalidOption => e
38+
puts "Error: #{e.message}"
39+
puts parser
40+
exit 1
41+
end
42+
43+
# After parsing, ARGV contains remaining args (Ruby options + benchmark file)
44+
ARGV.each do |arg|
45+
if arg.end_with?('.rb') && !benchmark_file
46+
benchmark_file = arg
47+
else
48+
ruby_args << arg
49+
end
50+
end
51+
52+
if !benchmark_file
53+
puts "Error: No benchmark file specified"
54+
puts parser
55+
exit 1
56+
end
57+
58+
unless File.exist?(benchmark_file)
59+
puts "Error: Benchmark file not found: #{benchmark_file}"
60+
exit 1
61+
end
62+
63+
# Automatically detect ractor benchmarks
64+
if !harness && benchmark_file.include?('benchmarks-ractor/')
65+
harness = 'ractor'
66+
end
67+
68+
# Build the command
69+
harness_dir = File.expand_path('harness', __dir__)
70+
harness_args = if harness && harness != 'default'
71+
harness_path = File.join(harness_dir, harness)
72+
unless File.exist?("#{harness_path}.rb")
73+
puts "Error: Harness not found: #{harness}"
74+
puts "Available harnesses: #{Dir.glob("#{harness_dir}/*.rb").map { |f| File.basename(f, '.rb') }.join(', ')}"
75+
exit 1
76+
end
77+
['-r', harness_path]
78+
else
79+
[]
80+
end
81+
82+
# Set environment for running once
83+
ENV['WARMUP_ITRS'] = '0'
84+
ENV['MIN_BENCH_ITRS'] = '1'
85+
ENV['MIN_BENCH_TIME'] = '0'
86+
87+
# Build and execute the command
88+
cmd = ['ruby', *ruby_args, *harness_args, benchmark_file]
89+
90+
exec(*cmd)

run_once.sh

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)