Class: Benchmark::IPS::Job

Inherits:
Object
  • Object
show all
Defined in:
lib/benchmark/ips/job.rb,
lib/benchmark/ips/job/entry.rb,
lib/benchmark/ips/job/stdout_report.rb

Overview

Benchmark jobs.

Defined Under Namespace

Classes: Entry, StdoutReport

Constant Summary collapse

MICROSECONDS_PER_100MS =

Microseconds per 100 millisecond.

100_000
MICROSECONDS_PER_SECOND =

Microseconds per second.

1_000_000
MAX_TIME_SKEW =

The percentage of the expected runtime to allow before reporting a weird runtime

0.05

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Job

Instantiate the Benchmark::IPS::Job.

Parameters:

  • opts (Hash) (defaults to: {})

    a customizable set of options

Options Hash (opts):

  • (nil) (Benchmark::Suite)

    :suite Specify Benchmark::Suite.

  • (false) (Boolean)

    :quiet Suppress the printing of information.


40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/benchmark/ips/job.rb', line 40

def initialize opts={}
  @suite = opts[:suite] || nil
  @stdout = opts[:quiet] ? nil : StdoutReport.new
  @list = []
  @compare = false
  @json_path = false

  @timing = {}
  @full_report = Report.new

  # Default warmup and calculation time in seconds.
  @warmup = 2
  @time = 5
end

Instance Attribute Details

#compareBoolean (readonly)

Determining whether to run comparison utility.

Returns:

  • (Boolean)

    true if needs to run compare.


19
20
21
# File 'lib/benchmark/ips/job.rb', line 19

def compare
  @compare
end

#full_reportReport (readonly)

Report object containing information about the run.

Returns:

  • (Report)

    the report object.


23
24
25
# File 'lib/benchmark/ips/job.rb', line 23

def full_report
  @full_report
end

#listArray<Entry> (readonly)

Two-element arrays, consisting of label and block pairs.

Returns:

  • (Array<Entry>)

    list of entries


15
16
17
# File 'lib/benchmark/ips/job.rb', line 15

def list
  @list
end

#timeInteger

Calculation time setter and getter (in seconds).

Returns:

  • (Integer)

35
36
37
# File 'lib/benchmark/ips/job.rb', line 35

def time
  @time
end

#timingHash (readonly)

Storing Iterations in time period.

Returns:

  • (Hash)

27
28
29
# File 'lib/benchmark/ips/job.rb', line 27

def timing
  @timing
end

#warmupInteger

Warmup time setter and getter (in seconds).

Returns:

  • (Integer)

31
32
33
# File 'lib/benchmark/ips/job.rb', line 31

def warmup
  @warmup
end

Instance Method Details

#compare!Object

Set @compare to true.


71
72
73
# File 'lib/benchmark/ips/job.rb', line 71

def compare!
  @compare = true
end

#compare?Boolean

Return true if job needs to be compared.

Returns:

  • (Boolean)

    Need to compare?


66
67
68
# File 'lib/benchmark/ips/job.rb', line 66

def compare?
  @compare
end

#config(opts) ⇒ Object

Job configuration options, set @warmup and @time.

Parameters:

  • opts (Hash)

    a customizable set of options

Options Hash (opts):

  • :warmup (Integer)

    Warmup time.

  • :time (Integer)

    Calculation time.


58
59
60
61
62
# File 'lib/benchmark/ips/job.rb', line 58

def config opts
  @warmup = opts[:warmup] if opts[:warmup]
  @time = opts[:time] if opts[:time]
  @suite = opts[:suite] if opts[:suite]
end

#create_report(item, measured_us, iter, avg_ips, sd_ips, cycles) ⇒ Object

Create report by add entry to @full_report.

Parameters:

  • item (Benchmark::IPS::Job::Entry)

    Report item.

  • measured_us (Integer)

    Measured time in microsecond.

  • iter (Integer)

    Iterations.

  • avg_ips (Float)

    Average iterations per second.

  • sd_ips (Float)

    Standard deviation iterations per second.

  • cycles (Integer)

    Number of Cycles.


236
237
238
# File 'lib/benchmark/ips/job.rb', line 236

def create_report(item, measured_us, iter, avg_ips, sd_ips, cycles)
  @full_report.add_entry item.label, measured_us, iter, avg_ips, sd_ips, cycles
end

#cycles_per_100ms(time_msec, iters) ⇒ Integer

Calculate the cycles needed to run for approx 100ms, given the number of iterations to run the given time.

Parameters:

  • time_msec (Float)

    Each iteration's time in ms.

  • iters (Integer)

    Iterations.

Returns:

  • (Integer)

    Cycles per 100ms.


111
112
113
114
115
# File 'lib/benchmark/ips/job.rb', line 111

def cycles_per_100ms time_msec, iters
  cycles = ((MICROSECONDS_PER_100MS / time_msec) * iters).to_i
  cycles = 1 if cycles <= 0
  cycles
end

#generate_jsonObject

Generate json from @full_report.


225
226
227
# File 'lib/benchmark/ips/job.rb', line 225

def generate_json
  @full_report.generate_json @json_path if json?
end

#item(label = "", str = nil, &blk) ⇒ Object Also known as: report

Registers the given label and block pair in the job list.

Parameters:

  • label (String) (defaults to: "")

    Label of benchmarked code.

  • str (String) (defaults to: nil)

    Code to be benchmarked.

  • blk (Proc)

    Code to be benchmarked.

Raises:

  • (ArgumentError)

    Raises if str and blk are both present.

  • (ArgumentError)

    Raises if str and blk are both absent.


93
94
95
96
97
98
99
100
101
102
103
# File 'lib/benchmark/ips/job.rb', line 93

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

#iterations_per_sec(cycles, time_us) ⇒ Float

Calculate the interations per second given the number of cycles run and the time in microseconds that elapsed.

Parameters:

  • cycles (Integer)

    Cycles.

  • time_us (Integer)

    Time in microsecond.

Returns:

  • (Float)

    Iteration per second.


130
131
132
# File 'lib/benchmark/ips/job.rb', line 130

def iterations_per_sec cycles, time_us
  MICROSECONDS_PER_SECOND * (cycles.to_f / time_us.to_f)
end

#json!(path = "data.json") ⇒ Object

Set @json_path to given path, defaults to “data.json”.


83
84
85
# File 'lib/benchmark/ips/job.rb', line 83

def json!(path="data.json")
  @json_path = path
end

#json?Boolean

Return true if job needs to generate json.

Returns:

  • (Boolean)

    Need to generate json?


78
79
80
# File 'lib/benchmark/ips/job.rb', line 78

def json?
  !!@json_path
end

#runObject

Run calculation.


165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/benchmark/ips/job.rb', line 165

def run
  @stdout.start_running if @stdout
  @list.each do |item|
    @suite.running item.label, @time if @suite
    @stdout.running item.label, @time if @stdout

    Timing.clean_env

    iter = 0

    target = Time.now + @time

    measurements_us = []

    # Running this number of cycles should take around 100ms.
    cycles = @timing[item]

    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, 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
  end
end

#run_comparisonObject

Run comparison of entries in @full_report.


220
221
222
# File 'lib/benchmark/ips/job.rb', line 220

def run_comparison
  @full_report.run_comparison if compare?
end

#run_warmupObject

Run warmup.


135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/benchmark/ips/job.rb', line 135

def run_warmup
  @stdout.start_warming if @stdout
  @list.each do |item|
    @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
  end
end

#time_us(before, after) ⇒ Float

Calculate the time difference of before and after in microseconds.

Parameters:

  • before (Time)

    time.

  • after (Time)

    time.

Returns:

  • (Float)

    Time difference of before and after.


121
122
123
# File 'lib/benchmark/ips/job.rb', line 121

def time_us before, after
  (after.to_f - before.to_f) * MICROSECONDS_PER_SECOND
end