| @@ -6,9 +6,9 @@ | ||
| 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 | 14 | if (! defined('ABSPATH') ) { die('Forbidden'); } |
| @@ -17,14 +17,19 @@ | ||
| 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 | + static $fh; | |
| 24 | + static $connections_list = []; | |
| 25 | + static $connections_start; | |
| 26 | + static $exclusions = []; | |
| 23 | 27 | private $tmp_iostats; |
| 24 | 28 | private $tmp_summary; |
| 25 | 29 | private $tmp_diskio; |
| 26 | - private $tmp_ticks; | |
| 30 | + private $tmp_calls; | |
| 31 | + private $tmp_connections; | |
| 27 | 32 | |
| 28 | 33 | /** |
| 29 | 34 | * Initialize |
| 30 | 35 | */ |
| @@ -31,27 +36,59 @@ | ||
| 31 | 36 | public function __construct() { |
| 32 | 37 | |
| 33 | 38 | $microtime = sanitize_file_name( $_REQUEST['CODE_PROFILER_ON'] ); |
| 34 | 39 | |
| 35 | - $this->tmp_summary = CODE_PROFILER_UPLOAD_DIR ."/$microtime." . | |
| 36 | - CODE_PROFILER_TMP_SUMMARY_LOG; | |
| 37 | - $this->tmp_iostats = CODE_PROFILER_UPLOAD_DIR ."/$microtime." . | |
| 38 | - CODE_PROFILER_TMP_IOSTATS_LOG; | |
| 39 | - $this->tmp_ticks = CODE_PROFILER_UPLOAD_DIR ."/$microtime." . | |
| 40 | - CODE_PROFILER_TMP_TICKS_LOG; | |
| 41 | - $this->tmp_diskio = CODE_PROFILER_UPLOAD_DIR ."/$microtime." . | |
| 42 | - 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; | |
| 43 | 50 | |
| 44 | - // Clear the temporary log because the buffer will be written | |
| 45 | - // with the FILE_APPEND flag | |
| 46 | - if ( file_exists( $this->tmp_ticks ) ) { | |
| 47 | - unlink( $this->tmp_ticks ); | |
| 51 | + if ( function_exists('hrtime') ) { | |
| 52 | + // PHP >=7.3 | |
| 53 | + self::$metrics = 'hrtime'; | |
| 54 | + } else { | |
| 55 | + self::$metrics = 'microtime'; | |
| 48 | 56 | } |
| 49 | 57 | |
| 50 | - if ( version_compare( PHP_VERSION, '7.3', '<') ) { | |
| 51 | - self::$metrics = 'microtime'; | |
| 52 | - } else { | |
| 53 | - 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 | + } | |
| 54 | 91 | } |
| 55 | 92 | |
| 56 | 93 | $cp_options = get_option('code-profiler'); |
| 57 | 94 | if ( empty( $cp_options['accuracy'] ) ) { |
| @@ -60,11 +97,42 @@ | ||
| 60 | 97 | define('CODE_PROFILER_TICKS', (int) $cp_options['accuracy'] ); |
| 61 | 98 | } |
| 62 | 99 | define('CODE_PROFILER_LENGTH', 17 + strlen( (string) CODE_PROFILER_TICKS ) ); |
| 63 | 100 | |
| 64 | - register_shutdown_function( array( $this, 'code_profiler_shutdown') ); | |
| 101 | + if ( empty( $cp_options['buffer'] ) || | |
| 102 | + ! preg_match('/^(?:[1-9]|10)$/', $cp_options['buffer'] ) ) { | |
| 65 | 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 | + ); | |
| 66 | 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 | + | |
| 67 | 135 | CodeProfiler_Stream::start(); |
| 68 | 136 | register_tick_function( array( $this, 'code_profiler_tick_handler') ); |
| 69 | 137 | } |
| 70 | 138 | |
| @@ -74,10 +142,13 @@ | ||
| 74 | 142 | public function code_profiler_shutdown() { |
| 75 | 143 | |
| 76 | 144 | CodeProfiler_Stream::stop(); |
| 77 | 145 | |
| 78 | - $summary['memory'] = memory_get_peak_usage(); | |
| 79 | - $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; | |
| 80 | 151 | file_put_contents( $this->tmp_summary, json_encode( $summary ) ); |
| 81 | 152 | |
| 82 | 153 | // Catch potential error |
| 83 | 154 | $e = error_get_last(); |
| @@ -97,11 +168,11 @@ | ||
| 97 | 168 | if ( $res === false ) { |
| 98 | 169 | $msg = sprintf( $err_msg, $this->tmp_iostats ); |
| 99 | 170 | code_profiler_log_error( $msg ); |
| 100 | 171 | } |
| 101 | - $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 ); | |
| 102 | 173 | if ( $res === false ) { |
| 103 | - $msg = sprintf( $err_msg, $this->tmp_ticks ); | |
| 174 | + $msg = sprintf( $err_msg, $this->tmp_calls ); | |
| 104 | 175 | code_profiler_log_error( $msg ); |
| 105 | 176 | } |
| 106 | 177 | $res = file_put_contents( |
| 107 | 178 | $this->tmp_diskio, "read\t". CodeProfiler_Stream::$io_read ."\nwrite\t". |
| @@ -106,8 +177,11 @@ | ||
| 106 | 177 | $res = file_put_contents( |
| 107 | 178 | $this->tmp_diskio, "read\t". CodeProfiler_Stream::$io_read ."\nwrite\t". |
| 108 | 179 | CodeProfiler_Stream::$io_write |
| 109 | 180 | ); |
| 181 | + if (! empty( self::$connections_list ) ) { | |
| 182 | + file_put_contents( $this->tmp_connections, json_encode( self::$connections_list) ); | |
| 183 | + } | |
| 110 | 184 | } |
| 111 | 185 | |
| 112 | 186 | /** |
| 113 | 187 | * Our tick handler. |
| @@ -136,17 +210,14 @@ | ||
| 136 | 210 | self::$tick_list .= $backtrace[0]['file']; |
| 137 | 211 | } else { |
| 138 | 212 | self::$tick_list .= '-'; |
| 139 | 213 | } |
| 214 | + $backtrace = null; | |
| 140 | 215 | |
| 141 | 216 | // Buffer can grow *very* big hence we flush it every 10MB by default |
| 142 | 217 | if ( strlen( self::$tick_list ) > self::$buffer ) { |
| 143 | 218 | CodeProfiler_Stream::stop(); |
| 144 | - file_put_contents( | |
| 145 | - $this->tmp_ticks, | |
| 146 | - self::$tick_list ."\t{$start}\t". $this->time() ."\n", | |
| 147 | - FILE_APPEND | |
| 148 | - ); | |
| 219 | + fwrite( self::$fh, self::$tick_list ."\t{$start}\t". $this->time() ."\n" ); | |
| 149 | 220 | CodeProfiler_Stream::start(); |
| 150 | 221 | self::$tick_list = ''; |
| 151 | 222 | |
| 152 | 223 | } else { |
| @@ -153,8 +224,31 @@ | ||
| 153 | 224 | self::$tick_list .="\t{$start}\t". $this->time() ."\n"; |
| 154 | 225 | } |
| 155 | 226 | } |
| 156 | 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 | + } | |
| 157 | 251 | |
| 158 | 252 | /** |
| 159 | 253 | * Return time |
| 160 | 254 | */ |