benchmark_driver 0.8.6 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +1 -3
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -6
- data/README.md +51 -52
- data/benchmark_driver.gemspec +3 -2
- data/bin/console +4 -11
- data/examples/exec_blank.rb +2 -2
- data/examples/exec_blank_simple.rb +2 -3
- data/exe/benchmark-driver +74 -83
- data/lib/benchmark_driver.rb +12 -1
- data/lib/benchmark_driver/config.rb +36 -0
- data/lib/benchmark_driver/default_job.rb +12 -0
- data/lib/benchmark_driver/default_job_parser.rb +68 -0
- data/lib/benchmark_driver/job_parser.rb +42 -0
- data/lib/benchmark_driver/metrics.rb +17 -0
- data/lib/benchmark_driver/output.rb +27 -0
- data/lib/benchmark_driver/output/compare.rb +196 -0
- data/lib/benchmark_driver/output/markdown.rb +102 -0
- data/lib/benchmark_driver/output/simple.rb +97 -0
- data/lib/benchmark_driver/rbenv.rb +11 -0
- data/lib/benchmark_driver/ruby_interface.rb +51 -0
- data/lib/benchmark_driver/runner.rb +42 -0
- data/lib/benchmark_driver/runner/ips.rb +239 -0
- data/lib/benchmark_driver/runner/memory.rb +142 -0
- data/lib/benchmark_driver/runner/time.rb +18 -0
- data/lib/benchmark_driver/struct.rb +85 -0
- data/lib/benchmark_driver/version.rb +3 -0
- metadata +21 -33
- data/bin/bench +0 -4
- data/examples/call.rb +0 -12
- data/examples/call_blank.rb +0 -13
- data/examples/call_erb.rb +0 -33
- data/examples/call_interpolation.rb +0 -13
- data/examples/eval_blank.rb +0 -12
- data/examples/eval_blank_loop.rb +0 -13
- data/examples/eval_interpolation.rb +0 -15
- data/lib/benchmark/driver.rb +0 -101
- data/lib/benchmark/driver/benchmark_result.rb +0 -21
- data/lib/benchmark/driver/bundle_installer.rb +0 -45
- data/lib/benchmark/driver/bundler.rb +0 -12
- data/lib/benchmark/driver/configuration.rb +0 -77
- data/lib/benchmark/driver/duration_runner.rb +0 -24
- data/lib/benchmark/driver/error.rb +0 -16
- data/lib/benchmark/driver/repeatable_runner.rb +0 -18
- data/lib/benchmark/driver/ruby_dsl_parser.rb +0 -78
- data/lib/benchmark/driver/time.rb +0 -12
- data/lib/benchmark/driver/version.rb +0 -5
- data/lib/benchmark/driver/yaml_parser.rb +0 -55
- data/lib/benchmark/output.rb +0 -20
- data/lib/benchmark/output/ips.rb +0 -143
- data/lib/benchmark/output/markdown.rb +0 -73
- data/lib/benchmark/output/memory.rb +0 -57
- data/lib/benchmark/output/time.rb +0 -57
- data/lib/benchmark/runner.rb +0 -14
- data/lib/benchmark/runner/call.rb +0 -97
- data/lib/benchmark/runner/eval.rb +0 -147
- data/lib/benchmark/runner/exec.rb +0 -193
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
|
-
# TODO: Support Windows... This depends on availability of which(1)
|
4
|
-
module Benchmark::Driver::BundleInstaller
|
5
|
-
class << self
|
6
|
-
# @param [Benchmark::Driver::Configuration::Executable] executable
|
7
|
-
def bundle_install_for(executable)
|
8
|
-
ruby_path = IO.popen(['which', executable.command.first], &:read).rstrip
|
9
|
-
unless $?.success?
|
10
|
-
abort "#{executable.command.first.dump} command was not found to execute `bundle install`"
|
11
|
-
end
|
12
|
-
|
13
|
-
bundler_path = Pathname.new(ruby_path).dirname.join('bundle')
|
14
|
-
unless bundler_path.executable?
|
15
|
-
abort "#{bundler_path.to_s.dump} was not a bundler executable, whose path was guessed from #{ruby_path.dump}"
|
16
|
-
end
|
17
|
-
bundle = bundler_path.to_s
|
18
|
-
|
19
|
-
Bundler.with_clean_env do
|
20
|
-
bundle_check(bundle, ruby: executable.name) || bundle_install(bundle)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
# @param [String] bundle - full path to bundle(1)
|
27
|
-
# @param [String] ruby - name of ruby
|
28
|
-
# @return [TrueClass,FalseClass] - true if success
|
29
|
-
def bundle_check(bundle, ruby:)
|
30
|
-
output = IO.popen([bundle, 'check'], &:read)
|
31
|
-
$?.success?.tap do |success|
|
32
|
-
unless success
|
33
|
-
$stderr.puts("For #{ruby}:")
|
34
|
-
$stderr.print(output)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# @param [String] bundle - full path to bundle(1)
|
40
|
-
def bundle_install(bundle)
|
41
|
-
pid = Process.spawn(bundle, 'install', '-j', ENV.fetch('BUNDLE_JOBS', '4'))
|
42
|
-
Process.wait(pid)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
# This module can be transparently run even if Bundler is not installed
|
2
|
-
module Benchmark::Driver::Bundler
|
3
|
-
def self.with_clean_env(&block)
|
4
|
-
begin
|
5
|
-
require 'bundler'
|
6
|
-
rescue LoadError
|
7
|
-
block.call # probably bundler is not used
|
8
|
-
else
|
9
|
-
::Bundler.with_clean_env { block.call }
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
# @param [Array<Benchmark::Driver::Configuration::Job>] jobs
|
2
|
-
# @param [Benchmark::Driver::Configuration::RunnerOptions] runner_options
|
3
|
-
# @param [Benchmark::Driver::Configuration::OutputOptions] output_options
|
4
|
-
class Benchmark::Driver::Configuration < Struct.new(:jobs, :runner_options, :output_options)
|
5
|
-
# @param [String,nil] name
|
6
|
-
# @param [String,Proc] sctipt
|
7
|
-
# @param [String,nil] prelude
|
8
|
-
# @param [Integer,nil] loop_count - If this is nil, loop count is automatically estimated by warmup.
|
9
|
-
Job = Struct.new(:name, :script, :prelude, :loop_count) do
|
10
|
-
# @param [Integer,nil] guessed_count - Set by runner only when loop_count is nil. This is not configuration.
|
11
|
-
attr_accessor :guessed_count
|
12
|
-
|
13
|
-
def warmup_needed?
|
14
|
-
# This needs to check original configuration
|
15
|
-
self[:loop_count].nil?
|
16
|
-
end
|
17
|
-
|
18
|
-
def loop_count
|
19
|
-
self[:loop_count] || guessed_count
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# @param [String] name
|
24
|
-
# @param [Array<String>] command - ["ruby", "-w", ...]. First element should be path to ruby command
|
25
|
-
Executable = Struct.new(:name, :command) do
|
26
|
-
def self.parse(name_path)
|
27
|
-
name, path = name_path.split('::', 2)
|
28
|
-
Benchmark::Driver::Configuration::Executable.new(name, path ? path.split(',') : [name])
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.parse_rbenv(spec)
|
32
|
-
version, *args = spec.split(',')
|
33
|
-
path = `RBENV_VERSION='#{version}' rbenv which ruby`.rstrip
|
34
|
-
abort "Failed to execute 'rbenv which ruby'" unless $?.success?
|
35
|
-
Benchmark::Driver::Configuration::Executable.new(version, [path, *args])
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
DEFAULT_EXECUTABLES = [Executable.new(RUBY_VERSION, [RbConfig.ruby])]
|
40
|
-
|
41
|
-
# @param [Symbol] type - Type of runner
|
42
|
-
# @param [Array<Benchmark::Driver::Configuration::Executable>] executables
|
43
|
-
# @param [Integer,nil] repeat_count - Times to repeat benchmarks. When this is not nil, benchmark_driver will use the best result.
|
44
|
-
RunnerOptions = Struct.new(:type, :executables, :repeat_count, :bundler) do
|
45
|
-
def initialize(*)
|
46
|
-
super
|
47
|
-
self.executables ||= DEFAULT_EXECUTABLES
|
48
|
-
end
|
49
|
-
|
50
|
-
def executables_specified?
|
51
|
-
executables != DEFAULT_EXECUTABLES
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# @param [Symbol] type - Type of output
|
56
|
-
# @param [TrueClass,FalseClass] compare
|
57
|
-
OutputOptions = Struct.new(:type, :compare)
|
58
|
-
|
59
|
-
# @param [Object] config
|
60
|
-
def self.symbolize_keys!(config)
|
61
|
-
case config
|
62
|
-
when Hash
|
63
|
-
config.keys.each do |key|
|
64
|
-
config[key.to_sym] = symbolize_keys!(config.delete(key))
|
65
|
-
end
|
66
|
-
when Array
|
67
|
-
config.map! { |c| symbolize_keys!(c) }
|
68
|
-
end
|
69
|
-
config
|
70
|
-
end
|
71
|
-
|
72
|
-
# @param [String] str
|
73
|
-
def self.camelize(str)
|
74
|
-
return str if str !~ /_/ && str =~ /[A-Z]+.*/
|
75
|
-
str.split('_').map { |e| e.capitalize }.join
|
76
|
-
end
|
77
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
class Benchmark::Driver::DurationRunner
|
2
|
-
# @param [Benchmark::Driver::Configuration::Job] job
|
3
|
-
def initialize(job)
|
4
|
-
@job = job
|
5
|
-
end
|
6
|
-
|
7
|
-
# @param [Integer,Float] seconds
|
8
|
-
# @param [Integer] unit_iters
|
9
|
-
# @param [Proc] runner - should take (job, unit_iters) and return duration.
|
10
|
-
# @return [Benchmark::Driver::BenchmarkResult]
|
11
|
-
def run(seconds:, unit_iters:, runner:)
|
12
|
-
real_time = 0.0
|
13
|
-
iterations = 0
|
14
|
-
unit_iters = unit_iters.to_i
|
15
|
-
|
16
|
-
benchmark_until = Benchmark::Driver::Time.now + seconds
|
17
|
-
while Benchmark::Driver::Time.now < benchmark_until
|
18
|
-
real_time += runner.call(@job, unit_iters)
|
19
|
-
iterations += unit_iters
|
20
|
-
end
|
21
|
-
|
22
|
-
Benchmark::Driver::BenchmarkResult.new(@job, iterations, real_time)
|
23
|
-
end
|
24
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module Benchmark::Driver
|
2
|
-
class Error < StandardError
|
3
|
-
end
|
4
|
-
|
5
|
-
class ExecutionTimeTooShort < Error
|
6
|
-
def initialize(job, iterations)
|
7
|
-
@job = job
|
8
|
-
@iterations = iterations
|
9
|
-
end
|
10
|
-
|
11
|
-
def message
|
12
|
-
"Execution time of job #{@job.name.dump} was too short in #{@iterations} executions;\n "\
|
13
|
-
'Please retry, try slower script or increase loop_count.'
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
class Benchmark::Driver::RepeatableRunner
|
2
|
-
# @param [Benchmark::Driver::Configuration::Job] job
|
3
|
-
def initialize(job)
|
4
|
-
@job = job
|
5
|
-
end
|
6
|
-
|
7
|
-
# @param [Integer] repeat_count
|
8
|
-
# @param [Proc] runner - should take (job, unit_iters) and return duration.
|
9
|
-
# @return [Benchmark::Driver::BenchmarkResult]
|
10
|
-
def run(repeat_count:, runner:)
|
11
|
-
real_times = (repeat_count || 1).times.map do
|
12
|
-
runner.call(@job, @job.loop_count)
|
13
|
-
end
|
14
|
-
Benchmark::Driver::BenchmarkResult.new(@job).tap do |result|
|
15
|
-
result.real = real_times.select { |d| d > 0 }.min || real_times.max
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
require 'benchmark/driver/configuration'
|
2
|
-
|
3
|
-
class Benchmark::Driver::RubyDslParser
|
4
|
-
# @param [Symbol,nil] runner - If this is nil, this is automatically decided by Benchmark::Driver#runner_type_for
|
5
|
-
# @param [Symbol] output
|
6
|
-
def initialize(runner: nil, output: :ips)
|
7
|
-
@prelude = nil
|
8
|
-
@loop_count = nil
|
9
|
-
@jobs = []
|
10
|
-
@runner = runner
|
11
|
-
@execs = nil
|
12
|
-
@bundler = false
|
13
|
-
@output = output
|
14
|
-
@compare = false
|
15
|
-
end
|
16
|
-
|
17
|
-
# API to fetch configuration parsed from DSL
|
18
|
-
# @return [Benchmark::Driver::Configuration]
|
19
|
-
def configuration
|
20
|
-
@jobs.each do |job|
|
21
|
-
job.prelude = @prelude
|
22
|
-
job.loop_count = @loop_count
|
23
|
-
end
|
24
|
-
Benchmark::Driver::Configuration.new(@jobs).tap do |c|
|
25
|
-
c.runner_options = Benchmark::Driver::Configuration::RunnerOptions.new(@runner, @execs, nil, @bundler)
|
26
|
-
c.output_options = Benchmark::Driver::Configuration::OutputOptions.new(@output, @compare)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# @param [String] prelude_script - Script required for benchmark whose execution time is not measured.
|
31
|
-
def prelude(prelude_script)
|
32
|
-
unless prelude_script.is_a?(String)
|
33
|
-
raise ArgumentError.new("prelude must be String but got #{prelude_script.inspect}")
|
34
|
-
end
|
35
|
-
unless @prelude.nil?
|
36
|
-
raise ArgumentError.new("prelude is already set:\n#{@prelude}")
|
37
|
-
end
|
38
|
-
|
39
|
-
@prelude = prelude_script
|
40
|
-
end
|
41
|
-
|
42
|
-
# @param [Array<String>] specs
|
43
|
-
def rbenv(*specs)
|
44
|
-
@execs ||= []
|
45
|
-
specs.each do |spec|
|
46
|
-
@execs << Benchmark::Driver::Configuration::Executable.parse_rbenv(spec)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def bundler
|
51
|
-
@bundler = true
|
52
|
-
end
|
53
|
-
|
54
|
-
# @param [String,nil] name - Name shown on result output. This must be provided if block is given.
|
55
|
-
# @param [String,nil] script - Benchmarked script in String. Only either of script or block must be provided.
|
56
|
-
# @param [Proc,nil] block - Benchmarked Proc object.
|
57
|
-
def report(name = nil, script = nil, &block)
|
58
|
-
if !script.nil? && block_given?
|
59
|
-
raise ArgumentError.new('script and block cannot be specified at the same time')
|
60
|
-
elsif name.nil? && block_given?
|
61
|
-
raise ArgumentError.new('name must be specified if block is given')
|
62
|
-
elsif !name.nil? && !name.is_a?(String)
|
63
|
-
raise ArgumentError.new("name must be String but got #{name.inspect}")
|
64
|
-
elsif !script.nil? && !script.is_a?(String)
|
65
|
-
raise ArgumentError.new("script must be String but got #{script.inspect}")
|
66
|
-
end
|
67
|
-
|
68
|
-
@jobs << Benchmark::Driver::Configuration::Job.new(name, script || block || name)
|
69
|
-
end
|
70
|
-
|
71
|
-
def compare!
|
72
|
-
@compare = true
|
73
|
-
end
|
74
|
-
|
75
|
-
def loop_count(count)
|
76
|
-
@loop_count = count
|
77
|
-
end
|
78
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
module Benchmark::Driver::Time
|
2
|
-
if defined?(Process::CLOCK_MONOTONIC)
|
3
|
-
def self.now
|
4
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
5
|
-
end
|
6
|
-
else
|
7
|
-
$stderr.puts "Process::CLOCK_MONOTONIC was unavailable. Using Time."
|
8
|
-
def self.now
|
9
|
-
::Time.now
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
module Benchmark::Driver::YamlParser
|
2
|
-
class << self
|
3
|
-
# @param [String] prelude
|
4
|
-
# @param [Integer,nil] loop_count
|
5
|
-
# @param [String,Array<String,Hash{ Symbol => String }>,Hash{ Symbol => String }] benchmark
|
6
|
-
# @return [Array<Benchmark::Driver::Configuration::Job>]
|
7
|
-
def parse(prelude: '', loop_count: nil, benchmark:)
|
8
|
-
jobs = parse_benchmark(benchmark)
|
9
|
-
jobs.each do |job|
|
10
|
-
job.prelude = prelude
|
11
|
-
job.loop_count ||= loop_count
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
# Parse "benchmark" declarative. This may have multiple benchmarks.
|
18
|
-
# @param [String,Array<String,Hash{ Symbol => String }>,Hash{ Symbol => String }] benchmark
|
19
|
-
def parse_benchmark(benchmark)
|
20
|
-
case benchmark
|
21
|
-
when String
|
22
|
-
[parse_each_benchmark(benchmark)]
|
23
|
-
when Array
|
24
|
-
benchmark.map { |b| parse_each_benchmark(b) }
|
25
|
-
when Hash
|
26
|
-
benchmark.map do |key, value|
|
27
|
-
Benchmark::Driver::Configuration::Job.new(key.to_s, value)
|
28
|
-
end
|
29
|
-
else
|
30
|
-
raise ArgumentError.new("benchmark must be String, Array or Hash, but got: #{benchmark.inspect}")
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# Parse one benchmark specified in "benchmark" declarative.
|
35
|
-
# @param [String,Hash{ Symbol => String }>] job
|
36
|
-
def parse_each_benchmark(benchmark)
|
37
|
-
case benchmark
|
38
|
-
when String
|
39
|
-
Benchmark::Driver::Configuration::Job.new(benchmark, benchmark)
|
40
|
-
when Hash
|
41
|
-
parse_job(benchmark)
|
42
|
-
else
|
43
|
-
raise ArgumentError.new("Expected String or Hash in element of benchmark, but got: #{benchmark.inspect}")
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# @param [String,nil] name
|
48
|
-
# @param [String] script
|
49
|
-
# TODO: support benchmark-specific prelude
|
50
|
-
def parse_job(name: nil, script:)
|
51
|
-
name = script if name.nil?
|
52
|
-
Benchmark::Driver::Configuration::Job.new(name, script)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
data/lib/benchmark/output.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
module Benchmark::Output
|
2
|
-
class << self
|
3
|
-
# Benchmark::Output is pluggable.
|
4
|
-
# Create `Benchmark::Output::FooBar` as benchmark-output-foo_bar.gem and specify `output: foo_bar`.
|
5
|
-
#
|
6
|
-
# @param [Symbol] name
|
7
|
-
def find(name)
|
8
|
-
class_name = Benchmark::Driver::Configuration.camelize(name.to_s)
|
9
|
-
unless Benchmark::Output.const_defined?("#{class_name}::REQUIRED_FIELDS")
|
10
|
-
require "benchmark/output/#{name}"
|
11
|
-
end
|
12
|
-
Benchmark::Output.const_get(class_name, false)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
require 'benchmark/output/ips'
|
18
|
-
require 'benchmark/output/markdown'
|
19
|
-
require 'benchmark/output/memory'
|
20
|
-
require 'benchmark/output/time'
|
data/lib/benchmark/output/ips.rb
DELETED
@@ -1,143 +0,0 @@
|
|
1
|
-
class Benchmark::Output::Ips
|
2
|
-
# This class requires runner to measure following fields in `Benchmark::Driver::BenchmarkResult` to show output.
|
3
|
-
REQUIRED_FIELDS = [:real]
|
4
|
-
|
5
|
-
NAME_LENGTH = 20
|
6
|
-
|
7
|
-
# @param [Array<Benchmark::Driver::Configuration::Job>] jobs
|
8
|
-
# @param [Array<Benchmark::Driver::Configuration::Executable>] executables
|
9
|
-
# @param [Benchmark::Driver::Configuration::OutputOptions] options
|
10
|
-
def initialize(jobs:, executables:, options:)
|
11
|
-
@jobs = jobs
|
12
|
-
@executables = executables
|
13
|
-
@options = options
|
14
|
-
@results = []
|
15
|
-
@name_by_result = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
def start_warming
|
19
|
-
$stdout.puts 'Warming up --------------------------------------'
|
20
|
-
end
|
21
|
-
|
22
|
-
# @param [String] name
|
23
|
-
def warming(name)
|
24
|
-
if name.length > NAME_LENGTH
|
25
|
-
$stdout.puts(name)
|
26
|
-
else
|
27
|
-
$stdout.print("%#{NAME_LENGTH}s" % name)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# @param [Benchmark::Driver::BenchmarkResult] result
|
32
|
-
def warmup_stats(result)
|
33
|
-
$stdout.puts "#{humanize(result.ip100ms)} i/100ms"
|
34
|
-
end
|
35
|
-
|
36
|
-
def start_running
|
37
|
-
$stdout.puts 'Calculating -------------------------------------'
|
38
|
-
if @executables.size > 1
|
39
|
-
$stdout.print(' ' * NAME_LENGTH)
|
40
|
-
@executables.each do |executable|
|
41
|
-
$stdout.print(" %10s " % executable.name)
|
42
|
-
end
|
43
|
-
$stdout.puts
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def running(name)
|
48
|
-
warming(name)
|
49
|
-
@row_results = []
|
50
|
-
end
|
51
|
-
|
52
|
-
# @param [Benchmark::Driver::BenchmarkResult] result
|
53
|
-
def benchmark_stats(result)
|
54
|
-
executable = @executables[@row_results.size]
|
55
|
-
$stdout.print("#{humanize(result.ips, [10, executable.name.length].max)} ")
|
56
|
-
|
57
|
-
@results << result
|
58
|
-
@row_results << result
|
59
|
-
if @row_results.size == @executables.size
|
60
|
-
$stdout.print("i/s - #{humanize(result.iterations)} in")
|
61
|
-
@row_results.each do |r|
|
62
|
-
$stdout.print(" %3.6fs" % r.real)
|
63
|
-
end
|
64
|
-
if @row_results.size == 1
|
65
|
-
sec = @row_results[0].real
|
66
|
-
iter = result.iterations
|
67
|
-
if File.exist?('/proc/cpuinfo') && (clks = estimate_clock(sec, iter)) < 1_000
|
68
|
-
$stdout.print(" (#{pretty_sec(sec, iter)}/i, #{clks}clocks/i)")
|
69
|
-
else
|
70
|
-
$stdout.print(" (#{pretty_sec(sec, iter)}/i)")
|
71
|
-
end
|
72
|
-
end
|
73
|
-
$stdout.puts
|
74
|
-
end
|
75
|
-
|
76
|
-
@name_by_result[result] = executable.name
|
77
|
-
end
|
78
|
-
|
79
|
-
def finish
|
80
|
-
if @results.size > 1 && @options.compare
|
81
|
-
compare
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
|
-
def humanize(value, width = 10)
|
88
|
-
scale = (Math.log10(value) / 3).to_i
|
89
|
-
suffix =
|
90
|
-
case scale
|
91
|
-
when 1; 'k'
|
92
|
-
when 2; 'M'
|
93
|
-
when 3; 'G'
|
94
|
-
when 4; 'T'
|
95
|
-
when 5; 'Q'
|
96
|
-
else # < 1000 or > 10^15, no scale or suffix
|
97
|
-
scale = 0
|
98
|
-
' '
|
99
|
-
end
|
100
|
-
"%#{width}.3f#{suffix}" % (value.to_f / (1000 ** scale))
|
101
|
-
end
|
102
|
-
|
103
|
-
def pretty_sec sec, iter
|
104
|
-
r = Rational(sec, iter)
|
105
|
-
case
|
106
|
-
when r >= 1
|
107
|
-
"#{'%3.2f' % r.to_f}s"
|
108
|
-
when r >= 1/1000r
|
109
|
-
"#{'%3.2f' % (r * 1_000).to_f}ms"
|
110
|
-
when r >= 1/1000_000r
|
111
|
-
"#{'%3.2f' % (r * 1_000_000).to_f}us"
|
112
|
-
else
|
113
|
-
"#{'%3.2f' % (r * 1_000_000_000).to_f}ns"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def estimate_clock sec, iter
|
118
|
-
hz = File.read('/proc/cpuinfo').scan(/cpu MHz\s+:\s+([\d\.]+)/){|(f)| break hz = Rational(f.to_f) * 1_000_000}
|
119
|
-
r = Rational(sec, iter)
|
120
|
-
Integer(r/(1/hz))
|
121
|
-
end
|
122
|
-
|
123
|
-
def compare
|
124
|
-
$stdout.puts("\nComparison:")
|
125
|
-
results = @results.sort_by { |r| -r.ips }
|
126
|
-
first = results.first
|
127
|
-
|
128
|
-
results.each do |result|
|
129
|
-
if result == first
|
130
|
-
slower = ''
|
131
|
-
else
|
132
|
-
slower = '- %.2fx slower' % (first.ips / result.ips)
|
133
|
-
end
|
134
|
-
|
135
|
-
name = result.job.name
|
136
|
-
if @executables.size > 1
|
137
|
-
name = "#{name} (#{@name_by_result.fetch(result)})"
|
138
|
-
end
|
139
|
-
$stdout.puts("%#{NAME_LENGTH}s: %11.1f i/s #{slower}" % [name, result.ips])
|
140
|
-
end
|
141
|
-
$stdout.puts
|
142
|
-
end
|
143
|
-
end
|