From 5230b6047ffa71294cab849a16169847164390bc Mon Sep 17 00:00:00 2001 From: Xuefer Date: Sun, 1 Oct 2006 08:57:51 +0000 Subject: [PATCH] coverager: new api xcache_coverager_start/xcache_coverager_stop/xcache_coverager_get(), coverager ini changed git-svn-id: svn://svn.lighttpd.net/xcache/trunk@204 c26eb9a1-5813-0410-bd6c-c2e55f420ca7 --- coverager.c | 188 +++++++++++++++++++++++++++++++++++++------ coverager.h | 5 +- xcache-zh-gb2312.ini | 8 +- xcache.c | 13 ++- xcache.ini | 12 +-- xcache_globals.h | 3 +- 6 files changed, 189 insertions(+), 40 deletions(-) diff --git a/coverager.c b/coverager.c index c34c5da..8215ed0 100644 --- a/coverager.c +++ b/coverager.c @@ -15,7 +15,7 @@ typedef HashTable *coverager_t; #define PCOV_HEADER_MAGIC 0x564f4350 -char *xc_coveragedump_dir = NULL; +static char *xc_coveragedump_dir = NULL; static zend_compile_file_t *origin_compile_file; #undef DEBUG @@ -192,34 +192,66 @@ bailout: if (buf) efree(buf); } /* }}} */ -void xc_coverager_request_init(TSRMLS_D) /* {{{ */ + +static void xc_coverager_initenv(TSRMLS_D) /* {{{ */ { - if (XG(coveragedumper)) { + if (!XG(coverages)) { XG(coverages) = emalloc(sizeof(HashTable)); zend_hash_init(XG(coverages), 0, NULL, xc_destroy_coverage, 0); } } /* }}} */ -void xc_coverager_request_shutdown(TSRMLS_D) /* {{{ */ +static void xc_coverager_clean(TSRMLS_D) /* {{{ */ +{ + if (XG(coverages)) { + zend_hash_destroy(XG(coverages)); + efree(XG(coverages)); + XG(coverages) = NULL; + } +} +/* }}} */ + +static void xc_coverager_enable(TSRMLS_D) /* {{{ */ +{ + XG(coverage_enabled) = 1; +} +/* }}} */ +static void xc_coverager_disable(TSRMLS_D) /* {{{ */ +{ + XG(coverage_enabled) = 0; +} +/* }}} */ + +void xc_coverager_request_init(TSRMLS_D) /* {{{ */ +{ + if (XG(coveragedumper)) { + xc_coverager_enable(TSRMLS_C); + xc_coverager_initenv(TSRMLS_C); + CG(extended_info) = 1; + } + else { + XG(coverage_enabled) = 0; + } +} +/* }}} */ +static void xc_coverager_autodump(TSRMLS_D) /* {{{ */ { coverager_t *pcov; zstr s; char *outfilename; int dumpdir_len, outfilelen, alloc_len = 0; uint size; + HashPosition pos; - if (!XG(coverages)) { - return; - } - if (XG(coveragedumper)) { + if (XG(coverages) && xc_coveragedump_dir) { dumpdir_len = strlen(xc_coveragedump_dir); alloc_len = dumpdir_len + 1 + 128; outfilename = emalloc(alloc_len); strcpy(outfilename, xc_coveragedump_dir); - zend_hash_internal_pointer_reset(XG(coverages)); - while (zend_hash_get_current_data(XG(coverages), (void **) &pcov) == SUCCESS) { - zend_hash_get_current_key_ex(XG(coverages), &s, &size, NULL, 0, NULL); + zend_hash_internal_pointer_reset_ex(XG(coverages), &pos); + while (zend_hash_get_current_data_ex(XG(coverages), (void **) &pcov, &pos) == SUCCESS) { + zend_hash_get_current_key_ex(XG(coverages), &s, &size, NULL, 0, &pos); outfilelen = dumpdir_len + size + 5; if (alloc_len < outfilelen) { alloc_len = outfilelen + 128; @@ -232,14 +264,56 @@ void xc_coverager_request_shutdown(TSRMLS_D) /* {{{ */ fprintf(stderr, "outfilename %s\n", outfilename); #endif xc_coverager_save_cov(ZSTR_S(s), outfilename, *pcov TSRMLS_CC); - zend_hash_move_forward(XG(coverages)); + zend_hash_move_forward_ex(XG(coverages), &pos); } efree(outfilename); } +} +/* }}} */ +static void xc_coverager_dump(zval *return_value TSRMLS_DC) /* {{{ */ +{ + coverager_t *pcov; + HashPosition pos; - zend_hash_destroy(XG(coverages)); - efree(XG(coverages)); - XG(coverages) = NULL; + if (XG(coverages)) { + array_init(return_value); + + zend_hash_internal_pointer_reset_ex(XG(coverages), &pos); + while (zend_hash_get_current_data_ex(XG(coverages), (void **) &pcov, &pos) == SUCCESS) { + zval *lines; + long *phits; + coverager_t cov; + HashPosition pos2; + zstr filename; + uint size; + + cov = *pcov; + zend_hash_get_current_key_ex(XG(coverages), &filename, &size, NULL, 0, &pos); + + MAKE_STD_ZVAL(lines); + array_init(lines); + zend_hash_internal_pointer_reset_ex(cov, &pos2); + while (zend_hash_get_current_data_ex(cov, (void**)&phits, &pos2) == SUCCESS) { + long hits = *phits; + add_index_long(lines, pos2->h, hits >= 0 ? hits : 0); + zend_hash_move_forward_ex(cov, &pos2); + } + add_assoc_zval_ex(return_value, ZSTR_S(filename), strlen(ZSTR_S(filename)) + 1, lines); + + zend_hash_move_forward_ex(XG(coverages), &pos); + } + } + else { + RETVAL_NULL(); + } +} +/* }}} */ +void xc_coverager_request_shutdown(TSRMLS_D) /* {{{ */ +{ + if (XG(coveragedumper)) { + xc_coverager_autodump(TSRMLS_C); + xc_coverager_clean(TSRMLS_C); + } } /* }}} */ @@ -350,8 +424,11 @@ static zend_op_array *xc_compile_file_for_coverage(zend_file_handle *h, int type zend_op_array *op_array; op_array = origin_compile_file(h, type TSRMLS_CC); - if (XG(coveragedumper) && XG(coverages) && op_array) { - xc_coverager_init_compile_result(op_array TSRMLS_CC); + if (op_array) { + if (XG(coveragedumper)) { + xc_coverager_initenv(TSRMLS_C); + xc_coverager_init_compile_result(op_array TSRMLS_CC); + } } return op_array; } @@ -362,7 +439,7 @@ void xc_coverager_handle_ext_stmt(zend_op_array *op_array, zend_uchar op) /* {{{ { TSRMLS_FETCH(); - if (XG(coveragedumper) && XG(coverages)) { + if (XG(coverages) && XG(coverage_enabled)) { int size = xc_coverager_get_op_array_size_no_tail(op_array); int oplineno = (*EG(opline_ptr)) - op_array->opcodes; if (oplineno < size) { @@ -375,19 +452,21 @@ void xc_coverager_handle_ext_stmt(zend_op_array *op_array, zend_uchar op) /* {{{ /* init/destroy */ int xc_coverager_init(int module_number TSRMLS_DC) /* {{{ */ { - if (xc_coveragedump_dir) { + origin_compile_file = zend_compile_file; + zend_compile_file = xc_compile_file_for_coverage; + + if (cfg_get_string("xcache.coveragedump_directory", &xc_coveragedump_dir) == SUCCESS && xc_coveragedump_dir) { int len = strlen(xc_coveragedump_dir); if (len) { if (xc_coveragedump_dir[len - 1] == '/') { xc_coveragedump_dir[len - 1] = '\0'; } } + if (!strlen(xc_coveragedump_dir)) { + xc_coveragedump_dir = NULL; + } } - if (xc_coveragedump_dir && xc_coveragedump_dir[0]) { - origin_compile_file = zend_compile_file; - zend_compile_file = xc_compile_file_for_coverage; - CG(extended_info) = 1; - } + return SUCCESS; } /* }}} */ @@ -397,14 +476,16 @@ void xc_coverager_destroy() /* {{{ */ zend_compile_file = origin_compile_file; } if (xc_coveragedump_dir) { - pefree(xc_coveragedump_dir, 1); xc_coveragedump_dir = NULL; } } /* }}} */ /* user api */ -PHP_FUNCTION(xcache_coverager_decode) /* {{{ */ +/* {{{ proto array xcache_coverager_decode(string data) + * decode specified data which is saved by auto dumper to array + */ +PHP_FUNCTION(xcache_coverager_decode) { char *str; int len; @@ -433,4 +514,59 @@ PHP_FUNCTION(xcache_coverager_decode) /* {{{ */ } } /* }}} */ +/* {{{ proto void xcache_coverager_start([bool clean = true]) + * starts coverager data collecting + */ +PHP_FUNCTION(xcache_coverager_start) +{ + zend_bool clean = 1; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean) == FAILURE) { + return; + } + + if (clean) { + xc_coverager_clean(TSRMLS_C); + } + + if (XG(coveragedumper)) { + xc_coverager_enable(TSRMLS_C); + } + else { + php_error(E_WARNING, "You can only start coverager after you set 'xcache.coveragedumper' to 'On' in ini"); + } +} +/* }}} */ +/* {{{ proto void xcache_coverager_stop([bool clean = false]) + * stop coverager data collecting + */ +PHP_FUNCTION(xcache_coverager_stop) +{ + zend_bool clean = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean) == FAILURE) { + return; + } + + xc_coverager_disable(TSRMLS_C); + if (clean) { + xc_coverager_clean(TSRMLS_C); + } +} +/* }}} */ +/* {{{ proto array xcache_coverager_get([bool clean = false]) + * get coverager data collected + */ +PHP_FUNCTION(xcache_coverager_get) +{ + zend_bool clean = 0; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean) == FAILURE) { + return; + } + + xc_coverager_dump(return_value TSRMLS_CC); + if (clean) { + xc_coverager_clean(TSRMLS_C); + } +} +/* }}} */ diff --git a/coverager.h b/coverager.h index ce560ae..defd3ae 100644 --- a/coverager.h +++ b/coverager.h @@ -1,11 +1,12 @@ #include "php.h" #include "xcache.h" -extern char *xc_coveragedump_dir; - void xc_coverager_handle_ext_stmt(zend_op_array *op_array, zend_uchar op); int xc_coverager_init(int module_number TSRMLS_DC); void xc_coverager_destroy(); void xc_coverager_request_init(TSRMLS_D); void xc_coverager_request_shutdown(TSRMLS_D); PHP_FUNCTION(xcache_coverager_decode); +PHP_FUNCTION(xcache_coverager_start); +PHP_FUNCTION(xcache_coverager_stop); +PHP_FUNCTION(xcache_coverager_get); diff --git a/xcache-zh-gb2312.ini b/xcache-zh-gb2312.ini index 3a633c5..b3a6307 100644 --- a/xcache-zh-gb2312.ini +++ b/xcache-zh-gb2312.ini @@ -65,8 +65,10 @@ xcache.stat = On xcache.optimizer = Off [xcache.coverager] -; 请确保本目录能被 coverage viewer 脚本读取 (注意 open_basedir) -xcache.coveragedump_directory = "/tmp/pcov/" ; 如果 xcache.coveragedump_directory 设置为空则本设置自动为 Off -xcache.coveragedumper = Off +xcache.coverager = Off + +; 请确保本目录能被 coverage viewer 脚本读取 (注意 open_basedir) +; 依赖于 xcache.coverager=On +xcache.coveragedump_directory = "" diff --git a/xcache.c b/xcache.c index b825288..5fef18d 100644 --- a/xcache.c +++ b/xcache.c @@ -2025,6 +2025,9 @@ static function_entry xcache_functions[] = /* {{{ */ #endif #ifdef HAVE_XCACHE_COVERAGER PHP_FE(xcache_coverager_decode, NULL) + PHP_FE(xcache_coverager_start, NULL) + PHP_FE(xcache_coverager_stop, NULL) + PHP_FE(xcache_coverager_get, NULL) #endif PHP_FE(xcache_get_special_value, NULL) PHP_FE(xcache_get_op_type, NULL) @@ -2157,8 +2160,8 @@ PHP_INI_BEGIN() #endif STD_PHP_INI_BOOLEAN("xcache.var_ttl", "0", PHP_INI_ALL, OnUpdateLong, var_ttl, zend_xcache_globals, xcache_globals) #ifdef HAVE_XCACHE_COVERAGER - PHP_INI_ENTRY1 ("xcache.coveragedump_directory", "/tmp/pcov/", PHP_INI_SYSTEM, xc_OnUpdateString, &xc_coveragedump_dir) - STD_PHP_INI_BOOLEAN("xcache.coveragedumper" , "0", PHP_INI_ALL, OnUpdateBool, coveragedumper, zend_xcache_globals, xcache_globals) + STD_PHP_INI_BOOLEAN("xcache.coverager" , "0", PHP_INI_ALL, OnUpdateBool, coverager, zend_xcache_globals, xcache_globals) + PHP_INI_ENTRY1 ("xcache.coveragedump_directory", "", PHP_INI_SYSTEM, xc_OnUpdateDummy, NULL) #endif PHP_INI_END() /* }}} */ @@ -2169,6 +2172,7 @@ static PHP_MINFO_FUNCTION(xcache) char *ptr; int left, len; xc_shm_scheme_t *scheme; + char *covdumpdir; php_info_print_table_start(); php_info_print_table_header(2, "XCache Support", "enabled"); @@ -2206,7 +2210,10 @@ static PHP_MINFO_FUNCTION(xcache) php_info_print_table_row(2, "Shared Memory Schemes", buf); #ifdef HAVE_XCACHE_COVERAGER - php_info_print_table_row(2, "Coverage Dumper", XG(coveragedumper) && xc_coveragedump_dir && xc_coveragedump_dir[0] ? "enabled" : "disabled"); + if (cfg_get_string("xcache.coveragedump_directory", &covdumpdir) != SUCCESS || !covdumpdir[0]) { + covdumpdir = NULL; + } + php_info_print_table_row(2, "Coverage Auto Dumper", XG(coverager) && covdumpdir ? "enabled" : "disabled"); #endif php_info_print_table_end(); diff --git a/xcache.ini b/xcache.ini index a40de23..79b1949 100644 --- a/xcache.ini +++ b/xcache.ini @@ -63,9 +63,11 @@ xcache.stat = On xcache.optimizer = Off [xcache.coverager] -; ini only settings -; make sure it's readable (care open_basedir) coverage viewer script -xcache.coveragedump_directory = "/tmp/pcov/" +; per request settings +; enable coverage data collecting for xcache.coveragedump_directory and xcache_coverager_start/stop/get/clean() functions (will hurt executing performance) +xcache.coverager = Off -; per request settings, will be auto disabled if xcache.coveragedump_directory is not set -xcache.coveragedumper = Off +; ini only settings +; make sure it's readable (care open_basedir) by coverage viewer script +; requires xcache.coverager=On +xcache.coveragedump_directory = "" diff --git a/xcache_globals.h b/xcache_globals.h index f6c5c90..f42229a 100644 --- a/xcache_globals.h +++ b/xcache_globals.h @@ -6,7 +6,8 @@ ZEND_BEGIN_MODULE_GLOBALS(xcache) zend_bool optimizer; /* true if enabled */ #endif #ifdef HAVE_XCACHE_COVERAGER - zend_bool coveragedumper; + zend_bool coverager; + zend_bool coverage_enabled; HashTable *coverages; /* coverages[file][line] = times */ #endif xc_stack_t *php_holds;