PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/dev/Profiler.php

http://github.com/silverstripe/sapphire
PHP | 235 lines | 151 code | 29 blank | 55 comment | 18 complexity | 6a1bf06edfb77d4ddbbc0275efc9a2e9 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, CC-BY-3.0, GPL-2.0, AGPL-1.0, LGPL-2.1
  1. <?php
  2. /********************************************************************************\
  3. * Copyright (C) Carl Taylor (cjtaylor@adepteo.com) *
  4. * Copyright (C) Torben Nehmer (torben@nehmer.net) for Code Cleanup *
  5. * Licensed under the BSD license upon request *
  6. \********************************************************************************/
  7. /// Enable multiple timers to aid profiling of performance over sections of code
  8. /**
  9. * Execution time profiler.
  10. *
  11. * @package sapphire
  12. * @subpackage misc
  13. */
  14. class Profiler {
  15. var $description;
  16. var $startTime;
  17. var $endTime;
  18. var $initTime;
  19. var $cur_timer;
  20. var $stack;
  21. var $trail;
  22. var $trace;
  23. var $count;
  24. var $running;
  25. protected static $inst;
  26. /**
  27. * Initialise the timer. with the current micro time
  28. */
  29. function Profiler( $output_enabled=false, $trace_enabled=false)
  30. {
  31. $this->description = array();
  32. $this->startTime = array();
  33. $this->endTime = array();
  34. $this->initTime = 0;
  35. $this->cur_timer = "";
  36. $this->stack = array();
  37. $this->trail = "";
  38. $this->trace = "";
  39. $this->count = array();
  40. $this->running = array();
  41. $this->initTime = $this->getMicroTime();
  42. $this->output_enabled = $output_enabled;
  43. $this->trace_enabled = $trace_enabled;
  44. $this->startTimer('unprofiled');
  45. }
  46. // Public Methods
  47. static function init() {
  48. if(!self::$inst) self::$inst = new Profiler(true,true);
  49. }
  50. static function mark($name, $level2 = "", $desc = "") {
  51. if($level2 && $_GET['debug_profile'] > 1) $name .= " $level2";
  52. if(!self::$inst) self::$inst = new Profiler(true,true);
  53. self::$inst->startTimer($name, $desc);
  54. }
  55. static function unmark($name, $level2 = "", $desc = "") {
  56. if($level2 && $_GET['debug_profile'] > 1) $name .= " $level2";
  57. if(!self::$inst) self::$inst = new Profiler(true,true);
  58. self::$inst->stopTimer($name, $desc);
  59. }
  60. static function show($showTrace = false) {
  61. if(!self::$inst) self::$inst = new Profiler(true,true);
  62. echo "<div style=\"position: absolute; z-index: 100000; top: 20px; left: 20px; background-color: white; padding: 20px; border: 1px #AAA solid; height: 80%; overflow: auto;\">";
  63. echo "<p><a href=\"#\" onclick=\"this.parentNode.parentNode.style.display = 'none'; return false;\">(Click to close)</a></p>";
  64. self::$inst->printTimers();
  65. if($showTrace) self::$inst->printTrace();
  66. echo "</div>";
  67. }
  68. /**
  69. * Start an individual timer
  70. * This will pause the running timer and place it on a stack.
  71. * @param string $name name of the timer
  72. * @param string optional $desc description of the timer
  73. */
  74. function startTimer($name, $desc="" ){
  75. $this->trace.="start $name\n";
  76. $n=array_push( $this->stack, $this->cur_timer );
  77. $this->__suspendTimer( $this->stack[$n-1] );
  78. $this->startTime[$name] = $this->getMicroTime();
  79. $this->cur_timer=$name;
  80. $this->description[$name] = $desc;
  81. if (!array_key_exists($name,$this->count))
  82. $this->count[$name] = 1;
  83. else
  84. $this->count[$name]++;
  85. }
  86. /**
  87. * Stop an individual timer
  88. * Restart the timer that was running before this one
  89. * @param string $name name of the timer
  90. */
  91. function stopTimer($name){
  92. $this->trace.="stop $name\n";
  93. $this->endTime[$name] = $this->getMicroTime();
  94. if (!array_key_exists($name, $this->running))
  95. $this->running[$name] = $this->elapsedTime($name);
  96. else
  97. $this->running[$name] += $this->elapsedTime($name);
  98. $this->cur_timer=array_pop($this->stack);
  99. $this->__resumeTimer($this->cur_timer);
  100. }
  101. /**
  102. * measure the elapsed time of a timer without stoping the timer if
  103. * it is still running
  104. */
  105. function elapsedTime($name){
  106. // This shouldn't happen, but it does once.
  107. if (!array_key_exists($name,$this->startTime))
  108. return 0;
  109. if(array_key_exists($name,$this->endTime)){
  110. return ($this->endTime[$name] - $this->startTime[$name]);
  111. } else {
  112. $now=$this->getMicroTime();
  113. return ($now - $this->startTime[$name]);
  114. }
  115. }//end start_time
  116. /**
  117. * Measure the elapsed time since the profile class was initialised
  118. *
  119. */
  120. function elapsedOverall(){
  121. $oaTime = $this->getMicroTime() - $this->initTime;
  122. return($oaTime);
  123. }//end start_time
  124. /**
  125. * print out a log of all the timers that were registered
  126. *
  127. */
  128. function printTimers($enabled=false)
  129. {
  130. if($this->output_enabled||$enabled){
  131. $TimedTotal = 0;
  132. $tot_perc = 0;
  133. ksort($this->description);
  134. print("<pre>\n");
  135. $oaTime = $this->getMicroTime() - $this->initTime;
  136. echo"============================================================================\n";
  137. echo " PROFILER OUTPUT\n";
  138. echo"============================================================================\n";
  139. print( "Calls Time Routine\n");
  140. echo"-----------------------------------------------------------------------------\n";
  141. while (list ($key, $val) = each ($this->description)) {
  142. $t = $this->elapsedTime($key);
  143. $total = $this->running[$key];
  144. $count = $this->count[$key];
  145. $TimedTotal += $total;
  146. $perc = ($total/$oaTime)*100;
  147. $tot_perc+=$perc;
  148. // $perc=sprintf("%3.2f", $perc );
  149. $lines[ sprintf( "%3d %3.4f ms (%3.2f %%) %s\n", $count, $total*1000, $perc, $key) ] = $total;
  150. }
  151. arsort($lines);
  152. foreach($lines as $line => $total) {
  153. echo $line;
  154. }
  155. echo "\n";
  156. $missed=$oaTime-$TimedTotal;
  157. $perc = ($missed/$oaTime)*100;
  158. $tot_perc+=$perc;
  159. // $perc=sprintf("%3.2f", $perc );
  160. printf( " %3.4f ms (%3.2f %%) %s\n", $missed*1000,$perc, "Missed");
  161. echo"============================================================================\n";
  162. printf( " %3.4f ms (%3.2f %%) %s\n", $oaTime*1000,$tot_perc, "OVERALL TIME");
  163. echo"============================================================================\n";
  164. print("</pre>");
  165. }
  166. }
  167. function printTrace( $enabled=false )
  168. {
  169. if($this->trace_enabled||$enabled){
  170. print("<pre>");
  171. print("Trace\n$this->trace\n\n");
  172. print("</pre>");
  173. }
  174. }
  175. /// Internal Use Only Functions
  176. /**
  177. * Get the current time as accuratly as possible
  178. *
  179. */
  180. function getMicroTime(){
  181. $tmp=explode(' ', microtime());
  182. $rt=$tmp[0]+$tmp[1];
  183. return $rt;
  184. }
  185. /**
  186. * resume an individual timer
  187. *
  188. */
  189. function __resumeTimer($name){
  190. $this->trace.="resume $name\n";
  191. $this->startTime[$name] = $this->getMicroTime();
  192. }
  193. /**
  194. * suspend an individual timer
  195. *
  196. */
  197. function __suspendTimer($name){
  198. $this->trace.="suspend $name\n";
  199. $this->endTime[$name] = $this->getMicroTime();
  200. if (!array_key_exists($name, $this->running))
  201. $this->running[$name] = $this->elapsedTime($name);
  202. else
  203. $this->running[$name] += $this->elapsedTime($name);
  204. }
  205. }
  206. ?>