PluginProbe
SQLite Object Cache / 1.6.5
SQLite Object Cache v1.6.5
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-opcache.php

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

319 lines 12.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Health checks for opcache exhaustion.
4 */
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10 /**
11 * Main plugin class.
12 *
13 * Only make one instance of this, please.
14 */
15 class SQLite_Object_Cache_Opcache {
16
17 private $cache_min = 256;
18 private $strings_min = 24;
19
20 private $enabled = false;
21
22 public function __construct() {
23
24 if ( function_exists( 'opcache_get_status' ) ) {
25 $status = @opcache_get_status( false ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- Warning emitted in failure case.
26 if ( $status && true === $status['opcache_enabled'] ) {
27 $this->enabled = true;
28 }
29 }
30
31 if ( $this->enabled ) {
32 add_filter( 'site_status_tests', [ $this, 'site_status_tests' ] );
33 }
34
35 }
36
37 /**
38 * Filters which site status tests are run on a site.
39 *
40 * The site health is determined by a set of tests based on best practices from
41 * both the WordPress Hosting Team and web standards in general.
42 *
43 * Some sites may not have the same requirements, for example the automatic update
44 * checks may be handled by a host, and are therefore disabled in core.
45 * Or maybe you want to introduce a new test, is caching enabled/disabled/stale for example.
46 *
47 * Tests may be added either as direct, or asynchronous ones. Any test that may require some time
48 * to complete should run asynchronously, to avoid extended loading periods within wp-admin.
49 *
50 * @param array[] $tests {
51 * An associative array of direct and asynchronous tests.
52 *
53 * @type array[] $direct {
54 * An array of direct tests.
55 *
56 * @type array ...$identifier {
57 * `$identifier` should be a unique identifier for the test. Plugins and themes are encouraged to
58 * prefix test identifiers with their slug to avoid collisions between tests.
59 *
60 * @type string $label The friendly label to identify the test.
61 * @type callable $test The callback function that runs the test and returns its result.
62 * @type bool $skip_cron Whether to skip this test when running as cron.
63 * }
64 * }
65 * @type array[] $async {
66 * An array of asynchronous tests.
67 *
68 * @type array ...$identifier {
69 * `$identifier` should be a unique identifier for the test. Plugins and themes are encouraged to
70 * prefix test identifiers with their slug to avoid collisions between tests.
71 *
72 * @type string $label The friendly label to identify the test.
73 * @type string $test An admin-ajax.php action to be called to perform the test, or
74 * if `$has_rest` is true, a URL to a REST API endpoint to perform
75 * the test.
76 * @type bool $has_rest Whether the `$test` property points to a REST API endpoint.
77 * @type bool $skip_cron Whether to skip this test when running as cron.
78 * @type callable $async_direct_test A manner of directly calling the test marked as asynchronous,
79 * as the scheduled event can not authenticate, and endpoints
80 * may require authentication.
81 * }
82 * }
83 * }
84 * @since 5.6.0 Added the `async_direct_test` array key for asynchronous tests.
85 * Added the `skip_cron` array key for all tests.
86 *
87 * @since 5.2.0
88 */
89 public function site_status_tests( $tests ) {
90
91 $tests['direct']['opcode_cache_full'] = array(
92 'label' => __( 'Your PHP opcode cache has sufficient RAM', 'sqlite-object-cache' ),
93 'test' => [ $this, 'test_opcache_full' ],
94 );
95 return $tests;
96 }
97
98 /**
99 * Get the cleaned-up opcache status.
100 *
101 * This returns an array:
102 * list( $mem_total, $frac_mem_used, $pct_mem_used, $mem_full, $mem_needed,
103 * $strings_total, $frac_strings_used,$pct_strings_used, $strings_full, $strings_needed ) = $this->get_status()
104 *
105 * @return array|false
106 */
107 public function get_status() {
108 if ( function_exists( 'opcache_get_status' ) ) {
109 $status = @opcache_get_status( false ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- Warning emitted in failure case.
110 } else {
111 return false;
112 }
113
114 try {
115 $mem_total = (float) $status['memory_usage']['used_memory'] + (float) $status['memory_usage']['free_memory'] + (float) $status['memory_usage']['wasted_memory'];
116 $frac_mem_used = 1.0 - ( (float) $status['memory_usage']['free_memory'] / $mem_total );
117 $mem_total = (int) $mem_total / ( MB_IN_BYTES );
118 $mem_needed = floor( (int) ( $mem_total * 1.5 ) );
119 $mem_needed = $mem_needed < $this->cache_min ? $this->cache_min : $mem_needed;
120 $pct_mem_used = number_format( 100 * $frac_mem_used, 0 );
121 $mem_full = $pct_mem_used >= 95;;
122
123 $strings_total = (float) $status['interned_strings_usage']['buffer_size'];
124 $frac_strings_used = (float) $status['interned_strings_usage']['used_memory'] / $strings_total;
125 $strings_total = (int) $strings_total / ( MB_IN_BYTES );
126 $strings_needed = floor( (int) ( $strings_total * 1.5 ) );
127 $strings_needed = $strings_needed < $this->strings_min ? $this->strings_min : $strings_needed;
128 $pct_strings_used = number_format( 100 * $frac_strings_used, 0 );
129 $strings_full = $pct_strings_used >= 95;
130
131 } catch ( Exception $ex ) {
132 return false;
133 }
134
135 return array(
136 $mem_total,
137 $frac_mem_used,
138 $pct_mem_used,
139 $mem_full,
140 $mem_needed,
141 $strings_total,
142 $frac_strings_used,
143 $pct_strings_used,
144 $strings_full,
145 $strings_needed,
146 );
147
148 }
149
150 /**
151 * Check whether the Opcode Cache has enough RAM.
152 * @return array
153 * @throws Exception
154 *
155 */
156 public function test_opcache_full() {
157 if ( ! function_exists( 'opcache_get_status' ) ) {
158 return array(
159 //phpcs:ignore WordPress.WP.I18n.MissingArgDomain
160 'label' => __( 'Opcode cache is not enabled' ),
161 'status' => 'recommended',
162 'badge' => array(
163 //phpcs:ignore WordPress.WP.I18n.MissingArgDomain
164 'label' => __( 'Performance' ),
165 'color' => 'blue',
166 ),
167 //phpcs:ignore WordPress.WP.I18n.MissingArgDomain
168 'description' => '<p>' . __( 'Enabling this cache can significantly improve the performance of your site.' ) . '</p>',
169 'test' => 'opcode_cache_full',
170
171 );
172 }
173
174 $result = $this->get_status();
175 if ( false === $result ) {
176 return array(
177 'label' => __( 'Your PHP opcode cache state seems to be corrupt', 'sqlite-object-cache' ),
178 'status' => 'recommended',
179 'badge' => array(
180 //phpcs:ignore WordPress.WP.I18n.MissingArgDomain
181 'label' => __( 'Performance' ),
182 'color' => 'blue',
183 ),
184 'description' => '<p>' . __( 'Something is wrong with your PHP opcode cache state', 'sqlite-object-cache' ) . '</p>',
185 'test' => 'opcode_cache_full',
186 );
187 }
188 list( $mem_total,
189 $frac_mem_used,
190 $pct_mem_used,
191 $mem_full,
192 $mem_needed,
193 $strings_total,
194 $frac_strings_used,
195 $pct_strings_used,
196 $strings_full,
197 $strings_needed ) = $result;
198
199 $mem_url = 'https://php.net/manual/en/opcache.configuration.php#ini.opcache.memory-consumption';
200 $strings_url = 'https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.interned-strings-buffer';
201
202
203 $description = array();
204 $action = array();
205 $message = ( $frac_mem_used < 0.995 )
206 ? sprintf(
207 /* Translators: 1: number of megabytes. 2: percent full */
208 __( '%1$d megabytes are allocated to PHP\'s opcode cache. It is %2$d%% full.', 'sqlite-object-cache' ),
209 $mem_total, $pct_mem_used )
210 : sprintf(
211 /* Translators: 1: number of megabytes */
212 __( '%1$d megabytes are allocated to PHP\'s opcode cache. It is full.', 'sqlite-object-cache' ),
213 $mem_total );
214 $description[] = $message . ' ' .
215 sprintf( '<a href="%1$s" target="_blank">%2$s<span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
216 esc_url( $mem_url ),
217 __( 'Learn how to configure it.', 'sqlite-object-cache' ),
218 //phpcs:ignore WordPress.WP.I18n.MissingArgDomain
219 __( '(opens in a new tab)' )
220 );
221 if ( $mem_full ) {
222
223 $action[] = sprintf(
224 /* translators: 1: a number of megabytes. Notice that this should not have any suffix, like MB, appended to it. */
225 __( 'Ask your hosting provider to increase the opcache.memory_consumption directive in php.ini, setting it to at least %1$d.', 'sqlite-object-cache' ),
226 $mem_needed );
227 }
228 $message = ( $frac_strings_used < 0.995 )
229 ? sprintf(
230 /* Translators: 1: number of megabytes. 2: percent full */
231 __( '%1$d megabytes are allocated to the opcode cache\'s strings buffer. It is %2$d%% full.', 'sqlite-object-cache' ),
232 $strings_total, $pct_strings_used )
233 : sprintf(
234 /* Translators: 1: number of megabytes */
235 __( '%1$d megabytes are allocated to the opcode cache\'s strings buffer. It is full.', 'sqlite-object-cache' ),
236 $strings_total );
237
238 $description[] = $message . ' ' .
239 sprintf( '<a href="%1$s" target="_blank">%2$s<span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
240 esc_url( $strings_url ),
241 __( 'Learn how to configure it.', 'sqlite-object-cache' ),
242 //phpcs:ignore WordPress.WP.I18n.MissingArgDomain
243 __( '(opens in a new tab)' )
244 );
245 if ( $strings_full ) {
246
247 $action[] = sprintf(
248 /* translators: 1: a number of megabytes. Notice that this should not have any suffix, like MB, appended to it. */
249 __( 'Ask your hosting provider to increase the opcache.interned_strings_buffer directive in php.ini, setting it to at least %1$d.', 'sqlite-object-cache' ),
250 $strings_needed );
251 }
252
253 $description_string = '<p>' . implode( '</p><p>', $description ) . '</p>';
254 $action_string = '<p>' . implode( '</p><p>', $action ) . '</p>';
255
256 if ( ! $mem_full && ! $strings_full ) {
257
258 return array(
259 'label' => __( "Opcode cache has enough RAM", 'sqlite-object-cache' ),
260 'status' => 'good',
261 'badge' => array(
262 //phpcs:ignore WordPress.WP.I18n.MissingArgDomain
263 'label' => __( 'Performance' ),
264 'color' => 'blue',
265 ),
266 'description' => $description_string,
267 'test' => 'opcode_cache_full',
268 );
269 }
270
271 if ( $mem_full && $strings_full ) {
272
273 return array(
274 'label' => __( "Your PHP opcode cache and its interned strings cache need more RAM allocated to them.", 'sqlite-object-cache' ),
275 'status' => 'recommended',
276 'badge' => array(
277 //phpcs:ignore WordPress.WP.I18n.MissingArgDomain
278 'label' => __( 'Performance' ),
279 'color' => 'blue',
280 ),
281 'description' => $description_string,
282 'actions' => $action_string,
283 'test' => 'opcode_cache_full',
284 );
285 }
286
287 if ( $strings_full ) {
288
289 return array(
290 'label' => __( "Your PHP opcode cache's interned strings cache needs more RAM allocated to it.", 'sqlite-object-cache' ),
291 'status' => 'recommended',
292 'badge' => array(
293 //phpcs:ignore WordPress.WP.I18n.MissingArgDomain
294 'label' => __( 'Performance' ),
295 'color' => 'blue',
296 ),
297 'description' => $description_string,
298 'actions' => $action_string,
299 'test' => 'opcode_cache_full',
300 );
301 }
302
303
304 return array(
305 'label' => __( "Your PHP opcode cache needs more RAM allocated to it.", 'sqlite-object-cache' ),
306 'status' => 'recommended',
307 'badge' => array(
308 //phpcs:ignore WordPress.WP.I18n.MissingArgDomain
309 'label' => __( 'Performance' ),
310 'color' => 'blue',
311 ),
312 'description' => $description_string,
313 'actions' => $action_string,
314 'test' => 'opcode_cache_full',
315 );
316 }
317
318 }
319