PluginProbe
SQLite Object Cache / 1.1.0
SQLite Object Cache v1.1.0
1.6.5 trunk 0.1.7 1.0.0 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.4.0 1.4.1 1.5.1 1.5.4 1.5.5 1.5.6 1.5.7 All 30 releases
sqlite-object-cache / includes / lib / class-sqlite-object-cache-statistics.php

class-sqlite-object-cache-statistics.php in SQLite Object Cache 1.1.0, at includes/lib/class-sqlite-object-cache-statistics.php

364 lines 9.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Statistics class file.
4 *
5 * @package SQLite Object Cache
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * statistics class.
14 */
15 class SQLite_Object_Cache_Statistics {
16
17 /**
18 * Associative array with selected cache items names most frequent first.
19 *
20 * @var array
21 */
22 public $selected_names;
23
24 /**
25 * Associative array with descriptive statistics.
26 *
27 * @var array
28 */
29 public $descriptions;
30 /**
31 * @var string
32 */
33 private $start_time;
34 /**
35 * @var string
36 */
37 private $end_time;
38
39 /**
40 * Initialize and load data.
41 *
42 * @return void
43 * @throws Exception Announce database failure.
44 */
45 public function init() {
46 global $wp_object_cache;
47
48 $first = PHP_INT_MAX;
49 $last = PHP_INT_MIN;
50
51 $selected_names = [];
52 $opens = [];
53 $selects = [];
54 $inserts = [];
55 $deletes = [];
56 $RAMratios = [];
57 $RAMhits = 0;
58 $RAMmisses = 0;
59 $DISKratios = [];
60 $DISKLookupsPerRequest = [];
61 $SavesPerRequest = [];
62 $DBMSqueriesPerRequest = [];
63 $DISKhits = 0;
64 $DISKmisses = 0;
65
66 if ( ! method_exists( $wp_object_cache, 'sqlite_load_statistics' ) ) {
67 return;
68 }
69
70 foreach ( $wp_object_cache->sqlite_load_statistics() as $data ) {
71 $first = min( $data->time, $first );
72 $last = max( $data->time, $last );
73 $RAMhits += $data->RAMhits;
74 $RAMmisses += $data->RAMmisses;
75 $DISKhits += $data->DISKhits;
76 $DISKmisses += $data->DISKmisses;
77 $DISKLookupsPerRequest[] = $data->DISKhits + $data->DISKmisses;
78 $RAMratio = $data->RAMhits / ( $data->RAMhits + $data->RAMmisses );
79 $RAMratios[] = $RAMratio;
80 $DISKratio = $data->DISKhits / ( $data->DISKhits + $data->DISKmisses );
81 $DISKratios[] = $DISKratio;
82 $opens [] = $data->open;
83 $selects [] = $data->selects;
84 $inserts [] = $data->inserts;
85 $SavesPerRequest [] = count( $data->inserts );
86 if ( property_exists( $data, 'DBMSqueries' ) && is_numeric( $data->DBMSqueries ) ) {
87 $DBMSqueriesPerRequest [] = $data->DBMSqueries;
88 }
89 $deletes[] = $data->deletes;
90
91 if ( property_exists( $data, 'select_names' ) && is_array( $data->select_names ) ) {
92 foreach ( $data->select_names as $name ) {
93 if ( ! array_key_exists( $name, $selected_names ) ) {
94 $selected_names[ $name ] = 0;
95 }
96 $selected_names[ $name ] ++;
97 }
98 }
99 }
100 $duration = $last - $first;
101 if ( $duration > 0 ) {
102 arsort( $selected_names );
103 $descriptions = [
104 __( 'RAM hit ratio', 'sqlite-object-cache' ) => $this->descriptive_stats( $RAMratios ),
105 __( 'Disk hit ratio', 'sqlite-object-cache' ) => $this->descriptive_stats( $DISKratios ),
106 __( 'Disk lookups/request', 'sqlite-object-cache' ) => $this->descriptive_stats( $DISKLookupsPerRequest ),
107 __( 'Disk saves/request', 'sqlite-object-cache' ) => $this->descriptive_stats( $SavesPerRequest ),
108 __( 'MySQL queries/request', 'sqlite-object-cache' ) => $this->descriptive_stats( $DBMSqueriesPerRequest ),
109 __( 'Initialization times', 'sqlite-object-cache' ) => $this->descriptive_stats( $opens ),
110 __( 'Lookup times', 'sqlite-object-cache' ) => $this->descriptive_stats( array_merge( ...$selects ) ),
111 __( 'Save times', 'sqlite-object-cache' ) => $this->descriptive_stats( array_merge( ...$inserts ) ),
112 __( 'Delete times', 'sqlite-object-cache' ) => $this->descriptive_stats( array_merge( ...$deletes ) ),
113 ];
114
115 $this->descriptions = $descriptions;
116 $this->selected_names = $selected_names;
117 $date_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
118 $this->start_time = wp_date( $date_format, (int) $first );
119 $this->end_time = wp_date( $date_format, (int) $last );
120 }
121 }
122
123 /**
124 * Descriptive statistics for an array of numbers.
125 *
126 * @param array $a The array.
127 *
128 * @return array
129 */
130 public function descriptive_stats( array $a ) {
131 $min = $this->minimum( $a );
132 $max = $this->maximum( $a );
133
134 return [
135 'n' => count( $a ),
136 '[min' => $min,
137 'p5' => $this->percentile( $a, 0.05 ),
138 'median' => $this->percentile( $a, 0.5 ),
139 'mean' => $this->mean( $a ),
140 'p95' => $this->percentile( $a, 0.95 ),
141 'max]' => $max,
142 'range' => $max - $min,
143 'mad' => $this->mad( $a ),
144 'stdev' => $this->stdev( $a ),
145 ];
146 }
147
148 /**
149 * The smallest value in an array.
150 *
151 * @param array $a The array.
152 *
153 * @return mixed|null
154 */
155 public function minimum( array $a ) {
156 sort( $a );
157
158 return count( $a ) > 0 ? $a[0] : null;
159 }
160
161 /**
162 * The largest value in an array.
163 *
164 * @param array $a The array.
165 *
166 * @return mixed|null
167 */
168 public function maximum( array $a ) {
169 sort( $a );
170
171 return count( $a ) > 0 ? $a[ count( $a ) - 1 ] : null;
172 }
173
174 /** Percentile.
175 *
176 * @param array $a dataset.
177 * @param number $p percentile as fraction 0-1.
178 *
179 * @return float
180 */
181 public function percentile( array $a, $p ) {
182 $n = count( $a );
183 if ( ! $n ) {
184 return null;
185 }
186 sort( $a );
187 $i = (int) floor( $n * $p );
188 if ( $i >= $n ) {
189 $i = $n - 1;
190 }
191
192 return $a[ $i ];
193 }
194
195 /**
196 * Arithmetic mean.
197 *
198 * @param array $a dataset.
199 *
200 * @return number
201 */
202 public function mean( array $a ) {
203 $n = count( $a );
204 if ( ! $n ) {
205 return null;
206 }
207 if ( 1 === $n ) {
208 return $a[0];
209 }
210 $acc = 0;
211 foreach ( $a as $v ) {
212 $acc += $v;
213 }
214
215 return $acc / $n;
216 }
217
218 /**
219 * Mean absolute deviation.
220 *
221 * @param array $a dataset.
222 *
223 * @return float|int|null
224 */
225 public function mad( array $a ) {
226 $n = count( $a );
227 if ( ! $n ) {
228 return null;
229 }
230 if ( 1 === $n ) {
231 return 0.0;
232 }
233 $acc = 0;
234 foreach ( $a as $v ) {
235 $acc += $v;
236 }
237 $mean = $acc / $n;
238 $acc = 0;
239 foreach ( $a as $v ) {
240 $acc += abs( $v - $mean );
241 }
242
243 return $acc / $n;
244 }
245
246 /**
247 * Standard deviation.
248 *
249 * @param array $a dataset.
250 *
251 * @return float|null
252 */
253 public function stdev( $a ) {
254 $n = count( $a );
255 if ( ! $n ) {
256 return null;
257 }
258 if ( 1 === $n ) {
259 return 0.0;
260 }
261 $sum = 0.0;
262 $sumsq = 0.0;
263 foreach ( $a as $v ) {
264 $sum += $v;
265 $sumsq += ( $v * $v );
266 }
267 $mean = $sum / $n;
268
269 return sqrt( ( $sumsq / $n ) - ( $mean * $mean ) );
270 }
271
272 /**
273 * Render the statistics display.
274 *
275 * @return void
276 */
277 public function render() {
278
279 echo '<h3>' . esc_html__( 'Cache performance statistics', 'sqlite-object-cache' ) . '</h3>';
280 if ( is_array( $this->descriptions ) ) {
281 echo '<p>' . esc_html( sprintf(
282 /* translators: 1 start time 2 end time both in localized format */
283 __( 'From %1$s to %2$s.', 'sqlite-object-cache' ),
284 $this->start_time, $this->end_time ) . ' ' . __( 'Times in microseconds.', 'sqlite-object-cache' ) ) . '</p>' . PHP_EOL;
285 echo '<table class="sql-object-cache-stats">' . PHP_EOL;
286 $first = true;
287 foreach ( $this->descriptions as $stat => $description ) {
288 if ( $first ) {
289 echo '<thead><tr>';
290 echo '<th scope="col"></th>';
291 foreach ( $description as $item => $value ) {
292 echo '<th scope="col" class="right">' . esc_html( $item ) . '</th>' . PHP_EOL;
293 }
294 echo '</tr></thead><tbody>' . PHP_EOL;
295 $first = false;
296 }
297 echo '<tr>';
298 echo '<th scope="row">' . esc_html( $stat ) . '</th>';
299 foreach ( $description as $value ) {
300 echo '<td>' . esc_html( round( $value, 2 ) ) . '</td>';
301 }
302 echo '</tr>' . PHP_EOL;
303 }
304 echo '</tr></tbody></table>' . PHP_EOL;
305 } else {
306 echo '<p>' . esc_html__( 'No cache statistics recorded yet.', 'sqlite-object-cache' ) . '</p>';
307 }
308
309 if ( is_array( $this->selected_names ) && count( $this->selected_names ) > 0 ) {
310
311 $names = $this->selected_names;
312 uksort( $names, function ( $a, $b ) {
313 /* Descending order of frequency */
314 if ( $this->selected_names[ $a ] !== $this->selected_names[ $b ] ) {
315 return $this->selected_names[ $a ] > $this->selected_names[ $b ] ? - 1 : 1;
316 }
317 $as = explode( '|', $a, 2 );
318 $bs = explode( '|', $b, 2 );
319 /* Ascending order by group name */
320 if ( $as[0] !== $bs[0] ) {
321 return strnatcmp( $as[0], $bs[0] );
322 }
323 /* Ascending order by key name, handling numeric keys correctly. */
324 if ( is_numeric( $as[1] ) && is_numeric( $bs[1] ) ) {
325 if ( (float) $as[1] === (float) $bs[1] ) {
326 return 0;
327 }
328
329 return ( (float) $as[1] ) < ( (float) $bs[1] ) ? - 1 : 1;
330 }
331
332 return strnatcmp( $as[1], $bs[1] );
333 } );
334
335 echo '<h3>' . esc_html__( 'Most frequently looked up cache items', 'sqlite-object-cache' ) . '</h3>' . PHP_EOL;
336
337 echo '<table class="sql-object-cache-items">' . PHP_EOL;
338 $count_threshold = - 1;
339 $first = true;
340 foreach ( $names as $name => $count ) {
341 if ( $first ) {
342 echo '<thead><tr>';
343 echo '<th scope="col">' . esc_html__( "Cache Group", 'sqlite-object-cache' ) . '</th>';
344 echo '<th scope="col">' . esc_html__( "Cache Key", 'sqlite-object-cache' ) . '</th>';
345 echo '<th scope="col">' . esc_html__( "Count", 'sqlite-object-cache' ) . '</th>';
346 echo '</tr></thead><tbody>' . PHP_EOL;
347 $count_threshold = (int) ( $count * 0.7 );
348 $first = false;
349 }
350 if ( $count < $count_threshold ) {
351 break;
352 }
353 $splits = explode( '|', $name, 2 );
354 echo '<tr>';
355 echo '<td>' . esc_html( $splits[0] ) . '</td>';
356 echo '<td>' . esc_html( $splits[1] ) . '</td>';
357 echo '<td>' . esc_html( $count ) . '</td>';
358 echo '</tr>' . PHP_EOL;
359 }
360 }
361 echo '</tbody></table>';
362 }
363 }
364