benchmark-memory 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,6 @@
1
- require "benchmark/memory/helpers"
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/helpers'
2
4
 
3
5
  module Benchmark
4
6
  module Memory
@@ -22,10 +24,26 @@ module Benchmark
22
24
  #
23
25
  # @return [String]
24
26
  def to_s
25
- [
26
- format("%s %s", scale(metric.allocated), metric.type),
27
- format("(%s retained)", scale(metric.retained)),
28
- ].join(" ")
27
+ [allocated_message, retained_message].join(' ')
28
+ end
29
+
30
+ private
31
+
32
+ # @return [String] the formated string for allocated memory
33
+ def allocated_message
34
+ format(
35
+ '%<allocated>s %<type>s',
36
+ allocated: scale(metric.allocated),
37
+ type: metric.type
38
+ )
39
+ end
40
+
41
+ # @return [String] the formated string for retained memory
42
+ def retained_message
43
+ format(
44
+ '(%<retained>s retained)',
45
+ retained: scale(metric.retained)
46
+ )
29
47
  end
30
48
  end
31
49
  end
@@ -1,5 +1,7 @@
1
- require "benchmark/memory/job/io_output/comparison_formatter"
2
- require "benchmark/memory/job/io_output/entry_formatter"
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/job/io_output/comparison_formatter'
4
+ require 'benchmark/memory/job/io_output/entry_formatter'
3
5
 
4
6
  module Benchmark
5
7
  module Memory
@@ -25,7 +27,7 @@ module Benchmark
25
27
  # @return [void]
26
28
  def put_comparison(comparison)
27
29
  @io.puts
28
- @io.puts "Comparison:"
30
+ @io.puts 'Comparison:'
29
31
  @io.puts ComparisonFormatter.new(comparison)
30
32
  end
31
33
 
@@ -33,7 +35,7 @@ module Benchmark
33
35
  #
34
36
  # @return [void]
35
37
  def put_header
36
- @io.puts "Calculating -------------------------------------"
38
+ @io.puts 'Calculating -------------------------------------'
37
39
  end
38
40
 
39
41
  # Put a notice that the execution is holding for another run.
@@ -41,8 +43,8 @@ module Benchmark
41
43
  # @return [void]
42
44
  def put_hold_notice
43
45
  @io.puts
44
- @io.puts "Pausing here -- run Ruby again to " \
45
- "measure the next benchmark..."
46
+ @io.puts 'Pausing here -- run Ruby again to ' \
47
+ 'measure the next benchmark...'
46
48
  end
47
49
  end
48
50
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Benchmark
2
4
  module Memory
3
5
  class Job
@@ -6,20 +8,17 @@ module Benchmark
6
8
  # Swallow entry output.
7
9
  #
8
10
  # @return [void]
9
- def put_entry(entry)
10
- end
11
+ def put_entry(entry); end
11
12
 
12
13
  # Swallow comparison output.
13
14
  #
14
15
  # @return [void]
15
- def put_comparison(comparison)
16
- end
16
+ def put_comparison(comparison); end
17
17
 
18
18
  # Swallow header output.
19
19
  #
20
20
  # @return [void]
21
- def put_header
22
- end
21
+ def put_header; end
23
22
  end
24
23
  end
25
24
  end
@@ -1,5 +1,7 @@
1
- require "memory_profiler"
2
- require "benchmark/memory/measurement"
1
+ # frozen_string_literal: true
2
+
3
+ require 'memory_profiler'
4
+ require 'benchmark/memory/measurement'
3
5
 
4
6
  module Benchmark
5
7
  module Memory
@@ -14,7 +16,7 @@ module Benchmark
14
16
  # @raise [ArgumentError] if the action does not respond to `#call`.
15
17
  def initialize(label, action)
16
18
  unless action.respond_to?(:call)
17
- fail(
19
+ raise(
18
20
  ArgumentError,
19
21
  "Invalid action (#{@action.inspect} does not respond to call)"
20
22
  )
@@ -1,9 +1,12 @@
1
- require "forwardable"
2
- require "benchmark/memory/job/task"
3
- require "benchmark/memory/job/io_output"
4
- require "benchmark/memory/job/null_output"
5
- require "benchmark/memory/held_results"
6
- require "benchmark/memory/report"
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'benchmark/memory/job/task'
5
+ require 'benchmark/memory/job/io_output'
6
+ require 'benchmark/memory/job/null_output'
7
+ require 'benchmark/memory/held_results'
8
+ require 'benchmark/memory/report'
9
+ require 'benchmark/memory/report/comparator'
7
10
 
8
11
  module Benchmark
9
12
  module Memory
@@ -18,7 +21,6 @@ module Benchmark
18
21
  #
19
22
  # @return [Job]
20
23
  def initialize(output: $stdout, quiet: false)
21
- @compare = false
22
24
  @full_report = Report.new
23
25
  @held_results = HeldResults.new
24
26
  @quiet = quiet
@@ -38,14 +40,14 @@ module Benchmark
38
40
  #
39
41
  # @return [Boolean]
40
42
  def compare?
41
- @compare
43
+ !!@comparator
42
44
  end
43
45
 
44
46
  # Enable output of a comparison of the different tasks.
45
47
  #
46
48
  # @return [void]
47
- def compare!
48
- @compare = true
49
+ def compare!(**spec)
50
+ @comparator = full_report.comparator = Report::Comparator.from_spec(spec.to_h)
49
51
  end
50
52
 
51
53
  # Enable holding results to compare between separate runs.
@@ -63,10 +65,8 @@ module Benchmark
63
65
  # @param block [Proc] Code the measure.
64
66
  #
65
67
  # @raise [ArgumentError] if no code block is specified.
66
- def report(label = "", &block)
67
- unless block_given?
68
- fail ArgumentError, "You did not specify a block for the item"
69
- end
68
+ def report(label = '', &block)
69
+ raise ArgumentError, 'You did not specify a block for the item' unless block_given?
70
70
 
71
71
  tasks.push Task.new(label, block)
72
72
  end
@@ -97,21 +97,9 @@ module Benchmark
97
97
  # @return [Boolean] A flag indicating whether to hold or not.
98
98
  def run_task(task)
99
99
  if @held_results.include?(task)
100
- measurement = @held_results[task.label]
101
- full_report.add_entry(task, measurement)
102
- return false
100
+ run_with_held_results(task)
103
101
  else
104
- measurement = task.call
105
- entry = full_report.add_entry(task, measurement)
106
- @output.put_entry(entry)
107
-
108
- if task == tasks.last
109
- @held_results.cleanup
110
- false
111
- else
112
- @held_results.add_result(entry)
113
- @held_results.holding?
114
- end
102
+ run_without_held_results(task)
115
103
  end
116
104
  end
117
105
 
@@ -119,9 +107,9 @@ module Benchmark
119
107
  #
120
108
  # @return [void]
121
109
  def run_comparison
122
- if compare? && full_report.comparable?
123
- @output.put_comparison(full_report.comparison)
124
- end
110
+ return unless compare? && full_report.comparable?
111
+
112
+ @output.put_comparison(full_report.comparison)
125
113
  end
126
114
 
127
115
  # Check whether the job is set to quiet.
@@ -130,6 +118,28 @@ module Benchmark
130
118
  def quiet?
131
119
  @quiet
132
120
  end
121
+
122
+ private
123
+
124
+ def run_with_held_results(task)
125
+ measurement = @held_results[task.label]
126
+ full_report.add_entry(task, measurement)
127
+ false
128
+ end
129
+
130
+ def run_without_held_results(task)
131
+ measurement = task.call
132
+ entry = full_report.add_entry(task, measurement)
133
+ @output.put_entry(entry)
134
+
135
+ if task == tasks.last
136
+ @held_results.cleanup
137
+ false
138
+ else
139
+ @held_results.add_result(entry)
140
+ @held_results.holding?
141
+ end
142
+ end
133
143
  end
134
144
  end
135
145
  end
@@ -1,12 +1,12 @@
1
- require "benchmark/memory/helpers"
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/helpers'
2
4
 
3
5
  module Benchmark
4
6
  module Memory
5
7
  class Measurement
6
8
  # Describe the ratio of allocated vs. retained memory in a measurement.
7
9
  class Metric
8
- include Comparable
9
-
10
10
  # Instantiate a Metric of allocated vs. retained memory.
11
11
  #
12
12
  # @param type [Symbol] The type of memory allocated in the metric.
@@ -26,15 +26,6 @@ module Benchmark
26
26
 
27
27
  # @return [Symbol] The type of memory allocated in the metric.
28
28
  attr_reader :type
29
-
30
- # Sort by the total allocated.
31
- #
32
- # @param other [Metric] The other metric.
33
- #
34
- # @return [Integer]
35
- def <=>(other)
36
- allocated <=> other.allocated
37
- end
38
29
  end
39
30
  end
40
31
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/measurement/metric'
4
+
5
+ module Benchmark
6
+ module Memory
7
+ # Extracts metrics from a memory profiler result
8
+ class MetricExtractor
9
+ # Extracts the memory-specific metrics from a profiler result
10
+ #
11
+ # @param result [MemoryProfiler::Results]
12
+ # @return [Benchmark::Memory::Measurement::Metric]
13
+ def self.extract_memory(result)
14
+ Measurement::Metric.new(
15
+ :memsize,
16
+ result.total_allocated_memsize,
17
+ result.total_retained_memsize
18
+ )
19
+ end
20
+
21
+ # Extracts the object-specific metrics from a profiler result
22
+ #
23
+ # @param result [MemoryProfiler::Results]
24
+ # @return [Benchmark::Memory::Measurement::Metric]
25
+ def self.extract_objects(result)
26
+ Measurement::Metric.new(
27
+ :objects,
28
+ result.total_allocated,
29
+ result.total_retained
30
+ )
31
+ end
32
+
33
+ # Extracts the string-specific metrics from a profiler result
34
+ #
35
+ # @param result [MemoryProfiler::Results]
36
+ # @return [Benchmark::Memory::Measurement::Metric]
37
+ def self.extract_strings(result)
38
+ Measurement::Metric.new(
39
+ :strings,
40
+ result.strings_allocated.size,
41
+ result.strings_retained.size
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,11 +1,12 @@
1
- require "forwardable"
2
- require "benchmark/memory/measurement/metric"
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'benchmark/memory/measurement/metric_extractor'
3
5
 
4
6
  module Benchmark
5
7
  module Memory
6
8
  # Encapsulate the combined metrics of an action.
7
9
  class Measurement
8
- include Comparable
9
10
  include Enumerable
10
11
  extend Forwardable
11
12
 
@@ -14,23 +15,11 @@ module Benchmark
14
15
  # @param result [MemoryProfiler::Results]
15
16
  # The results of a MemoryProfiler report.
16
17
  def self.from_result(result)
17
- memory = Metric.new(
18
- :memsize,
19
- result.total_allocated_memsize,
20
- result.total_retained_memsize
21
- )
22
- objects = Metric.new(
23
- :objects,
24
- result.total_allocated,
25
- result.total_retained
26
- )
27
- strings = Metric.new(
28
- :strings,
29
- result.strings_allocated.size,
30
- result.strings_retained.size
31
- )
18
+ memory = MetricExtractor.extract_memory(result)
19
+ objects = MetricExtractor.extract_objects(result)
20
+ strings = MetricExtractor.extract_strings(result)
32
21
 
33
- new(:memory => memory, :objects => objects, :strings => strings)
22
+ new(memory: memory, objects: objects, strings: strings)
34
23
  end
35
24
 
36
25
  # Instantiate a Measurement of memory usage.
@@ -59,22 +48,6 @@ module Benchmark
59
48
 
60
49
  # Enumerate through the metrics when enumerating a measurement.
61
50
  def_delegator :metrics, :each
62
-
63
- # Compare two measurements for sorting purposes.
64
- #
65
- # @param other [Measurement] The other measurement
66
- #
67
- # @return [Integer]
68
- def <=>(other)
69
- memory <=> other.memory
70
- end
71
-
72
- # Total amount of allocated memory for the measurement.
73
- #
74
- # @return [Integer]
75
- def allocated_memory
76
- memory.allocated
77
- end
78
51
  end
79
52
  end
80
53
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Benchmark
4
+ module Memory
5
+ class Report
6
+ # Compares two {Entry} for the purposes of sorting and outputting a {Comparison}.
7
+ class Comparator
8
+ # @private
9
+ METRICS = %i[memory objects strings].freeze
10
+
11
+ # @private
12
+ VALUES = %i[allocated retained].freeze
13
+
14
+ # Instantiates a {Comparator} from a spec given by {Job#compare!}
15
+ #
16
+ # @param spec [Hash<Symbol, Symbol>] The specification given for the {Comparator}
17
+ # @return [Comparator]
18
+ def self.from_spec(spec)
19
+ raise ArgumentError, 'Only send a single metric and value, in the form memory: :allocated' if spec.length > 1
20
+
21
+ metric, value = *spec.first
22
+ metric ||= :memory
23
+ value ||= :allocated
24
+
25
+ new(metric: metric, value: value)
26
+ end
27
+
28
+ # Instantiate a new comparator
29
+ #
30
+ # @param metric [Symbol] (see #metric)
31
+ # @param value [Symbol] (see #value)
32
+ def initialize(metric: :memory, value: :allocated)
33
+ raise ArgumentError, "Invalid metric: #{metric.inspect}" unless METRICS.include? metric
34
+ raise ArgumentError, "Invalid value: #{value.inspect}" unless VALUES.include? value
35
+
36
+ @metric = metric
37
+ @value = value
38
+ end
39
+
40
+ # @return [Symbol] The metric to compare, one of `:memory`, `:objects`, or `:strings`
41
+ attr_reader :metric
42
+
43
+ # @return [Symbol] The value to compare, one of `:allocated` or `:retained`
44
+ attr_reader :value
45
+
46
+ # Checks whether a {Comparator} equals another
47
+ #
48
+ # @param other [Benchmark::Memory::Comparator] The comparator to check against
49
+ #
50
+ # @return [Boolean]
51
+ def ==(other)
52
+ metric == other.metric && value == other.value
53
+ end
54
+
55
+ # Converts the {Comparator} to a Proc for passing to a block
56
+ #
57
+ # @return [Proc]
58
+ def to_proc
59
+ proc { |entry| entry.measurement.public_send(metric).public_send(value) }
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,18 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Benchmark
2
4
  module Memory
3
5
  class Report
4
6
  # Compare entries against each other.
5
7
  class Comparison
8
+ extend Forwardable
9
+
6
10
  # Instantiate a new comparison.
7
11
  #
8
12
  # @param entries [Array<Entry>] The entries to compare.
9
- def initialize(entries)
10
- @entries = entries.sort_by(&:measurement)
13
+ # @param comparator [Comparator] The comparator to use when generating.
14
+ def initialize(entries, comparator)
15
+ @entries = entries.sort_by(&comparator)
16
+ @comparator = comparator
11
17
  end
12
18
 
19
+ # @return [Comparator] The {Comparator} to use when generating the {Comparison}.
20
+ attr_reader :comparator
21
+
13
22
  # @return [Array<Entry>] The entries to compare.
14
23
  attr_reader :entries
15
24
 
25
+ # @!method metric
26
+ # @return [Symbol] The metric to compare, one of `:memory`, `:objects`, or `:strings`
27
+ # @!method value
28
+ # @return [Symbol] The value to compare, one of `:allocated` or `:retained`
29
+ def_delegators :@comparator, :metric, :value
30
+
16
31
  # Check if the comparison is possible
17
32
  #
18
33
  # @return [Boolean]
@@ -1,4 +1,6 @@
1
- require "forwardable"
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
2
4
 
3
5
  module Benchmark
4
6
  module Memory
@@ -22,9 +24,10 @@ module Benchmark
22
24
 
23
25
  # Get the total amount of memory allocated in the entry.
24
26
  #
27
+ # @param comparison [Comparison] The {Comparison} to compare.
25
28
  # @return [Integer]
26
- def allocated_memory
27
- measurement.memory.allocated
29
+ def compared_metric(comparison)
30
+ measurement.public_send(comparison.metric).public_send(comparison.value)
28
31
  end
29
32
  end
30
33
  end
@@ -1,5 +1,7 @@
1
- require "benchmark/memory/report/comparison"
2
- require "benchmark/memory/report/entry"
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/report/comparison'
4
+ require 'benchmark/memory/report/entry'
3
5
 
4
6
  module Benchmark
5
7
  module Memory
@@ -10,8 +12,12 @@ module Benchmark
10
12
  # @return [Report]
11
13
  def initialize
12
14
  @entries = []
15
+ @comparator = Comparator.new
13
16
  end
14
17
 
18
+ # @return [Comparator] The {Comparator} to use when creating the {Comparison}.
19
+ attr_accessor :comparator
20
+
15
21
  # @return [Array<Entry>] The entries in the report.
16
22
  attr_reader :entries
17
23
 
@@ -38,7 +44,7 @@ module Benchmark
38
44
  #
39
45
  # @return [Comparison]
40
46
  def comparison
41
- @comparison ||= Comparison.new(entries)
47
+ @comparison ||= Comparison.new(entries, comparator)
42
48
  end
43
49
  end
44
50
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Benchmark
2
4
  module Memory
3
- VERSION = "0.1.2".freeze
5
+ VERSION = '0.2.0'
4
6
  end
5
7
  end
@@ -1,6 +1,8 @@
1
- require "benchmark/memory/errors"
2
- require "benchmark/memory/job"
3
- require "benchmark/memory/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory/errors'
4
+ require 'benchmark/memory/job'
5
+ require 'benchmark/memory/version'
4
6
 
5
7
  # Performance benchmarking library
6
8
  module Benchmark
@@ -13,14 +15,9 @@ module Benchmark
13
15
  #
14
16
  # @return [Report]
15
17
  def memory(quiet: false)
16
- unless block_given?
17
- fail(
18
- ConfigurationError,
19
- "You did not give a test block to your call to `Benchmark.memory`"
20
- )
21
- end
18
+ raise ConfigurationError unless block_given?
22
19
 
23
- job = Job.new(:quiet => quiet)
20
+ job = Job.new(quiet: quiet)
24
21
 
25
22
  yield job
26
23
 
@@ -1,2 +1,3 @@
1
- # rubocop:disable Style/FileName
2
- require "benchmark/memory"
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/memory'