Passed
Push — master ( 8b49d6...8ffc72 )
by Alec
16:03
created

BenchmarkReport::computeRelatives()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
nc 2
nop 1
dl 0
loc 12
ccs 0
cts 8
cp 0
crap 12
rs 10
c 2
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace AlecRabbit\Tools\Reports;
4
5
use AlecRabbit\Accessories\MemoryUsage;
6
use AlecRabbit\Accessories\Pretty;
7
use AlecRabbit\Tools\Internal\BenchmarkFunction;
8
use AlecRabbit\Tools\Internal\BenchmarkRelative;
9
use AlecRabbit\Tools\Internal\BenchmarkResult;
10
11
class BenchmarkReport
12
{
13
    /** @var bool */
14
    protected $showReturns = false;
15
    /** @var BenchmarkFunction[] */
16
    protected $functions = [];
17
18
    public function withReturns(): self
19
    {
20
        $this->showReturns = true;
21
        return $this;
22
    }
23
24
    public function __toString(): string
25
    {
26
        $functions = $this->updateFunctions($this->functions);
27
28
        $str = '';
29
        /**
30
         * @var BenchmarkFunction $f
31
         */
32
        foreach ($functions as $name => $f) {
33
            $benchmarkRelative = $f->getRelative();
34
            if ($benchmarkRelative instanceof BenchmarkRelative) {
35
                $str .=
36
                    sprintf(
37
                        '%s. %s %s %s %s',
38
                        $benchmarkRelative->getRank(),
39
                        mb_str_pad($f->getAssignedName(), 30),
40
                        mb_str_pad('+' . Pretty::percent($benchmarkRelative->getRelative()), 8, ' ', STR_PAD_LEFT),
41
                        mb_str_pad(
42
                            (string)$benchmarkRelative->getBenchmarkResult(),
43
                            18,
44
                            ' ',
45
                            STR_PAD_LEFT
46
                        ),
47
                        (string)$f->getComment()
48
                    ) . PHP_EOL;
49
            }
50
        }
51
        $str .= PHP_EOL . MemoryUsage::getReport();
52
        return $str;
53
    }
54
55
    /**
56
     * @param BenchmarkFunction[] $functions
57
     * @return array
58
     */
59
    private function updateFunctions(array $functions): array
60
    {
61
        $averages = $this->computeAverages();
62
        $relatives = $this->computeRelatives($averages);
63
        $updatedFunctions = [];
64
        if (!empty($relatives)) {
65
            $rank = 0;
66
            foreach ($relatives as $name => $relative) {
67
                /** @var null|BenchmarkFunction $function */
68
                $function = $functions[$name] ?? null;
69
                $average = $averages[$name] ?? null;
70
                if (null !== $function && null !== $average) {
71
                    $function->setBenchmarkRelative(
72
                        new BenchmarkRelative(++$rank, (float)$relative - 1, $function->getResult())
73
                    );
74
                }
75
                unset($functions[$name]);
76
                $updatedFunctions[$name] = $function;
77
            }
78
        }
79
        foreach ($functions as $name => $function) {
80
            $updatedFunctions[$name] = $function;
81
        }
82
        return $updatedFunctions;
83
    }
84
85
    /**
86
     * @return array
87
     */
88
    protected function computeAverages(): array
89
    {
90
        $averages = [];
91
        /** @var BenchmarkFunction $f */
92
        foreach ($this->functions as $f) {
93
            $benchmarkResult = $f->getResult();
94
            if ($benchmarkResult instanceof BenchmarkResult) {
95
                $averages[$f->getIndexedName()] = $benchmarkResult->getMean();
96
            }
97
        }
98
        return $averages;
99
    }
100
101
    private function computeRelatives(array $averages): array
102
    {
103
        $rel = [];
104
        if (!empty($averages)) {
105
            $min = min($averages);
106
107
            foreach ($averages as $name => $average) {
108
                $rel[$name] = $average / $min;
109
            }
110
            asort($rel);
111
        }
112
        return $rel;
113
    }
114
115
    public function setFunctions(array $functions): self
116
    {
117
        $this->functions = [];
118
        /** @var BenchmarkFunction $f */
119
        foreach ($functions as $f) {
120
            $this->functions[$f->getIndexedName()] = $f;
121
        }
122
123
        return $this;
124
    }
125
}
126