Completed
Push — master ( 995492...78ac67 )
by Maarten
01:02
created

Benchmark::history()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.6333
c 0
b 0
f 0
cc 3
nc 2
nop 1
1
<?php
2
3
namespace Mtolhuys\LaravelRequestBenchmark;
4
5
class Benchmark
6
{
7
    /**
8
     * Informative label containing request method and url
9
     *
10
     * @var string $request
11
     */
12
    private static $request;
13
14
    /**
15
     * Float containing amount of time as microtime
16
     *
17
     * @var float $runtime
18
     */
19
    private static $runtime;
20
21
    /**
22
     * Array containing measured memory data
23
     *
24
     * @var array $memory
25
     */
26
    private static $memory = [
27
        'unit' => 'Kb',
28
        'pre' => null,
29
        'post' => null,
30
    ];
31
32
    /**
33
     * Start measuring, called before request handling
34
     *
35
     * @param string $request
36
     */
37
    public static function start(string $request)
38
    {
39
        self::$request = $request;
40
        self::$runtime = microtime(true);
41
        self::$memory['pre'] = self::getCurrentMemoryUsage();
42
    }
43
44
45
    /**
46
     * Stop measuring, called after request handling
47
     *
48
     * @throws \Exception
49
     */
50
    public static function stop()
51
    {
52
        self::$memory['post'] = self::getCurrentMemoryUsage();
53
54
        self::log();
55
    }
56
57
    /**
58
     * Log and/or store measured data
59
     *
60
     * @throws \Exception
61
     */
62
    private static function log()
63
    {
64
        $result = self::getResult();
65
66
        if (config('request-benchmark.log')) {
67
            \Log::debug(
68
                'request-benchmark: ' . self::$request . PHP_EOL
69
                . "Time: {$result->time}ms" . PHP_EOL
70
                . "Pre memory usage {$result->pre_memory_usage}" . PHP_EOL
71
                . "Post memory usage {$result->post_memory_usage} ({$result->actual_memory_usage})"
72
            );
73
        }
74
75
        if (config('request-benchmark.storage_path')) {
76
            self::storeJson($result);
77
        }
78
    }
79
80
81
    private static function getResult()
82
    {
83
        $time = self::getTime();
84
        $memory = self::getTotalMemoryUsage();
85
86
        return (object)[
87
            'time' => "{$time}ms",
88
            'pre_memory_usage' => $memory->pre,
89
            'post_memory_usage' => $memory->post,
90
            'actual_memory_usage' => $memory->difference,
91
        ];
92
    }
93
94
    /**
95
     * Get current memory usage for measuring
96
     *
97
     * @return float
98
     */
99
    private static function getCurrentMemoryUsage(): float
100
    {
101
        $usage = self::increaseMagnitude(memory_get_usage());
102
103
        if ($usage >= (10 * 1000)) {
104
            self::$memory['unit'] = 'Mb';
105
        }
106
107
        return $usage;
108
    }
109
110
    /**
111
     * Get total measured memory usage
112
     *
113
     * @return object
114
     */
115
    private static function getTotalMemoryUsage()
116
    {
117
        $unit = self::$memory['unit'];
118
        $pre = self::$memory['pre'];
119
        $post = self::$memory['post'];
120
121
        if (self::$memory['unit'] === 'Mb') {
122
            $pre = self::increaseMagnitude($pre);
123
            $post = self::increaseMagnitude($post);
124
        }
125
126
        return (object) [
127
            'pre' => "{$pre}{$unit}",
128
            'post' => "{$post}{$unit}",
129
            'difference' => ($post - $pre) . $unit,
130
        ];
131
    }
132
133
    /**
134
     * Get time between now and start() invocation
135
     *
136
     * @return float
137
     */
138
    private static function getTime(): float
139
    {
140
        $diff = microtime(true) - self::$runtime;
141
142
        return round(($diff - (int)$diff) * 1000, 2);
143
    }
144
145
    /**
146
     * Increasing measured byte $amount in magnitude Kb -> Mb etc.
147
     *
148
     * @param int $amount
149
     * @return float
150
     */
151
    private static function increaseMagnitude(int $amount): float
152
    {
153
        return round($amount / 1024, 2);
154
    }
155
156
    /**
157
     * @param $result
158
     *
159
     * @throws \Exception
160
     */
161
    private static function storeJson($result)
162
    {
163
        $file = config('request-benchmark.storage_path').'/request-benchmark.json';
164
        $requests = file_exists($file) ? json_decode(file_get_contents($file), true) : [];
165
166
        if (isset($requests[self::$request])) {
167
            $requests['history'] = self::history($requests);
168
        }
169
170
        $requests[self::$request] = $result;
171
172
        file_put_contents($file, json_encode($requests, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT));
173
    }
174
175
    /**
176
     * @param array $requests
177
     * @return mixed
178
     * @throws \Exception
179
     */
180
    private static function history(array $requests)
181
    {
182
        $timestamp = (new \DateTime('now'))->format('Y-m-d H:i:s');
183
        $history = $requests['history'] ?? [];
184
185
        if (!isset($history[self::$request]) || !self::maxHistoryReached($history)) {
186
            $history[self::$request][$timestamp] = $requests[self::$request];
187
        }
188
189
        else {
190
            unset($history[self::$request][array_key_last($history[self::$request])]);
191
192
            $history[self::$request] = [
193
                $timestamp => $requests[self::$request]
194
            ] + $history[self::$request];
195
        }
196
197
        return $history;
198
    }
199
200
    /**
201
     * @param array $history
202
     * @return bool
203
     */
204
    private static function maxHistoryReached(array $history): bool
205
    {
206
        return config('request-benchmark.max_history') <= count($history[self::$request]);
207
    }
208
}
209
210