Bench   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 175
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

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

10 Methods

Rating   Name   Duplication   Size   Complexity  
A start() 0 3 1
A run() 0 8 1
A hasEnded() 0 3 1
A end() 0 10 2
A getMemoryPeak() 0 9 2
A readableSize() 0 26 3
A hasStarted() 0 3 1
A getMemoryUsage() 0 15 4
A readableElapsedTime() 0 11 2
A getTime() 0 18 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
    public function end(): self
58
    {
59 6
        if (!$this->hasStarted()) {
60 1
            throw new LogicException('Bench has not been started. Call start() first.');
61
        }
62
63 5
        $this->endTime     = hrtime(true);
64 5
        $this->memoryUsage = memory_get_usage(true);
65
66 5
        return $this;
67
    }
68
69
    /**
70
     * @inheritDoc
71
     */
72 1
    public function getMemoryPeak(bool $readable = false, null|string $format = null): int|string
73
    {
74 1
        $memory = memory_get_peak_usage(true);
75
76 1
        if ($readable) {
77 1
            return $memory;
78
        }
79
80 1
        return self::readableSize($memory, $format);
81
    }
82
83
    /**
84
     * @inheritDoc
85
     */
86 3
    public function getMemoryUsage(bool $readable = false, null|string $format = null): int|string
87
    {
88 3
        if (!$this->hasStarted()) {
89 1
            throw new LogicException('Bench has not been started. Call start() first.');
90
        }
91
92 2
        if (!$this->hasEnded()) {
93 1
            throw new LogicException('Bench has not been ended. Call end() first.');
94
        }
95
96 1
        if ($readable) {
97 1
            return $this->memoryUsage;
98
        }
99
100 1
        return self::readableSize($this->memoryUsage, $format);
101
    }
102
103
    /**
104
     * @inheritDoc
105
     */
106 3
    public function getTime(bool $readable = false, null|string $format = null): float|string
107
    {
108 3
        if (!$this->hasStarted()) {
109 1
            throw new LogicException('Bench has not been started. Call start() first.');
110
        }
111
112 2
        if (!$this->hasEnded()) {
113 1
            throw new LogicException('Bench has not been ended. Call end() first.');
114
        }
115
116
        // Convert to seconds
117 1
        $elapsed = ($this->endTime - $this->startTime) / 1e9;
118
119 1
        if ($readable) {
120 1
            return $elapsed;
121
        }
122
123 1
        return self::readableElapsedTime($elapsed, $format);
124
    }
125
126
    /**
127
     * @inheritDoc
128
     */
129 5
    public function hasEnded(): bool
130
    {
131 5
        return $this->endTime !== 0.0;
132
    }
133
134
    /**
135
     * @inheritDoc
136
     */
137 11
    public function hasStarted(): bool
138
    {
139 11
        return $this->startTime !== 0.0;
140
    }
141
142
    /**
143
     * @inheritDoc
144
     *
145
     * @psalm-template T
146
     *
147
     * @param T $arguments
148
     */
149 2
    public function run(callable $callable, mixed ...$arguments): mixed
150
    {
151 2
        $this->start();
152
        /** @psalm-var T $result */
153 2
        $result = $callable(...$arguments);
154 2
        $this->end();
155
156 2
        return $result;
157
    }
158
159
    /**
160
     * @inheritDoc
161
     */
162 8
    public function start(): void
163
    {
164 8
        $this->startTime = hrtime(true);
165
    }
166
167
    /**
168
     * @inheritDoc
169
     */
170 3
    public static function readableElapsedTime(float $seconds, null|string $format = null, int $round = 3): string
171
    {
172 3
        $format ??= '%.3f%s';
173
174 3
        if ($seconds >= 1) {
175 2
            return \sprintf($format, round($seconds, $round), 's');
176
        }
177
178 2
        $format = (string) preg_replace('/(%.\d+f)/', '%d', $format);
179
180 2
        return \sprintf($format, round($seconds * 1000, $round), 'ms');
181
    }
182
183
    /**
184
     * @inheritDoc
185
     */
186 14
    public static function readableSize(int $size, null|string $format = null, int $round = 3): string
187
    {
188
        /**
189
         * @psalm-var array<array-key, string> $units
190
         */
191 14
        static $units = ['B', 'KB', 'MB', 'GB', 'TB'];
192
193
        /**
194
         * @psalm-var int $mod
195
         */
196 14
        static $mod = 1024;
197
198 14
        $format ??= '%.2f%s';
199
200 14
        if ($size <= $mod) {
201 4
            return \sprintf('%dB', round($size, $round));
202
        }
203
204 10
        $unit = 0;
205
206
        do {
207 10
            ++$unit;
208 10
            $size /= $mod;
209 10
        } while ($size > $mod);
210
211 10
        return \sprintf($format, round($size, $round), $units[$unit]);
212
    }
213
}
214