PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.7.3
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.7.3
1.9.5 1.9.4 1.9.3 trunk 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.6 1.6.1 1.6.10 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 All 40 releases
code-profiler / lib / class-profiler.php

class-profiler.php in Code Profiler – WordPress Performance Profiling and Debugging Made Easy 1.7.3, at lib/class-profiler.php

269 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 +=====================================================================+
4 | ____ _ ____ __ _ _ |
5 | / ___|___ __| | ___ | _ \ _ __ ___ / _(_) | ___ _ __ |
6 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
7 | | |__| (_) | (_| | __/ | __/| | | (_) | _| | | __/ | |
8 | \____\___/ \__,_|\___| |_| |_| \___/|_| |_|_|\___|_| |
9 | |
10 | (c) Jerome Bruandet ~ https://nintechnet.com/codeprofiler/ |
11 +=====================================================================+
12 */
13
14 if (! defined('ABSPATH') ) { die('Forbidden'); }
15
16 // =====================================================================
17
18 class CodeProfiler_Profiler {
19
20 static $tick_list;
21 static $buffer;
22 static $metrics;
23 static $fh;
24 static $connections_list = [];
25 static $connections_start;
26 static $exclusions = [];
27 private $tmp_iostats;
28 private $tmp_summary;
29 private $tmp_diskio;
30 private $tmp_calls;
31 private $tmp_connections;
32
33 /**
34 * Initialize
35 */
36 public function __construct() {
37
38 $microtime = sanitize_file_name( $_REQUEST['CODE_PROFILER_ON'] );
39
40 $this->tmp_summary = CODE_PROFILER_UPLOAD_DIR ."/$microtime." .
41 CODE_PROFILER_TMP_SUMMARY_LOG;
42 $this->tmp_iostats = CODE_PROFILER_UPLOAD_DIR ."/$microtime." .
43 CODE_PROFILER_TMP_IOSTATS_LOG;
44 $this->tmp_calls = CODE_PROFILER_UPLOAD_DIR ."/$microtime." .
45 CODE_PROFILER_TMP_CALLS_LOG;
46 $this->tmp_diskio = CODE_PROFILER_UPLOAD_DIR ."/$microtime." .
47 CODE_PROFILER_TMP_DISKIO_LOG;
48 $this->tmp_connections = CODE_PROFILER_UPLOAD_DIR ."/$microtime." .
49 CODE_PROFILER_TMP_CONNECTIONS_LOG;
50
51 if ( function_exists('hrtime') ) {
52 // PHP >=7.3
53 self::$metrics = 'hrtime';
54 } else {
55 self::$metrics = 'microtime';
56 }
57
58 // Select theme (stylesheet::template)
59 if (! empty( $_SERVER['HTTP_THEME'] ) ) {
60
61 $theme = explode('::', $_SERVER['HTTP_THEME'] );
62 if (! empty( $theme[1] ) ) {
63 define('CODE_PROFILER_STYLESHEET', sanitize_file_name( $theme[0] ) );
64 define('CODE_PROFILER_TEMPLATE', sanitize_file_name( $theme[1] ) );
65
66 if ( is_file( WP_CONTENT_DIR .'/themes/'. CODE_PROFILER_STYLESHEET .'/style.css' ) ) {
67
68 add_filter('pre_option_template', function () {
69 return CODE_PROFILER_TEMPLATE;
70 }, 1000 );
71
72 add_filter('pre_option_stylesheet', function () {
73 return CODE_PROFILER_STYLESHEET;
74 }, 1000 );
75
76 code_profiler_log_debug(
77 sprintf(
78 esc_html__('Setting theme to %s', 'code-profiler'),
79 CODE_PROFILER_STYLESHEET
80 )
81 );
82 } else {
83 code_profiler_log_error(
84 sprintf(
85 esc_html__('Unable to switch theme, %s not found', 'code-profiler'),
86 CODE_PROFILER_STYLESHEET
87 )
88 );
89 }
90 }
91 }
92
93 $cp_options = get_option('code-profiler');
94 if ( empty( $cp_options['accuracy'] ) ) {
95 define('CODE_PROFILER_TICKS', 1 );
96 } else {
97 define('CODE_PROFILER_TICKS', (int) $cp_options['accuracy'] );
98 }
99 define('CODE_PROFILER_LENGTH', 17 + strlen( (string) CODE_PROFILER_TICKS ) );
100
101 if ( empty( $cp_options['buffer'] ) ||
102 ! preg_match('/^(?:[1-9]|10)$/', $cp_options['buffer'] ) ) {
103
104 $recommended = code_profiler_suggested_memory();
105 self::$buffer = (int) $recommended * 1000000;
106 } else {
107 self::$buffer = $cp_options['buffer'] * 1000000;
108 }
109 code_profiler_log_debug(
110 sprintf(
111 esc_html__('Setting size of memory buffer to %sMB', 'code-profiler'),
112 self::$buffer / 1000000
113 )
114 );
115
116 // File & folder exclusions
117 if ( isset( $cp_options['exclusions'] ) ) {
118 self::$exclusions = json_decode( $cp_options['exclusions'] );
119 }
120
121 add_filter('pre_http_request', [ $this, 'pre_http_request'], 10000, 3 );
122 add_action('http_api_debug', [ $this, 'http_api_debug'], 10000, 5 );
123 register_shutdown_function( [ $this, 'code_profiler_shutdown'] );
124 code_profiler_log_debug(
125 esc_html__('Starting profiler', 'code-profiler')
126 );
127 require 'class-stream.php';
128
129 // Clear the temporary log because the buffer will be appended to it
130 if ( file_exists( $this->tmp_calls ) ) {
131 unlink( $this->tmp_calls );
132 }
133 self::$fh = fopen( $this->tmp_calls, 'wb');
134
135 CodeProfiler_Stream::start();
136 register_tick_function( array( $this, 'code_profiler_tick_handler') );
137 }
138
139 /**
140 * Save data and check for potential PHP errors.
141 */
142 public function code_profiler_shutdown() {
143
144 CodeProfiler_Stream::stop();
145
146 fclose( self::$fh );
147
148 $summary['memory'] = memory_get_peak_usage();
149 $summary['queries'] = get_num_queries() - 2;
150 $summary['precision'] = CODE_PROFILER_TICKS;
151 file_put_contents( $this->tmp_summary, json_encode( $summary ) );
152
153 // Catch potential error
154 $e = error_get_last();
155 if ( isset( $e['type'] ) && $e['type'] === E_ERROR ) {
156 $err = str_replace( "\n", ' - ', $e['message'] );
157 code_profiler_log_error( sprintf(
158 /* Translators: Error message, line number and script */
159 esc_html__('Error: E_ERROR (%s - line %s in %s)', 'code-profiler'),
160 esc_html( $err ),
161 (int) $e['line'],
162 esc_html( $e['file'] )
163 ));
164 }
165
166 $err_msg = esc_html__('Cannot open file for writting: %s', 'code-profiler');
167 $res = file_put_contents( $this->tmp_iostats, json_encode( CodeProfiler_Stream::$io_stats ) );
168 if ( $res === false ) {
169 $msg = sprintf( $err_msg, $this->tmp_iostats );
170 code_profiler_log_error( $msg );
171 }
172 $res = file_put_contents( $this->tmp_calls, self::$tick_list, FILE_APPEND );
173 if ( $res === false ) {
174 $msg = sprintf( $err_msg, $this->tmp_calls );
175 code_profiler_log_error( $msg );
176 }
177 $res = file_put_contents(
178 $this->tmp_diskio, "read\t". CodeProfiler_Stream::$io_read ."\nwrite\t".
179 CodeProfiler_Stream::$io_write
180 );
181 if (! empty( self::$connections_list ) ) {
182 file_put_contents( $this->tmp_connections, json_encode( self::$connections_list) );
183 }
184 }
185
186 /**
187 * Our tick handler.
188 */
189 public function code_profiler_tick_handler() {
190
191 $start = $this->time();
192
193 $backtrace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 );
194 if ( isset( $backtrace[1] ) ) {
195 $el = $backtrace[1];
196 } else {
197 $el = $backtrace[0];
198 }
199
200 if ( empty( $el['file'] ) ) {
201 if ( isset( $backtrace[0]['file'] ) ) {
202 $el['file'] = $backtrace[0]['file'];
203 } else {
204 return;
205 }
206 }
207
208 self::$tick_list .= "{$el['file']}\t";
209 if ( isset( $backtrace[0]['file'][0] ) ) {
210 self::$tick_list .= $backtrace[0]['file'];
211 } else {
212 self::$tick_list .= '-';
213 }
214 $backtrace = null;
215
216 // Buffer can grow *very* big hence we flush it every 10MB by default
217 if ( strlen( self::$tick_list ) > self::$buffer ) {
218 CodeProfiler_Stream::stop();
219 fwrite( self::$fh, self::$tick_list ."\t{$start}\t". $this->time() ."\n" );
220 CodeProfiler_Stream::start();
221 self::$tick_list = '';
222
223 } else {
224 self::$tick_list .="\t{$start}\t". $this->time() ."\n";
225 }
226 }
227
228
229 /**
230 * HTTP API request.
231 */
232 public function pre_http_request( $preempt, $r, $url ) {
233
234 if ( empty( $url ) ) {
235 return false;
236 }
237 $backtrace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS );
238 self::$connections_start = $this->time();
239 self::$connections_list[ self::$connections_start ]['bt'] = $backtrace;
240 return false;
241 }
242
243
244 /**
245 * HTTP API response.
246 */
247 public function http_api_debug( $response, $context, $class, $parsed_args, $url ) {
248
249 self::$connections_list[ self::$connections_start ]['stop'] = $this->time();
250 }
251
252 /**
253 * Return time
254 */
255 private function time() {
256
257 if ( self::$metrics == 'hrtime') {
258 return hrtime( true );
259 } else {
260 return microtime( true );
261 }
262 }
263 }
264
265 new CodeProfiler_Profiler();
266
267 // =====================================================================
268 // EOF
269