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

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