benchmark-memory 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ce1d2f5bdcc1fbcd47258b0baa40270454220de4
4
- data.tar.gz: 624cd04313af120944dcbe193dcace591a980a17
2
+ SHA256:
3
+ metadata.gz: 77c690ecb4b3640eb994fe9dbaddaac4dde593fb445b8e6fff50c771dec82c6f
4
+ data.tar.gz: 4f29c72bae6ec8a5d024c4c0d89ff7032a75c9c6a2dd738ecdde5d4dd3e162b9
5
5
  SHA512:
6
- metadata.gz: 07cae3b39fdaac96b4f9601288cc5972db7bb8cd14a3a71d3c55d300c22e7a850db993efae450727b27a73fe29ab2e6a3b6a3dece852adb783bee25ced15c023
7
- data.tar.gz: 33c02f69a9a8cca90bd528445447cce532cf93d188acc43fdd5abf3fac6cb4746c1788f35d035893f4fbd033ff652ec780195b4fc77b31c9e069d454e577afc7
6
+ metadata.gz: e31d03064d7de106086091ea7726d8ac239cee28f799f1536b96738bf1dbd676b192ca5e5a7862b6917770f6f3880c60d10d4d19f836e89be83ce0a3bb8357fa
7
+ data.tar.gz: '0789ccf4fa45943688b6a486e3816295216f0500b040ccc3843466582a8f42f0d9f3fcbc8dbb42fa439d293a4c4519f1b27460ca4ceb12100cfe5e234b4d82cf'
data/CHANGELOG.md CHANGED
@@ -4,26 +4,34 @@ All notable changes to this project will be documented in this file. This projec
4
4
 
5
5
  [semver]: http://semver.org/spec/v2.0.0.html
6
6
 
7
- ## [0.1.2] - 2017-01-30
7
+ ## [0.2.0](https://github.com/michaelherold/benchmark-memory/compare/v0.1.1...v0.2.0)
8
+
9
+ ### Added
10
+
11
+ - [#11](https://github.com/michaelherold/benchmark-memory/pull/11): Drop support for Ruby < 2.4 - [@dblock](https://github.com/dblock).
12
+ - [#23](https://github.com/michaelherold/benchmark-memory/pull/23): Allow for sorting the comparison by different criteria - [@michaelherold](https://github.com/michaelherold).
13
+
14
+ ### Updated
15
+
16
+ - [#16](https://github.com/michaelherold/benchmark-memory/pull/16): Updated Rubocop to ~> 1 and Ruby to 2.5.0+ - [@AlexWayfer](https://github.com/AlexWayfer).
17
+ - [#19](https://github.com/michaelherold/benchmark-memory/pull/19): Updated to `memory_profiler` 1.0 - [@AlexWayfer](https://github.com/AlexWayfer).
18
+
19
+ ## [0.1.2](https://github.com/michaelherold/benchmark-memory/compare/v0.1.1...v0.1.2) - 2017-01-30
8
20
 
9
21
  ### Fixed
10
22
 
11
23
  - [#4](https://github.com/michaelherold/benchmark-memory/pull/4): Fix a small bug when StringIO wasn't properly required - [@rzane](https://github.com/rzane).
12
24
 
13
- ## [0.1.1] - 2016-06-10
25
+ ## [0.1.1](https://github.com/michaelherold/benchmark-memory/compare/v0.1.0...v0.1.1) - 2016-06-10
14
26
 
15
27
  ### Fixed
16
28
 
17
29
  - Printing comparisons for multiple entries.
18
30
 
19
- ## [0.1.0] - 2016-05-18
31
+ ## [0.1.0](https://github.com/michaelherold/benchmark-memory/tree/v0.1.0) - 2016-05-18
20
32
 
21
33
  ### Added
22
34
 
23
35
  - Main `Benchmark.memory` method.
24
36
  - Holding results between invocations for measuring implementations on different versions of Ruby or different versions of libraries.
25
37
  - Quiet mode, with no command line output.
26
-
27
- [0.1.2]: https://github.com/michaelherold/benchmark-memory/compare/v0.1.1...v0.1.2
28
- [0.1.1]: https://github.com/michaelherold/benchmark-memory/compare/v0.1.0...v0.1.1
29
- [0.1.0]: https://github.com/michaelherold/benchmark-memory/tree/v0.1.0
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # benchmark-memory
2
2
 
3
- [![Build Status](https://travis-ci.org/michaelherold/benchmark-memory.svg)][travis]
3
+ [![CI](https://github.com/michaelherold/benchmark-memory/workflows/CI/badge.svg)][ci]
4
4
  [![Code Climate](https://codeclimate.com/github/michaelherold/benchmark-memory/badges/gpa.svg)][codeclimate]
5
- [![Inline docs](http://inch-ci.org/github/michaelherold/benchmark-memory.svg?branch=master)][inch]
5
+ [![Inline docs](http://inch-ci.org/github/michaelherold/benchmark-memory.svg?branch=main)][inch]
6
6
 
7
+ [ci]: https://github.com/michaelherold/benchmark-memory/actions
7
8
  [codeclimate]: https://codeclimate.com/github/michaelherold/benchmark-memory
8
9
  [inch]: http://inch-ci.org/github/michaelherold/benchmark-memory
9
- [travis]: https://travis-ci.org/michaelherold/benchmark-memory
10
10
 
11
11
  benchmark-memory is a tool that helps you to benchmark the memory usage of different pieces of code. It leverages the power of [memory_profiler] to give you a metric of the total amount of memory allocated and retained by a block, as well as the number of objects and strings allocated and retained.
12
12
 
@@ -71,7 +71,7 @@ Comparison:
71
71
  dynamic allocation: 40 allocated - Infx more
72
72
  ```
73
73
 
74
- Reading this output shows that the "dynamic allocation" example allocates one string that is not retained outside the scope of the block. The "frozen string" example, however, does not allocate anything because it reuses the frozen string that was created during the method definition.
74
+ Reading this output shows that the "dynamic allocation" example allocates one string that is not retained outside the scope of the block. The "frozen string" example, however, does not allocate anything because it reuses the frozen string that we created during the method definition.
75
75
 
76
76
  [benchmark-ips]: https://github.com/evanphx/benchmark-ips
77
77
 
@@ -95,7 +95,31 @@ Benchmark.memory do |x|
95
95
  end
96
96
  ```
97
97
 
98
- Calling `#compare!` on the job within the setup block of `Benchmark.memory` enables the output of the comparison section of the benchmark. Without it, this section is suppressed and you only get the raw numbers output during calculation.
98
+ Calling `#compare!` on the job within the setup block of `Benchmark.memory` enables the output of the comparison section of the benchmark. Without it, the benchmark suppresses this section and you only get the raw numbers output during calculation.
99
+
100
+ By default, this compares the reports by the amount of allocated memory. You can configure the comparison along two axes. The first axis is the metric, which is one of: `:memory`, `:objects`, or `:strings`. The second is the value, which is either `:allocated` or `:retained`.
101
+
102
+ Depending on what you're trying to benchmark, different configurations make sense. For example:
103
+
104
+ ``` ruby
105
+ Benchmark.memory do |bench|
106
+ bench.compare! memory: :allocated
107
+ # or, equivalently:
108
+ # bench.compare!
109
+ end
110
+ ```
111
+
112
+ The purpose of the default configuration is benchmarking the total amount of memory an algorithm might use. If you're trying to improve a memory-intensive task, this is the mode you want.
113
+
114
+ An alternative comparison might look like:
115
+
116
+ ``` ruby
117
+ Benchmark.memory do |bench|
118
+ bench.compare! memory: :retained
119
+ end
120
+ ```
121
+
122
+ When you're looking for a memory leak, this configuration can help you because it compares your reports by the amount of memory that the garbage collector does not collect after the benchmark.
99
123
 
100
124
  ### Hold results between invocations
101
125
 
@@ -107,7 +131,7 @@ end
107
131
 
108
132
  Often when you want to benchmark something, you compare two implementations of the same method. This is cumbersome because you have to keep two implementations side-by-side and call them in the same manner. Alternatively, you may want to compare how a method performs on two different versions of Ruby. To make both of these scenarios easier, you can enable "holding" on the benchmark.
109
133
 
110
- By calling `#hold!` on the benchmark, you enable the benchmark to write to the given file to store its results in a file that can be read in between invocations of your benchmark.
134
+ By calling `#hold!` on the benchmark, you enable the benchmark to write to the given file to store its results in a file that can the benchmark reads in between invocations of your benchmark.
111
135
 
112
136
  For example, imagine that you have a library that exposes a method called `Statistics.calculate_monthly_recurring_revenue` that you want to optimize for memory usage because it keeps causing your worker server to run out of memory. You make some changes to the method and commit them to an `optimize-memory` branch in Git.
113
137
 
@@ -133,33 +157,34 @@ Note that the method calls are the same for both tests and that we have enabled
133
157
  You could then run the following (assuming you saved your benchmark as `benchmark_mrr.rb`:
134
158
 
135
159
  ```sh
136
- $ git checkout master
160
+ $ git checkout main
137
161
  $ ruby benchmark_mrr.rb
138
162
  $ git checkout optimize-memory
139
163
  $ ruby benchmark_mrr.rb
140
164
  ```
141
165
 
142
- The first invocation of `ruby benchmark_mrr.rb` runs the benchmark in the "original" entry using your code in your `master` Git branch. The second invocation runs the benchmark in the "optimized" entry using the code in your `optimize-memory` Git branch. These two results are collated and then compared to show you the difference between the two.
166
+ The first invocation of `ruby benchmark_mrr.rb` runs the benchmark in the "original" entry using your code in your `main` Git branch. The second invocation runs the benchmark in the "optimized" entry using the code in your `optimize-memory` Git branch. It then collates and compares the two results to show you the difference between the two.
143
167
 
144
168
  When enabling holding, the benchmark writes to the file passed into the `#hold!` method. After you run all of the entries in the benchmark, the benchmark automatically cleans up its log by deleting the file.
145
169
 
146
170
  ## Supported Ruby Versions
147
171
 
148
- This library aims to support and is [tested against][travis] the following Ruby versions:
172
+ This library aims to support and is [tested against][ci] the following Ruby versions:
149
173
 
150
- * Ruby 2.1
151
- * Ruby 2.2
152
- * Ruby 2.3
174
+ * Ruby 2.5
175
+ * Ruby 2.6
176
+ * Ruby 2.7
177
+ * Ruby 3.0
153
178
 
154
179
  If something doesn't work on one of these versions, it's a bug.
155
180
 
156
- This library may inadvertently work (or seem to work) on other Ruby versions, however, support will only be provided for the versions listed above.
181
+ This library may inadvertently work (or seem to work) on other Ruby versions, however, we will only give support for the versions listed above.
157
182
 
158
- If you would like this library to support another Ruby version or implementation, you may volunteer to be a maintainer. Being a maintainer entails making sure all tests run and pass on that implementation. When something breaks on your implementation, you will be responsible for providing patches in a timely fashion. If critical issues for a particular implementation exist at the time of a major release, support for that Ruby version may be dropped.
183
+ If you would like this library to support another Ruby version or implementation, you may volunteer to be a maintainer. Being a maintainer entails making sure all tests run and pass on that implementation. When something breaks on your implementation, you will be responsible for providing patches in a timely fashion. If critical issues for a particular implementation exist at the time of a major release, we may drop support for that Ruby version.
159
184
 
160
185
  ## Versioning
161
186
 
162
- This library aims to adhere to [Semantic Versioning 2.0.0][semver]. Violations of this scheme should be reported as bugs. Specifically, if a minor or patch version is released that breaks backward compatibility, that version should be immediately yanked and/or a new version should be immediately released that restores compatibility. Breaking changes to the public API will only be introduced with new major versions. As a result of this policy, you can (and should) specify a dependency on this gem using the [Pessimistic Version Constraint][pessimistic] with two digits of precision. For example:
187
+ This library aims to adhere to [Semantic Versioning 2.0.0][semver]. Report violations of this scheme as bugs. Specifically, if we release a minor or patch version that breaks backward compatibility, that version should be immediately yanked and/or a new version should be immediately released that restores compatibility. We will only introduce breaking changes to the public API with new major versions. As a result of this policy, you can (and should) specify a dependency on this gem using the [Pessimistic Version Constraint][pessimistic] with two digits of precision. For example:
163
188
 
164
189
  spec.add_dependency "benchmark-memory", "~> 0.1"
165
190
 
data/Rakefile CHANGED
@@ -1,29 +1,19 @@
1
- require "bundler"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler'
2
4
  Bundler.setup
3
5
  Bundler::GemHelper.install_tasks
4
6
 
5
- require "inch/rake"
7
+ require 'inch/rake'
6
8
  Inch::Rake::Suggest.new(:inch)
7
9
 
8
- require "rspec/core/rake_task"
10
+ require 'rspec/core/rake_task'
9
11
  RSpec::Core::RakeTask.new(:spec)
10
12
 
11
- require "rubocop/rake_task"
13
+ require 'rubocop/rake_task'
12
14
  RuboCop::RakeTask.new(:rubocop)
13
15
 
14
- require "yard/rake/yardoc_task"
16
+ require 'yard/rake/yardoc_task'
15
17
  YARD::Rake::YardocTask.new(:yard)
16
18
 
17
- task :mutant do
18
- command = [
19
- "bundle exec mutant",
20
- "--include lib",
21
- "--require interactor-contracts",
22
- "--use rspec",
23
- "Interactor::Contracts*",
24
- ].join(" ")
25
-
26
- system command
27
- end
28
-
29
- task :default => [:spec, :rubocop, :yard, :inch]
19
+ task default: %i[spec rubocop yard inch]
@@ -1,24 +1,24 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require File.expand_path("../lib/benchmark/memory/version", __FILE__)
3
+ require File.expand_path('lib/benchmark/memory/version', __dir__)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "benchmark-memory"
6
+ spec.name = 'benchmark-memory'
7
7
  spec.version = Benchmark::Memory::VERSION
8
- spec.authors = ["Michael Herold"]
9
- spec.email = ["michael.j.herold@gmail.com"]
8
+ spec.authors = ['Michael Herold']
9
+ spec.email = ['michael.j.herold@gmail.com']
10
10
 
11
- spec.summary = "Benchmark-style memory profiling for Ruby 2.1+"
11
+ spec.summary = 'Benchmark-style memory profiling'
12
12
  spec.description = spec.summary
13
- spec.homepage = "https://github.com/michaelherold/benchmark-memory"
14
- spec.license = "MIT"
13
+ spec.homepage = 'https://github.com/michaelherold/benchmark-memory'
14
+ spec.license = 'MIT'
15
15
 
16
- spec.files = %w(CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md Rakefile)
17
- spec.files += %w(benchmark-memory.gemspec)
18
- spec.files += Dir["lib/**/*.rb"]
19
- spec.require_paths = ["lib"]
16
+ spec.files = %w[CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md Rakefile]
17
+ spec.files += %w[benchmark-memory.gemspec]
18
+ spec.files += Dir['lib/**/*.rb']
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_dependency "memory_profiler", "~> 0.9"
21
+ spec.required_ruby_version = '>= 2.5.0'
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.12"
23
+ spec.add_dependency 'memory_profiler', '~> 1'
24
24
  end
@@ -1,7 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Benchmark
2
4
  module Memory
3
5
  Error = Class.new(StandardError)
4
6
 
5
- ConfigurationError = Class.new(Error)
7
+ ConfigurationError = Class.new(Error) do
8
+ def message
9
+ 'You did not give a test block to your call to `Benchmark.memory`'
10
+ end
11
+ end
6
12
  end
7
13
  end
@@ -1,6 +1,8 @@
1
- require "benchmark/memory/held_results/serializer"
2
- require "benchmark/memory/held_results/measurement_serializer"
3
- require "benchmark/memory/report/entry"
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/held_results/serializer'
4
+ require 'benchmark/memory/held_results/measurement_serializer'
5
+ require 'benchmark/memory/report/entry'
4
6
 
5
7
  module Benchmark
6
8
  module Memory
@@ -14,8 +16,8 @@ module Benchmark
14
16
  # @return [Report::Entry]
15
17
  def load(hash)
16
18
  @object = Report::Entry.new(
17
- hash["item"],
18
- MeasurementSerializer.load(hash["measurement"])
19
+ hash['item'],
20
+ MeasurementSerializer.load(hash['measurement'])
19
21
  )
20
22
  self
21
23
  end
@@ -25,8 +27,8 @@ module Benchmark
25
27
  # @return [Hash] The entry as a Hash.
26
28
  def to_h
27
29
  {
28
- :item => object.label,
29
- :measurement => MeasurementSerializer.new(object.measurement).to_h,
30
+ item: object.label,
31
+ measurement: MeasurementSerializer.new(object.measurement).to_h
30
32
  }
31
33
  end
32
34
  end
@@ -1,6 +1,8 @@
1
- require "benchmark/memory/held_results/serializer"
2
- require "benchmark/memory/held_results/metric_serializer"
3
- require "benchmark/memory/measurement"
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/held_results/serializer'
4
+ require 'benchmark/memory/held_results/metric_serializer'
5
+ require 'benchmark/memory/measurement'
4
6
 
5
7
  module Benchmark
6
8
  module Memory
@@ -14,9 +16,9 @@ module Benchmark
14
16
  # @return [Measurement]
15
17
  def load(hash)
16
18
  @object = Measurement.new(
17
- :memory => MetricSerializer.load(hash["memory"]),
18
- :objects => MetricSerializer.load(hash["objects"]),
19
- :strings => MetricSerializer.load(hash["strings"])
19
+ memory: MetricSerializer.load(hash['memory']),
20
+ objects: MetricSerializer.load(hash['objects']),
21
+ strings: MetricSerializer.load(hash['strings'])
20
22
  )
21
23
  self
22
24
  end
@@ -26,9 +28,9 @@ module Benchmark
26
28
  # @return [Hash] The measurement as a Hash.
27
29
  def to_h
28
30
  {
29
- :memory => MetricSerializer.new(object.memory).to_h,
30
- :objects => MetricSerializer.new(object.objects).to_h,
31
- :strings => MetricSerializer.new(object.strings).to_h,
31
+ memory: MetricSerializer.new(object.memory).to_h,
32
+ objects: MetricSerializer.new(object.objects).to_h,
33
+ strings: MetricSerializer.new(object.strings).to_h
32
34
  }
33
35
  end
34
36
  end
@@ -1,5 +1,7 @@
1
- require "benchmark/memory/held_results/serializer"
2
- require "benchmark/memory/measurement/metric"
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/held_results/serializer'
4
+ require 'benchmark/memory/measurement/metric'
3
5
 
4
6
  module Benchmark
5
7
  module Memory
@@ -14,9 +16,9 @@ module Benchmark
14
16
  #
15
17
  def load(hash)
16
18
  @object = Measurement::Metric.new(
17
- hash["type"],
18
- hash["allocated"],
19
- hash["retained"]
19
+ hash['type'],
20
+ hash['allocated'],
21
+ hash['retained']
20
22
  )
21
23
  self
22
24
  end
@@ -26,9 +28,9 @@ module Benchmark
26
28
  # @return [Hash] The metric as a Hash.
27
29
  def to_h
28
30
  {
29
- :allocated => object.allocated,
30
- :retained => object.retained,
31
- :type => object.type,
31
+ allocated: object.allocated,
32
+ retained: object.retained,
33
+ type: object.type
32
34
  }
33
35
  end
34
36
  end
@@ -1,4 +1,6 @@
1
- require "json"
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
2
4
 
3
5
  module Benchmark
4
6
  module Memory
@@ -33,9 +35,9 @@ module Benchmark
33
35
  # @raise [NotImplementedError]
34
36
  # If the inheriting subclass didn't implement.
35
37
  def load(_hash)
36
- fail(
38
+ raise(
37
39
  NotImplementedError,
38
- "You must implement a concrete version in a subclass"
40
+ 'You must implement a concrete version in a subclass'
39
41
  )
40
42
  end
41
43
 
@@ -45,19 +47,19 @@ module Benchmark
45
47
  # @raise [NotImplementedError]
46
48
  # If the inheriting subclass didn't implement.
47
49
  def to_h
48
- fail(
50
+ raise(
49
51
  NotImplementedError,
50
- "You must implement a concrete version in a subclass"
52
+ 'You must implement a concrete version in a subclass'
51
53
  )
52
54
  end
53
55
 
54
56
  # Convert the object to a JSON document.
55
57
  #
56
58
  # @return [String] The object as a JSON document.
57
- def to_json
58
- JSON.generate(to_h)
59
+ def to_json(*args)
60
+ JSON.generate(to_h, *args)
59
61
  end
60
- alias_method :to_s, :to_json
62
+ alias to_s to_json
61
63
  end
62
64
  end
63
65
  end
@@ -1,5 +1,7 @@
1
- require "forwardable"
2
- require "benchmark/memory/held_results/entry_serializer"
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'benchmark/memory/held_results/entry_serializer'
3
5
 
4
6
  module Benchmark
5
7
  module Memory
@@ -30,7 +32,7 @@ module Benchmark
30
32
  #
31
33
  # @return [void]
32
34
  def add_result(entry)
33
- with_hold_file("a") do |file|
35
+ with_hold_file('a') do |file|
34
36
  file.write EntrySerializer.new(entry)
35
37
  file.write "\n"
36
38
  end
@@ -43,7 +45,7 @@ module Benchmark
43
45
  if @path.is_a?(String)
44
46
  File.exist?(@path)
45
47
  else
46
- @path.size > 0 # rubocop:disable Style/ZeroLengthPredicate
48
+ @path.size.positive?
47
49
  end
48
50
  end
49
51
 
@@ -51,9 +53,7 @@ module Benchmark
51
53
  #
52
54
  # @return [void]
53
55
  def cleanup
54
- if @path.is_a?(String) && File.exist?(@path)
55
- File.delete(@path)
56
- end
56
+ File.delete(@path) if @path.is_a?(String) && File.exist?(@path)
57
57
  end
58
58
 
59
59
  # Check whether to hold results.
@@ -81,9 +81,7 @@ module Benchmark
81
81
  results = with_hold_file do |file|
82
82
  file.map { |line| EntrySerializer.load(line) }
83
83
  end
84
- @results = Hash[results.map do |result|
85
- [result.label, result.measurement]
86
- end]
84
+ @results = results.map { |result| [result.label, result.measurement] }.to_h
87
85
  end
88
86
 
89
87
  private
@@ -94,13 +92,11 @@ module Benchmark
94
92
  # @param _block [Proc] The block to execute on each line of the file.
95
93
  #
96
94
  # @return [void]
97
- def with_hold_file(access_mode = "r", &_block)
95
+ def with_hold_file(access_mode = 'r', &block)
98
96
  return unless @path
99
97
 
100
98
  if @path.is_a?(String)
101
- File.open(@path, access_mode) do |f|
102
- yield f
103
- end
99
+ File.open(@path, access_mode, &block)
104
100
  else
105
101
  yield @path
106
102
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/human_readable_unit'
4
+
1
5
  module Benchmark
2
6
  module Memory
3
7
  # Helper methods for formatting output.
@@ -23,24 +27,11 @@ module Benchmark
23
27
  #
24
28
  # @return [String] The scaled value.
25
29
  def scale(value)
26
- scale = Math.log10(value)
27
- scale = 0 if scale.infinite?
28
- scale = (scale / 3).to_i
29
- suffix =
30
- case scale
31
- when 1 then "k"
32
- when 2 then "M"
33
- when 3 then "B"
34
- when 4 then "T"
35
- when 5 then "Q"
36
- else
37
- scale = 0
38
- " "
39
- end
30
+ value = HumanReadableUnit.new(value)
40
31
 
41
- format("%10.3f#{suffix}", value.to_f / (1000**scale))
32
+ format("%10.3f#{value.unit}", value.to_f / (1000**value.scale))
42
33
  end
43
- module_function :scale
34
+ module_function :scale # rubocop:disable Style/AccessModifierDeclarations
44
35
  end
45
36
  end
46
37
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+
5
+ module Benchmark
6
+ module Memory
7
+ # Transforms raw numbers into a human-readable scale and suffix
8
+ class HumanReadableUnit < SimpleDelegator
9
+ # @return [Integer] the exponential scale of the value
10
+ def scale
11
+ scale = Math.log10(__getobj__)
12
+ scale = 0 if scale.infinite?
13
+ scale = (scale / 3).to_i
14
+
15
+ if scale <= 5
16
+ scale
17
+ else
18
+ 0
19
+ end
20
+ end
21
+
22
+ # @return [String] the single-character unit for the value
23
+ def unit
24
+ case scale
25
+ when 1 then 'k'
26
+ when 2 then 'M'
27
+ when 3 then 'B'
28
+ when 4 then 'T'
29
+ when 5 then 'Q'
30
+ else ' '
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,5 +1,7 @@
1
- require "benchmark/memory/helpers"
2
- require "benchmark/memory/job/io_output/metric_formatter"
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/helpers'
4
+ require 'benchmark/memory/job/io_output/metric_formatter'
3
5
 
4
6
  module Benchmark
5
7
  module Memory
@@ -23,7 +25,7 @@ module Benchmark
23
25
  #
24
26
  # @return [String]
25
27
  def to_s
26
- return "" unless comparison.possible?
28
+ return '' unless comparison.possible?
27
29
 
28
30
  output = StringIO.new
29
31
  best, *rest = comparison.entries
@@ -41,27 +43,27 @@ module Benchmark
41
43
  private
42
44
 
43
45
  def add_best_summary(best, output)
44
- output << summary_message("%20s: %10i allocated\n", best)
46
+ output << summary_message("%20s: %10i %s\n", best)
45
47
  end
46
48
 
47
49
  def add_comparison(entry, best, output)
48
- output << summary_message("%20s: %10i allocated - ", entry)
50
+ output << summary_message('%20s: %10i %s - ', entry)
49
51
  output << comparison_between(entry, best)
50
52
  output << "\n"
51
53
  end
52
54
 
53
55
  def comparison_between(entry, best)
54
- ratio = entry.allocated_memory.to_f / best.allocated_memory.to_f
56
+ ratio = entry.compared_metric(comparison).to_f / best.compared_metric(comparison)
55
57
 
56
58
  if ratio.abs > 1
57
- format("%.2fx more", ratio)
59
+ format('%<ratio>.2fx more', ratio: ratio)
58
60
  else
59
- "same"
61
+ 'same'
60
62
  end
61
63
  end
62
64
 
63
65
  def summary_message(message, entry)
64
- format(message, entry.label, entry.allocated_memory)
66
+ format(message, entry.label, entry.compared_metric(comparison), comparison.value)
65
67
  end
66
68
  end
67
69
  end
@@ -1,6 +1,8 @@
1
- require "stringio"
2
- require "benchmark/memory/helpers"
3
- require "benchmark/memory/job/io_output/metric_formatter"
1
+ # frozen_string_literal: true
2
+
3
+ require 'stringio'
4
+ require 'benchmark/memory/helpers'
5
+ require 'benchmark/memory/job/io_output/metric_formatter'
4
6
 
5
7
  module Benchmark
6
8
  module Memory
@@ -26,11 +28,14 @@ module Benchmark
26
28
  def to_s
27
29
  output = StringIO.new
28
30
  output << rjust(entry.label)
29
- entry.measurement.each_with_index.map do |metric, index|
30
- output << " " * 20 unless index == 0
31
- output << MetricFormatter.new(metric)
32
- output << "\n"
31
+
32
+ first, *rest = *entry.measurement
33
+
34
+ output << "#{MetricFormatter.new(first)}\n"
35
+ rest.each do |metric|
36
+ output << "#{' ' * 20}#{MetricFormatter.new(metric)}\n"
33
37
  end
38
+
34
39
  output.string
35
40
  end
36
41
  end