Skip to content

Commit

Permalink
- MF20: Improve code coverage gathering performace by 1000%.
Browse files Browse the repository at this point in the history
SVN Rev: 2535
  • Loading branch information
derickr committed Oct 11, 2007
1 parent b22ffad commit 9e76e80
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 19 deletions.
2 changes: 1 addition & 1 deletion php_xdebug.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ ZEND_BEGIN_MODULE_GLOBALS(xdebug)
xdebug_hash *code_coverage; xdebug_hash *code_coverage;
zend_bool code_coverage_unused; zend_bool code_coverage_unused;
zend_bool code_coverage_dead_code_analysis; zend_bool code_coverage_dead_code_analysis;
xdebug_hash *code_coverage_op_array_cache;
unsigned int function_count; unsigned int function_count;
int reserved_offset;


/* used for collection errors */ /* used for collection errors */
zend_bool do_collect_errors; zend_bool do_collect_errors;
Expand Down
15 changes: 11 additions & 4 deletions xdebug.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -543,6 +543,8 @@ XDEBUG_OPCODE_OVERRIDE(concat)


PHP_MINIT_FUNCTION(xdebug) PHP_MINIT_FUNCTION(xdebug)
{ {
zend_extension dummy_ext;

ZEND_INIT_MODULE_GLOBALS(xdebug, php_xdebug_init_globals, php_xdebug_shutdown_globals); ZEND_INIT_MODULE_GLOBALS(xdebug, php_xdebug_init_globals, php_xdebug_shutdown_globals);
REGISTER_INI_ENTRIES(); REGISTER_INI_ENTRIES();
#if 0 #if 0
Expand Down Expand Up @@ -570,6 +572,9 @@ PHP_MINIT_FUNCTION(xdebug)
new_error_cb = xdebug_error_cb; new_error_cb = xdebug_error_cb;


#ifdef ZEND_ENGINE_2 #ifdef ZEND_ENGINE_2
/* Get reserved offset */
XG(reserved_offset) = zend_get_resource_handle(&dummy_ext);

/* Overload the "exit" opcode */ /* Overload the "exit" opcode */
XDEBUG_SET_OPCODE_OVERRIDE(exit, ZEND_EXIT); XDEBUG_SET_OPCODE_OVERRIDE(exit, ZEND_EXIT);
XDEBUG_SET_OPCODE_OVERRIDE(jmp, ZEND_JMP); XDEBUG_SET_OPCODE_OVERRIDE(jmp, ZEND_JMP);
Expand Down Expand Up @@ -728,7 +733,6 @@ PHP_RINIT_FUNCTION(xdebug)
XG(do_trace) = 0; XG(do_trace) = 0;
XG(do_code_coverage) = 0; XG(do_code_coverage) = 0;
XG(code_coverage) = xdebug_hash_alloc(32, xdebug_coverage_file_dtor); XG(code_coverage) = xdebug_hash_alloc(32, xdebug_coverage_file_dtor);
XG(code_coverage_op_array_cache) = xdebug_hash_alloc(1024, NULL);
XG(stack) = xdebug_llist_alloc(xdebug_stack_element_dtor); XG(stack) = xdebug_llist_alloc(xdebug_stack_element_dtor);
XG(trace_file) = NULL; XG(trace_file) = NULL;
XG(tracefile_name) = NULL; XG(tracefile_name) = NULL;
Expand Down Expand Up @@ -861,7 +865,6 @@ PHP_RSHUTDOWN_FUNCTION(xdebug)
XG(do_code_coverage) = 0; XG(do_code_coverage) = 0;


xdebug_hash_destroy(XG(code_coverage)); xdebug_hash_destroy(XG(code_coverage));
xdebug_hash_destroy(XG(code_coverage_op_array_cache));


if (XG(context.list.last_file)) { if (XG(context.list.last_file)) {
xdfree(XG(context).list.last_file); xdfree(XG(context).list.last_file);
Expand Down Expand Up @@ -1508,7 +1511,7 @@ void xdebug_execute(zend_op_array *op_array TSRMLS_DC)
} }


if (XG(do_code_coverage) && XG(code_coverage_unused)) { if (XG(do_code_coverage) && XG(code_coverage_unused)) {
xdebug_prefill_code_coverage(fse, op_array TSRMLS_CC); xdebug_prefill_code_coverage(op_array TSRMLS_CC);
} }


/* If we're in an eval, we need to create an ID for it. This ID however /* If we're in an eval, we need to create an ID for it. This ID however
Expand Down Expand Up @@ -2421,7 +2424,11 @@ zend_op_array *xdebug_compile_file(zend_file_handle *file_handle, int type TSRML
zend_op_array *op_array; zend_op_array *op_array;


op_array = old_compile_file(file_handle, type TSRMLS_CC); op_array = old_compile_file(file_handle, type TSRMLS_CC);

op_array->reserved[XG(reserved_offset)] = 0;

if (XG(do_code_coverage) && XG(code_coverage_unused)) {
xdebug_prefill_code_coverage(op_array TSRMLS_CC);
}
return op_array; return op_array;
} }
/* }}} */ /* }}} */
Expand Down
28 changes: 15 additions & 13 deletions xdebug_code_coverage.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void xdebug_count_line(char *filename, int lineno, int executable, int deadcode
xdfree(sline); xdfree(sline);
} }


static void prefill_from_opcode(function_stack_entry *fse, char *fn, zend_op opcode, int deadcode TSRMLS_DC) static void prefill_from_opcode(char *fn, zend_op opcode, int deadcode TSRMLS_DC)
{ {
if ( if (
opcode.opcode != ZEND_NOP && opcode.opcode != ZEND_NOP &&
Expand Down Expand Up @@ -220,19 +220,16 @@ static void xdebug_analyse_branch(zend_op_array *opa, unsigned int position, xde
xdebug_set_add(set, position); xdebug_set_add(set, position);
} }
} }
static void prefill_from_oparray(function_stack_entry *fse, char *fn, zend_op_array *opa TSRMLS_DC)
static void prefill_from_oparray(char *fn, zend_op_array *opa TSRMLS_DC)
{ {
char cache_key[256]; char cache_key[256];
int cache_key_len; int cache_key_len;
void *dummy; void *dummy;
unsigned int i; unsigned int i;
xdebug_set *set = NULL; xdebug_set *set = NULL;


cache_key_len = snprintf(cache_key, sizeof(cache_key) - 1, "%p", opa->opcodes); opa->reserved[XG(reserved_offset)] = 1;
if (xdebug_hash_find(XG(code_coverage_op_array_cache), cache_key, cache_key_len, (void*) &dummy)) {
return;
}
xdebug_hash_add(XG(code_coverage_op_array_cache), cache_key, cache_key_len, NULL);


#ifdef ZEND_ENGINE_2 #ifdef ZEND_ENGINE_2
/* Check for abstract methods and simply return from this function in those /* Check for abstract methods and simply return from this function in those
Expand All @@ -252,7 +249,7 @@ static void prefill_from_oparray(function_stack_entry *fse, char *fn, zend_op_ar
/* The normal loop then finally */ /* The normal loop then finally */
for (i = 0; i < opa->size; i++) { for (i = 0; i < opa->size; i++) {
zend_op opcode = opa->opcodes[i]; zend_op opcode = opa->opcodes[i];
prefill_from_opcode(NULL, fn, opcode, set ? !xdebug_set_in(set, i) : 0 TSRMLS_CC); prefill_from_opcode(fn, opcode, set ? !xdebug_set_in(set, i) : 0 TSRMLS_CC);
} }


if (set) { if (set) {
Expand All @@ -267,8 +264,8 @@ static int prefill_from_function_table(zend_op_array *opa, int num_args, va_list


new_filename = va_arg(args, char*); new_filename = va_arg(args, char*);
if (opa->type == ZEND_USER_FUNCTION) { if (opa->type == ZEND_USER_FUNCTION) {
if (opa->filename && strcmp(opa->filename, new_filename) == 0) { if (opa->reserved[XG(reserved_offset)] != 1/* && opa->filename && strcmp(opa->filename, new_filename) == 0)*/) {
prefill_from_oparray(NULL, new_filename, opa TSRMLS_CC); prefill_from_oparray(opa->filename, opa TSRMLS_CC);
} }
} }


Expand All @@ -292,15 +289,20 @@ static int prefill_from_class_table(zend_class_entry *class_entry, int num_args,


new_filename = va_arg(args, char*); new_filename = va_arg(args, char*);
if (ce->type == ZEND_USER_CLASS) { if (ce->type == ZEND_USER_CLASS) {
zend_hash_apply_with_arguments(&ce->function_table, (apply_func_args_t) prefill_from_function_table, 1, new_filename); if (!(ce->ce_flags & ZEND_XDEBUG_VISITED)) {
ce->ce_flags |= ZEND_XDEBUG_VISITED;
zend_hash_apply_with_arguments(&ce->function_table, (apply_func_args_t) prefill_from_function_table, 1, new_filename);
}
} }


return ZEND_HASH_APPLY_KEEP; return ZEND_HASH_APPLY_KEEP;
} }


void xdebug_prefill_code_coverage(function_stack_entry *fse, zend_op_array *op_array TSRMLS_DC) void xdebug_prefill_code_coverage(zend_op_array *op_array TSRMLS_DC)
{ {
prefill_from_oparray(fse, op_array->filename, op_array TSRMLS_CC); if (op_array->reserved[XG(reserved_offset)] == 0) {
prefill_from_oparray(op_array->filename, op_array TSRMLS_CC);
}


zend_hash_apply_with_arguments(CG(function_table), (apply_func_args_t) prefill_from_function_table, 1, op_array->filename); zend_hash_apply_with_arguments(CG(function_table), (apply_func_args_t) prefill_from_function_table, 1, op_array->filename);
zend_hash_apply_with_arguments(CG(class_table), (apply_func_args_t) prefill_from_class_table, 1, op_array->filename); zend_hash_apply_with_arguments(CG(class_table), (apply_func_args_t) prefill_from_class_table, 1, op_array->filename);
Expand Down
2 changes: 1 addition & 1 deletion xdebug_code_coverage.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void xdebug_coverage_line_dtor(void *data);
void xdebug_coverage_file_dtor(void *data); void xdebug_coverage_file_dtor(void *data);


void xdebug_count_line(char *file, int lineno, int executable, int deadcode TSRMLS_DC); void xdebug_count_line(char *file, int lineno, int executable, int deadcode TSRMLS_DC);
void xdebug_prefill_code_coverage(function_stack_entry *fse, zend_op_array *op_array TSRMLS_DC); void xdebug_prefill_code_coverage(zend_op_array *op_array TSRMLS_DC);


PHP_FUNCTION(xdebug_start_code_coverage); PHP_FUNCTION(xdebug_start_code_coverage);
PHP_FUNCTION(xdebug_stop_code_coverage); PHP_FUNCTION(xdebug_stop_code_coverage);
Expand Down
2 changes: 2 additions & 0 deletions xdebug_private.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ typedef struct xdebug_var {


#define XDEBUG_ERROR_ENCODING_NOT_SUPPORTED 900 #define XDEBUG_ERROR_ENCODING_NOT_SUPPORTED 900


#define ZEND_XDEBUG_VISITED 0x1000000

typedef struct _xdebug_func { typedef struct _xdebug_func {
char *class; char *class;
char *function; char *function;
Expand Down

0 comments on commit 9e76e80

Please sign in to comment.