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 +5 -5
- data/CHANGELOG.md +15 -7
- data/README.md +40 -15
- data/Rakefile +8 -18
- data/benchmark-memory.gemspec +14 -14
- data/lib/benchmark/memory/errors.rb +7 -1
- data/lib/benchmark/memory/held_results/entry_serializer.rb +9 -7
- data/lib/benchmark/memory/held_results/measurement_serializer.rb +11 -9
- data/lib/benchmark/memory/held_results/metric_serializer.rb +10 -8
- data/lib/benchmark/memory/held_results/serializer.rb +10 -8
- data/lib/benchmark/memory/held_results.rb +10 -14
- data/lib/benchmark/memory/helpers.rb +7 -16
- data/lib/benchmark/memory/human_readable_unit.rb +35 -0
- data/lib/benchmark/memory/job/io_output/comparison_formatter.rb +11 -9
- data/lib/benchmark/memory/job/io_output/entry_formatter.rb +12 -7
- data/lib/benchmark/memory/job/io_output/metric_formatter.rb +23 -5
- data/lib/benchmark/memory/job/io_output.rb +8 -6
- data/lib/benchmark/memory/job/null_output.rb +5 -6
- data/lib/benchmark/memory/job/task.rb +5 -3
- data/lib/benchmark/memory/job.rb +41 -31
- data/lib/benchmark/memory/measurement/metric.rb +3 -12
- data/lib/benchmark/memory/measurement/metric_extractor.rb +46 -0
- data/lib/benchmark/memory/measurement.rb +8 -35
- data/lib/benchmark/memory/report/comparator.rb +64 -0
- data/lib/benchmark/memory/report/comparison.rb +17 -2
- data/lib/benchmark/memory/report/entry.rb +6 -3
- data/lib/benchmark/memory/report.rb +9 -3
- data/lib/benchmark/memory/version.rb +3 -1
- data/lib/benchmark/memory.rb +7 -10
- data/lib/benchmark-memory.rb +3 -2
- metadata +14 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 77c690ecb4b3640eb994fe9dbaddaac4dde593fb445b8e6fff50c771dec82c6f
|
4
|
+
data.tar.gz: 4f29c72bae6ec8a5d024c4c0d89ff7032a75c9c6a2dd738ecdde5d4dd3e162b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
[![
|
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=
|
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
|
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
|
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
|
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
|
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 `
|
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][
|
172
|
+
This library aims to support and is [tested against][ci] the following Ruby versions:
|
149
173
|
|
150
|
-
* Ruby 2.
|
151
|
-
* Ruby 2.
|
152
|
-
* Ruby 2.
|
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,
|
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
|
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].
|
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
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler'
|
2
4
|
Bundler.setup
|
3
5
|
Bundler::GemHelper.install_tasks
|
4
6
|
|
5
|
-
require
|
7
|
+
require 'inch/rake'
|
6
8
|
Inch::Rake::Suggest.new(:inch)
|
7
9
|
|
8
|
-
require
|
10
|
+
require 'rspec/core/rake_task'
|
9
11
|
RSpec::Core::RakeTask.new(:spec)
|
10
12
|
|
11
|
-
require
|
13
|
+
require 'rubocop/rake_task'
|
12
14
|
RuboCop::RakeTask.new(:rubocop)
|
13
15
|
|
14
|
-
require
|
16
|
+
require 'yard/rake/yardoc_task'
|
15
17
|
YARD::Rake::YardocTask.new(:yard)
|
16
18
|
|
17
|
-
task :
|
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]
|
data/benchmark-memory.gemspec
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require File.expand_path(
|
3
|
+
require File.expand_path('lib/benchmark/memory/version', __dir__)
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
6
|
+
spec.name = 'benchmark-memory'
|
7
7
|
spec.version = Benchmark::Memory::VERSION
|
8
|
-
spec.authors = [
|
9
|
-
spec.email = [
|
8
|
+
spec.authors = ['Michael Herold']
|
9
|
+
spec.email = ['michael.j.herold@gmail.com']
|
10
10
|
|
11
|
-
spec.summary =
|
11
|
+
spec.summary = 'Benchmark-style memory profiling'
|
12
12
|
spec.description = spec.summary
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
13
|
+
spec.homepage = 'https://github.com/michaelherold/benchmark-memory'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
|
-
spec.files = %w
|
17
|
-
spec.files += %w
|
18
|
-
spec.files += Dir[
|
19
|
-
spec.require_paths = [
|
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.
|
21
|
+
spec.required_ruby_version = '>= 2.5.0'
|
22
22
|
|
23
|
-
spec.
|
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
|
-
|
2
|
-
|
3
|
-
require
|
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[
|
18
|
-
MeasurementSerializer.load(hash[
|
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
|
-
:
|
29
|
-
:
|
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
|
-
|
2
|
-
|
3
|
-
require
|
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
|
-
:
|
18
|
-
:
|
19
|
-
:
|
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
|
-
:
|
30
|
-
:
|
31
|
-
:
|
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
|
-
|
2
|
-
|
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[
|
18
|
-
hash[
|
19
|
-
hash[
|
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
|
-
:
|
30
|
-
:
|
31
|
-
:
|
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
|
-
|
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
|
-
|
38
|
+
raise(
|
37
39
|
NotImplementedError,
|
38
|
-
|
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
|
-
|
50
|
+
raise(
|
49
51
|
NotImplementedError,
|
50
|
-
|
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
|
-
|
62
|
+
alias to_s to_json
|
61
63
|
end
|
62
64
|
end
|
63
65
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
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(
|
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
|
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 =
|
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 =
|
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)
|
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
|
-
|
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#{
|
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
|
-
|
2
|
-
|
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
|
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
|
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(
|
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.
|
56
|
+
ratio = entry.compared_metric(comparison).to_f / best.compared_metric(comparison)
|
55
57
|
|
56
58
|
if ratio.abs > 1
|
57
|
-
format(
|
59
|
+
format('%<ratio>.2fx more', ratio: ratio)
|
58
60
|
else
|
59
|
-
|
61
|
+
'same'
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
63
65
|
def summary_message(message, entry)
|
64
|
-
format(message, entry.label, entry.
|
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
|
-
|
2
|
-
|
3
|
-
require
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|