-
-
Notifications
You must be signed in to change notification settings - Fork 117
/
timer.php
136 lines (119 loc) · 3.2 KB
/
timer.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?php
/**
* Class to stop the script time.
*
* @author gharlan
*
* @package redaxo\core
*/
class rex_timer
{
public const SEC = 1;
public const MILLISEC = 1_000;
public const MICROSEC = 1_000_000;
/**
* @internal
*
* @var array<string, array{sum: mixed, timings: list<array{start: float, end: float}>}>
*/
public static $serverTimings = [];
/** @var float */
private $start;
/** @var null|float */
private $duration;
/**
* @param float $start Start time
*/
public function __construct($start = null)
{
if ($start) {
$this->start = $start;
} else {
$this->reset();
}
}
/**
* Measures the runtime of the given callable.
*
* On sufficient user permissions - or in debug mode - this timings will be sent over the wire to the browser via server timing api http headers.
*
* @template T
*
* @param string $label
* @param callable():T $callable
*
* @return T result of callable
*/
public static function measure($label, callable $callable)
{
if (!rex::isDebugMode()) {
return $callable();
}
$timer = new self();
try {
return $callable();
} finally {
$timer->stop();
self::measured($label, $timer);
}
}
/**
* Saves the measurement of the given timer.
*
* This method should be used only if the measured code can not be wrapped inside a callable, otherwise use `measure()`.
*/
public static function measured(string $label, self $timer): void
{
$duration = self::$serverTimings[$label]['sum'] ?? 0;
$duration += $timer->getDelta(self::MILLISEC);
self::$serverTimings[$label]['sum'] = $duration;
self::$serverTimings[$label]['timings'][] = [
'start' => $timer->start,
'end' => self::now(),
];
}
/**
* Resets the timer.
* @return void
*/
public function reset()
{
$this->start = self::now();
}
/**
* Stops the timer.
* @return void
*/
public function stop()
{
$this->duration = self::now() - $this->start;
}
/**
* Returns the time difference.
*
* @param int $precision Factor which will be multiplied, for convertion into different units (e.g. 1000 for milli,...)
*
* @return float Time difference
*/
public function getDelta($precision = self::MILLISEC)
{
$duration = $this->duration ?? self::now() - $this->start;
return $duration * $precision;
}
/**
* Returns the formatted time difference.
*
* @param int $precision Factor which will be multiplied, for convertion into different units (e.g. 1000 for milli,...)
* @param int $decimals Number of decimals points
*
* @return string Formatted time difference
*/
public function getFormattedDelta($precision = self::MILLISEC, $decimals = 3)
{
$time = $this->getDelta($precision);
return rex_formatter::number($time, [$decimals]);
}
static private function now() {
return hrtime(true) / 1e9;
}
}