1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
# frozen_string_literal: true
require 'forwardable'
require 'benchmark/memory/job/task'
require 'benchmark/memory/job/io_output'
require 'benchmark/memory/job/null_output'
require 'benchmark/memory/held_results'
require 'benchmark/memory/report'
require 'benchmark/memory/report/comparator'
module Benchmark
module Memory
# Encapsulate the memory measurements of reports.
class Job
extend Forwardable
# Instantiate a job for containing memory performance reports.
#
# @param output [#puts] The output to use for showing the job results.
# @param quiet [Boolean] A flag for stopping output.
#
# @return [Job]
def initialize(output: $stdout, quiet: false)
@full_report = Report.new
@held_results = HeldResults.new
@quiet = quiet
@output = quiet? ? NullOutput.new : IOOutput.new(output)
@tasks = []
end
# @return [Report] the full report of all measurements in the job.
attr_reader :full_report
# @return [Array<Task>] the measurement tasks to run.
attr_reader :tasks
def_delegator :@held_results, :holding?
# Check whether the job should do a comparison.
#
# @return [Boolean]
def compare?
!!@comparator
end
# Enable output of a comparison of the different tasks.
#
# @return [void]
def compare!(**spec)
@comparator = full_report.comparator = Report::Comparator.from_spec(spec.to_h)
end
# Enable holding results to compare between separate runs.
#
# @param held_path [String, IO] The location to save the held results.
#
# @return [void]
def hold!(held_path)
@held_results.path = held_path
end
# Add a measurement entry to the job to measure the specified block.
#
# @param label [String] The label for the measured code.
# @param block [Proc] Code the measure.
#
# @raise [ArgumentError] if no code block is specified.
def report(label = '', &block)
raise ArgumentError, 'You did not specify a block for the item' unless block_given?
tasks.push Task.new(label, block)
end
# Run the job and outputs its full report.
#
# @return [Report]
def run
@output.put_header
@held_results.load
tasks.each do |task|
held = run_task(task)
if held
@output.put_hold_notice
break
end
end
full_report
end
# Run a task.
#
# @param task [Task]
#
# @return [Boolean] A flag indicating whether to hold or not.
def run_task(task)
if @held_results.include?(task)
run_with_held_results(task)
else
run_without_held_results(task)
end
end
# Run a comparison of the entries and puts it on the output.
#
# @return [void]
def run_comparison
return unless compare? && full_report.comparable?
@output.put_comparison(full_report.comparison)
end
# Check whether the job is set to quiet.
#
# @return [Boolean]
def quiet?
@quiet
end
private
def run_with_held_results(task)
measurement = @held_results[task.label]
full_report.add_entry(task, measurement)
false
end
def run_without_held_results(task)
measurement = task.call
entry = full_report.add_entry(task, measurement)
@output.put_entry(entry)
if task == tasks.last
@held_results.cleanup
false
else
@held_results.add_result(entry)
@held_results.holding?
end
end
end
end
end
|