PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/mysqlnd - mysqlnd_debug.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 3 310 1.0 %
Date: 2016-08-17 Functions: 1 11 9.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | PHP Version 7                                                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2006-2016 The PHP Group                                |
       6             :   +----------------------------------------------------------------------+
       7             :   | This source file is subject to version 3.01 of the PHP license,      |
       8             :   | that is bundled with this package in the file LICENSE, and is        |
       9             :   | available through the world-wide-web at the following url:           |
      10             :   | http://www.php.net/license/3_01.txt                                  |
      11             :   | If you did not receive a copy of the PHP license and are unable to   |
      12             :   | obtain it through the world-wide-web, please send a note to          |
      13             :   | license@php.net so we can mail you a copy immediately.               |
      14             :   +----------------------------------------------------------------------+
      15             :   | Authors: Andrey Hristov <andrey@php.net>                             |
      16             :   |          Ulf Wendel <uw@php.net>                                     |
      17             :   +----------------------------------------------------------------------+
      18             : */
      19             : 
      20             : #include "php.h"
      21             : #include "mysqlnd.h"
      22             : #include "mysqlnd_priv.h"
      23             : #include "mysqlnd_debug.h"
      24             : 
      25             : static const char * const mysqlnd_debug_default_trace_file = "/tmp/mysqlnd.trace";
      26             : static const char * const mysqlnd_debug_empty_string = "";
      27             : 
      28             : 
      29             : /* {{{ mysqlnd_debug::open */
      30             : static enum_func_status
      31           0 : MYSQLND_METHOD(mysqlnd_debug, open)(MYSQLND_DEBUG * self, zend_bool reopen)
      32             : {
      33           0 :         if (!self->file_name) {
      34           0 :                 return FAIL;
      35             :         }
      36             : 
      37           0 :         self->stream = php_stream_open_wrapper(self->file_name,
      38             :                                                                                    reopen == TRUE || self->flags & MYSQLND_DEBUG_APPEND? "ab":"wb",
      39             :                                                                                    REPORT_ERRORS, NULL);
      40           0 :         return self->stream? PASS:FAIL;
      41             : }
      42             : /* }}} */
      43             : 
      44             : 
      45             : /* {{{ mysqlnd_debug::log */
      46             : static enum_func_status
      47           0 : MYSQLND_METHOD(mysqlnd_debug, log)(MYSQLND_DEBUG * self,
      48             :                                                                    unsigned int line, const char * const file,
      49             :                                                                    unsigned int level, const char * type, const char * message)
      50             : {
      51             :         char pipe_buffer[512];
      52             :         enum_func_status ret;
      53             :         int i;
      54             :         char * message_line;
      55             :         unsigned int message_line_len;
      56           0 :         unsigned int flags = self->flags;
      57             :         char pid_buffer[10], time_buffer[30], file_buffer[200],
      58             :                  line_buffer[6], level_buffer[7];
      59             : 
      60           0 :         if (!self->stream && FAIL == self->m->open(self, FALSE)) {
      61           0 :                 return FAIL;
      62             :         }
      63             : 
      64           0 :         if (level == -1) {
      65           0 :                 level = zend_stack_count(&self->call_stack);
      66             :         }
      67           0 :         i = MIN(level, sizeof(pipe_buffer) / 2  - 1);
      68           0 :         pipe_buffer[i*2] = '\0';
      69           0 :         for (;i > 0;i--) {
      70           0 :                 pipe_buffer[i*2 - 1] = ' ';
      71           0 :                 pipe_buffer[i*2 - 2] = '|';
      72             :         }
      73             : 
      74             : 
      75           0 :         if (flags & MYSQLND_DEBUG_DUMP_PID) {
      76           0 :                 snprintf(pid_buffer, sizeof(pid_buffer) - 1, "%5u: ", self->pid);
      77           0 :                 pid_buffer[sizeof(pid_buffer) - 1 ] = '\0';
      78             :         }
      79           0 :         if (flags & MYSQLND_DEBUG_DUMP_TIME) {
      80             :                 /* The following from FF's DBUG library, which is in the public domain */
      81             : #if defined(PHP_WIN32)
      82             :                 /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
      83             :                 in system ticks, 10 ms intervals. See my_getsystime.c for high res */
      84             :                 SYSTEMTIME loc_t;
      85             :                 GetLocalTime(&loc_t);
      86             :                 snprintf(time_buffer, sizeof(time_buffer) - 1,
      87             :                                  /* "%04d-%02d-%02d " */
      88             :                                  "%02d:%02d:%02d.%06d ",
      89             :                                  /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
      90             :                                  loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
      91             :                 time_buffer[sizeof(time_buffer) - 1 ] = '\0';
      92             : #else
      93             :                 struct timeval tv;
      94             :                 struct tm *tm_p;
      95           0 :                 if (gettimeofday(&tv, NULL) != -1) {
      96           0 :                         if ((tm_p= localtime((const time_t *)&tv.tv_sec))) {
      97           0 :                                 snprintf(time_buffer, sizeof(time_buffer) - 1,
      98             :                                                  /* "%04d-%02d-%02d " */
      99             :                                                  "%02d:%02d:%02d.%06d ",
     100             :                                                  /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
     101             :                                                  tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
     102           0 :                                                  (int) (tv.tv_usec));
     103           0 :                                 time_buffer[sizeof(time_buffer) - 1 ] = '\0';
     104             :                         }
     105             :                 }
     106             : #endif
     107             :         }
     108           0 :         if (flags & MYSQLND_DEBUG_DUMP_FILE) {
     109           0 :                 snprintf(file_buffer, sizeof(file_buffer) - 1, "%14s: ", file);
     110           0 :                 file_buffer[sizeof(file_buffer) - 1 ] = '\0';
     111             :         }
     112           0 :         if (flags & MYSQLND_DEBUG_DUMP_LINE) {
     113           0 :                 snprintf(line_buffer, sizeof(line_buffer) - 1, "%5u: ", line);
     114           0 :                 line_buffer[sizeof(line_buffer) - 1 ] = '\0';
     115             :         }
     116           0 :         if (flags & MYSQLND_DEBUG_DUMP_LEVEL) {
     117           0 :                 snprintf(level_buffer, sizeof(level_buffer) - 1, "%4u: ", level);
     118           0 :                 level_buffer[sizeof(level_buffer) - 1 ] = '\0';
     119             :         }
     120             : 
     121           0 :         message_line_len = mnd_sprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n",
     122             :                                                                 flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"",
     123             :                                                                 flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"",
     124             :                                                                 flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"",
     125             :                                                                 flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"",
     126             :                                                                 flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"",
     127             :                                                                 pipe_buffer, type? type:"", message);
     128             : 
     129           0 :         ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL;
     130           0 :         mnd_sprintf_free(message_line);
     131           0 :         if (flags & MYSQLND_DEBUG_FLUSH) {
     132           0 :                 self->m->close(self);
     133           0 :                 self->m->open(self, TRUE);
     134             :         }
     135           0 :         return ret;
     136             : }
     137             : /* }}} */
     138             : 
     139             : 
     140             : /* {{{ mysqlnd_debug::log_va */
     141             : static enum_func_status
     142           0 : MYSQLND_METHOD(mysqlnd_debug, log_va)(MYSQLND_DEBUG *self,
     143             :                                                                           unsigned int line, const char * const file,
     144             :                                                                           unsigned int level, const char * type,
     145             :                                                                           const char *format, ...)
     146             : {
     147             :         char pipe_buffer[512];
     148             :         int i;
     149             :         enum_func_status ret;
     150             :         char * message_line, *buffer;
     151             :         unsigned int message_line_len;
     152             :         va_list args;
     153           0 :         unsigned int flags = self->flags;
     154             :         char pid_buffer[10], time_buffer[30], file_buffer[200],
     155             :                  line_buffer[6], level_buffer[7];
     156             : 
     157           0 :         if (!self->stream && FAIL == self->m->open(self, FALSE)) {
     158           0 :                 return FAIL;
     159             :         }
     160             : 
     161           0 :         if (level == -1) {
     162           0 :                 level = zend_stack_count(&self->call_stack);
     163             :         }
     164           0 :         i = MIN(level, sizeof(pipe_buffer) / 2  - 1);
     165           0 :         pipe_buffer[i*2] = '\0';
     166           0 :         for (;i > 0;i--) {
     167           0 :                 pipe_buffer[i*2 - 1] = ' ';
     168           0 :                 pipe_buffer[i*2 - 2] = '|';
     169             :         }
     170             : 
     171             : 
     172           0 :         if (flags & MYSQLND_DEBUG_DUMP_PID) {
     173           0 :                 snprintf(pid_buffer, sizeof(pid_buffer) - 1, "%5u: ", self->pid);
     174           0 :                 pid_buffer[sizeof(pid_buffer) - 1 ] = '\0';
     175             :         }
     176           0 :         if (flags & MYSQLND_DEBUG_DUMP_TIME) {
     177             :                 /* The following from FF's DBUG library, which is in the public domain */
     178             : #if defined(PHP_WIN32)
     179             :                 /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
     180             :                 in system ticks, 10 ms intervals. See my_getsystime.c for high res */
     181             :                 SYSTEMTIME loc_t;
     182             :                 GetLocalTime(&loc_t);
     183             :                 snprintf(time_buffer, sizeof(time_buffer) - 1,
     184             :                                  /* "%04d-%02d-%02d " */
     185             :                                  "%02d:%02d:%02d.%06d ",
     186             :                                  /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
     187             :                                  loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
     188             :                 time_buffer[sizeof(time_buffer) - 1 ] = '\0';
     189             : #else
     190             :                 struct timeval tv;
     191             :                 struct tm *tm_p;
     192           0 :                 if (gettimeofday(&tv, NULL) != -1) {
     193           0 :                         if ((tm_p= localtime((const time_t *)&tv.tv_sec))) {
     194           0 :                                 snprintf(time_buffer, sizeof(time_buffer) - 1,
     195             :                                                  /* "%04d-%02d-%02d " */
     196             :                                                  "%02d:%02d:%02d.%06d ",
     197             :                                                  /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
     198             :                                                  tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
     199           0 :                                                  (int) (tv.tv_usec));
     200           0 :                                 time_buffer[sizeof(time_buffer) - 1 ] = '\0';
     201             :                         }
     202             :                 }
     203             : #endif
     204             :         }
     205           0 :         if (flags & MYSQLND_DEBUG_DUMP_FILE) {
     206           0 :                 snprintf(file_buffer, sizeof(file_buffer) - 1, "%14s: ", file);
     207           0 :                 file_buffer[sizeof(file_buffer) - 1 ] = '\0';
     208             :         }
     209           0 :         if (flags & MYSQLND_DEBUG_DUMP_LINE) {
     210           0 :                 snprintf(line_buffer, sizeof(line_buffer) - 1, "%5u: ", line);
     211           0 :                 line_buffer[sizeof(line_buffer) - 1 ] = '\0';
     212             :         }
     213           0 :         if (flags & MYSQLND_DEBUG_DUMP_LEVEL) {
     214           0 :                 snprintf(level_buffer, sizeof(level_buffer) - 1, "%4u: ", level);
     215           0 :                 level_buffer[sizeof(level_buffer) - 1 ] = '\0';
     216             :         }
     217             : 
     218           0 :         va_start(args, format);
     219           0 :         mnd_vsprintf(&buffer, 0, format, args);
     220           0 :         va_end(args);
     221             : 
     222           0 :         message_line_len = mnd_sprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n",
     223             :                                                                 flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"",
     224             :                                                                 flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"",
     225             :                                                                 flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"",
     226             :                                                                 flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"",
     227             :                                                                 flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"",
     228             :                                                                 pipe_buffer, type? type:"", buffer);
     229           0 :         mnd_sprintf_free(buffer);
     230           0 :         ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL;
     231           0 :         mnd_sprintf_free(message_line);
     232             : 
     233           0 :         if (flags & MYSQLND_DEBUG_FLUSH) {
     234           0 :                 self->m->close(self);
     235           0 :                 self->m->open(self, TRUE);
     236             :         }
     237           0 :         return ret;
     238             : }
     239             : /* }}} */
     240             : 
     241             : 
     242             : /* FALSE - The DBG_ calls won't be traced, TRUE - will be traced */
     243             : /* {{{ mysqlnd_debug::func_enter */
     244             : static zend_bool
     245           0 : MYSQLND_METHOD(mysqlnd_debug, func_enter)(MYSQLND_DEBUG * self,
     246             :                                                                                   unsigned int line, const char * const file,
     247             :                                                                                   const char * const func_name, unsigned int func_name_len)
     248             : {
     249           0 :         if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) {
     250           0 :                 return FALSE;
     251             :         }
     252           0 :         if ((uint) zend_stack_count(&self->call_stack) >= self->nest_level_limit) {
     253           0 :                 return FALSE;
     254             :         }
     255             : 
     256           0 :         if ((self->flags & MYSQLND_DEBUG_TRACE_MEMORY_CALLS) == 0 && self->skip_functions) {
     257           0 :                 const char ** p = self->skip_functions;
     258           0 :                 while (*p) {
     259           0 :                         if (*p == func_name) {
     260           0 :                                 zend_stack_push(&self->call_stack, &mysqlnd_debug_empty_string);
     261             : #ifndef MYSQLND_PROFILING_DISABLED
     262           0 :                                 if (self->flags & MYSQLND_DEBUG_PROFILE_CALLS) {
     263           0 :                                         uint64_t some_time = 0;
     264           0 :                                         zend_stack_push(&self->call_time_stack, &some_time);
     265             :                                 }
     266             : #endif
     267           0 :                                 return FALSE;
     268             :                         }
     269           0 :                         p++;
     270             :                 }
     271             :         }
     272             : 
     273           0 :         zend_stack_push(&self->call_stack, &func_name);
     274             : #ifndef MYSQLND_PROFILING_DISABLED
     275           0 :         if (self->flags & MYSQLND_DEBUG_PROFILE_CALLS) {
     276           0 :                 uint64_t some_time = 0;
     277           0 :                 zend_stack_push(&self->call_time_stack, &some_time);
     278             :         }
     279             : #endif
     280             : 
     281           0 :         if (zend_hash_num_elements(&self->not_filtered_functions) &&
     282           0 :                 0 == zend_hash_str_exists(&self->not_filtered_functions, func_name, strlen(func_name)))
     283             :         {
     284           0 :                 return FALSE;
     285             :         }
     286             : 
     287           0 :         self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, ">%s", func_name);
     288           0 :         return TRUE;
     289             : }
     290             : /* }}} */
     291             : 
     292             : #ifndef MYSQLND_PROFILING_DISABLED
     293             : struct st_mysqlnd_dbg_function_profile {
     294             :         uint64_t calls;
     295             :         uint64_t min_own;
     296             :         uint64_t max_own;
     297             :         uint64_t avg_own;
     298             :         uint64_t own_underporm_calls;
     299             :         uint64_t min_in_calls;
     300             :         uint64_t max_in_calls;
     301             :         uint64_t avg_in_calls;
     302             :         uint64_t in_calls_underporm_calls;
     303             :         uint64_t min_total;
     304             :         uint64_t max_total;
     305             :         uint64_t avg_total;
     306             :         uint64_t total_underporm_calls;
     307             : };
     308             : #define PROFILE_UNDERPERFORM_THRESHOLD 10
     309             : #endif
     310             : 
     311             : /* {{{ mysqlnd_debug::func_leave */
     312             : static enum_func_status
     313           0 : MYSQLND_METHOD(mysqlnd_debug, func_leave)(MYSQLND_DEBUG * self, unsigned int line, const char * const file, uint64_t call_time)
     314             : {
     315             :         char **func_name;
     316           0 :         uint64_t * parent_non_own_time_ptr = NULL, * mine_non_own_time_ptr = NULL;
     317           0 :         uint64_t mine_non_own_time = 0;
     318           0 :         zend_bool profile_calls = self->flags & MYSQLND_DEBUG_PROFILE_CALLS? TRUE:FALSE;
     319             : 
     320           0 :         if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) {
     321           0 :                 return PASS;
     322             :         }
     323           0 :         if ((uint) zend_stack_count(&self->call_stack) >= self->nest_level_limit) {
     324           0 :                 return PASS;
     325             :         }
     326             : 
     327           0 :         func_name = zend_stack_top(&self->call_stack);
     328             : 
     329             : #ifndef MYSQLND_PROFILING_DISABLED
     330           0 :         if (profile_calls) {
     331           0 :                 mine_non_own_time_ptr = zend_stack_top(&self->call_time_stack);
     332           0 :                 mine_non_own_time = *mine_non_own_time_ptr;
     333           0 :                 zend_stack_del_top(&self->call_time_stack); /* callee - removing ourselves */
     334             :         }
     335             : #endif
     336             : 
     337           0 :         if ((*func_name)[0] == '\0') {
     338             :                 ; /* don't log that function */
     339           0 :         } else if (!zend_hash_num_elements(&self->not_filtered_functions) ||
     340           0 :                            1 == zend_hash_str_exists(&self->not_filtered_functions, (*func_name), strlen((*func_name))))
     341             :         {
     342             : #ifndef MYSQLND_PROFILING_DISABLED
     343           0 :                 if (FALSE == profile_calls) {
     344             : #endif
     345           0 :                         self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s", *func_name);
     346             : 
     347             : #ifndef MYSQLND_PROFILING_DISABLED
     348             :                 } else {
     349           0 :                         struct st_mysqlnd_dbg_function_profile f_profile_stack = {0};
     350           0 :                         struct st_mysqlnd_dbg_function_profile * f_profile = NULL;
     351           0 :                         uint64_t own_time = call_time - mine_non_own_time;
     352           0 :                         uint func_name_len = strlen(*func_name);
     353             : 
     354           0 :                         self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s (total=%u own=%u in_calls=%u)",
     355             :                                                 *func_name, (unsigned int) call_time, (unsigned int) own_time, (unsigned int) mine_non_own_time
     356             :                                         );
     357             : 
     358           0 :                         if ((f_profile = zend_hash_str_find_ptr(&self->function_profiles, *func_name, func_name_len)) != NULL) {
     359             :                                 /* found */
     360           0 :                                         if (f_profile) {
     361           0 :                                         if (mine_non_own_time < f_profile->min_in_calls) {
     362           0 :                                                 f_profile->min_in_calls = mine_non_own_time;
     363           0 :                                         } else if (mine_non_own_time > f_profile->max_in_calls) {
     364           0 :                                                 f_profile->max_in_calls = mine_non_own_time;
     365             :                                         }
     366           0 :                                         f_profile->avg_in_calls = (f_profile->avg_in_calls * f_profile->calls + mine_non_own_time) / (f_profile->calls + 1);
     367             : 
     368           0 :                                         if (own_time < f_profile->min_own) {
     369           0 :                                                 f_profile->min_own = own_time;
     370           0 :                                         } else if (own_time > f_profile->max_own) {
     371           0 :                                                 f_profile->max_own = own_time;
     372             :                                         }
     373           0 :                                         f_profile->avg_own = (f_profile->avg_own * f_profile->calls + own_time) / (f_profile->calls + 1);
     374             : 
     375           0 :                                         if (call_time < f_profile->min_total) {
     376           0 :                                                 f_profile->min_total = call_time;
     377           0 :                                         } else if (call_time > f_profile->max_total) {
     378           0 :                                                 f_profile->max_total = call_time;
     379             :                                         }
     380           0 :                                         f_profile->avg_total = (f_profile->avg_total * f_profile->calls + call_time) / (f_profile->calls + 1);
     381             : 
     382           0 :                                         ++f_profile->calls;
     383           0 :                                         if (f_profile->calls > PROFILE_UNDERPERFORM_THRESHOLD) {
     384           0 :                                                 if (f_profile->avg_in_calls < mine_non_own_time) {
     385           0 :                                                         f_profile->in_calls_underporm_calls++;
     386             :                                                 }
     387           0 :                                                 if (f_profile->avg_own < own_time) {
     388           0 :                                                         f_profile->own_underporm_calls++;
     389             :                                                 }
     390           0 :                                                 if (f_profile->avg_total < call_time) {
     391           0 :                                                         f_profile->total_underporm_calls++;
     392             :                                                 }
     393             :                                         }
     394             :                                 }
     395             :                         } else {
     396             :                                 /* add */
     397           0 :                                 f_profile = &f_profile_stack;
     398           0 :                                 f_profile->min_in_calls = f_profile->max_in_calls = f_profile->avg_in_calls = mine_non_own_time;
     399           0 :                                 f_profile->min_total = f_profile->max_total = f_profile->avg_total = call_time;
     400           0 :                                 f_profile->min_own = f_profile->max_own = f_profile->avg_own = own_time;
     401           0 :                                 f_profile->calls = 1;
     402           0 :                                 zend_hash_str_add_mem(&self->function_profiles, *func_name, func_name_len, f_profile, sizeof(struct st_mysqlnd_dbg_function_profile));
     403             :                         }
     404           0 :                         if ((uint) zend_stack_count(&self->call_time_stack)) {
     405           0 :                                 uint64_t parent_non_own_time = 0;
     406             : 
     407           0 :                                 parent_non_own_time_ptr = zend_stack_top(&self->call_time_stack);
     408           0 :                                 parent_non_own_time = *parent_non_own_time_ptr;
     409           0 :                                 parent_non_own_time += call_time;
     410           0 :                                 zend_stack_del_top(&self->call_time_stack); /* the caller */
     411           0 :                                 zend_stack_push(&self->call_time_stack, &parent_non_own_time); /* add back the caller */
     412             :                         }
     413             :                 }
     414             : #endif
     415             :         }
     416             : 
     417           0 :         return zend_stack_del_top(&self->call_stack) == SUCCESS? PASS:FAIL;
     418             : }
     419             : /* }}} */
     420             : 
     421             : 
     422             : /* {{{ mysqlnd_debug::close */
     423             : static enum_func_status
     424           0 : MYSQLND_METHOD(mysqlnd_debug, close)(MYSQLND_DEBUG * self)
     425             : {
     426           0 :         if (self->stream) {
     427             : #ifndef MYSQLND_PROFILING_DISABLED
     428           0 :                 if (!(self->flags & MYSQLND_DEBUG_FLUSH) && (self->flags & MYSQLND_DEBUG_PROFILE_CALLS)) {
     429             :                         struct st_mysqlnd_dbg_function_profile * f_profile;
     430           0 :                         zend_string     *string_key = NULL;
     431             : 
     432           0 :                         self->m->log_va(self, __LINE__, __FILE__, 0, "info : ",
     433             :                                         "number of functions: %d", zend_hash_num_elements(&self->function_profiles));
     434           0 :                         ZEND_HASH_FOREACH_STR_KEY_PTR(&self->function_profiles, string_key, f_profile) {
     435           0 :                                 self->m->log_va(self, __LINE__, __FILE__, -1, "info : ",
     436             :                                                 "%-40s\tcalls=%5llu  own_slow=%5llu  in_calls_slow=%5llu  total_slow=%5llu"
     437             :                                                 "   min_own=%5llu  max_own=%7llu  avg_own=%7llu   "
     438             :                                                 "   min_in_calls=%5llu  max_in_calls=%7llu  avg_in_calls=%7llu"
     439             :                                                 "   min_total=%5llu  max_total=%7llu  avg_total=%7llu"
     440             :                                                 ,ZSTR_VAL(string_key)
     441             :                                                 ,(uint64_t) f_profile->calls
     442             :                                                 ,(uint64_t) f_profile->own_underporm_calls
     443             :                                                 ,(uint64_t) f_profile->in_calls_underporm_calls
     444             :                                                 ,(uint64_t) f_profile->total_underporm_calls
     445             : 
     446             :                                                 ,(uint64_t) f_profile->min_own
     447             :                                                 ,(uint64_t) f_profile->max_own
     448             :                                                 ,(uint64_t) f_profile->avg_own
     449             :                                                 ,(uint64_t) f_profile->min_in_calls
     450             :                                                 ,(uint64_t) f_profile->max_in_calls
     451             :                                                 ,(uint64_t) f_profile->avg_in_calls
     452             :                                                 ,(uint64_t) f_profile->min_total
     453             :                                                 ,(uint64_t) f_profile->max_total
     454             :                                                 ,(uint64_t) f_profile->avg_total
     455             :                                                 );
     456             :                         } ZEND_HASH_FOREACH_END();
     457             :                 }
     458             : #endif
     459             : 
     460           0 :                 php_stream_close(self->stream);
     461           0 :                 self->stream = NULL;
     462             :         }
     463             :         /* no DBG_RETURN please */
     464           0 :         return PASS;
     465             : }
     466             : /* }}} */
     467             : 
     468             : 
     469             : /* {{{ mysqlnd_res_meta::free */
     470             : static enum_func_status
     471           0 : MYSQLND_METHOD(mysqlnd_debug, free)(MYSQLND_DEBUG * self)
     472             : {
     473           0 :         if (self->file_name && self->file_name != mysqlnd_debug_default_trace_file) {
     474           0 :                 efree(self->file_name);
     475           0 :                 self->file_name = NULL;
     476             :         }
     477           0 :         zend_stack_destroy(&self->call_stack);
     478           0 :         zend_stack_destroy(&self->call_time_stack);
     479           0 :         zend_hash_destroy(&self->not_filtered_functions);
     480           0 :         zend_hash_destroy(&self->function_profiles);
     481           0 :         free(self);
     482           0 :         return PASS;
     483             : }
     484             : /* }}} */
     485             : 
     486             : enum mysqlnd_debug_parser_state
     487             : {
     488             :         PARSER_WAIT_MODIFIER,
     489             :         PARSER_WAIT_COLON,
     490             :         PARSER_WAIT_VALUE
     491             : };
     492             : 
     493             : 
     494             : /* {{{ mysqlnd_res_meta::set_mode */
     495             : static void
     496           0 : MYSQLND_METHOD(mysqlnd_debug, set_mode)(MYSQLND_DEBUG * self, const char * const mode)
     497             : {
     498             :         unsigned int mode_len, i;
     499           0 :         enum mysqlnd_debug_parser_state state = PARSER_WAIT_MODIFIER;
     500             : 
     501           0 :         mode_len = mode? strlen(mode) : 0;
     502             : 
     503           0 :         self->flags = 0;
     504           0 :         self->nest_level_limit = 0;
     505           0 :         if (self->file_name && self->file_name != mysqlnd_debug_default_trace_file) {
     506           0 :                 efree(self->file_name);
     507           0 :                 self->file_name = NULL;
     508             :         }
     509           0 :         if (zend_hash_num_elements(&self->not_filtered_functions)) {
     510           0 :                 zend_hash_destroy(&self->not_filtered_functions);
     511           0 :                 zend_hash_init(&self->not_filtered_functions, 0, NULL, NULL, 0);
     512             :         }
     513             : 
     514           0 :         for (i = 0; i < mode_len; i++) {
     515           0 :                 switch (mode[i]) {
     516             :                         case 'O':
     517             :                         case 'A':
     518           0 :                                 self->flags |= MYSQLND_DEBUG_FLUSH;
     519             :                         case 'a':
     520             :                         case 'o':
     521           0 :                                 if (mode[i] == 'a' || mode[i] == 'A') {
     522           0 :                                         self->flags |= MYSQLND_DEBUG_APPEND;
     523             :                                 }
     524           0 :                                 if (i + 1 < mode_len && mode[i+1] == ',') {
     525           0 :                                         unsigned int j = i + 2;
     526             : #ifdef PHP_WIN32
     527             :                                         if (i+4 < mode_len && mode[i+3] == ':' && (mode[i+4] == '\\' || mode[i+5] == '/')) {
     528             :                                                 j = i + 5;
     529             :                                         }
     530             : #endif
     531           0 :                                         while (j < mode_len) {
     532           0 :                                                 if (mode[j] == ':') {
     533           0 :                                                         break;
     534             :                                                 }
     535           0 :                                                 j++;
     536             :                                         }
     537           0 :                                         if (j > i + 2) {
     538           0 :                                                 self->file_name = estrndup(mode + i + 2, j - i - 2);
     539             :                                         }
     540           0 :                                         i = j;
     541             :                                 } else {
     542           0 :                                         if (!self->file_name)
     543           0 :                                                 self->file_name = (char *) mysqlnd_debug_default_trace_file;
     544             :                                 }
     545           0 :                                 state = PARSER_WAIT_COLON;
     546           0 :                                 break;
     547             :                         case ':':
     548             : #if 0
     549             :                                 if (state != PARSER_WAIT_COLON) {
     550             :                                         php_error_docref(NULL, E_WARNING, "Consecutive semicolons at position %u", i);
     551             :                                 }
     552             : #endif
     553           0 :                                 state = PARSER_WAIT_MODIFIER;
     554           0 :                                 break;
     555             :                         case 'f': /* limit output to these functions */
     556           0 :                                 if (i + 1 < mode_len && mode[i+1] == ',') {
     557           0 :                                         unsigned int j = i + 2;
     558           0 :                                         i++;
     559           0 :                                         while (j < mode_len) {
     560           0 :                                                 if (mode[j] == ':') {
     561             :                                                         /* function names with :: */
     562           0 :                                                         if ((j + 1 < mode_len) && mode[j+1] == ':') {
     563           0 :                                                                 j += 2;
     564           0 :                                                                 continue;
     565             :                                                         }
     566             :                                                 }
     567           0 :                                                 if (mode[j] == ',' || mode[j] == ':') {
     568           0 :                                                         if (j > i + 2) {
     569             :                                                                 char func_name[1024];
     570           0 :                                                                 unsigned int func_name_len = MIN(sizeof(func_name) - 1, j - i - 1);
     571           0 :                                                                 memcpy(func_name, mode + i + 1, func_name_len);
     572           0 :                                                                 func_name[func_name_len] = '\0';
     573             : 
     574           0 :                                                                 zend_hash_str_add_empty_element(&self->not_filtered_functions,
     575             :                                                                                                                         func_name, func_name_len);
     576           0 :                                                                 i = j;
     577             :                                                         }
     578           0 :                                                         if (mode[j] == ':') {
     579           0 :                                                                 break;
     580             :                                                         }
     581             :                                                 }
     582           0 :                                                 j++;
     583             :                                         }
     584           0 :                                         i = j;
     585             :                                 } else {
     586             : #if 0
     587             :                                         php_error_docref(NULL, E_WARNING,
     588             :                                                                          "Expected list of functions for '%c' found none", mode[i]);
     589             : #endif
     590             :                                 }
     591           0 :                                 state = PARSER_WAIT_COLON;
     592           0 :                                 break;
     593             :                         case 'D':
     594             :                         case 'd':
     595             :                         case 'g':
     596             :                         case 'p':
     597             :                                 /* unsupported */
     598           0 :                                 if ((i + 1) < mode_len && mode[i+1] == ',') {
     599           0 :                                         i+= 2;
     600           0 :                                         while (i < mode_len) {
     601           0 :                                                 if (mode[i] == ':') {
     602           0 :                                                         break;
     603             :                                                 }
     604           0 :                                                 i++;
     605             :                                         }
     606             :                                 }
     607           0 :                                 state = PARSER_WAIT_COLON;
     608           0 :                                 break;
     609             :                         case 'F':
     610           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_FILE;
     611           0 :                                 state = PARSER_WAIT_COLON;
     612           0 :                                 break;
     613             :                         case 'i':
     614           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_PID;
     615           0 :                                 state = PARSER_WAIT_COLON;
     616           0 :                                 break;
     617             :                         case 'L':
     618           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_LINE;
     619           0 :                                 state = PARSER_WAIT_COLON;
     620           0 :                                 break;
     621             :                         case 'n':
     622           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_LEVEL;
     623           0 :                                 state = PARSER_WAIT_COLON;
     624           0 :                                 break;
     625             :                         case 't':
     626           0 :                                 if (mode[i+1] == ',') {
     627           0 :                                         unsigned int j = i + 2;
     628           0 :                                         while (j < mode_len) {
     629           0 :                                                 if (mode[j] == ':') {
     630           0 :                                                         break;
     631             :                                                 }
     632           0 :                                                 j++;
     633             :                                         }
     634           0 :                                         if (j > i + 2) {
     635           0 :                                                 char *value_str = estrndup(mode + i + 2, j - i - 2);
     636           0 :                                                 self->nest_level_limit = atoi(value_str);
     637           0 :                                                 efree(value_str);
     638             :                                         }
     639           0 :                                         i = j;
     640             :                                 } else {
     641           0 :                                         self->nest_level_limit = 200; /* default value for FF DBUG */
     642             :                                 }
     643           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_TRACE;
     644           0 :                                 state = PARSER_WAIT_COLON;
     645           0 :                                 break;
     646             :                         case 'T':
     647           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_TIME;
     648           0 :                                 state = PARSER_WAIT_COLON;
     649           0 :                                 break;
     650             :                         case 'N':
     651             :                         case 'P':
     652             :                         case 'r':
     653             :                         case 'S':
     654           0 :                                 state = PARSER_WAIT_COLON;
     655           0 :                                 break;
     656             :                         case 'm': /* mysqlnd extension - trace memory functions */
     657           0 :                                 self->flags |= MYSQLND_DEBUG_TRACE_MEMORY_CALLS;
     658           0 :                                 state = PARSER_WAIT_COLON;
     659           0 :                                 break;
     660             :                         case 'x': /* mysqlnd extension - profile calls */
     661           0 :                                 self->flags |= MYSQLND_DEBUG_PROFILE_CALLS;
     662           0 :                                 state = PARSER_WAIT_COLON;
     663           0 :                                 break;
     664             :                         default:
     665           0 :                                 if (state == PARSER_WAIT_MODIFIER) {
     666             : #if 0
     667             :                                         php_error_docref(NULL, E_WARNING, "Unrecognized format '%c'", mode[i]);
     668             : #endif
     669           0 :                                         if (i+1 < mode_len && mode[i+1] == ',') {
     670           0 :                                                 i+= 2;
     671           0 :                                                 while (i < mode_len) {
     672           0 :                                                         if (mode[i] == ':') {
     673           0 :                                                                 break;
     674             :                                                         }
     675           0 :                                                         i++;
     676             :                                                 }
     677             :                                         }
     678           0 :                                         state = PARSER_WAIT_COLON;
     679             :                                 } else if (state == PARSER_WAIT_COLON) {
     680             : #if 0
     681             :                                         php_error_docref(NULL, E_WARNING, "Colon expected, '%c' found", mode[i]);
     682             : #endif
     683             :                                 }
     684             :                                 break;
     685             :                 }
     686             :         }
     687           0 : }
     688             : /* }}} */
     689             : 
     690             : MYSQLND_CLASS_METHODS_START(mysqlnd_debug)
     691             :         MYSQLND_METHOD(mysqlnd_debug, open),
     692             :         MYSQLND_METHOD(mysqlnd_debug, set_mode),
     693             :         MYSQLND_METHOD(mysqlnd_debug, log),
     694             :         MYSQLND_METHOD(mysqlnd_debug, log_va),
     695             :         MYSQLND_METHOD(mysqlnd_debug, func_enter),
     696             :         MYSQLND_METHOD(mysqlnd_debug, func_leave),
     697             :         MYSQLND_METHOD(mysqlnd_debug, close),
     698             :         MYSQLND_METHOD(mysqlnd_debug, free),
     699             : MYSQLND_CLASS_METHODS_END;
     700             : 
     701             : 
     702             : /* {{{ mysqlnd_debug_init */
     703             : PHPAPI MYSQLND_DEBUG *
     704           0 : mysqlnd_debug_init(const char * skip_functions[])
     705             : {
     706           0 :         MYSQLND_DEBUG *ret = calloc(1, sizeof(MYSQLND_DEBUG));
     707             : 
     708           0 :         ret->nest_level_limit = 0;
     709           0 :         ret->pid = getpid();
     710           0 :         zend_stack_init(&ret->call_stack, sizeof(char *));
     711           0 :         zend_stack_init(&ret->call_time_stack, sizeof(uint64_t));
     712           0 :         zend_hash_init(&ret->not_filtered_functions, 0, NULL, NULL, 0);
     713           0 :         zend_hash_init(&ret->function_profiles, 0, NULL, NULL, 0);
     714             : 
     715           0 :         ret->m = & mysqlnd_mysqlnd_debug_methods;
     716           0 :         ret->skip_functions = skip_functions;
     717             : 
     718           0 :         return ret;
     719             : }
     720             : /* }}} */
     721             : 
     722             : 
     723             : /* {{{ mysqlnd_debug */
     724           0 : PHPAPI void mysqlnd_debug(const char * mode)
     725             : {
     726             : #if PHP_DEBUG
     727             :         MYSQLND_DEBUG * dbg = MYSQLND_G(dbg);
     728             :         if (!dbg) {
     729             :                 struct st_mysqlnd_plugin_trace_log * trace_log_plugin = mysqlnd_plugin_find("debug_trace");
     730             :                 if (trace_log_plugin) {
     731             :                         dbg = trace_log_plugin->methods.trace_instance_init(mysqlnd_debug_std_no_trace_funcs);
     732             :                         if (!dbg) {
     733             :                                 return;
     734             :                         }
     735             :                         MYSQLND_G(dbg) = dbg;
     736             :                 }
     737             :         }
     738             :         if (dbg) {
     739             :                 dbg->m->close(dbg);
     740             :                 dbg->m->set_mode(dbg, mode);
     741             :                 while (zend_stack_count(&dbg->call_stack)) {
     742             :                         zend_stack_del_top(&dbg->call_stack);
     743             :                 }
     744             :                 while (zend_stack_count(&dbg->call_time_stack)) {
     745             :                         zend_stack_del_top(&dbg->call_time_stack);
     746             :                 }
     747             :         }
     748             : #endif
     749           0 : }
     750             : /* }}} */
     751             : 
     752             : 
     753             : static struct st_mysqlnd_plugin_trace_log mysqlnd_plugin_trace_log_plugin =
     754             : {
     755             :         {
     756             :                 MYSQLND_PLUGIN_API_VERSION,
     757             :                 "debug_trace",
     758             :                 MYSQLND_VERSION_ID,
     759             :                 PHP_MYSQLND_VERSION,
     760             :                 "PHP License 3.01",
     761             :                 "Andrey Hristov <andrey@php.net>,  Ulf Wendel <uw@php.net>, Georg Richter <georg@php.net>",
     762             :                 {
     763             :                         NULL, /* no statistics , will be filled later if there are some */
     764             :                         NULL, /* no statistics */
     765             :                 },
     766             :                 {
     767             :                         NULL /* plugin shutdown */
     768             :                 }
     769             :         },
     770             :         {/* methods */
     771             :                 mysqlnd_debug_init,
     772             :         }
     773             : };
     774             : 
     775             : 
     776             : /* {{{ mysqlnd_debug_trace_plugin_register */
     777             : void
     778       23504 : mysqlnd_debug_trace_plugin_register(void)
     779             : {
     780       23504 :         mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_plugin_trace_log_plugin);
     781       23504 : }
     782             : /* }}} */
     783             : 
     784             : 
     785             : /*
     786             :  * Local variables:
     787             :  * tab-width: 4
     788             :  * c-basic-offset: 4
     789             :  * End:
     790             :  * vim600: noet sw=4 ts=4 fdm=marker
     791             :  * vim<600: noet sw=4 ts=4
     792             :  */

Generated by: LCOV version 1.10

Generated at Wed, 17 Aug 2016 23:09:26 +0000 (6 days ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.