benchmark_driver 0.15.12 → 0.15.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/exe/benchmark-driver +4 -1
- data/lib/benchmark_driver/config.rb +4 -1
- data/lib/benchmark_driver/default_job_parser.rb +1 -1
- data/lib/benchmark_driver/job_parser.rb +12 -9
- data/lib/benchmark_driver/output/markdown.rb +1 -0
- data/lib/benchmark_driver/runner.rb +4 -0
- data/lib/benchmark_driver/runner/ips.rb +18 -12
- data/lib/benchmark_driver/runner/ruby_stdout.rb +73 -15
- data/lib/benchmark_driver/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc6888fbbe3ec73fcb84874bbc31535a08ae07859cbc8b86c0dd53d2e33ed2b7
|
4
|
+
data.tar.gz: cc052011eb026f8dd4d250a191fcbe30bdb3024b2157659c80696649d0c58840
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2516d64721d7b53f1466468263464024ebcdcc9906787ff29b38a494e2f8ecab275ccad7fcdc4928c1482c43b4ec0195d2733b38476ca919ff95b3b304cc4174
|
7
|
+
data.tar.gz: e6e62c506e94fe8e2add9af0ea3bd6abd531299117d28e7a2b1cbfee1d56db309907d1787b6cb090bdd64cefe0206641ec753b15ceb0625ed118406e61af1d33
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
# v0.15.17
|
2
|
+
|
3
|
+
- Jobs returned from job parsers are made mutable for plugins
|
4
|
+
|
5
|
+
# v0.15.16
|
6
|
+
|
7
|
+
- Add `--alternate` runner option to run executables alternately.
|
8
|
+
This is supported only for `ruby_stdout` runner for now.
|
9
|
+
|
10
|
+
# v0.15.15
|
11
|
+
|
12
|
+
- An absolute path is passed to `command_stdout`'s `working_directory`
|
13
|
+
and v0.15.14's relative path resolution of job type
|
14
|
+
|
15
|
+
# v0.15.14
|
16
|
+
|
17
|
+
- YAML's `type` key allows a value with `/` to specify a relative path of a runner plugin
|
18
|
+
|
19
|
+
# v0.15.13
|
20
|
+
|
21
|
+
- Show a command and stdout on `-vv` for `ips`, `time`, and `block` runner
|
22
|
+
|
1
23
|
# v0.15.12
|
2
24
|
|
3
25
|
- Show comparison on `--output=markdown` when `--output-compare` is also specified
|
data/exe/benchmark-driver
CHANGED
@@ -67,6 +67,9 @@ config = BenchmarkDriver::Config.new.tap do |c|
|
|
67
67
|
end
|
68
68
|
c.repeat_result = v
|
69
69
|
end
|
70
|
+
o.on('--alternate', 'Alternate executables instead of running the same executable in a row with --repeat-count') do |v|
|
71
|
+
c.alternate = v
|
72
|
+
end
|
70
73
|
o.on('--bundler', 'Install and use gems specified in Gemfile') do |v|
|
71
74
|
bundler = v
|
72
75
|
end
|
@@ -124,7 +127,7 @@ jobs = config.paths.flat_map do |path|
|
|
124
127
|
|
125
128
|
begin
|
126
129
|
# `working_directory` is YAML-specific special parameter, mainly for "command_stdout"
|
127
|
-
BenchmarkDriver::JobParser.parse(job,
|
130
|
+
BenchmarkDriver::JobParser.parse(job, working_directory: File.expand_path(File.dirname(path)))
|
128
131
|
rescue ArgumentError
|
129
132
|
$stderr.puts "benchmark-driver: Failed to parse #{path.dump}."
|
130
133
|
$stderr.puts ' YAML format may be wrong. See error below:'
|
@@ -13,6 +13,7 @@ module BenchmarkDriver
|
|
13
13
|
:filters, # @param [Array<Regexp>]
|
14
14
|
:repeat_count, # @param [Integer]
|
15
15
|
:repeat_result, # @param [String]
|
16
|
+
:alternate, # @param [TrueClass,FalseClass]
|
16
17
|
:run_duration, # @param [Float]
|
17
18
|
:timeout, # @param [Float,nil]
|
18
19
|
:verbose, # @param [Integer]
|
@@ -23,15 +24,17 @@ module BenchmarkDriver
|
|
23
24
|
filters: [],
|
24
25
|
repeat_count: 1,
|
25
26
|
repeat_result: 'best',
|
27
|
+
alternate: false,
|
26
28
|
run_duration: 3.0,
|
27
29
|
verbose: 0,
|
28
30
|
},
|
29
31
|
)
|
30
32
|
|
31
|
-
# Subset of
|
33
|
+
# Subset of Config passed to JobRunner
|
32
34
|
Config::RunnerConfig = ::BenchmarkDriver::Struct.new(
|
33
35
|
:repeat_count, # @param [Integer]
|
34
36
|
:repeat_result, # @param [String]
|
37
|
+
:alternate, # @param [TrueClass,FalseClass]
|
35
38
|
:run_duration, # @param [Float]
|
36
39
|
:timeout, # @param [Float,nil]
|
37
40
|
:verbose, # @param [Integer]
|
@@ -3,24 +3,27 @@ require 'benchmark_driver/runner'
|
|
3
3
|
module BenchmarkDriver
|
4
4
|
class << JobParser = Module.new
|
5
5
|
# @param [Hash] config
|
6
|
-
# @param [Hash]
|
7
|
-
def parse(config,
|
6
|
+
# @param [Hash] working_directory - YAML-specific special parameter for "command_stdout" and a relative path in type
|
7
|
+
def parse(config, working_directory: nil)
|
8
8
|
config = symbolize_keys(config)
|
9
9
|
type = config.fetch(:type)
|
10
10
|
if !type.is_a?(String)
|
11
11
|
raise ArgumentError.new("Invalid type: #{config[:type].inspect} (expected String)")
|
12
|
-
elsif !type.match(/\A[A-Za-z0-9_]+\z/)
|
13
|
-
raise ArgumentError.new("Invalid type: #{config[:type].inspect} (expected to include only [A-Za-z0-9_])")
|
12
|
+
elsif !type.match(/\A[A-Za-z0-9_\/]+\z/)
|
13
|
+
raise ArgumentError.new("Invalid type: #{config[:type].inspect} (expected to include only [A-Za-z0-9_\/])")
|
14
14
|
end
|
15
15
|
config.delete(:type)
|
16
16
|
|
17
17
|
# Dynamic dispatch for plugin support
|
18
|
-
|
18
|
+
if type.include?('/')
|
19
|
+
require File.join(working_directory || '.', type)
|
20
|
+
type = File.basename(type)
|
21
|
+
else
|
22
|
+
require "benchmark_driver/runner/#{type}"
|
23
|
+
end
|
19
24
|
job = ::BenchmarkDriver.const_get("Runner::#{camelize(type)}::JobParser", false).parse(**config)
|
20
|
-
|
21
|
-
|
22
|
-
job.public_send("#{key}=", value)
|
23
|
-
end
|
25
|
+
if job.respond_to?(:working_directory) && job.respond_to?(:working_directory=) && job.working_directory.nil?
|
26
|
+
job.working_directory = working_directory
|
24
27
|
end
|
25
28
|
job
|
26
29
|
end
|
@@ -8,6 +8,7 @@ class BenchmarkDriver::Output::Markdown
|
|
8
8
|
# @param [Array<BenchmarkDriver::Metric>] metrics
|
9
9
|
# @param [Array<BenchmarkDriver::Job>] jobs
|
10
10
|
# @param [Array<BenchmarkDriver::Context>] contexts
|
11
|
+
# @param [Hash{ Symbol => Object }] options
|
11
12
|
def initialize(metrics:, jobs:, contexts:, options:)
|
12
13
|
@metrics = metrics
|
13
14
|
@contexts = contexts
|
@@ -30,6 +30,10 @@ module BenchmarkDriver
|
|
30
30
|
contexts_jobs.group_by(&:metrics).each do |metrics, metrics_jobs|
|
31
31
|
metrics_jobs.group_by(&:class).each do |klass, klass_jobs|
|
32
32
|
runner = runner_for(klass)
|
33
|
+
if runner_config.alternate && runner != BenchmarkDriver::Runner::RubyStdout
|
34
|
+
abort "--alternate is supported only for ruby_stdout runner for now"
|
35
|
+
end
|
36
|
+
|
33
37
|
contexts = build_contexts(contexts, executables: config.executables)
|
34
38
|
output = Output.new(
|
35
39
|
type: config.output_type,
|
@@ -40,8 +40,8 @@ class BenchmarkDriver::Runner::Ips
|
|
40
40
|
@output.report(values: { metric => value }, duration: duration, loop_count: loop_count)
|
41
41
|
end
|
42
42
|
|
43
|
-
loop_count = (loop_count.to_f * @config.run_duration / duration).floor
|
44
|
-
|
43
|
+
job.loop_count = (loop_count.to_f * @config.run_duration / duration).floor
|
44
|
+
job
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -107,8 +107,8 @@ class BenchmarkDriver::Runner::Ips
|
|
107
107
|
|
108
108
|
duration = Tempfile.open(['benchmark_driver-', '.rb']) do |f|
|
109
109
|
with_script(benchmark.render(result: f.path)) do |path|
|
110
|
-
|
111
|
-
if
|
110
|
+
success = execute(*context.executable.command, path, exception: false)
|
111
|
+
if success && ((value = Float(f.read)) > 0)
|
112
112
|
value
|
113
113
|
else
|
114
114
|
BenchmarkDriver::Result::ERROR
|
@@ -137,10 +137,7 @@ class BenchmarkDriver::Runner::Ips
|
|
137
137
|
end
|
138
138
|
|
139
139
|
def with_script(script)
|
140
|
-
if @config.verbose >= 2
|
141
|
-
sep = '-' * 30
|
142
|
-
$stdout.puts "\n\n#{sep}[Script begin]#{sep}\n#{script}#{sep}[Script end]#{sep}\n\n"
|
143
|
-
end
|
140
|
+
debug_output('Script', script) if @config.verbose >= 2
|
144
141
|
|
145
142
|
Tempfile.open(['benchmark_driver-', '.rb']) do |f|
|
146
143
|
f.puts script
|
@@ -149,11 +146,20 @@ class BenchmarkDriver::Runner::Ips
|
|
149
146
|
end
|
150
147
|
end
|
151
148
|
|
152
|
-
def execute(*args)
|
153
|
-
|
154
|
-
|
155
|
-
|
149
|
+
def execute(*args, exception: true)
|
150
|
+
$stderr.puts "$ #{args.shelljoin}" if @config.verbose >= 2
|
151
|
+
|
152
|
+
stdout = IO.popen(args, &:read)
|
153
|
+
debug_output('Command output', stdout) if @config.verbose >= 2
|
154
|
+
if exception && !$?.success?
|
155
|
+
raise "Failed to execute: #{args.shelljoin} (status: #{$?})"
|
156
156
|
end
|
157
|
+
$?.success?
|
158
|
+
end
|
159
|
+
|
160
|
+
def debug_output(name, text)
|
161
|
+
sep = '-' * 30
|
162
|
+
$stdout.puts "\n\n#{sep}[#{name} begin]#{sep}\n#{text}#{sep}[#{name} end]#{sep}\n\n"
|
157
163
|
end
|
158
164
|
|
159
165
|
WarmupScript = ::BenchmarkDriver::Struct.new(:preludes, :script, :teardown, :loop_count, :first_warmup_duration, :second_warmup_duration) do
|
@@ -77,6 +77,63 @@ class BenchmarkDriver::Runner::RubyStdout
|
|
77
77
|
# This method is dynamically called by `BenchmarkDriver::JobRunner.run`
|
78
78
|
# @param [Array<BenchmarkDriver::Default::Job>] jobs
|
79
79
|
def run(jobs)
|
80
|
+
if @config.alternate
|
81
|
+
alternated_run(jobs)
|
82
|
+
else
|
83
|
+
incremental_run(jobs)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# Special mode. Execution order: RubyA, RubyB, ..., RubyA, RubyB, ...
|
90
|
+
def alternated_run(jobs)
|
91
|
+
metric = jobs.first.metrics.first
|
92
|
+
|
93
|
+
@output.with_benchmark do
|
94
|
+
jobs.each do |job|
|
95
|
+
@output.with_job(name: job.name) do
|
96
|
+
# Running benchmarks in an alternated manner is NOT compatible with two things:
|
97
|
+
# * Output plugins. They expect RubyA, RubyA, RubyB, RubyB, ...
|
98
|
+
# * BenchmarkDriver::Repeater. It should be used for results of the same condition.
|
99
|
+
#
|
100
|
+
# Therefore, we run all benchmarks with executables alternated first here, and then
|
101
|
+
# aggregate the results as if the same executable were repeated in a row.
|
102
|
+
context_results = Hash.new do |hash, context|
|
103
|
+
hash[context] = []
|
104
|
+
end
|
105
|
+
jobs.each do |job|
|
106
|
+
@config.repeat_count.times do
|
107
|
+
@contexts.each do |context|
|
108
|
+
context_results[context] << run_job(job, exec: context.executable)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Aggregate reslts by BenchmarkDriver::Repeater and pass them to output.
|
114
|
+
@contexts.each do |context|
|
115
|
+
repeat_params = { config: @config, larger_better: metric.larger_better }
|
116
|
+
result = BenchmarkDriver::Repeater.with_repeat(**repeat_params) do
|
117
|
+
context_results[context].shift
|
118
|
+
end
|
119
|
+
value, environment = result.value
|
120
|
+
|
121
|
+
exec = context.executable
|
122
|
+
@output.with_context(name: exec.name, executable: exec) do
|
123
|
+
@output.report(
|
124
|
+
values: { metric => value },
|
125
|
+
all_values: { metric => result.all_values },
|
126
|
+
environment: environment,
|
127
|
+
)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Default mode. Execution order: RubyA, RubyA, RubyB, RubyB, ...
|
136
|
+
def incremental_run(jobs)
|
80
137
|
metric = jobs.first.metrics.first
|
81
138
|
|
82
139
|
@output.with_benchmark do
|
@@ -86,20 +143,7 @@ class BenchmarkDriver::Runner::RubyStdout
|
|
86
143
|
exec = context.executable
|
87
144
|
repeat_params = { config: @config, larger_better: metric.larger_better }
|
88
145
|
result = BenchmarkDriver::Repeater.with_repeat(**repeat_params) do
|
89
|
-
|
90
|
-
stdout = with_chdir(job.working_directory) do
|
91
|
-
with_ruby_prefix(exec) { execute(*exec.command, *job.command) }
|
92
|
-
end
|
93
|
-
script = StdoutToMetrics.new(
|
94
|
-
stdout: stdout,
|
95
|
-
value_from_stdout: job.value_from_stdout,
|
96
|
-
environment_from_stdout: job.environment_from_stdout,
|
97
|
-
)
|
98
|
-
[script.value, script.environment]
|
99
|
-
rescue CommandFailure => e
|
100
|
-
$stderr.puts("\n```\n#{e.message}```\n")
|
101
|
-
[BenchmarkDriver::Result::ERROR, {}]
|
102
|
-
end
|
146
|
+
run_job(job, exec: exec)
|
103
147
|
end
|
104
148
|
value, environment = result.value
|
105
149
|
|
@@ -116,7 +160,21 @@ class BenchmarkDriver::Runner::RubyStdout
|
|
116
160
|
end
|
117
161
|
end
|
118
162
|
|
119
|
-
|
163
|
+
# Run a job and return what BenchmarkDriver::Repeater.with_repeat takes.
|
164
|
+
def run_job(job, exec:)
|
165
|
+
stdout = with_chdir(job.working_directory) do
|
166
|
+
with_ruby_prefix(exec) { execute(*exec.command, *job.command) }
|
167
|
+
end
|
168
|
+
script = StdoutToMetrics.new(
|
169
|
+
stdout: stdout,
|
170
|
+
value_from_stdout: job.value_from_stdout,
|
171
|
+
environment_from_stdout: job.environment_from_stdout,
|
172
|
+
)
|
173
|
+
[script.value, script.environment]
|
174
|
+
rescue CommandFailure => e
|
175
|
+
$stderr.puts("\n```\n#{e.message}```\n")
|
176
|
+
[BenchmarkDriver::Result::ERROR, {}]
|
177
|
+
end
|
120
178
|
|
121
179
|
def with_ruby_prefix(executable, &block)
|
122
180
|
env = ENV.to_h.dup
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: benchmark_driver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.15.
|
4
|
+
version: 0.15.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Takashi Kokubun
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -131,7 +131,7 @@ homepage: https://github.com/benchmark-driver/benchmark-driver
|
|
131
131
|
licenses:
|
132
132
|
- MIT
|
133
133
|
metadata: {}
|
134
|
-
post_install_message:
|
134
|
+
post_install_message:
|
135
135
|
rdoc_options: []
|
136
136
|
require_paths:
|
137
137
|
- lib
|
@@ -146,8 +146,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
146
|
- !ruby/object:Gem::Version
|
147
147
|
version: '0'
|
148
148
|
requirements: []
|
149
|
-
rubygems_version: 3.2.
|
150
|
-
signing_key:
|
149
|
+
rubygems_version: 3.2.6
|
150
|
+
signing_key:
|
151
151
|
specification_version: 4
|
152
152
|
summary: Fully-featured accurate benchmark driver for Ruby
|
153
153
|
test_files: []
|