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 +150 -44 1.51.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,27 +36,59 @@
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';
53 - } else {
54 - self::$metrics = 'hrtime';
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 + }
55 91 }
56 92
57 93 $cp_options = get_option('code-profiler');
58 94 if ( empty( $cp_options['accuracy'] ) ) {
@@ -61,16 +97,47 @@
61 97 define('CODE_PROFILER_TICKS', (int) $cp_options['accuracy'] );
62 98 }
63 99 define('CODE_PROFILER_LENGTH', 17 + strlen( (string) CODE_PROFILER_TICKS ) );
64 100
65 - register_shutdown_function( array( $this, 'code_profiler_shutdown' ) );
101 + if ( empty( $cp_options['buffer'] ) ||
102 + ! preg_match('/^(?:[1-9]|10)$/', $cp_options['buffer'] ) ) {
66 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 + );
67 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 +
68 135 CodeProfiler_Stream::start();
69 - register_tick_function( array( $this, 'code_profiler_tick_handler' ) );
136 + register_tick_function( array( $this, 'code_profiler_tick_handler') );
70 137 }
71 138
72 - /*
139 + /**
73 140 * Save data and check for potential PHP errors.
74 141 */
75 142 public function code_profiler_shutdown() {
76 143
@@ -75,10 +142,13 @@
75 142 public function code_profiler_shutdown() {
76 143
77 144 CodeProfiler_Stream::stop();
78 145
79 - $summary['memory'] = memory_get_peak_usage();
80 - $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;
81 151 file_put_contents( $this->tmp_summary, json_encode( $summary ) );
82 152
83 153 // Catch potential error
84 154 $e = error_get_last();
@@ -98,11 +168,11 @@
98 168 if ( $res === false ) {
99 169 $msg = sprintf( $err_msg, $this->tmp_iostats );
100 170 code_profiler_log_error( $msg );
101 171 }
102 - $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 );
103 173 if ( $res === false ) {
104 - $msg = sprintf( $err_msg, $this->tmp_ticks );
174 + $msg = sprintf( $err_msg, $this->tmp_calls );
105 175 code_profiler_log_error( $msg );
106 176 }
107 177 $res = file_put_contents(
108 178 $this->tmp_diskio, "read\t". CodeProfiler_Stream::$io_read ."\nwrite\t".
@@ -107,21 +177,19 @@
107 177 $res = file_put_contents(
108 178 $this->tmp_diskio, "read\t". CodeProfiler_Stream::$io_read ."\nwrite\t".
109 179 CodeProfiler_Stream::$io_write
110 180 );
111 -
181 + if (! empty( self::$connections_list ) ) {
182 + file_put_contents( $this->tmp_connections, json_encode( self::$connections_list) );
183 + }
112 184 }
113 185
114 - /*
186 + /**
115 187 * Our tick handler.
116 188 */
117 189 public function code_profiler_tick_handler() {
118 190
119 - if ( self::$metrics == 'hrtime' ) {
120 - $start = hrtime( true );
121 - } else {
122 - $start = microtime( true );
123 - }
191 + $start = $this->time();
124 192
125 193 $backtrace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 );
126 194 if ( isset( $backtrace[1] ) ) {
127 195 $el = $backtrace[1];
@@ -129,9 +197,13 @@
129 197 $el = $backtrace[0];
130 198 }
131 199
132 200 if ( empty( $el['file'] ) ) {
133 - return;
201 + if ( isset( $backtrace[0]['file'] ) ) {
202 + $el['file'] = $backtrace[0]['file'];
203 + } else {
204 + return;
205 + }
134 206 }
135 207
136 208 self::$tick_list .= "{$el['file']}\t";
137 209 if ( isset( $backtrace[0]['file'][0] ) ) {
@@ -138,21 +210,55 @@
138 210 self::$tick_list .= $backtrace[0]['file'];
139 211 } else {
140 212 self::$tick_list .= '-';
141 213 }
214 + $backtrace = null;
142 215
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 216 // Buffer can grow *very* big hence we flush it every 10MB by default
150 217 if ( strlen( self::$tick_list ) > self::$buffer ) {
151 218 CodeProfiler_Stream::stop();
152 - file_put_contents( $this->tmp_ticks, self::$tick_list, FILE_APPEND );
219 + fwrite( self::$fh, self::$tick_list ."\t{$start}\t". $this->time() ."\n" );
153 220 CodeProfiler_Stream::start();
154 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 );
155 261 }
156 262 }
157 263 }
158 264