File: job.rb

package info (click to toggle)
ruby-benchmark-memory 0.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 300 kB
  • sloc: ruby: 1,121; makefile: 7; sh: 4
file content (145 lines) | stat: -rw-r--r-- 3,778 bytes parent folder | download
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