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 +171 -43 1.4.21.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,37 +37,114 @@
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';
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 + }
96 + }
97 +
98 + $cp_options = get_option('code-profiler');
99 + if ( empty( $cp_options['accuracy'] ) ) {
100 + define('CODE_PROFILER_TICKS', 1 );
53 101 } else {
54 - self::$metrics = 'hrtime';
102 + define('CODE_PROFILER_TICKS', (int) $cp_options['accuracy'] );
55 103 }
104 + define('CODE_PROFILER_LENGTH', 17 + strlen( (string) CODE_PROFILER_TICKS ) );
56 105
57 - register_shutdown_function( array( $this, 'code_profiler_shutdown' ) );
106 + if ( empty( $cp_options['buffer'] ) ||
107 + ! preg_match('/^(?:[1-9]|10)$/', $cp_options['buffer'] ) ) {
58 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 + );
59 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 +
60 142 CodeProfiler_Stream::start();
61 - register_tick_function( array( $this, 'code_profiler_tick_handler' ) );
143 + register_tick_function( array( $this, 'code_profiler_tick_handler') );
62 144 }
63 145
64 - /*
146 + /**
65 147 * Save data and check for potential PHP errors.
66 148 */
67 149 public function code_profiler_shutdown() {
68 150
@@ -67,10 +149,19 @@
67 149 public function code_profiler_shutdown() {
68 150
69 151 CodeProfiler_Stream::stop();
70 152
71 - $summary['memory'] = memory_get_peak_usage();
72 - $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;
73 164 file_put_contents( $this->tmp_summary, json_encode( $summary ) );
74 165
75 166 // Catch potential error
76 167 $e = error_get_last();
@@ -76,8 +167,9 @@
76 167 $e = error_get_last();
77 168 if ( isset( $e['type'] ) && $e['type'] === E_ERROR ) {
78 169 $err = str_replace( "\n", ' - ', $e['message'] );
79 170 code_profiler_log_error( sprintf(
171 + /* Translators: Error message, line number and script */
80 172 esc_html__('Error: E_ERROR (%s - line %s in %s)', 'code-profiler'),
81 173 esc_html( $err ),
82 174 (int) $e['line'],
83 175 esc_html( $e['file'] )
@@ -89,11 +181,11 @@
89 181 if ( $res === false ) {
90 182 $msg = sprintf( $err_msg, $this->tmp_iostats );
91 183 code_profiler_log_error( $msg );
92 184 }
93 - $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 );
94 186 if ( $res === false ) {
95 - $msg = sprintf( $err_msg, $this->tmp_ticks );
187 + $msg = sprintf( $err_msg, $this->tmp_calls );
96 188 code_profiler_log_error( $msg );
97 189 }
98 190 $res = file_put_contents(
99 191 $this->tmp_diskio, "read\t". CodeProfiler_Stream::$io_read ."\nwrite\t".
@@ -98,21 +190,19 @@
98 190 $res = file_put_contents(
99 191 $this->tmp_diskio, "read\t". CodeProfiler_Stream::$io_read ."\nwrite\t".
100 192 CodeProfiler_Stream::$io_write
101 193 );
102 -
194 + if (! empty( self::$connections_list ) ) {
195 + file_put_contents( $this->tmp_connections, json_encode( self::$connections_list) );
196 + }
103 197 }
104 198
105 - /*
199 + /**
106 200 * Our tick handler.
107 201 */
108 202 public function code_profiler_tick_handler() {
109 203
110 - if ( self::$metrics == 'hrtime' ) {
111 - $start = hrtime( true );
112 - } else {
113 - $start = microtime( true );
114 - }
204 + $start = $this->time();
115 205
116 206 $backtrace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 );
117 207 if ( isset( $backtrace[1] ) ) {
118 208 $el = $backtrace[1];
@@ -120,9 +210,13 @@
120 210 $el = $backtrace[0];
121 211 }
122 212
123 213 if ( empty( $el['file'] ) ) {
124 - return;
214 + if ( isset( $backtrace[0]['file'] ) ) {
215 + $el['file'] = $backtrace[0]['file'];
216 + } else {
217 + return;
218 + }
125 219 }
126 220
127 221 self::$tick_list .= "{$el['file']}\t";
128 222 if ( isset( $backtrace[0]['file'][0] ) ) {
@@ -129,21 +223,55 @@
129 223 self::$tick_list .= $backtrace[0]['file'];
130 224 } else {
131 225 self::$tick_list .= '-';
132 226 }
227 + $backtrace = null;
133 228
134 - if ( self::$metrics == 'hrtime' ) {
135 - self::$tick_list .="\t{$start}\t". hrtime(true) ."\n";
136 - } else {
137 - self::$tick_list .="\t{$start}\t". microtime(true) ."\n";
138 - }
139 -
140 229 // Buffer can grow *very* big hence we flush it every 10MB by default
141 230 if ( strlen( self::$tick_list ) > self::$buffer ) {
142 231 CodeProfiler_Stream::stop();
143 - file_put_contents( $this->tmp_ticks, self::$tick_list, FILE_APPEND );
232 + fwrite( self::$fh, self::$tick_list ."\t{$start}\t". $this->time() ."\n" );
144 233 CodeProfiler_Stream::start();
145 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 );
146 274 }
147 275 }
148 276 }
149 277