diff -ur xdebug-2.0.0RC1/xdebug.c xdebug-2.0.0RC1.new/xdebug.c --- xdebug-2.0.0RC1/xdebug.c 2006-10-08 16:54:14.000000000 -0400 +++ xdebug-2.0.0RC1.new/xdebug.c 2006-10-27 00:57:30.000000000 -0400 @@ -976,8 +976,8 @@ if ( (strcmp(tmpf->common.function_name, "call_user_func") == 0) || (strcmp(tmpf->common.function_name, "call_user_func_array") == 0) || - (strcmp(tmpf->common.function_name, "call_user_func_method") == 0) || - (strcmp(tmpf->common.function_name, "call_user_func_method_array") == 0) + (strcmp(tmpf->common.function_name, "call_user_method") == 0) || + (strcmp(tmpf->common.function_name, "call_user_method_array") == 0) ) { tmp->filename = xdstrdup(((function_stack_entry*) XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack))))->filename); } diff -ur xdebug-2.0.0RC1/xdebug_profiler.c xdebug-2.0.0RC1.new/xdebug_profiler.c --- xdebug-2.0.0RC1/xdebug_profiler.c 2006-10-08 16:54:15.000000000 -0400 +++ xdebug-2.0.0RC1.new/xdebug_profiler.c 2006-10-27 17:05:22.000000000 -0400 @@ -146,33 +146,62 @@ #endif } +static int xdebug_profiler_skip_p(function_stack_entry* fse) { + return fse->prev && fse->function.function && + (!strcmp(fse->function.function, "call_user_func") || + !strcmp(fse->function.function, "call_user_func_array") || + !strcmp(fse->function.function, "call_user_method") || + !strcmp(fse->function.function, "call_without_strict") || + !strcmp(fse->function.function, "call_user_method_array") || + (fse->function.class && + !strcmp(fse->function.class, "Packages") && + !strcmp(fse->function.function, "need"))); +} + +static char* xdebug_profiler_fse_name(function_stack_entry* fse, int* default_lineno TSRMLS_DC) { + char *tmp_fname, *tmp_name; + + tmp_name = show_fname(fse->function, 0, 0 TSRMLS_CC); + switch (fse->function.type) { + case XFUNC_INCLUDE: + case XFUNC_INCLUDE_ONCE: + case XFUNC_REQUIRE: + case XFUNC_REQUIRE_ONCE: + tmp_fname = xdebug_sprintf("%s::%s", tmp_name, fse->include_filename); + xdfree(tmp_name); + tmp_name = tmp_fname; + if(default_lineno) { + *default_lineno = 1; + } + + break; + + default: + if(default_lineno) { + *default_lineno = fse->lineno; + } + + break; + } + + return tmp_name; +} + void xdebug_profiler_function_user_end(function_stack_entry *fse, zend_op_array* op_array TSRMLS_DC) { xdebug_llist_element *le; - char *tmp_fname, *tmp_name; + char *tmp_name; int default_lineno = 0; + xdebug_call_entry *ce = NULL; xdebug_profiler_function_push(fse); - tmp_name = show_fname(fse->function, 0, 0 TSRMLS_CC); - switch (fse->function.type) { - case XFUNC_INCLUDE: - case XFUNC_INCLUDE_ONCE: - case XFUNC_REQUIRE: - case XFUNC_REQUIRE_ONCE: - tmp_fname = xdebug_sprintf("%s::%s", tmp_name, fse->include_filename); - xdfree(tmp_name); - tmp_name = tmp_fname; - default_lineno = 1; - break; - - default: - default_lineno = fse->lineno; - break; - } - + + tmp_name = xdebug_profiler_fse_name(fse, &default_lineno); + //fprintf(stderr, "End of function '%s'\n", tmp_name); + if (fse->prev) { - xdebug_call_entry *ce = xdmalloc(sizeof(xdebug_call_entry)); + ce = xdmalloc(sizeof(xdebug_call_entry)); ce->filename = xdstrdup(fse->filename); ce->function = xdstrdup(tmp_name); ce->time_taken = fse->profile.time; @@ -181,10 +210,10 @@ #if HAVE_PHP_MEMORY_USAGE ce->mem_used = fse->profile.memory - XG_MEMORY_USAGE(); #endif - + xdebug_llist_insert_next(fse->prev->profile.call_list, NULL, ce); } - + if (op_array) { fprintf(XG(profile_file), "fl=%s\n", op_array->filename); } else { @@ -195,8 +224,7 @@ } else { fprintf(XG(profile_file), "fn=php::%s\n", tmp_name); } - xdfree(tmp_name); - + if (fse->function.function && strcmp(fse->function.function, "{main}") == 0) { #if HAVE_PHP_MEMORY_USAGE fprintf(XG(profile_file), "\nsummary: %lu %u\n\n", (unsigned long) (fse->profile.time * 10000000), XG_MEMORY_USAGE()); @@ -205,47 +233,94 @@ #endif } fflush(XG(profile_file)); - - /* update aggregate data */ - if (XG(profiler_aggregate)) { - fse->aggr_entry->time_inclusive += fse->profile.time; - fse->aggr_entry->call_count++; - } - + + double net_time_taken = fse->profile.time; + +#ifdef HAVE_PHP_MEMORY_USAGE + long net_mem_used = fse->memory; +#endif + /* Subtract time in calledfunction from time here */ for (le = XDEBUG_LLIST_HEAD(fse->profile.call_list); le != NULL; le = XDEBUG_LLIST_NEXT(le)) { xdebug_call_entry *call_entry = XDEBUG_LLIST_VALP(le); - fse->profile.time -= call_entry->time_taken; + net_time_taken -= call_entry->time_taken; #if HAVE_PHP_MEMORY_USAGE - fse->memory -= call_entry->mem_used; + net_mem_used -= call_entry->mem_used; #endif } + + /* Reassign children of this node to our parent if we've marked it as "skip" */ + if (xdebug_profiler_skip_p(fse)) { + + /* update aggregate data with net data */ + if (XG(profiler_aggregate)) { + fse->aggr_entry->time_inclusive += net_time_taken; + fse->aggr_entry->call_count++; + } + + /* xdebug_profiler_skip_p(fse) implies fse->prev, which + * implies that ce is valid */ + ce->time_taken = net_time_taken; + #if HAVE_PHP_MEMORY_USAGE - fprintf(XG(profile_file), "%d %lu %ld\n", default_lineno, (unsigned long) (fse->profile.time * 10000000), (XG_MEMORY_USAGE() - fse->profile.memory) < 0 ? 0 : (XG_MEMORY_USAGE() - fse->profile.memory)); + ce->mem_used = net_mem_used; +#endif + + /* Move the call list to the parent call list; if + * xdebug_profile_p is true, we know there is a parent */ + char* prevname = xdebug_profiler_fse_name(fse->prev, NULL); + + for(le = XDEBUG_LLIST_HEAD(fse->profile.call_list); le != NULL; le = XDEBUG_LLIST_NEXT(le)) + { + xdebug_call_entry *ce1 = XDEBUG_LLIST_VALP(le); + xdebug_call_entry *ce2 = xdmalloc(sizeof(xdebug_call_entry)); + memcpy(ce2, ce1, sizeof(xdebug_call_entry)); + ce2->filename = ce1->filename ? xdstrdup(ce1->filename) : NULL; + ce2->function = ce1->function ? xdstrdup(ce1->function) : NULL; + xdebug_llist_insert_next(fse->prev->profile.call_list, NULL, ce2); + //fprintf(stderr, " moving '%s' from '%s' to '%s'\n", ce2->function, + // tmp_name, prevname); + } + + xdebug_llist_empty(fse->profile.call_list, NULL); + xdfree(prevname); + } else { + /* update aggregate data with gross data */ + if (XG(profiler_aggregate)) { + fse->aggr_entry->time_inclusive += fse->profile.time; + fse->aggr_entry->call_count++; + } + } + +#if HAVE_PHP_MEMORY_USAGE + fprintf(XG(profile_file), "%d %lu %ld\n", default_lineno, (unsigned long) (net_time_taken * 10000000), (XG_MEMORY_USAGE() - fse->profile.memory) < 0 ? 0 : (XG_MEMORY_USAGE() - fse->profile.memory)); #else fprintf(XG(profile_file), "%d %lu\n", default_lineno, (unsigned long) (fse->profile.time * 10000000)); #endif - + /* update aggregate data */ if (XG(profiler_aggregate)) { - fse->aggr_entry->time_own += fse->profile.time; + fse->aggr_entry->time_own += net_time_taken; #if HAVE_PHP_MEMORY_USAGE - fse->aggr_entry->mem_used += fse->memory; + fse->aggr_entry->mem_used += net_mem_used; #endif } - + /* dump call list */ for (le = XDEBUG_LLIST_HEAD(fse->profile.call_list); le != NULL; le = XDEBUG_LLIST_NEXT(le)) { xdebug_call_entry *call_entry = XDEBUG_LLIST_VALP(le); - + if (call_entry->user_defined == XDEBUG_EXTERNAL) { fprintf(XG(profile_file), "cfn=%s\n", call_entry->function); } else { fprintf(XG(profile_file), "cfn=php::%s\n", call_entry->function); } + //fprintf(stderr, " call item: %s\n", call_entry->function); + + fprintf(XG(profile_file), "calls=1 0 0\n"); #if HAVE_PHP_MEMORY_USAGE fprintf(XG(profile_file), "%d %lu %ld\n", call_entry->lineno, (unsigned long) (call_entry->time_taken * 10000000), call_entry->mem_used < 0 ? 0 : call_entry->mem_used); @@ -253,8 +328,13 @@ fprintf(XG(profile_file), "%d %lu\n", call_entry->lineno, (unsigned long) (call_entry->time_taken * 10000000)); #endif } + fprintf(XG(profile_file), "\n"); fflush(XG(profile_file)); + xdfree(tmp_name); + + fse->profile.time = net_time_taken; + fse->memory = net_mem_used; }