Skip to content

Commit adee480

Browse files
Merge pull request #93 from TheDragonCode/4.x
Added deviation calculation
2 parents 21eeae4 + 5133303 commit adee480

11 files changed

Lines changed: 455 additions & 30 deletions

File tree

README.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ Or manually update `require-dev` block of `composer.json` and run `composer upda
3434
>
3535
> The result of the execution is printed to the console, so make sure you call the code from the console.
3636
37+
### Quick Start
38+
39+
```php
40+
use DragonCode\Benchmark\Benchmark;
41+
42+
new Benchmark()
43+
->compare(
44+
static fn () => true,
45+
static fn () => true
46+
)
47+
->toConsole();
48+
```
49+
50+
### How To Use
51+
3752
```php
3853
use DragonCode\Benchmark\Benchmark;
3954

@@ -160,6 +175,82 @@ Result example:
160175
+-------+----------------------+----------------------+
161176
```
162177

178+
### Deviation Values
179+
180+
In some cases, it is necessary to test not only the functionality of the options themselves, but also to determine the
181+
level of deviation between them. To do this, use the `deviations` method.
182+
183+
When you specify this method during a call, all your loops will repeat the specified number of times.
184+
Meanwhile, the resulting table and DTO will display values from the results, where:
185+
186+
- `min` - minimum among all result values
187+
- `max` - maximum among all results
188+
- `avg` - arithmetic mean of all result values
189+
- `total` - the total value among the values of all results
190+
- `deviation` - deviation calculated from the mean of all results
191+
192+
For example:
193+
194+
```php
195+
new Benchmark()
196+
->deviations(4)
197+
->iterations(5)
198+
->compare(
199+
foo: fn () => /* some code */,
200+
bar: fn () => /* some code */,
201+
)
202+
->toConsole();
203+
```
204+
205+
```bash
206+
+------------------+----------------------+-----------------------+
207+
| # | foo | bar |
208+
+------------------+----------------------+-----------------------+
209+
| min | 0.0011 ms - 0 bytes | 0.0009 ms - 0 bytes |
210+
| max | 0.0111 ms - 0 bytes | 0.0082 ms - 0 bytes |
211+
| avg | 0.00453 ms - 0 bytes | 0.002715 ms - 0 bytes |
212+
| total | 0.0906 ms - 0 bytes | 0.0543 ms - 0 bytes |
213+
+------------------+----------------------+-----------------------+
214+
| order | 2 | 1 |
215+
+------------------+----------------------+-----------------------+
216+
| deviation time | +0.002768 | +0.000919 |
217+
| deviation memory | 0 | 0 |
218+
+------------------+----------------------+-----------------------+
219+
```
220+
221+
#### To understand work without deviations
222+
223+
```php
224+
$iterations = 10;
225+
$result = [];
226+
227+
for ($i = 0; $i < $iterations; $i++) {
228+
$result[] = /* perform some code */;
229+
}
230+
231+
return $result;
232+
```
233+
234+
#### To understand work with deviations
235+
236+
```php
237+
$iterations = 10;
238+
$deviations = 4;
239+
$result = [];
240+
241+
for ($i = 0; $i < $deviations; $i++) {
242+
$insideResult = [];
243+
244+
for ($j = 0; $j < $iterations; $j++) {
245+
$insideResult[] = /* perform some code */;
246+
}
247+
248+
$result[] = $this->performResult($insideResult);
249+
}
250+
251+
return $result;
252+
```
253+
163254
### Callbacks
164255

165256
#### Before
@@ -401,6 +492,35 @@ new Benchmark()
401492
+-------+----------------------+----------------------+
402493
```
403494

495+
##### Option 5: With Deviation Values
496+
497+
```php
498+
new Benchmark()
499+
->deviations(4)
500+
->round(2)
501+
->compare(
502+
foo: static fn () => /* some code */,
503+
bar: static fn () => /* some code */,
504+
)
505+
->toConsole();
506+
```
507+
508+
```bash
509+
+------------------+-----------------------+---------------------+
510+
| # | 0 | 1 |
511+
+------------------+-----------------------+---------------------+
512+
| min | 15.68 ms - 202 bytes | 2.35 ms - 102 bytes |
513+
| max | 112.79 ms - 209 bytes | 9.76 ms - 109 bytes |
514+
| avg | 53.03 ms - 205 bytes | 5.94 ms - 105 bytes |
515+
| total | 1696.81 ms - 6.42 KB | 190.17 ms - 3.30 KB |
516+
+------------------+-----------------------+---------------------+
517+
| order | 2 | 1 |
518+
+------------------+-----------------------+---------------------+
519+
| deviation time | +0.100715 | +0.114023 |
520+
| deviation memory | 0 | 0 |
521+
+------------------+-----------------------+---------------------+
522+
```
523+
404524
#### toData
405525

406526
This method returns benchmark results as an array of `DragonCode\Benchmark\Data\ResultData` DTO objects.
@@ -457,6 +577,73 @@ array:2 [
457577
]
458578
```
459579

580+
##### With Deviation Values
581+
582+
When calling the benchmark with deviation calculation, the DTO will contain the `deviations` property:
583+
584+
```php
585+
return new Benchmark()
586+
->deviations()
587+
->compare(
588+
foo: fn () => /* some code */,
589+
bar: fn () => /* some code */,
590+
)
591+
->toData();
592+
```
593+
594+
```bash
595+
array:2 [
596+
"foo" => DragonCode\Benchmark\Data\ResultData {#23
597+
+min: DragonCode\Benchmark\Data\MetricData {#64
598+
+time: 0.001
599+
+memory: 0.0
600+
}
601+
+max: DragonCode\Benchmark\Data\MetricData {#65
602+
+time: 0.0036
603+
+memory: 0.0
604+
}
605+
+avg: DragonCode\Benchmark\Data\MetricData {#66
606+
+time: 0.0024209375
607+
+memory: 0.0
608+
}
609+
+total: DragonCode\Benchmark\Data\MetricData {#67
610+
+time: 0.7747
611+
+memory: 0.0
612+
}
613+
+deviation: DragonCode\Benchmark\Data\DeviationData {#68
614+
+percent: DragonCode\Benchmark\Data\MetricData {#69
615+
+time: 0.0007048383984778
616+
+memory: 0.0
617+
}
618+
}
619+
}
620+
"bar" => DragonCode\Benchmark\Data\ResultData {#70
621+
+min: DragonCode\Benchmark\Data\MetricData {#71
622+
+time: 0.001
623+
+memory: 0.0
624+
}
625+
+max: DragonCode\Benchmark\Data\MetricData {#72
626+
+time: 0.0032
627+
+memory: 0.0
628+
}
629+
+avg: DragonCode\Benchmark\Data\MetricData {#73
630+
+time: 0.00242875
631+
+memory: 0.0
632+
}
633+
+total: DragonCode\Benchmark\Data\MetricData {#74
634+
+time: 0.7772
635+
+memory: 0.0
636+
}
637+
+deviation: DragonCode\Benchmark\Data\DeviationData {#75
638+
+percent: DragonCode\Benchmark\Data\MetricData {#76
639+
+time: 0.00061642429076895
640+
+memory: 0.0
641+
}
642+
}
643+
}
644+
]
645+
```
646+
460647
#### toAssert
461648

462649
This method allows you to validate benchmark results against expected values.

src/Benchmark.php

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use DragonCode\Benchmark\Services\AssertService;
99
use DragonCode\Benchmark\Services\CallbacksService;
1010
use DragonCode\Benchmark\Services\CollectorService;
11+
use DragonCode\Benchmark\Services\DeviationService;
1112
use DragonCode\Benchmark\Services\ResultService;
1213
use DragonCode\Benchmark\Services\RunnerService;
1314
use DragonCode\Benchmark\Services\ViewService;
@@ -22,13 +23,16 @@ class Benchmark
2223
{
2324
protected int $iterations = 100;
2425

26+
protected int $deviations = 1;
27+
2528
public function __construct(
2629
protected RunnerService $runner = new RunnerService,
2730
protected ViewService $view = new ViewService,
2831
protected CallbacksService $callbacks = new CallbacksService,
2932
protected CollectorService $collector = new CollectorService,
3033
protected ResultService $result = new ResultService,
31-
protected ResultTransformer $transformer = new ResultTransformer
34+
protected ResultTransformer $transformer = new ResultTransformer,
35+
protected DeviationService $deviation = new DeviationService,
3236
) {}
3337

3438
public static function make(): static
@@ -86,6 +90,18 @@ public function iterations(int $count): static
8690
return $this;
8791
}
8892

93+
/**
94+
* @param int<2, max> $count
95+
*/
96+
public function deviations(int $count = 2): static
97+
{
98+
$this->clear();
99+
100+
$this->deviations = max(2, abs($count));
101+
102+
return $this;
103+
}
104+
89105
/**
90106
* @param int<0, max>|null $precision
91107
*/
@@ -98,6 +114,8 @@ public function round(?int $precision): static
98114

99115
public function compare(array|Closure ...$callbacks): static
100116
{
117+
$this->clear();
118+
101119
$this->callbacks->compare(...$callbacks);
102120

103121
return $this;
@@ -108,11 +126,11 @@ public function compare(array|Closure ...$callbacks): static
108126
*/
109127
public function toData(): array
110128
{
111-
$this->performCallbacks();
129+
if (! $this->result->has()) {
130+
$this->perform();
131+
}
112132

113-
return $this->result->get(
114-
$this->collector->all()
115-
);
133+
return $this->mapResult();
116134
}
117135

118136
public function toConsole(): static
@@ -133,10 +151,22 @@ public function toAssert(): AssertService
133151
);
134152
}
135153

136-
protected function performCallbacks(): void
154+
protected function perform(): void
137155
{
138-
$this->clear();
156+
$this->deviations === 1
157+
? $this->performCompare()
158+
: $this->performDeviation();
159+
}
139160

161+
protected function mapResult(): array
162+
{
163+
return $this->result->get(
164+
$this->collector->all()
165+
);
166+
}
167+
168+
protected function performCompare(): void
169+
{
140170
$callbacks = $this->callbacks->compare;
141171

142172
$this->withProgress(
@@ -145,6 +175,29 @@ protected function performCallbacks(): void
145175
);
146176
}
147177

178+
protected function performDeviation(): void
179+
{
180+
$results = [];
181+
182+
$callbacks = $this->callbacks->compare;
183+
184+
$this->withProgress(function (ProgressBarView $bar) use (&$results, $callbacks) {
185+
for ($i = 1; $i <= $this->deviations; $i++) {
186+
$this->clear();
187+
188+
$this->chunks($callbacks, $bar);
189+
190+
$results[] = $this->mapResult();
191+
}
192+
}, $this->steps($callbacks, $this->deviations));
193+
194+
$this->clear();
195+
196+
$this->result->force(
197+
$this->deviation->calculate($results)
198+
);
199+
}
200+
148201
protected function withProgress(Closure $callback, int $total): void
149202
{
150203
$this->view->emptyLine();
@@ -157,9 +210,9 @@ protected function withProgress(Closure $callback, int $total): void
157210
$this->view->emptyLine(2);
158211
}
159212

160-
protected function steps(array $callbacks): int
213+
protected function steps(array $callbacks, int $multiplier = 1): int
161214
{
162-
return count($callbacks) * $this->iterations;
215+
return count($callbacks) * $this->iterations * $multiplier;
163216
}
164217

165218
protected function chunks(array $callbacks, ProgressBarView $progressBar): void

src/Data/DeviationData.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DragonCode\Benchmark\Data;
6+
7+
readonly class DeviationData
8+
{
9+
public function __construct(
10+
public MetricData $percent,
11+
) {}
12+
}

src/Data/ResultData.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ public function __construct(
1111
public MetricData $max,
1212
public MetricData $avg,
1313
public MetricData $total,
14+
public ?DeviationData $deviation = null,
1415
) {}
1516
}

0 commit comments

Comments
 (0)