Passed
Push — develop ( aa265d...8b49d6 )
by Alec
14:04
created

BenchmarkReport::__toString()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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