PluginProbe
SQLite Object Cache / 1.0.0
SQLite Object Cache v1.0.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.0.0, at includes/lib/class-sqlite-object-cache-statistics.php

352 lines 8.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 $DISKhits = 0;
61 $DISKmisses = 0;
62
63 if ( ! method_exists( $wp_object_cache, 'sqlite_load_statistics' ) ) {
64 return;
65 }
66
67 foreach ( $wp_object_cache->sqlite_load_statistics() as $data ) {
68 $first = min( $data->time, $first );
69 $last = max( $data->time, $last );
70 $RAMhits += $data->RAMhits;
71 $RAMmisses += $data->RAMmisses;
72 $DISKhits += $data->RAMhits;
73 $DISKmisses += $data->RAMmisses;
74 $RAMratio = $data->RAMhits / ( $data->RAMhits + $data->RAMmisses );
75 $RAMratios[] = $RAMratio;
76 $DISKratio = $data->DISKhits / ( $data->DISKhits + $data->DISKmisses );
77 $DISKratios[] = $DISKratio;
78 $opens [] = $data->open;
79 $selects [] = $data->selects;
80 $inserts [] = $data->inserts;
81 $deletes[] = $data->deletes;
82
83 if ( is_array( $data->select_names ) ) {
84 foreach ( $data->select_names as $name ) {
85 if ( ! array_key_exists( $name, $selected_names ) ) {
86 $selected_names[ $name ] = 0;
87 }
88 $selected_names[ $name ] ++;
89 }
90 }
91 }
92 $duration = $last - $first;
93 if ( $duration > 0 ) {
94 arsort( $selected_names );
95 $descriptions = [
96 __( 'Start', 'sqlite-object-cache' ) => $this->descriptive_stats( $opens ),
97 __( 'RAM Hit Ratio', 'sqlite-object-cache' ) => $this->descriptive_stats( $RAMratios ),
98 __( 'Disk Hit Ratio', 'sqlite-object-cache' ) => $this->descriptive_stats( $DISKratios ),
99 __( 'Lookup', 'sqlite-object-cache' ) => $this->descriptive_stats( array_merge( ...$selects ) ),
100 __( 'Save', 'sqlite-object-cache' ) => $this->descriptive_stats( array_merge( ...$inserts ) ),
101 __( 'Delete', 'sqlite-object-cache' ) => $this->descriptive_stats( array_merge( ...$deletes ) ),
102 ];
103
104 $this->descriptions = $descriptions;
105 $this->selected_names = $selected_names;
106 $date_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
107 $this->start_time = wp_date( $date_format, (int) $first );
108 $this->end_time = wp_date( $date_format, (int) $last );
109 }
110 }
111
112 /**
113 * Descriptive statistics for an array of numbers.
114 *
115 * @param array $a The array.
116 *
117 * @return array
118 */
119 public function descriptive_stats( array $a ) {
120 $min = $this->minimum( $a );
121 $max = $this->maximum( $a );
122
123 return [
124 'n' => count( $a ),
125 '[min' => $min,
126 'median' => $this->percentile( $a, 0.5 ),
127 'mean' => $this->mean( $a ),
128 'p95' => $this->percentile( $a, 0.95 ),
129 'max]' => $max,
130 'range' => $max - $min,
131 'mad' => $this->mad( $a ),
132 'stdev' => $this->stdev( $a ),
133 ];
134 }
135
136 /**
137 * The smallest value in an array.
138 *
139 * @param array $a The array.
140 *
141 * @return mixed|null
142 */
143 public function minimum( array $a ) {
144 sort( $a );
145
146 return count( $a ) > 0 ? $a[0] : null;
147 }
148
149 /**
150 * The largest value in an array.
151 *
152 * @param array $a The array.
153 *
154 * @return mixed|null
155 */
156 public function maximum( array $a ) {
157 sort( $a );
158
159 return count( $a ) > 0 ? $a[ count( $a ) - 1 ] : null;
160 }
161
162 /** Percentile.
163 *
164 * @param array $a dataset.
165 * @param number $p percentile as fraction 0-1.
166 *
167 * @return float
168 */
169 public function percentile( array $a, $p ) {
170 $n = count( $a );
171 if ( ! $n ) {
172 return null;
173 }
174 sort( $a );
175 $i = (int) floor( $n * $p );
176 if ( $i >= $n ) {
177 $i = $n - 1;
178 }
179
180 return $a[ $i ];
181 }
182
183 /**
184 * Arithmetic mean.
185 *
186 * @param array $a dataset.
187 *
188 * @return number
189 */
190 public function mean( array $a ) {
191 $n = count( $a );
192 if ( ! $n ) {
193 return null;
194 }
195 if ( 1 === $n ) {
196 return $a[0];
197 }
198 $acc = 0;
199 foreach ( $a as $v ) {
200 $acc += $v;
201 }
202
203 return $acc / $n;
204 }
205
206 /**
207 * Mean absolute deviation.
208 *
209 * @param array $a dataset.
210 *
211 * @return float|int|null
212 */
213 public function mad( array $a ) {
214 $n = count( $a );
215 if ( ! $n ) {
216 return null;
217 }
218 if ( 1 === $n ) {
219 return 0.0;
220 }
221 $acc = 0;
222 foreach ( $a as $v ) {
223 $acc += $v;
224 }
225 $mean = $acc / $n;
226 $acc = 0;
227 foreach ( $a as $v ) {
228 $acc += abs( $v - $mean );
229 }
230
231 return $acc / $n;
232 }
233
234 /**
235 * Standard deviation.
236 *
237 * @param array $a dataset.
238 *
239 * @return float|null
240 */
241 public function stdev( $a ) {
242 $n = count( $a );
243 if ( ! $n ) {
244 return null;
245 }
246 if ( 1 === $n ) {
247 return 0.0;
248 }
249 $sum = 0.0;
250 $sumsq = 0.0;
251 foreach ( $a as $v ) {
252 $sum += $v;
253 $sumsq += ( $v * $v );
254 }
255 $mean = $sum / $n;
256
257 return sqrt( ( $sumsq / $n ) - ( $mean * $mean ) );
258 }
259
260 /**
261 * Render the statistics display.
262 *
263 * @return void
264 */
265 public function render() {
266
267 echo '<h3>' . esc_html__( 'Cache performance statistics', 'sqlite-object-cache' ) . '</h3>';
268 if ( is_array( $this->descriptions ) ) {
269 echo '<p>' . esc_html( sprintf(
270 /* translators: 1 start time 2 end time both in localized format */
271 __( 'From %1$s to %2$s.', 'sqlite-object-cache' ),
272 $this->start_time, $this->end_time ) . ' ' . __( 'Times in microseconds.', 'sqlite-object-cache' ) ) . '</p>' . PHP_EOL;
273 echo '<table class="sql-object-cache-stats">' . PHP_EOL;
274 $first = true;
275 foreach ( $this->descriptions as $stat => $description ) {
276 if ( $first ) {
277 echo '<thead><tr>';
278 echo '<th scope="col">' . esc_html__( 'Item', 'sqlite-object-cache' ) . '</th>';
279 foreach ( $description as $item => $value ) {
280 echo '<th scope="col">' . esc_html( $item ) . '</th>' . PHP_EOL;
281 }
282 echo '</tr></thead><tbody>' . PHP_EOL;
283 $first = false;
284 }
285 echo '<tr>';
286 echo '<th scope="row">' . esc_html( $stat ) . '</th>';
287 foreach ( $description as $value ) {
288 echo '<td>' . esc_html( round( $value, 2 ) ) . '</td>';
289 }
290 echo '</tr>' . PHP_EOL;
291 }
292 echo '</tr></tbody></table>' . PHP_EOL;
293 } else {
294 echo '<p>' . esc_html__( 'No cache statistics recorded yet.', 'sqlite-object-cache' ) . '</p>';
295 }
296
297 if ( is_array( $this->selected_names ) && count( $this->selected_names ) > 0 ) {
298
299 $names = $this->selected_names;
300 uksort( $names, function ( $a, $b ) {
301 /* Descending order of frequency */
302 if ( $this->selected_names[ $a ] !== $this->selected_names[ $b ] ) {
303 return $this->selected_names[ $a ] > $this->selected_names[ $b ] ? - 1 : 1;
304 }
305 $as = explode( '|', $a, 2 );
306 $bs = explode( '|', $b, 2 );
307 /* Ascending order by group name */
308 if ( $as[0] !== $bs[0] ) {
309 return strnatcmp( $as[0], $bs[0] );
310 }
311 /* Ascending order by key name, handling numeric keys correctly. */
312 if ( is_numeric( $as[1] ) && is_numeric( $bs[1] ) ) {
313 if ( (float) $as[1] === (float) $bs[1] ) {
314 return 0;
315 }
316
317 return ( (float) $as[1] ) < ( (float) $bs[1] ) ? - 1 : 1;
318 }
319
320 return strnatcmp( $as[1], $bs[1] );
321 } );
322
323 echo '<h3>' . esc_html__( 'Most frequently looked up cache items', 'sqlite-object-cache' ) . '</h3>' . PHP_EOL;
324
325 echo '<table class="sql-object-cache-items">' . PHP_EOL;
326 $count_threshold = - 1;
327 $first = true;
328 foreach ( $names as $name => $count ) {
329 if ( $first ) {
330 echo '<thead><tr>';
331 echo '<th scope="col">' . esc_html__( "Cache Group", 'sqlite-object-cache' ) . '</th>';
332 echo '<th scope="col">' . esc_html__( "Cache Key", 'sqlite-object-cache' ) . '</th>';
333 echo '<th scope="col">' . esc_html__( "Count", 'sqlite-object-cache' ) . '</th>';
334 echo '</tr></thead><tbody>' . PHP_EOL;
335 $count_threshold = (int) ( $count * 0.7 );
336 $first = false;
337 }
338 if ( $count < $count_threshold ) {
339 break;
340 }
341 $splits = explode( '|', $name, 2 );
342 echo '<tr>';
343 echo '<td>' . esc_html( $splits[0] ) . '</td>';
344 echo '<td>' . esc_html( $splits[1] ) . '</td>';
345 echo '<td>' . esc_html( $count ) . '</td>';
346 echo '</tr>' . PHP_EOL;
347 }
348 }
349 echo '</tbody></table>';
350 }
351 }
352