File: report.rb

package info (click to toggle)
ruby-benchmark-ips 2.7.2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 188 kB
  • sloc: ruby: 807; makefile: 11
file content (189 lines) | stat: -rw-r--r-- 6,159 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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
# encoding: utf-8

module Benchmark
  module IPS

    # Report contains benchmarking entries.
    # Perform operations like add new entry, run comparison between entries.
    class Report

      # Represents benchmarking code data for Report.
      class Entry
        # Instantiate the Benchmark::IPS::Report::Entry.
        # @param [#to_s] label Label of entry.
        # @param [Integer] us Measured time in microsecond.
        # @param [Integer] iters Iterations.
        # @param [Object] stats Statistics.
        # @param [Integer] cycles Number of Cycles.
        def initialize(label, us, iters, stats, cycles)
          @label = label
          @microseconds = us
          @iterations = iters
          @stats = stats
          @measurement_cycle = cycles
          @show_total_time = false
        end

        # Label of entry.
        # @return [String] the label of entry.
        attr_reader :label

        # Measured time in microsecond.
        # @return [Integer] number of microseconds.
        attr_reader :microseconds

        # Number of Iterations.
        # @return [Integer] number of iterations.
        attr_reader :iterations

        # Statistical summary of samples.
        # @return [Object] statisical summary.
        attr_reader :stats

        # LEGACY: Iterations per second.
        # @return [Float] number of iterations per second.
        def ips
          @stats.central_tendency
        end

        # LEGACY: Standard deviation of iteration per second.
        # @return [Float] standard deviation of iteration per second.
        def ips_sd
          @stats.error
        end

        # Number of Cycles.
        # @return [Integer] number of cycles.
        attr_reader :measurement_cycle

        # Control if the total time the job took is reported.
        # Typically this value is not significant because it's very
        # close to the expected time, so it's supressed by default.
        def show_total_time!
          @show_total_time = true
        end

        # Return entry's microseconds in seconds.
        # @return [Float] +@microseconds+ in seconds.
        def seconds
          @microseconds.to_f / 1_000_000.0
        end

        # Return entry's standard deviation of iteration per second in percentage.
        # @return [Float] +@ips_sd+ in percentage.
        def error_percentage
          100.0 * (@stats.error.to_f / @stats.central_tendency)
        end

        alias_method :runtime, :seconds

        # Return Entry body text with left padding.
        # Body text contains information of iteration per second with
        # percentage of standard deviation, iterations in runtime.
        # @return [String] Left justified body.
        def body
          case Benchmark::IPS.options[:format]
          when :human
            left = "%s (±%4.1f%%) i/s" % [Helpers.scale(@stats.central_tendency), error_percentage]
            iters = Helpers.scale(@iterations)

            if @show_total_time
              left.ljust(20) + (" - %s in %10.6fs" % [iters, runtime])
            else
              left.ljust(20) + (" - %s" % iters)
            end
          else
            left = "%10.1f (±%.1f%%) i/s" % [@stats.central_tendency, error_percentage]

            if @show_total_time
              left.ljust(20) + (" - %10d in %10.6fs" % [@iterations, runtime])
            else
              left.ljust(20) + (" - %10d" % @iterations)
            end
          end
        end

        # Return header with padding if +@label+ is < length of 20.
        # @return [String] Right justified header (+@label+).
        def header
          @label.to_s.rjust(20)
        end

        # Return string repesentation of Entry object.
        # @return [String] Header and body.
        def to_s
          "#{header} #{body}"
        end

        # Print entry to current standard output ($stdout).
        def display
          $stdout.puts to_s
        end
      end # End of Entry

      # class Report

      # Entry to represent each benchmarked code in Report.
      # @return [Array<Report::Entry>] Entries in Report.
      attr_reader :entries

      # Instantiate the Report.
      def initialize
        @entries = []
        @data = nil
      end

      # Add entry to report.
      # @param label [String] Entry label.
      # @param microseconds [Integer] Measured time in microsecond.
      # @param iters [Integer] Iterations.
      # @param stats [Object] Statistical results.
      # @param measurement_cycle [Integer] Number of cycles.
      # @return [Report::Entry] Last added entry.
      def add_entry label, microseconds, iters, stats, measurement_cycle
        entry = Entry.new(label, microseconds, iters, stats, measurement_cycle)
        @entries.delete_if { |e| e.label == label }
        @entries << entry
        entry
      end

      # Entries data in array for generate json.
      # Each entry is a hash, consists of:
      #   name:   Entry#label
      #   ips:    Entry#ips
      #   stddev: Entry#ips_sd
      #   microseconds: Entry#microseconds
      #   iterations:   Entry#iterations
      #   cycles:       Entry#measurement_cycles
      # @return [Array<Hash<Symbol,String|Float|Integer>] Array of hashes
      def data
        @data ||= @entries.collect do |entry|
          {
            :name => entry.label,
            :central_tendency =>  entry.stats.central_tendency,
            :ips =>  entry.stats.central_tendency, # for backwards compatibility
            :error => entry.stats.error,
            :stddev => entry.stats.error, # for backwards compatibility
            :microseconds => entry.microseconds,
            :iterations => entry.iterations,
            :cycles => entry.measurement_cycle,
          }
        end
      end

      # Run comparison of entries.
      def run_comparison
        Benchmark.compare(*@entries)
      end

      # Generate json from Report#data to given path.
      # @param path [String] path to generate json.
      def generate_json(path)
        File.open path, "w" do |f|
          require "json"
          f.write JSON.pretty_generate(data)
        end
      end
    end
  end
end