class Benchmark::IPS::Job
Benchmark jobs.
def compare!
def compare! @compare = true end
def compare?
-
(Boolean)
- Need to compare?
def compare? @compare end
def config opts
(**iterations)
-
:time
(Integer
) -- Warmup and calculation iterations. -
:time
(Integer
) -- Calculation time. -
:warmup
(Integer
) -- Warmup time.
def config opts @warmup = opts[:warmup] if opts[:warmup] @time = opts[:time] if opts[:time] @suite = opts[:suite] if opts[:suite] @iterations = opts[:iterations] if opts[:iterations] end
def create_report(label, measured_us, iter, avg_ips, sd_ips, cycles)
-
(Report::Entry)
- Entry with data.
Parameters:
-
cycles
(Integer
) -- Number of Cycles. -
sd_ips
(Float
) -- Standard deviation iterations per second. -
avg_ips
(Float
) -- Average iterations per second. -
iter
(Integer
) -- Iterations. -
measured_us
(Integer
) -- Measured time in microsecond. -
label
(String
) -- Report item label.
def create_report(label, measured_us, iter, avg_ips, sd_ips, cycles) @full_report.add_entry label, measured_us, iter, avg_ips, sd_ips, cycles end
def cycles_per_100ms time_msec, iters
-
(Integer)
- Cycles per 100ms.
Parameters:
-
iters
(Integer
) -- Iterations. -
time_msec
(Float
) -- Each iteration's time in ms.
def cycles_per_100ms time_msec, iters cycles = ((MICROSECONDS_PER_100MS / time_msec) * iters).to_i cycles = 1 if cycles <= 0 cycles end
def generate_json
def generate_json @full_report.generate_json @json_path if json? end
def held_results?
def held_results? File.exist?(@held_path) end
def hold!(held_path)
def hold!(held_path) @held_path = held_path end
def hold?
-
(Boolean)
- Need to hold results between multiple Ruby invocations?
def hold? !!@held_path end
def initialize opts={}
(**opts)
-
(false)
(Boolean
) -- :quiet Suppress the printing of information. -
(nil)
(Benchmark::Suite
) -- :suite Specify Benchmark::Suite.
def initialize opts={} @suite = opts[:suite] || nil @stdout = opts[:quiet] ? nil : StdoutReport.new @list = [] @compare = false @json_path = false @held_path = nil @held_results = nil @timing = {} @full_report = Report.new # Default warmup and calculation time in seconds. @warmup = 2 @time = 5 @iterations = 1 end
def item(label="", str=nil, &blk) # :yield:
-
(ArgumentError)
- Raises if str and blk are both absent. -
(ArgumentError)
- Raises if str and blk are both present.
Parameters:
-
blk
(Proc
) -- Code to be benchmarked. -
str
(String
) -- Code to be benchmarked. -
label
(String
) -- Label of benchmarked code.
def item(label="", str=nil, &blk) # :yield: if blk and str raise ArgumentError, "specify a block and a str, but not both" end action = str || blk raise ArgumentError, "no block or string" unless action @list.push Entry.new(label, action) self end
def iterations_per_sec cycles, time_us
-
(Float)
- Iteration per second.
Parameters:
-
time_us
(Integer
) -- Time in microsecond. -
cycles
(Integer
) -- Cycles.
def iterations_per_sec cycles, time_us MICROSECONDS_PER_SECOND * (cycles.to_f / time_us.to_f) end
def json!(path="data.json")
def json!(path="data.json") @json_path = path end
def json?
-
(Boolean)
- Need to generate json?
def json? !!@json_path end
def load_held_results
def load_held_results require "json" @held_results = Hash[File.open(@held_path).map { |line| result = JSON.parse(line) [result['item'], result] }] end
def run
def run @stdout.start_warming if @stdout @iterations.times do run_warmup end @stdout.start_running if @stdout held = nil @iterations.times do |n| held = run_benchmark end if held puts puts 'Pausing here -- run Ruby again to measure the next benchmark...' end end
def run_benchmark
def run_benchmark @list.each do |item| if hold? && @held_results && @held_results.key?(item.label) result = @held_results[item.label] create_report(item.label, result['measured_us'], result['iter'], result['avg_ips'], result['sd_ips'], result['cycles']) next end @suite.running item.label, @time if @suite @stdout.running item.label, @time if @stdout Timing.clean_env iter = 0 measurements_us = [] # Running this number of cycles should take around 100ms. cycles = @timing[item] target = Time.now + @time while Time.now < target before = Time.now item.call_times cycles after = Time.now # If for some reason the timing said this took no time (O_o) # then ignore the iteration entirely and start another. iter_us = time_us before, after next if iter_us <= 0.0 iter += cycles measurements_us << iter_us end final_time = Time.now measured_us = measurements_us.inject(0) { |a,i| a + i } all_ips = measurements_us.map { |time_us| iterations_per_sec cycles, time_us } avg_ips = Timing.mean(all_ips) sd_ips = Timing.stddev(all_ips, avg_ips).round rep = create_report(item.label, measured_us, iter, avg_ips, sd_ips, cycles) if (final_time - target).abs >= (@time.to_f * MAX_TIME_SKEW) rep.show_total_time! end @stdout.add_report rep, caller(1).first if @stdout @suite.add_report rep, caller(1).first if @suite if hold? && item != @list.last File.open @held_path, "a" do |f| require "json" f.write JSON.generate({ :item => item.label, :measured_us => measured_us, :iter => iter, :avg_ips => avg_ips, :sd_ips => sd_ips, :cycles => cycles }) f.write "\n" end return true end end if hold? && @full_report.entries.size == @list.size File.delete @held_path if File.exist?(@held_path) end false end
def run_comparison
def run_comparison @full_report.run_comparison if compare? end
def run_warmup
def run_warmup @list.each do |item| next if hold? && @held_results && @held_results.key?(item.label) @suite.warming item.label, @warmup if @suite @stdout.warming item.label, @warmup if @stdout Timing.clean_env before = Time.now target = Time.now + @warmup warmup_iter = 0 while Time.now < target item.call_times(1) warmup_iter += 1 end after = Time.now warmup_time_us = time_us before, after @timing[item] = cycles_per_100ms warmup_time_us, warmup_iter @stdout.warmup_stats warmup_time_us, @timing[item] if @stdout @suite.warmup_stats warmup_time_us, @timing[item] if @suite break if hold? end end
def time_us before, after
-
(Float)
- Time difference of before and after.
Parameters:
-
after
(Time
) -- time. -
before
(Time
) -- time.
def time_us before, after (after.to_f - before.to_f) * MICROSECONDS_PER_SECOND end