PageRenderTime 25ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/unit-test/bpm-testlib/bpm-profiler.php

http://buddypress-media.googlecode.com/
PHP | 248 lines | 160 code | 62 blank | 26 comment | 12 complexity | 4322fd93f56d15a8ec543aa056c929af MD5 | raw file
Possible License(s): AGPL-1.0, Apache-2.0, GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * BP-MEDIA UNIT TEST PROFILER
  4. * A simple manually-instrumented profiler for WordPress. Records basic execution time, and a summary of the actions and SQL
  5. * queries run within each block. Start() and stop() must be called in pairs, for example:
  6. *
  7. * function something_to_profile() {
  8. * wppf_start(__FUNCTION__);
  9. * do_stuff();
  10. * wppf_stop();
  11. * }
  12. *
  13. * Multiple profile blocks are permitted, and they may be nested.
  14. *
  15. * @version 0.1.9
  16. * @since 0.1.9
  17. * @author original version from http://svn.automattic.com/wordpress-tests/
  18. * @package BP-Media
  19. * @subpackage Unit Test
  20. * @link http://code.google.com/p/buddypress-media/
  21. *
  22. * ========================================================================================================
  23. */
  24. class BPM_Profiler {
  25. var $stack;
  26. var $profile;
  27. function BPM_Profiler() {
  28. $this->stack = array();
  29. $this->profile = array();
  30. }
  31. function start($name) {
  32. $time = $this->microtime();
  33. if (!$this->stack) {
  34. // Log all actions and filters
  35. add_filter('all', array(&$this, 'log_filter'));
  36. }
  37. // Reset the WP DB queries log, storing it on the profile stack if necessary
  38. global $wpdb;
  39. if ($this->stack) {
  40. $this->stack[count($this->stack)-1]['queries'] = $wpdb->queries;
  41. }
  42. $wpdb->queries = array();
  43. global $wp_object_cache;
  44. $this->stack[] = array(
  45. 'start' => $time,
  46. 'name' => $name,
  47. 'cache_cold_hits' => $wp_object_cache->cold_cache_hits,
  48. 'cache_warm_hits' => $wp_object_cache->warm_cache_hits,
  49. 'cache_misses' => $wp_object_cache->cache_misses,
  50. 'cache_dirty_objects' => $this->_dirty_objects_count($wp_object_cache->dirty_objects),
  51. 'actions' => array(),
  52. 'filters' => array(),
  53. 'queries' => array(),
  54. );
  55. }
  56. function stop() {
  57. $item = array_pop($this->stack);
  58. $time = $this->microtime($item['start']);
  59. $name = $item['name'];
  60. global $wpdb;
  61. $item['queries'] = $wpdb->queries;
  62. global $wp_object_cache;
  63. $cache_dirty_count = $this->_dirty_objects_count($wp_object_cache->dirty_objects);
  64. $cache_dirty_delta = $this->array_sub($cache_dirty_count, $item['cache_dirty_objects']);
  65. if (isset($this->profile[$name])) {
  66. $this->profile[$name]['time'] += $time;
  67. $this->profile[$name]['calls'] ++;
  68. $this->profile[$name]['cache_cold_hits'] += ($wp_object_cache->cold_cache_hits - $item['cache_cold_hits']);
  69. $this->profile[$name]['cache_warm_hits'] += ($wp_object_cache->warm_cache_hits - $item['cache_warm_hits']);
  70. $this->profile[$name]['cache_misses'] += ($wp_object_cache->cache_misses - $item['cache_misses']);
  71. $this->profile[$name]['cache_dirty_objects'] = array_add( $this->profile[$name]['cache_dirty_objects'], $cache_dirty_delta) ;
  72. $this->profile[$name]['actions'] = array_add( $this->profile[$name]['actions'], $item['actions'] );
  73. $this->profile[$name]['filters'] = array_add( $this->profile[$name]['filters'], $item['filters'] );
  74. $this->profile[$name]['queries'] = array_add( $this->profile[$name]['queries'], $item['queries'] );
  75. //$this->_query_summary($item['queries'], $this->profile[$name]['queries']);
  76. }
  77. else {
  78. $queries = array();
  79. $this->_query_summary($item['queries'], $queries);
  80. $this->profile[$name] = array(
  81. 'time' => $time,
  82. 'calls' => 1,
  83. 'cache_cold_hits' => ($wp_object_cache->cold_cache_hits - $item['cache_cold_hits']),
  84. 'cache_warm_hits' => ($wp_object_cache->warm_cache_hits - $item['cache_warm_hits']),
  85. 'cache_misses' => ($wp_object_cache->cache_misses - $item['cache_misses']),
  86. 'cache_dirty_objects' => $cache_dirty_delta,
  87. 'actions' => $item['actions'],
  88. 'filters' => $item['filters'],
  89. // 'queries' => $item['queries'],
  90. 'queries' => $queries,
  91. );
  92. }
  93. if (!$this->stack) {
  94. remove_filter('all', array(&$this, 'log_filter'));
  95. }
  96. }
  97. function microtime($since = 0.0) {
  98. list($usec, $sec) = explode(' ', microtime());
  99. return (float)$sec + (float)$usec - $since;
  100. }
  101. function log_filter($tag) {
  102. if ($this->stack) {
  103. global $wp_actions;
  104. if ($tag == end($wp_actions))
  105. @$this->stack[count($this->stack)-1]['actions'][$tag] ++;
  106. else
  107. @$this->stack[count($this->stack)-1]['filters'][$tag] ++;
  108. }
  109. return $arg;
  110. }
  111. function log_action($tag) {
  112. if ($this->stack)
  113. @$this->stack[count($this->stack)-1]['actions'][$tag] ++;
  114. }
  115. function _current_action() {
  116. global $wp_actions;
  117. return $wp_actions[count($wp_actions)-1];
  118. }
  119. function results() {
  120. return $this->profile;
  121. }
  122. function _query_summary($queries, &$out) {
  123. foreach ($queries as $q) {
  124. $sql = $q[0];
  125. $sql = preg_replace('/(WHERE \w+ =) \d+/', '$1 x', $sql);
  126. $sql = preg_replace('/(WHERE \w+ =) \'\[-\w]+\'/', '$1 \'xxx\'', $sql);
  127. @$out[$sql] ++;
  128. }
  129. asort($out);
  130. return;
  131. }
  132. function _query_count($queries) {
  133. $out = array();
  134. foreach ($queries as $q) {
  135. if (empty($q[2]))
  136. @$out['unknown'] ++;
  137. else
  138. @$out[$q[2]] ++;
  139. }
  140. return $out;
  141. }
  142. function _dirty_objects_count($dirty_objects) {
  143. $out = array();
  144. foreach (array_keys($dirty_objects) as $group)
  145. $out[$group] = count($dirty_objects[$group]);
  146. return $out;
  147. }
  148. function array_add($a, $b) {
  149. $out = $a;
  150. foreach (array_keys($b) as $key)
  151. if (array_key_exists($key, $out))
  152. $out[$key] += $b[$key];
  153. else
  154. $out[$key] = $b[$key];
  155. return $out;
  156. }
  157. function array_sub($a, $b) {
  158. $out = $a;
  159. foreach (array_keys($b) as $key)
  160. if (array_key_exists($key, $b))
  161. $out[$key] -= $b[$key];
  162. return $out;
  163. }
  164. function print_summary() {
  165. $results = $this->results();
  166. printf("\nname calls time action filter warm cold misses dirty\n");
  167. foreach ($results as $name=>$stats) {
  168. printf("%24.24s %6d %6.4f %6d %6d %6d %6d %6d %6d\n", $name, $stats['calls'], $stats['time'], array_sum($stats['actions']), array_sum($stats['filters']), $stats['cache_warm_hits'], $stats['cache_cold_hits'], $stats['cache_misses'], array_sum($stats['cache_dirty_objects']));
  169. }
  170. }
  171. }
  172. global $bpmp;
  173. $bpmp = new BPM_Profiler();
  174. function bpmp_start($name) {
  175. $GLOBALS['wppf']->start($name);
  176. }
  177. function bpmp_stop() {
  178. $GLOBALS['wppf']->stop();
  179. }
  180. function bpmp_results() {
  181. return $GLOBALS['wppf']->results();
  182. }
  183. function bpmp_print_summary() {
  184. $GLOBALS['wppf']->print_summary();
  185. }
  186. ?>