packages/deriver/bench/SymfonyBench.php
1<?php
2
3declare(strict_types=1);
4
5namespace Bench;
6
7use Deriver\Deriver;
8use Deriver\Deriver\BranchEvaluators;
9use Deriver\Deriver\Candidate\CandidateCollection;
10use Deriver\Deriver\DeriverConfig;
11use Deriver\Deriver\MicroEvaluator;
12use Deriver\Finder;
13use PhpBench\Attributes as Bench;
14use RuntimeException;
15
16#[Bench\Iterations(5)]
17#[Bench\Revs(1)]
18#[Bench\Warmup(0)]
19#[Bench\OutputTimeUnit('milliseconds')]
20final class SymfonyBench
21{
22 private const QUERIES = [
23 'App\Service\PublishingRules::initialState#return',
24 'App\Service\PublishingRules::notificationMessage#return',
25 'App\Service\PublishingRules::reportDeadlineHours#return',
26 'App\Service\Publishing::create#return',
27 ];
28
29 /** @var list<string> */
30 private array $files;
31 private DeriverConfig $configuration;
32 private Deriver $prepared;
33 /** @var list<CandidateCollection> */
34 private array $results = [];
35
36 public function locate(): void
37 {
38 $this->locateWithEvaluators([]);
39 }
40
41 public function locateWithBranchPruning(): void
42 {
43 $this->locateWithEvaluators(BranchEvaluators::truth());
44 }
45
46 /** @param list<MicroEvaluator> $evaluators */
47 public function locateWithEvaluators(array $evaluators): void
48 {
49 $root = __DIR__ . '/target/symfony';
50 $this->files = (new Finder())->in($root)
51 ->include('**/*.php', 'bin/console')
52 ->exclude('vendor', 'tests', 'var', 'templates', 'config/reference.php')
53 ->files();
54 // Include the framework traits used by these application sources.
55 $this->files = [
56 ...$this->files,
57 $root . '/vendor/symfony/dependency-injection/Kernel/KernelTrait.php',
58 $root . '/vendor/symfony/framework-bundle/Kernel/MicroKernelTrait.php',
59 ];
60 sort($this->files, SORT_STRING);
61 $this->configuration = new DeriverConfig(phpVersion: '8.4', evaluators: $evaluators);
62 }
63
64 public function prepare(): void
65 {
66 $this->locate();
67 $this->prepared = Deriver::prepare($this->files, $this->configuration);
68 }
69
70 public function prepareWithBranchPruning(): void
71 {
72 $this->locateWithBranchPruning();
73 $this->prepared = Deriver::prepare($this->files, $this->configuration);
74 }
75
76 #[Bench\BeforeMethods('locate')]
77 #[Bench\Groups(['preparation'])]
78 public function benchPrepare(): void
79 {
80 $this->prepared = Deriver::prepare($this->files, $this->configuration);
81 }
82
83 #[Bench\BeforeMethods('prepare')]
84 #[Bench\Groups(['first-query'])]
85 #[Bench\AfterMethods('verifyResults')]
86 public function benchFirstQuery(): void
87 {
88 $this->results = [$this->prepared->derive(self::QUERIES[0])];
89 }
90
91 #[Bench\BeforeMethods('prepare')]
92 #[Bench\Groups(['query-batch'])]
93 #[Bench\AfterMethods('verifyResults')]
94 public function benchQueryBatch(): void
95 {
96 $this->results = [];
97 foreach (self::QUERIES as $query) {
98 $this->results[] = $this->prepared->derive($query);
99 }
100 }
101
102 #[Bench\BeforeMethods('locateWithBranchPruning')]
103 #[Bench\Groups(['preparation', 'branch-pruning'])]
104 public function benchPrepareWithBranchPruning(): void
105 {
106 $this->benchPrepare();
107 }
108
109 #[Bench\BeforeMethods('prepareWithBranchPruning')]
110 #[Bench\Groups(['first-query', 'branch-pruning'])]
111 #[Bench\AfterMethods('verifyResults')]
112 public function benchFirstQueryWithBranchPruning(): void
113 {
114 $this->benchFirstQuery();
115 }
116
117 #[Bench\BeforeMethods('prepareWithBranchPruning')]
118 #[Bench\Groups(['query-batch', 'branch-pruning'])]
119 #[Bench\AfterMethods('verifyResults')]
120 public function benchQueryBatchWithBranchPruning(): void
121 {
122 $this->benchQueryBatch();
123 }
124
125 public function verifyResults(): void
126 {
127 foreach ($this->results as $collection) {
128 if (count($collection) === 0) {
129 throw new RuntimeException('A benchmark query returned no candidates.');
130 }
131 }
132 }
133}
134