Skip to content

Commit 224b13c

Browse files
Merge pull request #127 from TheDragonCode/4.x
Add warmup support to benchmark iterations and tests
2 parents 2aec502 + f85cdc5 commit 224b13c

6 files changed

Lines changed: 122 additions & 3 deletions

File tree

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,27 @@ new Benchmark()
8686
->toConsole();
8787
```
8888

89+
### Warm-up
90+
91+
Use the `warmup` method to run each callback a few times before the measured iterations. Warm-up runs behave
92+
identically to regular ones (`beforeEach` / `afterEach` are invoked, the progress bar advances), but their
93+
time and memory are not included in the final statistics.
94+
95+
This stabilizes results by absorbing one-time costs such as cold caches, JIT/opcache priming and lazy autoloading.
96+
97+
Disabled by default.
98+
99+
```php
100+
use DragonCode\Benchmark\Benchmark;
101+
102+
new Benchmark()
103+
->warmup(3) // run 3 warm-up iterations per callback before measuring
104+
->compare(
105+
foo: fn () => /* some code */,
106+
bar: fn () => /* some code */,
107+
);
108+
```
109+
89110
### Round Precision
90111

91112
Use the `round` method to set the number of decimal places in console output:

src/Benchmark.php

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class Benchmark
2727

2828
protected int $deviations = 1;
2929

30+
protected int $warmup = 0;
31+
3032
public function __construct(
3133
protected RunnerService $runner = new RunnerService,
3234
protected ViewService $view = new ViewService,
@@ -57,6 +59,19 @@ public function snapshots(string $directory): static
5759
return $this;
5860
}
5961

62+
/**
63+
* Specifies the number of warm-up iterations for each callback.
64+
*
65+
* @param int<1, max> $count
66+
* @return $this
67+
*/
68+
public function warmup(int $count = 1): static
69+
{
70+
$this->warmup = max(1, abs($count));
71+
72+
return $this;
73+
}
74+
6075
/**
6176
* Sets a callback to be executed before all iterations for each comparison.
6277
*
@@ -292,7 +307,10 @@ protected function withProgress(Closure $callback, int $total): void
292307
*/
293308
protected function steps(array $callbacks, int $multiplier = 1): int
294309
{
295-
return count($callbacks) * $this->iterations * $multiplier;
310+
$count = count($callbacks);
311+
$warmup = $count * $this->warmup;
312+
313+
return $count * $this->iterations * $multiplier + $warmup;
296314
}
297315

298316
/**
@@ -321,14 +339,18 @@ protected function chunks(array $callbacks, ProgressBar $progressBar): void
321339
*/
322340
protected function run(mixed $name, Closure $callback, ProgressBar $progressBar): void
323341
{
324-
for ($i = 1; $i <= $this->iterations; $i++) {
342+
$warmedUp = $this->warmup === 0;
343+
344+
for ($i = 1; $i <= $this->iterations + $this->warmup; $i++) {
325345
$result = $this->callbacks->performBeforeEach($name, $i);
326346

327347
[$time, $memory] = $this->call($callback, [$i, $result]);
328348

329349
$this->callbacks->performAfterEach($name, $i, $time, $memory);
330350

331-
$this->push($name, $time, $memory);
351+
if ($warmedUp) {
352+
$this->push($name, $time, $memory);
353+
}
332354

333355
$progressBar->advance();
334356
}

tests/.pest/snapshots/Unit/WarmUp/WarmUpTest/warmup_with_data_set___10__.snap

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
3+
0/26 [░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0% 1/26 [▓░░░░░░░░░░░░░░░░░░░░░░░░░░░] 3% 2/26 [▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░] 7% 3/26 [▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░] 11% 4/26 [▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░] 15% 5/26 [▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░] 19% 6/26 [▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░] 23% 7/26 [▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░] 26% 8/26 [▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░] 30% 9/26 [▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░] 34% 10/26 [▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░] 38% 11/26 [▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░] 42% 12/26 [▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░] 46% 13/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░] 50% 14/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░] 53% 15/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░] 57% 16/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░] 61% 17/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░] 65% 18/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░] 69% 19/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░] 73% 20/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░] 76% 21/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░] 80% 22/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░] 84% 23/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░] 88% 24/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░] 92% 25/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░] 96% 26/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% 26/26 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
4+
5+
6+
7+
+-------+------------------------+------------------------+
8+
| # | 0 | 1 |
9+
+-------+------------------------+------------------------+
10+
| min | 15.6789 ms - 202 bytes | 2.3457 ms - 102 bytes |
11+
| max | 112.789 ms - 209 bytes | 9.7568 ms - 109 bytes |
12+
| avg | 53.0252 ms - 205 bytes | 5.9429 ms - 105 bytes |
13+
| total | 424.202 ms - 1.61 KB | 47.5432 ms - 844 bytes |
14+
+-------+------------------------+------------------------+
15+
| order | 2 | 1 |
16+
+-------+------------------------+------------------------+

tests/.pest/snapshots/Unit/WarmUp/WarmUpTest/warmup_with_data_set___1__.snap

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
3+
0/8 [░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0% 1/8 [▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░] 12% 2/8 [▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░] 25% 3/8 [▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░] 37% 4/8 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░] 50% 5/8 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░] 62% 6/8 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░] 75% 7/8 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░] 87% 8/8 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% 8/8 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
4+
5+
6+
7+
+-------+------------------------+------------------------+
8+
| # | 0 | 1 |
9+
+-------+------------------------+------------------------+
10+
| min | 15.6789 ms - 202 bytes | 2.3457 ms - 102 bytes |
11+
| max | 112.789 ms - 209 bytes | 9.7568 ms - 109 bytes |
12+
| avg | 53.0252 ms - 205 bytes | 5.9429 ms - 105 bytes |
13+
| total | 424.202 ms - 1.61 KB | 47.5432 ms - 844 bytes |
14+
+-------+------------------------+------------------------+
15+
| order | 2 | 1 |
16+
+-------+------------------------+------------------------+

tests/.pest/snapshots/Unit/WarmUp/WarmUpTest/warmup_with_data_set___5__.snap

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
3+
0/16 [░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0% 1/16 [▓░░░░░░░░░░░░░░░░░░░░░░░░░░░] 6% 2/16 [▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░] 12% 3/16 [▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░] 18% 4/16 [▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░] 25% 5/16 [▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░] 31% 6/16 [▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░] 37% 7/16 [▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░] 43% 8/16 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░] 50% 9/16 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░] 56% 10/16 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░] 62% 11/16 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░] 68% 12/16 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░] 75% 13/16 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░] 81% 14/16 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░] 87% 15/16 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░] 93% 16/16 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% 16/16 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
4+
5+
6+
7+
+-------+------------------------+------------------------+
8+
| # | 0 | 1 |
9+
+-------+------------------------+------------------------+
10+
| min | 15.6789 ms - 202 bytes | 2.3457 ms - 102 bytes |
11+
| max | 112.789 ms - 209 bytes | 9.7568 ms - 109 bytes |
12+
| avg | 53.0252 ms - 205 bytes | 5.9429 ms - 105 bytes |
13+
| total | 424.202 ms - 1.61 KB | 47.5432 ms - 844 bytes |
14+
+-------+------------------------+------------------------+
15+
| order | 2 | 1 |
16+
+-------+------------------------+------------------------+

tests/Unit/WarmUp/WarmUpTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use DragonCode\Benchmark\Benchmark;
6+
use Tests\Fixtures\CollectorFixture;
7+
8+
test('warmup', function (int $warmup) {
9+
$count = 0;
10+
11+
(new Benchmark(collector: new CollectorFixture))
12+
->iterations(3)
13+
->round(4)
14+
->warmup($warmup)
15+
->compare(
16+
foo: function () use (&$count) {
17+
$count++;
18+
},
19+
bar: function () use (&$count) {
20+
$count++;
21+
},
22+
)
23+
->toConsole();
24+
25+
expect($count)->toBe(6 + $warmup * 2);
26+
27+
expectOutputToMatchSnapshot();
28+
})->with([1, 5, 10]);

0 commit comments

Comments
 (0)