packages/deriver/bench/CliBench.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 CliBench
21{
22    private const QUERIES = [
23        'HarborOps\Queue\RetryPolicy::delay#return',
24        'HarborOps\Moderation\ReviewPolicy::initialState#return',
25        'HarborOps\Moderation\ReviewPolicy::resolutionState#return',
26        'HarborOps\Import\Importer::import#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/cli';
50        $this->files = (new Finder())->in($root)
51            ->include('**/*.php', 'bin/harbor')
52            ->exclude('vendor', 'tests', 'var')
53            ->files();
54        $this->configuration = new DeriverConfig(phpVersion: '8.4', evaluators: $evaluators);
55    }
56
57    public function prepare(): void
58    {
59        $this->locate();
60        $this->prepared = Deriver::prepare($this->files, $this->configuration);
61    }
62
63    public function prepareWithBranchPruning(): void
64    {
65        $this->locateWithBranchPruning();
66        $this->prepared = Deriver::prepare($this->files, $this->configuration);
67    }
68
69    #[Bench\BeforeMethods('locate')]
70    #[Bench\Groups(['preparation'])]
71    public function benchPrepare(): void
72    {
73        $this->prepared = Deriver::prepare($this->files, $this->configuration);
74    }
75
76    #[Bench\BeforeMethods('prepare')]
77    #[Bench\Groups(['first-query'])]
78    #[Bench\AfterMethods('verifyResults')]
79    public function benchFirstQuery(): void
80    {
81        $this->results = [$this->prepared->derive(self::QUERIES[0])];
82    }
83
84    #[Bench\BeforeMethods('prepare')]
85    #[Bench\Groups(['query-batch'])]
86    #[Bench\AfterMethods('verifyResults')]
87    public function benchQueryBatch(): void
88    {
89        $this->results = [];
90        foreach (self::QUERIES as $query) {
91            $this->results[] = $this->prepared->derive($query);
92        }
93    }
94
95    #[Bench\BeforeMethods('locateWithBranchPruning')]
96    #[Bench\Groups(['preparation', 'branch-pruning'])]
97    public function benchPrepareWithBranchPruning(): void
98    {
99        $this->benchPrepare();
100    }
101
102    #[Bench\BeforeMethods('prepareWithBranchPruning')]
103    #[Bench\Groups(['first-query', 'branch-pruning'])]
104    #[Bench\AfterMethods('verifyResults')]
105    public function benchFirstQueryWithBranchPruning(): void
106    {
107        $this->benchFirstQuery();
108    }
109
110    #[Bench\BeforeMethods('prepareWithBranchPruning')]
111    #[Bench\Groups(['query-batch', 'branch-pruning'])]
112    #[Bench\AfterMethods('verifyResults')]
113    public function benchQueryBatchWithBranchPruning(): void
114    {
115        $this->benchQueryBatch();
116    }
117
118    public function verifyResults(): void
119    {
120        foreach ($this->results as $collection) {
121            if (count($collection) === 0) {
122                throw new RuntimeException('A benchmark query returned no candidates.');
123            }
124        }
125    }
126}
127