Bench   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 185
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 60
c 4
b 0
f 0
dl 0
loc 185
ccs 56
cts 56
cp 1
rs 10
wmc 21

10 Methods

Rating   Name   Duplication   Size   Complexity  
A hasEnded() 0 4 1
A end() 0 11 2
A getMemoryPeak() 0 10 2
A readableSize() 0 27 3
A start() 0 4 1
A run() 0 9 1
A hasStarted() 0 4 1
A getMemoryUsage() 0 16 4
A readableElapsedTime() 0 12 2
A getTime() 0 19 4
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of Esi\Bench.
7
 *
8
 * (c) Eric Sizemore <[email protected]>
9
 * (c) Jeremy Perret <[email protected]>
10
 *
11
 * This source file is subject to the MIT license. For the full copyright,
12
 * license information, and credits/acknowledgements, please view the LICENSE
13
 * and README files that were distributed with this source code.
14
 */
15
/**
16
 * Esi\Bench is a fork of Ubench (https://github.com/devster/ubench) which is:
17
 *     Copyright (c) 2012-2020 Jeremy Perret<[email protected]>
18
 *
19
 * For a list of changes in this library, in comparison to the original library, please {@see CHANGELOG.md}.
20
 */
21
22
namespace Esi\Bench;
23
24
use LogicException;
25
26
use function hrtime;
27
use function memory_get_peak_usage;
28
use function memory_get_usage;
29
use function preg_replace;
30
use function round;
31
32
/**
33
 * Micro PHP library for benchmarking.
34
 *
35
 * @see Tests\BenchTest
36
 */
37
class Bench implements BenchInterface
38
{
39
    /**
40
     * End time in nanoseconds.
41
     */
42
    protected float $endTime = 0.0;
43
44
    /**
45
     * Memory usage.
46
     */
47
    protected int $memoryUsage = 0;
48
49
    /**
50
     * Start time in nanoseconds.
51
     */
52
    protected float $startTime = 0.0;
53
54
    /**
55
     * @inheritDoc
56
     */
57 6
    #[\Override]
58
    public function end(): self
59
    {
60 6
        if (!$this->hasStarted()) {
61 1
            throw new LogicException('Bench has not been started. Call start() first.');
62
        }
63
64 5
        $this->endTime     = hrtime(true);
65 5
        $this->memoryUsage = memory_get_usage(true);
66
67 5
        return $this;
68
    }
69
70
    /**
71
     * @inheritDoc
72
     */
73 1
    #[\Override]
74
    public function getMemoryPeak(bool $readable = false, ?string $format = null): int|string
75
    {
76 1
        $memory = memory_get_peak_usage(true);
77
78 1
        if ($readable) {
79 1
            return $memory;
80
        }
81
82 1
        return self::readableSize($memory, $format);
83
    }
84
85
    /**
86
     * @inheritDoc
87
     */
88 3
    #[\Override]
89
    public function getMemoryUsage(bool $readable = false, ?string $format = null): int|string
90
    {
91 3
        if (!$this->hasStarted()) {
92 1
            throw new LogicException('Bench has not been started. Call start() first.');
93
        }
94
95 2
        if (!$this->hasEnded()) {
96 1
            throw new LogicException('Bench has not been ended. Call end() first.');
97
        }
98
99 1
        if ($readable) {
100 1
            return $this->memoryUsage;
101
        }
102
103 1
        return self::readableSize($this->memoryUsage, $format);
104
    }
105
106
    /**
107
     * @inheritDoc
108
     */
109 3
    #[\Override]
110
    public function getTime(bool $readable = false, ?string $format = null): float|string
111
    {
112 3
        if (!$this->hasStarted()) {
113 1
            throw new LogicException('Bench has not been started. Call start() first.');
114
        }
115
116 2
        if (!$this->hasEnded()) {
117 1
            throw new LogicException('Bench has not been ended. Call end() first.');
118
        }
119
120
        // Convert to seconds
121 1
        $elapsed = ($this->endTime - $this->startTime) / 1e9;
122
123 1
        if ($readable) {
124 1
            return $elapsed;
125
        }
126
127 1
        return self::readableElapsedTime($elapsed, $format);
128
    }
129
130
    /**
131
     * @inheritDoc
132
     */
133 5
    #[\Override]
134
    public function hasEnded(): bool
135
    {
136 5
        return $this->endTime !== 0.0;
137
    }
138
139
    /**
140
     * @inheritDoc
141
     */
142 11
    #[\Override]
143
    public function hasStarted(): bool
144
    {
145 11
        return $this->startTime !== 0.0;
146
    }
147
148
    /**
149
     * @inheritDoc
150
     *
151
     * @psalm-template T
152
     *
153
     * @param T $arguments
154
     */
155 2
    #[\Override]
156
    public function run(callable $callable, mixed ...$arguments): mixed
157
    {
158 2
        $this->start();
159
        /** @psalm-var T $result */
160 2
        $result = $callable(...$arguments);
161 2
        $this->end();
162
163 2
        return $result;
164
    }
165
166
    /**
167
     * @inheritDoc
168
     */
169 8
    #[\Override]
170
    public function start(): void
171
    {
172 8
        $this->startTime = hrtime(true);
173
    }
174
175
    /**
176
     * @inheritDoc
177
     */
178 3
    #[\Override]
179
    public static function readableElapsedTime(float $seconds, ?string $format = null, int $round = 3): string
180
    {
181 3
        $format ??= '%.3f%s';
182
183 3
        if ($seconds >= 1) {
184 2
            return \sprintf($format, round($seconds, $round), 's');
185
        }
186
187 2
        $format = (string) preg_replace('/(%.\d+f)/', '%d', $format);
188
189 2
        return \sprintf($format, round($seconds * 1000.0, $round), 'ms');
190
    }
191
192
    /**
193
     * @inheritDoc
194
     */
195 14
    #[\Override]
196
    public static function readableSize(int $size, ?string $format = null, int $round = 3): string
197
    {
198
        /**
199
         * @psalm-var array<array-key, string> $units
200
         */
201 14
        static $units = ['B', 'KB', 'MB', 'GB', 'TB'];
202
203
        /**
204
         * @psalm-var int $mod
205
         */
206 14
        static $mod = 1024;
207
208 14
        $format ??= '%.2f%s';
209
210 14
        if ($size <= $mod) {
211 4
            return \sprintf('%dB', (int) round($size, $round));
212
        }
213
214 10
        $unit = 0;
215
216
        do {
217 10
            ++$unit;
218 10
            $size /= $mod;
219 10
        } while ($size > $mod);
220
221 10
        return \sprintf($format, round($size, $round), $units[$unit]);
222
    }
223
}
224