From 3a4a1a2c0912e20e076ef81fd35c8a85a105f63d Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Fri, 16 Feb 2018 16:58:33 -0500 Subject: [PATCH 1/5] Support for Sampling interval --- extension/xhprof.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/extension/xhprof.c b/extension/xhprof.c index 4636697d..976448cb 100644 --- a/extension/xhprof.c +++ b/extension/xhprof.c @@ -101,7 +101,8 @@ #define XHPROF_FLAGS_MEMORY 0x0004 /* gather memory usage for funcs */ /* Constants for XHPROF_MODE_SAMPLED */ -#define XHPROF_SAMPLING_INTERVAL 100000 /* In microsecs */ +#define XHPROF_DEFAULT_SAMPLING_INTERVAL 100000 /* In microsecs */ +#define XHPROF_MINIMAL_SAMPLING_INTERVAL 100 /* In microsecs */ #if !defined(uint64) typedef unsigned long long uint64; @@ -189,7 +190,9 @@ typedef struct hp_global_t { struct timeval last_sample_time; uint64 last_sample_tsc; /* XHPROF_SAMPLING_INTERVAL in ticks */ + long sampling_interval; uint64 sampling_interval_tsc; + int sampling_depth; /* This array is used to store cpu frequencies for all available logical * cpus. For now, we assume the cpu frequencies will not change for power @@ -327,6 +330,9 @@ zend_module_entry xhprof_module_entry = { STANDARD_MODULE_PROPERTIES }; +#define STRINGIFY_(X) #X +#define STRINGIFY(X) STRINGIFY_(X) + PHP_INI_BEGIN() /* output directory: @@ -337,6 +343,16 @@ PHP_INI_BEGIN() */ PHP_INI_ENTRY("xhprof.output_dir", "", PHP_INI_ALL, NULL) +/* sampling_interval: + * Sampling interval to be used by the sampling profiler, in microseconds. + */ +STD_PHP_INI_ENTRY("xhprof.sampling_interval", STRINGIFY(XHPROF_DEFAULT_SAMPLING_INTERVAL), PHP_INI_ALL, OnUpdateLong, sampling_interval, hp_global_t, hp_globals) + +/* sampling_depth: + * Depth to trace call-chain by the sampling profiler + */ +STD_PHP_INI_ENTRY("xhprof.sampling_depth", STRINGIFY(INT_MAX), PHP_INI_ALL, OnUpdateLong, sampling_depth, hp_global_t, hp_globals) + PHP_INI_END() /* Init module */ @@ -449,6 +465,10 @@ PHP_MINIT_FUNCTION(xhprof) { hp_globals.func_hash_counters[i] = 0; } + if (hp_globals.sampling_interval < XHPROF_MINIMAL_SAMPLING_INTERVAL) { + hp_globals.sampling_interval = XHPROF_MINIMAL_SAMPLING_INTERVAL; + } + #if defined(DEBUG) /* To make it random number generator repeatable to ease testing. */ srand(0); @@ -520,6 +540,8 @@ PHP_MINFO_FUNCTION(xhprof) } php_info_print_table_end(); + + DISPLAY_INI_ENTRIES(); } @@ -1019,7 +1041,7 @@ void hp_sample_stack(hp_entry_t **entries TSRMLS_DC) { /* Init stats in the global stats_count hashtable */ hp_get_function_stack(*entries, - INT_MAX, + hp_globals.sampling_depth, symbol, sizeof(symbol)); @@ -1053,7 +1075,7 @@ void hp_sample_check(hp_entry_t **entries TSRMLS_DC) { hp_globals.last_sample_tsc += hp_globals.sampling_interval_tsc; /* bump last_sample_time - HAS TO BE UPDATED BEFORE calling hp_sample_stack */ - incr_us_interval(&hp_globals.last_sample_time, XHPROF_SAMPLING_INTERVAL); + incr_us_interval(&hp_globals.last_sample_time, hp_globals.sampling_interval); /* sample the stack */ hp_sample_stack(entries TSRMLS_CC); @@ -1339,7 +1361,7 @@ void hp_mode_sampled_init_cb(TSRMLS_D) { /* Find the microseconds that need to be truncated */ gettimeofday(&hp_globals.last_sample_time, 0); now = hp_globals.last_sample_time; - hp_trunc_time(&hp_globals.last_sample_time, XHPROF_SAMPLING_INTERVAL); + hp_trunc_time(&hp_globals.last_sample_time, hp_globals.sampling_interval); /* Subtract truncated time from last_sample_tsc */ truncated_us = get_us_interval(&hp_globals.last_sample_time, &now); @@ -1351,7 +1373,7 @@ void hp_mode_sampled_init_cb(TSRMLS_D) { /* Convert sampling interval to ticks */ hp_globals.sampling_interval_tsc = - get_tsc_from_us(XHPROF_SAMPLING_INTERVAL, cpu_freq); + get_tsc_from_us(hp_globals.sampling_interval, cpu_freq); } From aef9953507dc758e16e190a5929f395aa165780a Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Wed, 21 Feb 2018 17:14:32 -0500 Subject: [PATCH 2/5] Handle opline not being set due to use of create_function --- extension/xhprof.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/extension/xhprof.c b/extension/xhprof.c index 976448cb..7d9349b7 100644 --- a/extension/xhprof.c +++ b/extension/xhprof.c @@ -870,6 +870,13 @@ static zend_string *xhprof_get_opline_name( } const zend_op *opline = execute_data->prev_execute_data->opline; + + /* In some cases, such as functions from `create_function` + * opline will not be set. */ + if (!zend_op) { + return NULL; + } + const char *label; int include_filename = 0; From 503449553d2f7e2b98a826a81614f7be13778d61 Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Wed, 21 Feb 2018 17:17:56 -0500 Subject: [PATCH 3/5] Fix var name --- extension/xhprof.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/xhprof.c b/extension/xhprof.c index 7d9349b7..0cf72e71 100644 --- a/extension/xhprof.c +++ b/extension/xhprof.c @@ -873,7 +873,7 @@ static zend_string *xhprof_get_opline_name( /* In some cases, such as functions from `create_function` * opline will not be set. */ - if (!zend_op) { + if (!opline) { return NULL; } From 30c753b52de10d75e521e420187b6541520d8b3a Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Mon, 30 Apr 2018 20:28:25 -0400 Subject: [PATCH 4/5] Handle opline being an invalid pointer --- extension/xhprof.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/extension/xhprof.c b/extension/xhprof.c index 0cf72e71..ab94363a 100644 --- a/extension/xhprof.c +++ b/extension/xhprof.c @@ -869,6 +869,12 @@ static zend_string *xhprof_get_opline_name( return NULL; } + /* In some cases, the opline member is an invalid + * pointer to 0x1 due to unknown reasons. */ + if (execute_data->prev_execute_data->opline == 0x1) { + return NULL; + } + const zend_op *opline = execute_data->prev_execute_data->opline; /* In some cases, such as functions from `create_function` From 5a9fdf9475906c0063d6cab3fa609ac4bd0609f5 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 22 Aug 2018 12:06:18 +1000 Subject: [PATCH 5/5] Handle eval from unknown source This applies the correction that debug_print_backtrace() uses internally. --- extension/xhprof.c | 68 ++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/extension/xhprof.c b/extension/xhprof.c index ab94363a..e7b8433c 100644 --- a/extension/xhprof.c +++ b/extension/xhprof.c @@ -869,46 +869,42 @@ static zend_string *xhprof_get_opline_name( return NULL; } - /* In some cases, the opline member is an invalid - * pointer to 0x1 due to unknown reasons. */ - if (execute_data->prev_execute_data->opline == 0x1) { - return NULL; - } - - const zend_op *opline = execute_data->prev_execute_data->opline; - - /* In some cases, such as functions from `create_function` - * opline will not be set. */ - if (!opline) { - return NULL; - } + const zend_execute_data *prev = execute_data->prev_execute_data; const char *label; int include_filename = 0; - switch (opline->extended_value) { - case ZEND_EVAL: - label = "eval"; - break; - case ZEND_INCLUDE: - label = "include"; - include_filename = 1; - break; - case ZEND_REQUIRE: - label = "require"; - include_filename = 1; - break; - case ZEND_INCLUDE_ONCE: - label = "include_once"; - include_filename = 1; - break; - case ZEND_REQUIRE_ONCE: - label = "require_once"; - include_filename = 1; - break; - default: - label = "(unknown-internal-op)"; - break; + if (!prev->func || !ZEND_USER_CODE(prev->func->common.type)|| prev->opline->opcode != ZEND_INCLUDE_OR_EVAL) { + /* can happen when calling eval from a custom sapi + * per https://github.com/php/php-src/blob/ab8094c666048b747481df0b9da94e08cadc4160/Zend/zend_builtin_functions.c#L2376 */ + label = "(unknown-internal-op)"; + } else { + const zend_op *opline = prev->opline; + + switch (opline->extended_value) { + case ZEND_EVAL: + label = "eval"; + break; + case ZEND_INCLUDE: + label = "include"; + include_filename = 1; + break; + case ZEND_REQUIRE: + label = "require"; + include_filename = 1; + break; + case ZEND_INCLUDE_ONCE: + label = "include_once"; + include_filename = 1; + break; + case ZEND_REQUIRE_ONCE: + label = "require_once"; + include_filename = 1; + break; + default: + label = "(unknown-internal-op)"; + break; + } } int len = strlen(label) + 2 + 1;