PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.6.7
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.6.7
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.6.7, at lib/class-profiler.php

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