sus-fixtures-benchmark 0.1.0 → 0.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63078795b33d87a934f27e4b1a3499b67a5a1dbc3d4fb9c50cc83a3014dc9916
4
- data.tar.gz: c2c82e5e602dfd1f3a2e9f27609cbd518fc8822b70da8bb226a606bd9f6de06a
3
+ metadata.gz: de94d05fdae13b52e4e260d2f2fc5fc65792436d6756409fb332e77e4bc64b81
4
+ data.tar.gz: c0a75a615f5021dbd5ae2f26bb6d5a1eb4ac7c9d5ae22955bffe6573106d260b
5
5
  SHA512:
6
- metadata.gz: a7fb2ab5b00ab5061b5fee54bb1bdfe0587ec6e95f811eca1b49e914a3511c0f7da13dbabe861b30c797c476c65577d3eb4200243cd2557ce19083b25269ab0a
7
- data.tar.gz: 96a95d1c1e20585ff56e82035b0819f0c40cb967436ef32837bc389e67524b318e7e04b2ac863f55d172f8e108151e2850de2d169d4b36b10e796514ddb626a4
6
+ metadata.gz: 0212ff21fd9e1dc27a2ee42d08bce8e1a2a713bdb204c869789f37a651fa828ff9047d4c2b4f4c85cf1322c822ce232fa2691da90a8d1808e1e7b94636eeb9e4
7
+ data.tar.gz: 72b37243db4d7c841924e17458dae86e8c028f1327f27711ece5603cb21f87831399498756fe2e1b4ad09be3119db714208c918c99d22a8742bb9efff1c47d0d
checksums.yaml.gz.sig CHANGED
Binary file
@@ -0,0 +1,127 @@
1
+ # Getting Started
2
+
3
+ This guide explains how to use the `sus-fixtures-benchmark` gem to measure and benchmark code performance within your Sus test suite.
4
+
5
+ ## Quick Start
6
+
7
+ ### Project Structure
8
+
9
+ We recommend organizing your benchmarks in a dedicated `benchmark/` directory:
10
+
11
+ ```
12
+ your-project/
13
+ ├── benchmark/
14
+ │ ├── database_performance.rb
15
+ │ ├── algorithm_comparison.rb
16
+ │ └── memory_usage.rb
17
+ ├── test/
18
+ ├── lib/
19
+ └── Gemfile
20
+ ```
21
+
22
+ This keeps your benchmarks separate from your regular tests and makes them easy to find and run.
23
+
24
+ ### Basic Measurement
25
+
26
+ The simplest way to measure code performance is using the `measure` method:
27
+
28
+ ```ruby
29
+ # benchmark/array_performance.rb
30
+ require "sus/fixtures/benchmark"
31
+
32
+ describe "Array Performance" do
33
+ include Sus::Fixtures::Benchmark
34
+
35
+ let(:data) {(1..1000).to_a}
36
+
37
+ measure "array iteration" do |repeats|
38
+ repeats.times do
39
+ data.each{|i| i * 2}
40
+ end
41
+ end
42
+ end
43
+ ```
44
+
45
+ This will automatically run your code until statistical convergence is reached and report the results.
46
+
47
+ **Run with:** `sus --verbose benchmark/array_performance.rb`
48
+
49
+ ### Understanding the Output
50
+
51
+ When you run your tests with `sus --verbose`, you'll see output like:
52
+
53
+ ```
54
+ measure array iteration 34 samples, mean: 0.15ms, standard deviation: 0.02ms, standard error: 0.003ms
55
+ ```
56
+
57
+ **Important:** You must run `sus --verbose` to see the benchmark output. Without the verbose flag, the benchmark results will not be displayed.
58
+
59
+ This tells you:
60
+ - **34 samples**: How many times the code was executed.
61
+ - **mean: 0.15ms**: Average execution time.
62
+ - **standard deviation: 0.02ms**: How much variation there was between runs.
63
+ - **standard error: 0.003ms**: How reliable the mean estimate is.
64
+
65
+ ## Measurement Modes
66
+
67
+ ### Automatic Convergence (Default)
68
+
69
+ By default, the benchmark runs until it achieves statistical convergence:
70
+
71
+ ```ruby
72
+ measure "database query" do |repeats|
73
+ repeats.times do
74
+ User.where(active: true).count
75
+ end
76
+ end
77
+ ```
78
+
79
+ The system will automatically determine when it has enough samples to provide a reliable measurement based on:
80
+ - **Confidence level**: 95% by default
81
+ - **Margin of error**: 2% of the mean by default (0.02)
82
+ - **Minimum samples**: 8 by default
83
+
84
+ ### Fixed Number of Iterations
85
+
86
+ If you need a specific number of iterations, use the `exactly` method:
87
+
88
+ ```ruby
89
+ measure "quick test" do |repeats|
90
+ repeats.exactly(10).times do
91
+ # Your code here
92
+ end
93
+ end
94
+ ```
95
+
96
+ This is useful for:
97
+ - Quick smoke tests.
98
+ - When you know the exact number of iterations needed.
99
+ - Debugging or development scenarios.
100
+
101
+ ## Configuration Options
102
+
103
+ ### Customizing the Sampler
104
+
105
+ You can customize the statistical parameters directly in the `measure` method:
106
+
107
+ ```ruby
108
+ measure "high precision", minimum: 20, confidence: 0.98, margin_of_error: 0.01 do |repeats|
109
+ repeats.times do
110
+ # Your code here
111
+ end
112
+ end
113
+ ```
114
+
115
+ ### Parameter Reference
116
+
117
+ You should try to avoid deviating from the defaults.
118
+
119
+ - **`minimum`** (Integer): Minimum samples before convergence (default: 8).
120
+ - **Lower `minimum`**: Quick development feedback (e.g., `minimum: 3`)
121
+ - **Higher `minimum`**: High-variance operations (e.g., `minimum: 30`)
122
+ - **`confidence`** (Float): Confidence level 0.0-1.0 (default: 0.95). High confidence (above 0.98) may take an extremely long time to converge.
123
+ - **Lower `confidence`**: Faster results (e.g., `confidence: 0.90`)
124
+ - **Higher `confidence`**: Production guarantees (e.g., `confidence: 0.98`)
125
+ - **`margin_of_error`** (Float): Acceptable error as a fraction of the mean (default: 0.02 = 2%).
126
+ - **Lower `margin_of_error`**: High precision (e.g., `margin_of_error: 0.01`)
127
+ - **Higher `margin_of_error`**: Rough estimates (e.g., `margin_of_error: 0.05`)
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- #
4
3
  # Released under the MIT License.
5
4
  # Copyright, 2025, by Samuel Williams.
6
5
 
@@ -12,27 +11,71 @@ module Sus
12
11
  # Represents a benchmarking helper that executes a block multiple times, collecting timing samples until statistical convergence is reached.
13
12
  class Repeats
14
13
  # Initializes a new {Repeats} object with a sampler to collect timing data.
15
- # @parameter samples [Sampler] The sampler object to collect timing data.
16
- def initialize(samples)
17
- @samples = samples
14
+ # @parameter sampler [Sampler] The sampler object to collect timing data.
15
+ def initialize(sampler)
16
+ @sampler = sampler
18
17
  end
19
18
 
19
+ # @attribute [Sampler] The sampler that collects timing data.
20
+ attr :sampler
21
+
20
22
  # Samples the execution time of the given block and adds the result to the sampler.
21
23
  # @parameter block [Proc] The block to benchmark.
22
24
  private def sample!(block)
23
25
  time = Benchmark::Time.measure do
24
26
  block.call
25
27
  end
26
- @samples.add(time.real)
28
+ @sampler.add(time.real)
27
29
  end
28
30
 
29
31
  # Repeatedly executes the block until the sampler reports convergence.
30
32
  # @parameter block [Proc] The block to benchmark.
31
33
  def times(&block)
32
- until @samples.converged?
34
+ until @sampler.converged?
33
35
  sample!(block)
34
36
  end
35
37
  end
38
+
39
+ # Represents a benchmarking helper that executes a block a fixed number of times.
40
+ class Exactly
41
+ # Initializes a new {Exactly} object with a sampler and a fixed count.
42
+ # @parameter sampler [Sampler] The sampler object to collect timing data.
43
+ # @parameter count [Integer] The exact number of times to execute the block.
44
+ def initialize(sampler, count)
45
+ @sampler = sampler
46
+ @count = count
47
+ end
48
+
49
+ # @attribute [Sampler] The sampler that collects timing data.
50
+ attr :sampler
51
+
52
+ # @attribute [Integer] The number of times to execute the block.
53
+ attr :count
54
+
55
+ # Samples the execution time of the given block and adds the result to the sampler.
56
+ # @parameter block [Proc] The block to benchmark.
57
+ private def sample!(block)
58
+ time = Benchmark::Time.measure do
59
+ block.call
60
+ end
61
+ @sampler.add(time.real)
62
+ end
63
+
64
+ # Executes the block exactly the specified number of times.
65
+ # @parameter block [Proc] The block to benchmark.
66
+ def times(&block)
67
+ @count.times do
68
+ sample!(block)
69
+ end
70
+ end
71
+ end
72
+
73
+ # Sets a fixed number of times to execute the block, returning a new {Exactly} instance.
74
+ # @parameter count [Integer] The exact number of times to execute the block.
75
+ # @returns [Exactly] A new instance that will execute the block exactly the specified number of times.
76
+ def exactly(count)
77
+ Exactly.new(@sampler, count)
78
+ end
36
79
  end
37
80
  end
38
81
  end
@@ -41,7 +41,7 @@ module Sus
41
41
  # The real (wall clock) time in seconds.
42
42
  # @returns [Float]
43
43
  attr :real
44
-
44
+
45
45
  # Returns a string representation of the real time in seconds.
46
46
  # @returns [String]
47
47
  def to_s
@@ -6,7 +6,7 @@
6
6
  module Sus
7
7
  module Fixtures
8
8
  module Benchmark
9
- VERSION = "0.1.0"
9
+ VERSION = "0.2.1"
10
10
  end
11
11
  end
12
12
  end
@@ -26,15 +26,19 @@ module Sus
26
26
  # @parameter parent [Class] The parent test context class.
27
27
  # @parameter description [String] The description of the measure.
28
28
  # @parameter unique [Boolean] Whether the measure should have a unique identity.
29
+ # @parameter **options [Hash] Options to pass to the Sampler constructor.
29
30
  # @parameter block [Proc] The block to execute for the measure.
30
31
  # @returns [Class] The new measure class.
31
- def self.build(parent, description, unique: true, &block)
32
+ def self.build(parent, description, unique: true, **options, &block)
32
33
  base = Class.new(parent)
33
34
  base.extend(self)
34
35
  base.description = description
35
36
  base.identity = Identity.nested(parent.identity, base.description, unique: unique)
36
37
  base.set_temporary_name("#{self}[#{description}]")
37
38
 
39
+ # Store sampler options for later use
40
+ base.define_singleton_method(:sampler_options) {options}
41
+
38
42
  if block_given?
39
43
  base.define_method(:run, &block)
40
44
  end
@@ -67,7 +71,8 @@ module Sus
67
71
  assertions.nested(self, identity: self.identity, isolated: true, measure: true) do |assertions|
68
72
  instance = self.new(assertions)
69
73
 
70
- samples = Sampler.new
74
+ # Create sampler with options
75
+ samples = Sampler.new(**self.sampler_options)
71
76
  repeats = Repeats.new(samples)
72
77
 
73
78
  instance.around do
data/readme.md CHANGED
@@ -12,11 +12,19 @@ bundle add sus-fixtures-benchmark
12
12
 
13
13
  ## Usage
14
14
 
15
- Please see the [project documentation](https://suspecting.github.io/sus-fixtures-benchmark/) for more details.
15
+ Please see the [project documentation](https://socketry.github.io/sus-fixtures-benchmark/) for more details.
16
16
 
17
17
  ## Releases
18
18
 
19
- Please see the [project releases](https://suspecting.github.io/sus-fixtures-benchmark/releases/index) for all releases.
19
+ Please see the [project releases](https://socketry.github.io/sus-fixtures-benchmark/releases/index) for all releases.
20
+
21
+ ### v0.2.1
22
+
23
+ - Fix links and add context.
24
+
25
+ ### v0.2.0
26
+
27
+ - Added `exactly(count)` method to `Sus::Fixtures::Benchmark::Repeats` which returns an `Exactly` instance for fixed-count benchmarking.
20
28
 
21
29
  ### v0.1.0
22
30
 
data/releases.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Releases
2
2
 
3
+ ## v0.2.1
4
+
5
+ - Fix links and add context.
6
+
7
+ ## v0.2.0
8
+
9
+ - Added `exactly(count)` method to `Sus::Fixtures::Benchmark::Repeats` which returns an `Exactly` instance for fixed-count benchmarking.
10
+
3
11
  ## v0.1.0
4
12
 
5
13
  - Added `Sus::Fixtures::Benchmark::Repeats` which is not an integer, but an instance that allows the block to be executed multiple times until the benchmark converges.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sus-fixtures-benchmark
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -57,6 +57,7 @@ extensions: []
57
57
  extra_rdoc_files: []
58
58
  files:
59
59
  - agent.md
60
+ - context/getting-started.md
60
61
  - lib/sus/fixtures/benchmark.rb
61
62
  - lib/sus/fixtures/benchmark/repeats.rb
62
63
  - lib/sus/fixtures/benchmark/sampler.rb
@@ -65,13 +66,13 @@ files:
65
66
  - license.md
66
67
  - readme.md
67
68
  - releases.md
68
- homepage: https://github.com/suspecting/sus-fixtures-benchmark
69
+ homepage: https://github.com/socketry/sus-fixtures-benchmark
69
70
  licenses:
70
71
  - MIT
71
72
  metadata:
72
- documentation_uri: https://suspecting.github.io/sus-fixtures-benchmark/
73
+ documentation_uri: https://socketry.github.io/sus-fixtures-benchmark/
73
74
  funding_uri: https://github.com/sponsors/ioquatix/
74
- source_code_uri: https://github.com/suspecting/sus-fixtures-benchmark.git
75
+ source_code_uri: https://github.com/socketry/sus-fixtures-benchmark.git
75
76
  rdoc_options: []
76
77
  require_paths:
77
78
  - lib
metadata.gz.sig CHANGED
Binary file