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