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