diff --git a/README.md b/README.md index b1b21e4..2952b64 100644 --- a/README.md +++ b/README.md @@ -226,6 +226,12 @@ seaslog.trace_performance_start_depth = 1 ;Performance Tracking Depth Level. 5(Default) seaslog.trace_performance_max_depth = 5 +;Performance trace namespace/class filtering, empty default, multiple values concatenated with a comma (used to limit the scope of the class trace, the following example will trace App\xxoo or Service\xxoo, commonly used in frameworks, specifying the trace namespace) +seaslog.trace_performance_include_class_prefix=App,Services + +;Performance trace Function name filter, default null, multiple values concatenated with a comma (used to limit the scope of Function tracing for non-class members, the following example will trace only two functions, config() and app()). +seaslog.trace_performance_include_function_prefix=config,app + ;Maximum number of functions per layer in descending order of wall_time for performance tracking. ;Top default top5 seaslog.trace_performance_max_functions_per_depth = 5 diff --git a/README_zh.md b/README_zh.md index 820e7ce..c999476 100644 --- a/README_zh.md +++ b/README_zh.md @@ -216,6 +216,12 @@ seaslog.trace_performance_start_depth = 1 ;性能追踪时深度层级 默认5层 seaslog.trace_performance_max_depth = 5 +;性能追踪 命名空间/类 过滤,默认为空,多个值用半角逗号连接(用于限定类追踪范围,下面示例将会追踪 App\xxoo 或 Service\xxoo,常用于框架,指定追踪命名空间) +seaslog.trace_performance_include_class_prefix=App,Services + +;性能追踪 函数名 过滤,默认为空,多个值用半角逗号连接(用于限定非类成员Function追踪范围,下面示例只会追踪 config() 和 app() 两个Function) +seaslog.trace_performance_include_function_prefix=config,app + ;性能追踪时每层的函数最大数 按wall_time降序排列top 默认top5 seaslog.trace_performance_max_functions_per_depth = 5 diff --git a/include/Performance.h b/include/Performance.h index 48ca983..f88c31c 100644 --- a/include/Performance.h +++ b/include/Performance.h @@ -25,6 +25,10 @@ void seaslog_peak_memory_usage(smart_str *buf TSRMLS_DC); void init_zend_hooks(TSRMLS_D); void recovery_zend_hooks(TSRMLS_D); +void init_performance(TSRMLS_D); +void clear_performance(TSRMLS_D); +void include_prefix_list(char *include_str, int *res_include_list_count, char ***res_include_list TSRMLS_DC); + void seaslog_rinit_performance(TSRMLS_D); void seaslog_clear_performance(zend_class_entry *ce TSRMLS_DC); int seaslog_check_performance_active(TSRMLS_D); diff --git a/php_seaslog.h b/php_seaslog.h index bd364fc..9d28f0e 100644 --- a/php_seaslog.h +++ b/php_seaslog.h @@ -96,6 +96,12 @@ ZEND_BEGIN_MODULE_GLOBALS(seaslog) zend_bool trace_error; zend_bool trace_exception; + int trace_performance_include_class_prefix_count; + int trace_performance_include_function_prefix_count; + char *trace_performance_include_class_prefix; + char *trace_performance_include_function_prefix; + char **trace_performance_include_class_prefix_list; + char **trace_performance_include_function_prefix_list; int trace_performance_active; int trace_performance_sample_active; zend_bool trace_performance; diff --git a/seaslog.c b/seaslog.c index d07be04..2666a6c 100644 --- a/seaslog.c +++ b/seaslog.c @@ -244,6 +244,8 @@ STD_PHP_INI_BOOLEAN("seaslog.throw_exception", "1", PHP_INI_ALL, OnUpdateBool, t STD_PHP_INI_BOOLEAN("seaslog.ignore_warning", "1", PHP_INI_ALL, OnUpdateBool, ignore_warning, zend_seaslog_globals, seaslog_globals) STD_PHP_INI_BOOLEAN("seaslog.trace_performance", "0", PHP_INI_SYSTEM, OnUpdateBool, trace_performance, zend_seaslog_globals, seaslog_globals) +STD_PHP_INI_ENTRY("seaslog.trace_performance_include_class_prefix", "", PHP_INI_ALL, OnUpdateString, trace_performance_include_class_prefix, zend_seaslog_globals, seaslog_globals) +STD_PHP_INI_ENTRY("seaslog.trace_performance_include_function_prefix", "", PHP_INI_ALL, OnUpdateString, trace_performance_include_function_prefix, zend_seaslog_globals, seaslog_globals) STD_PHP_INI_ENTRY("seaslog.trace_performance_sample_rate", "10", PHP_INI_ALL, OnUpdateLongGEZero, trace_performance_sample_rate, zend_seaslog_globals, seaslog_globals) STD_PHP_INI_ENTRY("seaslog.trace_performance_start_depth", "1", PHP_INI_ALL, OnUpdateLongGEZero, trace_performance_start_depth, zend_seaslog_globals, seaslog_globals) STD_PHP_INI_ENTRY("seaslog.trace_performance_max_depth", "5", PHP_INI_ALL, OnUpdateLongGEZero, trace_performance_max_depth, zend_seaslog_globals, seaslog_globals) @@ -315,12 +317,15 @@ PHP_MINIT_FUNCTION(seaslog) init_buffer_switch(TSRMLS_C); init_remote_timeout(TSRMLS_C); init_zend_hooks(TSRMLS_C); + init_performance(TSRMLS_C); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(seaslog) { + clear_performance(TSRMLS_C); + recovery_error_hooks(TSRMLS_C); recovery_exception_hooks(TSRMLS_C); recovery_zend_hooks(TSRMLS_C); diff --git a/src/Performance.c b/src/Performance.c index c0c0c12..f6b034c 100644 --- a/src/Performance.c +++ b/src/Performance.c @@ -146,6 +146,91 @@ void recovery_zend_hooks(TSRMLS_D) } } +void init_performance(TSRMLS_D) +{ + SEASLOG_G(trace_performance_include_class_prefix_count) = 0; + SEASLOG_G(trace_performance_include_function_prefix_count) = 0; + SEASLOG_G(trace_performance_include_class_prefix_list) = NULL; + SEASLOG_G(trace_performance_include_function_prefix_list) = NULL; + + if (!SEASLOG_G(trace_performance)) + { + return; + } + + int include_class_str_len = strlen(SEASLOG_G(trace_performance_include_class_prefix)); + if (include_class_str_len > 0) + { + include_prefix_list( + SEASLOG_G(trace_performance_include_class_prefix), + &SEASLOG_G(trace_performance_include_class_prefix_count), + &SEASLOG_G(trace_performance_include_class_prefix_list)); + } + + int include_function_str_len = strlen(SEASLOG_G(trace_performance_include_function_prefix)); + if (include_function_str_len > 0) + { + include_prefix_list( + SEASLOG_G(trace_performance_include_function_prefix), + &SEASLOG_G(trace_performance_include_function_prefix_count), + &SEASLOG_G(trace_performance_include_function_prefix_list)); + } +} + +void clear_performance(TSRMLS_D) +{ + if (SEASLOG_G(trace_performance_include_class_prefix_count) > 0) { + for (int i = 0; i < SEASLOG_G(trace_performance_include_class_prefix_count); ++i) { + efree(SEASLOG_G(trace_performance_include_class_prefix_list)[i]); + } + + efree(SEASLOG_G(trace_performance_include_class_prefix_list)); + } + + if (SEASLOG_G(trace_performance_include_function_prefix_count) > 0) { + for (int i = 0; i < SEASLOG_G(trace_performance_include_function_prefix_count); ++i) { + efree(SEASLOG_G(trace_performance_include_function_prefix_list)[i]); + } + + efree(SEASLOG_G(trace_performance_include_function_prefix_list)); + } +} + +void include_prefix_list(char *include_str, int *res_include_list_count, char ***res_include_list TSRMLS_DC) +{ + int prefix_index = 0; + int prefix_count = 0; + + for (int i = 0; i < strlen(include_str); ++i) + { + if (include_str[i] == ',') + { + prefix_count++; + prefix_index = i; + } + } + + if (strlen(include_str) > prefix_index) { + prefix_count++; + } + + *res_include_list_count = prefix_count; + + char **include_prefix_list = (char **)emalloc(prefix_count * sizeof(char *)); + char *include_prefix = strtok(include_str, ","); + + while(include_prefix != NULL) + { + char *prefix = (char *)emalloc(strlen(include_prefix) * sizeof(char)); + strcpy(prefix, include_prefix); + include_prefix_list[prefix_count - 1] = prefix; + include_prefix = strtok(NULL, ","); + prefix_count--; + } + + *res_include_list = include_prefix_list; +} + void seaslog_rinit_performance(TSRMLS_D) { if (SEASLOG_G(trace_performance)) @@ -296,11 +381,13 @@ ZEND_DLEXPORT void seaslog_execute_internal(zend_execute_data *execute_data, int int performance_frame_begin(zend_execute_data *execute_data TSRMLS_DC) { - char *function; + char *function, *class; seaslog_frame *current_frame; seaslog_frame *p; int recurse_level = 0; int stack_level = 0; + int hit_include_class = -1; + int hit_include_function = -1; if (FAILURE == seaslog_check_performance_sample(TSRMLS_C)) { @@ -318,16 +405,67 @@ int performance_frame_begin(zend_execute_data *execute_data TSRMLS_DC) return FAILURE; } + class = seaslog_performance_get_class_name(execute_data TSRMLS_CC); + if (class != NULL) + { + for (int i = 0; i < SEASLOG_G(trace_performance_include_class_prefix_count); ++i) + { + char *class_prefix = SEASLOG_G(trace_performance_include_class_prefix_list)[i]; + + if (strlen(class) >= strlen(class_prefix) && !memcmp(class, class_prefix, strlen(class_prefix))) + { + hit_include_class = i; + break; + } + } + + if (SEASLOG_G(trace_performance_include_class_prefix_count) > 0 && hit_include_class == -1) + { + efree(class); + efree(function); + return FAILURE; + } + } + + if (class == NULL && function != NULL) + { + for (int i = 0; i < SEASLOG_G(trace_performance_include_function_prefix_count); ++i) + { + char *function_prefix = SEASLOG_G(trace_performance_include_function_prefix_list)[i]; + + if (strlen(function) >= strlen(function_prefix) && !memcmp(function, function_prefix, strlen(function_prefix))) + { + hit_include_function = i; + break; + } + } + + if (SEASLOG_G(trace_performance_include_function_prefix_count) > 0 && hit_include_function == -1) + { + efree(function); + return FAILURE; + } + } + SEASLOG_G(stack_level) += 1; if (SEASLOG_G(stack_level) - SEASLOG_G(trace_performance_start_depth) < 0) { - efree(function); + if (function != NULL) + { + efree(function); + } + + if (class != NULL) + { + efree(class); + } + return SEASLOG_CONTINUE; } current_frame = seaslog_performance_fast_alloc_frame(TSRMLS_C); - current_frame->class_name = seaslog_performance_get_class_name(execute_data TSRMLS_CC); + current_frame->class_name = class; current_frame->function_name = function; current_frame->previous_frame = SEASLOG_G(performance_frames); current_frame->wt_start = performance_microsecond(TSRMLS_C); @@ -411,9 +549,29 @@ static inline void seaslog_performance_bucket_process(seaslog_frame* current_fra bucket->count = 0; bucket->wall_time = 0; bucket->memory = 0; - bucket->next = SEASLOG_G(performance_buckets)[slot]; + bucket->next = NULL; + + seaslog_performance_bucket *slot_bucket_list = SEASLOG_G(performance_buckets)[slot]; + + if (slot_bucket_list == NULL) + { + SEASLOG_G(performance_buckets)[slot] = bucket; + } + else + { + int indexxx = 0; + + do { + if (slot_bucket_list->next == NULL) + { + slot_bucket_list->next = bucket; + break; + } - SEASLOG_G(performance_buckets)[slot] = bucket; + indexxx+=1; + slot_bucket_list = slot_bucket_list->next; + } while (slot_bucket_list); + } } bucket->count++; @@ -583,60 +741,22 @@ int process_seaslog_performance_log(zend_class_entry *ce TSRMLS_DC) } SEASLOG_PERFORMANCE_BUCKET_FOREACH(bucket, i) - SEASLOG_G(performance_buckets)[i] = bucket->next; - - if (bucket->stack_level <= SEASLOG_G(trace_performance_max_depth) && bucket->wall_time >= trace_performance_min_function_wall_time) - { - stack_level = bucket->stack_level - 1; + do { + SEASLOG_G(performance_buckets)[i] = bucket->next; - for (n = 0; n < SEASLOG_G(trace_performance_max_functions_per_depth); n++) + if (bucket->stack_level <= SEASLOG_G(trace_performance_max_depth) && bucket->wall_time >= trace_performance_min_function_wall_time) { - if (result_array[stack_level][n]->hash_code == 0 && n == 0) - { - result_array[stack_level][n]->hash_code = bucket->hash_code; - result_array[stack_level][n]->wall_time = bucket->wall_time; - result_array[stack_level][n]->count = bucket->count; - result_array[stack_level][n]->memory = bucket->memory; + stack_level = bucket->stack_level - 1; - if (NULL == bucket->class_name) - { - spprintf(&result_array[stack_level][n]->function,0,"%s",bucket->function_name); - } - else - { - spprintf(&result_array[stack_level][n]->function,0,"%s::%s",bucket->class_name,bucket->function_name); - } - break; - } - else + for (n = 0; n < SEASLOG_G(trace_performance_max_functions_per_depth); n++) { - if (result_array[stack_level][n]->wall_time >= bucket->wall_time) + if (result_array[stack_level][n]->hash_code == 0 && n == 0) { - continue; - } - else - { - for (r = SEASLOG_G(trace_performance_max_functions_per_depth) - 1; r > n; r--) - { - if (result_array[stack_level][r-1]->hash_code == 0 && result_array[stack_level][r-1]->wall_time == 0) - { - continue; - } - - result_forward = result_array[stack_level][r]; - result_array[stack_level][r] = result_array[stack_level][r-1]; - result_array[stack_level][r-1] = result_forward; - } - - if (result_array[stack_level][n]->hash_code > 0) - { - efree(result_array[stack_level][n]->function); - } - result_array[stack_level][n]->hash_code = bucket->hash_code; result_array[stack_level][n]->wall_time = bucket->wall_time; result_array[stack_level][n]->count = bucket->count; result_array[stack_level][n]->memory = bucket->memory; + if (NULL == bucket->class_name) { spprintf(&result_array[stack_level][n]->function,0,"%s",bucket->function_name); @@ -647,11 +767,52 @@ int process_seaslog_performance_log(zend_class_entry *ce TSRMLS_DC) } break; } + else + { + if (result_array[stack_level][n]->wall_time >= bucket->wall_time) + { + continue; + } + else + { + for (r = SEASLOG_G(trace_performance_max_functions_per_depth) - 1; r > n; r--) + { + if (result_array[stack_level][r-1]->hash_code == 0 && result_array[stack_level][r-1]->wall_time == 0) + { + continue; + } + + result_forward = result_array[stack_level][r]; + result_array[stack_level][r] = result_array[stack_level][r-1]; + result_array[stack_level][r-1] = result_forward; + } + + if (result_array[stack_level][n]->hash_code > 0) + { + efree(result_array[stack_level][n]->function); + } + + result_array[stack_level][n]->hash_code = bucket->hash_code; + result_array[stack_level][n]->wall_time = bucket->wall_time; + result_array[stack_level][n]->count = bucket->count; + result_array[stack_level][n]->memory = bucket->memory; + if (NULL == bucket->class_name) + { + spprintf(&result_array[stack_level][n]->function,0,"%s",bucket->function_name); + } + else + { + spprintf(&result_array[stack_level][n]->function,0,"%s::%s",bucket->class_name,bucket->function_name); + } + break; + } + } } } - } - seaslog_performance_bucket_free(bucket TSRMLS_CC); - bucket = SEASLOG_G(performance_buckets)[i]; + seaslog_performance_bucket_free(bucket TSRMLS_CC); + + bucket = SEASLOG_G(performance_buckets)[i]; + } while (bucket); SEASLOG_PERFORMANCE_BUCKET_FOREACH_END; SEASLOG_ARRAY_INIT(performance_log_array);