[xdebug-dev] xdebug xdebug/php_xdebug.h xdebug/xdebug.c xdebug/xdebug_private.h xdebug/xdebug_profiler.c xdebug/xdebug_profiler.h - Added profiling aggregation functions (patch by Andrei Zmievski)

From: Derick Rethans <derick[@]derickrethans.nl>
Date: Tue, 31 Jan 2006 22:04:05 +0100

Date: Tue Jan 31 22:04:04 CET 2006
User: Derick Rethans
Directory: xdebug

Log Message:
[10.00]
- Added profiling aggregation functions (patch by Andrei Zmievski)

Modified files:
           xdebug/php_xdebug.h (version: 1.100)
           xdebug/xdebug.c (version: 1.294)
           xdebug/xdebug_private.h (version: 1.18)
           xdebug/xdebug_profiler.c (version: 1.33)
           xdebug/xdebug_profiler.h (version: 1.11)

[FILE: /xdebug/php_xdebug.h]

===================================================================
RCS file: cvstemp,v
retrieving revision 1.99
retrieving revision 1.100
diff -u -r1.99 -r1.100
--- xdebug/php_xdebug.h:1.99 Tue Jan 17 19:58:35 2006 GMT
+++ xdebug/php_xdebug.h Tue Jan 31 20:04:04 2006 GMT
@@ -85,6 +85,8 @@
 
 /* profiling functions */
 PHP_FUNCTION(xdebug_get_profiler_filename);
+PHP_FUNCTION(xdebug_dump_aggr_profiling_data);
+PHP_FUNCTION(xdebug_clear_aggr_profiling_data);
 
 /* misc functions */
 PHP_FUNCTION(xdebug_dump_superglobals);
@@ -183,6 +185,10 @@
         int stderr_redirected;
         int stdin_redirected;
 
+ /* aggregate profiling */
+ HashTable aggr_calls;
+ zend_bool profiler_aggregate;
+
 ZEND_END_MODULE_GLOBALS(xdebug)
 
 #ifdef ZTS

[FILE: /xdebug/xdebug.c]

===================================================================
RCS file: cvstemp,v
retrieving revision 1.293
retrieving revision 1.294
diff -u -r1.293 -r1.294
--- xdebug/xdebug.c:1.293 Wed Jan 25 07:49:15 2006 GMT
+++ xdebug/xdebug.c Tue Jan 31 20:04:04 2006 GMT
@@ -144,7 +144,9 @@
         PHP_FE(xdebug_stop_trace, NULL)
         PHP_FE(xdebug_get_tracefile_name, NULL)
 
- PHP_FE(xdebug_get_profiler_filename, NULL)
+ PHP_FE(xdebug_get_profiler_filename, NULL)
+ PHP_FE(xdebug_dump_aggr_profiling_data, NULL)
+ PHP_FE(xdebug_clear_aggr_profiling_data, NULL)
 
 #if MEMORY_LIMIT
         PHP_FE(xdebug_memory_usage, NULL)
@@ -311,6 +313,7 @@
         STD_PHP_INI_ENTRY("xdebug.profiler_output_name", "crc32", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, profiler_output_name, zend_xdebug_globals, xdebug_globals)
         STD_PHP_INI_BOOLEAN("xdebug.profiler_enable_trigger", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, profiler_enable_trigger, zend_xdebug_globals, xdebug_globals)
         STD_PHP_INI_BOOLEAN("xdebug.profiler_append", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, profiler_append, zend_xdebug_globals, xdebug_globals)
+ STD_PHP_INI_BOOLEAN("xdebug.profiler_aggregate", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, profiler_aggregate, zend_xdebug_globals, xdebug_globals)
 
         /* Remote debugger settings */
         STD_PHP_INI_BOOLEAN("xdebug.remote_enable", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, remote_enable, zend_xdebug_globals, xdebug_globals)
@@ -512,6 +515,9 @@
         /* get xdebug ini entries from the environment also */
         xdebug_env_config();
 
+ /* initialize aggregate call information hash */
+ zend_hash_init_ex(&XG(aggr_calls), 50, NULL, (dtor_func_t) profile_aggr_call_entry_dtor, 1, 0);
+
         /* Redirect compile and execute functions to our own */
         old_compile_file = zend_compile_file;
         zend_compile_file = xdebug_compile_file;
@@ -575,14 +581,31 @@
 }
 
 
+static xdebug_output_aggr_data(TSRMLS_D)
+{
+ xdebug_aggregate_entry *xae;
+
+ zend_hash_internal_pointer_reset(&XG(aggr_calls));
+ while (zend_hash_get_current_data(&XG(aggr_calls), (void**)&xae) == SUCCESS) {
+ fprintf(stderr, "filename=%s\nfunction=%s\nlineno=%d\ntime_own=%lu\ntime_inclusive=%lu\n\n", xae->filename, xae->function, xae->lineno, (unsigned long) (xae->time_own * 10000000), (unsigned long) (xae->time_inclusive * 10000000));
+ zend_hash_move_forward(&XG(aggr_calls));
+ }
+}
+
 PHP_MSHUTDOWN_FUNCTION(xdebug)
 {
+ if (XG(profiler_aggregate)) {
+ xdebug_profiler_output_aggr_data(NULL TSRMLS_C);
+ }
+
         /* Reset compile, execute and error callbacks */
         zend_compile_file = old_compile_file;
         zend_execute = xdebug_old_execute;
         zend_execute_internal = xdebug_old_execute_internal;
         zend_error_cb = old_error_cb;
 
+ zend_hash_destroy(&XG(aggr_calls));
+
 #ifdef ZTS
         ts_free_id(xdebug_globals_id);
 #else
@@ -878,6 +901,8 @@
         void **p;
         int arg_count = 0;
         int i = 0;
+ char *aggr_key;
+ int aggr_key_len;
 
         if (EG(argument_stack).top >= 2) {
                 p = EG(argument_stack).top_element - 2;
@@ -991,14 +1016,58 @@
                 xdebug_count_line(tmp->filename, tmp->lineno, 0 TSRMLS_CC);
         }
 
+ if (XG(profiler_aggregate)) {
+ char *func_name = show_fname(tmp->function, 0, 0 TSRMLS_CC);
+
+ aggr_key = xdebug_sprintf("%s.%s.%d", tmp->filename, func_name, tmp->lineno);
+ aggr_key_len = strlen(aggr_key);
+
+ if (zend_hash_find(&XG(aggr_calls), aggr_key, aggr_key_len+1, (void**)&tmp->aggr_entry) == FAILURE) {
+ xdebug_aggregate_entry xae;
+
+ if (tmp->user_defined == XDEBUG_EXTERNAL) {
+ xae.filename = xdstrdup(tmp->op_array->filename);
+ } else {
+ xae.filename = xdstrdup("php:internal");
+ }
+ xae.function = func_name;
+ xae.lineno = tmp->lineno;
+ xae.user_defined = tmp->user_defined;
+ xae.call_count = 0;
+ xae.time_own = 0;
+ xae.time_inclusive = 0;
+#if MEMORY_LIMIT
+ xae.frame.mem_used = 0;
+#endif
+ xae.call_list = NULL;
+
+ zend_hash_add(&XG(aggr_calls), aggr_key, aggr_key_len+1, (void*)&xae, sizeof(xdebug_aggregate_entry), (void**)&tmp->aggr_entry);
+ }
+ }
+
         if (XDEBUG_LLIST_TAIL(XG(stack))) {
                 function_stack_entry *prev = XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack)));
                 tmp->prev = prev;
+ if (XG(profiler_aggregate)) {
+ if (prev->aggr_entry->call_list) {
+ if (!zend_hash_exists(prev->aggr_entry->call_list, aggr_key, aggr_key_len+1)) {
+ zend_hash_add(prev->aggr_entry->call_list, aggr_key, aggr_key_len+1, (void*)&tmp->aggr_entry, sizeof(xdebug_aggregate_entry*), NULL);
+ }
+ } else {
+ prev->aggr_entry->call_list = xdmalloc(sizeof(HashTable));
+ zend_hash_init_ex(prev->aggr_entry->call_list, 1, NULL, NULL, 1, 0);
+ zend_hash_add(prev->aggr_entry->call_list, aggr_key, aggr_key_len+1, (void*)&tmp->aggr_entry, sizeof(xdebug_aggregate_entry*), NULL);
+ }
+ }
         } else {
                 tmp->prev = 0;
         }
         xdebug_llist_insert_next(XG(stack), XDEBUG_LLIST_TAIL(XG(stack)), tmp);
 
+ if (XG(profiler_aggregate)) {
+ xdfree(aggr_key);
+ }
+
         return tmp;
 }
 
@@ -2284,6 +2353,37 @@
         }
 }
 
+PHP_FUNCTION(xdebug_dump_aggr_profiling_data)
+{
+ char *prefix = NULL;
+ int prefix_len;
+
+ if (!XG(profiler_aggregate)) {
+ RETURN_FALSE;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &prefix, &prefix_len) == FAILURE) {
+ return;
+ }
+
+ if (xdebug_profiler_output_aggr_data(prefix TSRMLS_CC) == SUCCESS) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+}
+
+PHP_FUNCTION(xdebug_clear_aggr_profiling_data)
+{
+ if (!XG(profiler_aggregate)) {
+ RETURN_FALSE;
+ }
+
+ zend_hash_clean(&XG(aggr_calls));
+
+ RETURN_TRUE;
+}
+
 #if MEMORY_LIMIT
 PHP_FUNCTION(xdebug_memory_usage)
 {

[FILE: /xdebug/xdebug_private.h]

===================================================================
RCS file: cvstemp,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- xdebug/xdebug_private.h:1.17 Fri Jan 27 08:22:44 2006 GMT
+++ xdebug/xdebug_private.h Tue Jan 31 20:04:04 2006 GMT
@@ -124,6 +124,18 @@
         long mem_used;
 } xdebug_call_entry;
 
+typedef struct xdebug_aggregate_entry {
+ int user_defined;
+ char *filename;
+ char *function;
+ int lineno;
+ int call_count;
+ double time_own;
+ double time_inclusive;
+ long mem_used;
+ HashTable *call_list;
+} xdebug_aggregate_entry;
+
 typedef struct xdebug_profile {
         double time;
         double mark;
@@ -166,6 +178,7 @@
         int refcount;
         struct _function_stack_entry *prev;
         zend_op_array *op_array;
+ xdebug_aggregate_entry *aggr_entry;
 } function_stack_entry;
 
 function_stack_entry *xdebug_get_stack_head(TSRMLS_D);

[FILE: /xdebug/xdebug_profiler.c]

===================================================================
RCS file: cvstemp,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -r1.32 -r1.33
--- xdebug/xdebug_profiler.c:1.32 Sun Jan 01 14:27:27 2006 GMT
+++ xdebug/xdebug_profiler.c Tue Jan 31 20:04:04 2006 GMT
@@ -31,6 +31,17 @@
 
 ZEND_EXTERN_MODULE_GLOBALS(xdebug)
 
+void profile_aggr_call_entry_dtor(void *elem)
+{
+ xdebug_aggregate_entry *xae = (xdebug_aggregate_entry *) elem;
+ if (xae->filename) {
+ xdfree(xae->filename);
+ }
+ if (xae->function) {
+ xdfree(xae->function);
+ }
+}
+
 void profile_call_entry_dtor(void *dummy, void *elem)
 {
         xdebug_call_entry *ce = elem;
@@ -176,6 +187,12 @@
         }
         fflush(XG(profile_file));
 
+ /* update aggregate data */
+ if (XG(profiler_aggregate)) {
+ fse->aggr_entry->time_inclusive += fse->profile.time;
+ fse->aggr_entry->call_count++;
+ }
+
         /* Subtract time in calledfunction from time here */
         for (le = XDEBUG_LLIST_HEAD(fse->profile.call_list); le != NULL; le = XDEBUG_LLIST_NEXT(le))
         {
@@ -191,6 +208,14 @@
         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;
+#if MEMORY_LIMIT
+ fse->aggr_entry->mem_used += fse->memory;
+#endif
+ }
+
         /* dump call list */
         for (le = XDEBUG_LLIST_HEAD(fse->profile.call_list); le != NULL; le = XDEBUG_LLIST_NEXT(le))
         {
@@ -225,4 +250,68 @@
         xdebug_profiler_function_user_end(fse, NULL TSRMLS_CC);
 }
 
+static int xdebug_print_aggr_entry(void *pDest, void *argument TSRMLS_DC)
+{
+ FILE *fp = (FILE *) argument;
+ xdebug_aggregate_entry *xae = (xdebug_aggregate_entry *) pDest;
+
+ fprintf(fp, "fl=%s\n", xae->filename);
+ fprintf(fp, "fn=%s\n", xae->function);
+#if MEMORY_LIMIT
+ fprintf(fp, "%d %lu %ld\n", 0, (unsigned long) (xae->time_own * 10000000), (xae->mem_used < 0) ? 0 : xae->mem_used);
+#else
+ fprintf(fp, "%d %lu\n", 0, (unsigned long) (xae->time_own * 10000000));
+#endif
+ if (strcmp(xae->function, "{main}") == 0) {
+#if MEMORY_LIMIT
+ fprintf(fp, "\nsummary: %lu %u\n\n", (unsigned long) (xae->time_inclusive * 10000000), (xae->mem_used));
+#else
+ fprintf(fp, "\nsummary: %lu\n\n", (unsigned long) (xae->time_inclusive * 10000000), (xae->mem_used));
+#endif
+ }
+ if (xae->call_list) {
+ xdebug_aggregate_entry **xae_call;
 
+ zend_hash_internal_pointer_reset(xae->call_list);
+ while (zend_hash_get_current_data(xae->call_list, (void**)&xae_call) == SUCCESS) {
+ fprintf(fp, "cfn=%s\n", (*xae_call)->function);
+ fprintf(fp, "calls=%d 0 0\n", (*xae_call)->call_count);
+#if MEMORY_LIMIT
+ fprintf(fp, "%d %lu %ld\n", (*xae_call)->lineno, (unsigned long) ((*xae_call)->time_inclusive * 10000000), (*xae_call)->mem_used < 0 ? 0 : (*xae_call)->mem_used);
+#else
+ fprintf(fp, "%d %lu\n", (*xae_call)->lineno, (unsigned long) ((*xae_call)->time_inclusive * 10000000));
+#endif
+ zend_hash_move_forward(xae->call_list);
+ }
+ }
+ fprintf(fp, "\n");
+ fflush(fp);
+}
+
+int xdebug_profiler_output_aggr_data(const char *prefix TSRMLS_DC)
+{
+ char *filename;
+ FILE *aggr_file;
+
+ fprintf(stderr, "in xdebug_profiler_output_aggr_data() with %d entries\n", zend_hash_num_elements(&XG(aggr_calls)));
+
+ if (zend_hash_num_elements(&XG(aggr_calls)) == 0) return SUCCESS;
+
+ if (prefix) {
+ filename = xdebug_sprintf("%s/cachegrind.out.aggregate.%s.%ld", XG(profiler_output_dir), prefix, getpid());
+ } else {
+ filename = xdebug_sprintf("%s/cachegrind.out.aggregate.%ld", XG(profiler_output_dir), getpid());
+ }
+
+ fprintf(stderr, "opening %s\n", filename);
+ aggr_file = fopen(filename, "w");
+ if (!aggr_file) {
+ return FAILURE;
+ }
+ fprintf(aggr_file, "version: 0.9.6\npart: 1\n\nevents: Time Memory\n\n");
+ fflush(aggr_file);
+ zend_hash_apply_with_argument(&XG(aggr_calls), xdebug_print_aggr_entry, aggr_file TSRMLS_CC);
+ fclose(aggr_file);
+ fprintf(stderr, "wrote info for %d entries to %s\n", zend_hash_num_elements(&XG(aggr_calls)), filename);
+ return SUCCESS;
+}

[FILE: /xdebug/xdebug_profiler.h]

===================================================================
RCS file: cvstemp,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- xdebug/xdebug_profiler.h:1.10 Sun Jan 01 14:27:27 2006 GMT
+++ xdebug/xdebug_profiler.h Tue Jan 31 20:04:04 2006 GMT
@@ -26,6 +26,7 @@
 
 int xdebug_profiler_init(char *script_name TSRMLS_DC);
 void xdebug_profiler_deinit(TSRMLS_D);
+int xdebug_profiler_output_aggr_data(const char *prefix TSRMLS_DC);
 
 void xdebug_profiler_function_user_begin(function_stack_entry *fse TSRMLS_DC);
 void xdebug_profiler_function_user_end(function_stack_entry *fse, zend_op_array *op_array TSRMLS_DC);
@@ -33,5 +34,6 @@
 void xdebug_profiler_function_internal_end(function_stack_entry *fse TSRMLS_DC);
 
 void profile_call_entry_dtor(void *dummy, void *elem);
+void profile_aggr_call_entry_dtor(void *elem);
 
 #endif
Received on Tue Jan 31 2006 - 22:04:15 GMT

This archive was generated by hypermail 2.2.0 : Sun Jun 24 2018 - 04:00:03 BST