PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.7.4
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.7.4
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
← All changes | lib/class-profiler.php +158 -43 1.41.7.4 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,21 @@
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;
28 32
29 - /*
33 + /**
30 34 * Initialize
31 35 */
32 36 public function __construct() {
33 37
@@ -32,37 +36,108 @@
32 36 public function __construct() {
33 37
34 38 $microtime = sanitize_file_name( $_REQUEST['CODE_PROFILER_ON'] );
35 39
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;
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;
44 50
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 );
51 + if ( function_exists('hrtime') ) {
52 + // PHP >=7.3
53 + self::$metrics = 'hrtime';
54 + } else {
55 + self::$metrics = 'microtime';
49 56 }
50 57
51 - if ( version_compare( PHP_VERSION, '7.3', '<' ) ) {
52 - self::$metrics = 'microtime';
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 );
53 96 } else {
54 - self::$metrics = 'hrtime';
97 + define('CODE_PROFILER_TICKS', (int) $cp_options['accuracy'] );
55 98 }
99 + define('CODE_PROFILER_LENGTH', 17 + strlen( (string) CODE_PROFILER_TICKS ) );
56 100
57 - register_shutdown_function( array( $this, 'code_profiler_shutdown' ) );
101 + if ( empty( $cp_options['buffer'] ) ||
102 + ! preg_match('/^(?:[1-9]|10)$/', $cp_options['buffer'] ) ) {
58 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 + );
59 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 +
60 135 CodeProfiler_Stream::start();
61 - register_tick_function( array( $this, 'code_profiler_tick_handler' ) );
136 + register_tick_function( array( $this, 'code_profiler_tick_handler') );
62 137 }
63 138
64 - /*
139 + /**
65 140 * Save data and check for potential PHP errors.
66 141 */
67 142 public function code_profiler_shutdown() {
68 143
@@ -67,10 +142,13 @@
67 142 public function code_profiler_shutdown() {
68 143
69 144 CodeProfiler_Stream::stop();
70 145
71 - $summary['memory'] = memory_get_peak_usage();
72 - $summary['queries'] = get_num_queries() - 2;
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;
73 151 file_put_contents( $this->tmp_summary, json_encode( $summary ) );
74 152
75 153 // Catch potential error
76 154 $e = error_get_last();
@@ -76,8 +154,9 @@
76 154 $e = error_get_last();
77 155 if ( isset( $e['type'] ) && $e['type'] === E_ERROR ) {
78 156 $err = str_replace( "\n", ' - ', $e['message'] );
79 157 code_profiler_log_error( sprintf(
158 + /* Translators: Error message, line number and script */
80 159 esc_html__('Error: E_ERROR (%s - line %s in %s)', 'code-profiler'),
81 160 esc_html( $err ),
82 161 (int) $e['line'],
83 162 esc_html( $e['file'] )
@@ -89,11 +168,11 @@
89 168 if ( $res === false ) {
90 169 $msg = sprintf( $err_msg, $this->tmp_iostats );
91 170 code_profiler_log_error( $msg );
92 171 }
93 - $res = file_put_contents( $this->tmp_ticks, self::$tick_list, FILE_APPEND );
172 + $res = file_put_contents( $this->tmp_calls, self::$tick_list, FILE_APPEND );
94 173 if ( $res === false ) {
95 - $msg = sprintf( $err_msg, $this->tmp_ticks );
174 + $msg = sprintf( $err_msg, $this->tmp_calls );
96 175 code_profiler_log_error( $msg );
97 176 }
98 177 $res = file_put_contents(
99 178 $this->tmp_diskio, "read\t". CodeProfiler_Stream::$io_read ."\nwrite\t".
@@ -98,21 +177,19 @@
98 177 $res = file_put_contents(
99 178 $this->tmp_diskio, "read\t". CodeProfiler_Stream::$io_read ."\nwrite\t".
100 179 CodeProfiler_Stream::$io_write
101 180 );
102 -
181 + if (! empty( self::$connections_list ) ) {
182 + file_put_contents( $this->tmp_connections, json_encode( self::$connections_list) );
183 + }
103 184 }
104 185
105 - /*
186 + /**
106 187 * Our tick handler.
107 188 */
108 189 public function code_profiler_tick_handler() {
109 190
110 - if ( self::$metrics == 'hrtime' ) {
111 - $start = hrtime( true );
112 - } else {
113 - $start = microtime( true );
114 - }
191 + $start = $this->time();
115 192
116 193 $backtrace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 );
117 194 if ( isset( $backtrace[1] ) ) {
118 195 $el = $backtrace[1];
@@ -120,9 +197,13 @@
120 197 $el = $backtrace[0];
121 198 }
122 199
123 200 if ( empty( $el['file'] ) ) {
124 - return;
201 + if ( isset( $backtrace[0]['file'] ) ) {
202 + $el['file'] = $backtrace[0]['file'];
203 + } else {
204 + return;
205 + }
125 206 }
126 207
127 208 self::$tick_list .= "{$el['file']}\t";
128 209 if ( isset( $backtrace[0]['file'][0] ) ) {
@@ -129,21 +210,55 @@
129 210 self::$tick_list .= $backtrace[0]['file'];
130 211 } else {
131 212 self::$tick_list .= '-';
132 213 }
214 + $backtrace = null;
133 215
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 216 // Buffer can grow *very* big hence we flush it every 10MB by default
141 217 if ( strlen( self::$tick_list ) > self::$buffer ) {
142 218 CodeProfiler_Stream::stop();
143 - file_put_contents( $this->tmp_ticks, self::$tick_list, FILE_APPEND );
219 + fwrite( self::$fh, self::$tick_list ."\t{$start}\t". $this->time() ."\n" );
144 220 CodeProfiler_Stream::start();
145 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 );
146 261 }
147 262 }
148 263 }
149 264