| [ Index ] |
|
Code source de PHP PEAR 1.4.5 |
1 <?php 2 // 3 // +----------------------------------------------------------------------+ 4 // | PEAR :: Benchmark | 5 // +----------------------------------------------------------------------+ 6 // | Copyright (c) 2002-2006 Matthias Englert <Matthias.Englert@gmx.de>. | 7 // +----------------------------------------------------------------------+ 8 // | This source file is subject to the New BSD license, That is bundled | 9 // | with this package in the file LICENSE, and is available through | 10 // | the world-wide-web at | 11 // | http://www.opensource.org/licenses/bsd-license.php | 12 // | If you did not receive a copy of the new BSDlicense and are unable | 13 // | to obtain it through the world-wide-web, please send a note to | 14 // | license@php.net so we can mail you a copy immediately. | 15 // +----------------------------------------------------------------------+ 16 // 17 // $Id: Profiler.php,v 1.19 2006/03/01 19:26:09 anant Exp $ 18 // 19 20 require_once 'PEAR.php'; 21 22 /** 23 * Provides timing and profiling information. 24 * 25 * Example 1: Automatic profiling start, stop, and output. 26 * 27 * <code> 28 * <?php 29 * require_once 'Benchmark/Profiler.php'; 30 * 31 * $profiler = new Benchmark_Profiler(TRUE); 32 * 33 * function myFunction() { 34 * global $profiler; 35 * $profiler->enterSection('myFunction'); 36 * //do something 37 * $profiler->leaveSection('myFunction'); 38 * return; 39 * } 40 * 41 * //do something 42 * myFunction(); 43 * //do more 44 * ?> 45 * </code> 46 * 47 * Example 2: Manual profiling start, stop, and output. 48 * 49 * <code> 50 * <?php 51 * require_once 'Benchmark/Profiler.php'; 52 * 53 * $profiler = new Benchmark_Profiler(); 54 * 55 * function myFunction() { 56 * global $profiler; 57 * $profiler->enterSection('myFunction'); 58 * //do something 59 * $profiler->leaveSection('myFunction'); 60 * return; 61 * } 62 * 63 * $profiler->start(); 64 * //do something 65 * myFunction(); 66 * //do more 67 * $profiler->stop(); 68 * $profiler->display(); 69 * ?> 70 * </code> 71 * 72 * @author Matthias Englert <Matthias.Englert@gmx.de> 73 * @copyright Copyright © 2002-2005 Matthias Englert <Matthias.Englert@gmx.de> 74 * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 75 * @category Benchmarking 76 * @package Benchmark 77 * @since 1.2.0 78 */ 79 class Benchmark_Profiler extends PEAR { 80 /** 81 * Contains the total ex. time of each section 82 * 83 * @var array 84 * @access private 85 */ 86 var $_sections = array(); 87 88 /** 89 * Calling stack 90 * 91 * @var array 92 * @access private 93 */ 94 var $_stack = array(); 95 96 /** 97 * Notes how often a section was entered 98 * 99 * @var array 100 * @access private 101 */ 102 var $_numberOfCalls = array(); 103 104 /** 105 * Notes for each section how much time is spend in sub-sections 106 * 107 * @var array 108 * @access private 109 */ 110 var $_subSectionsTime = array(); 111 112 /** 113 * Notes for each section how often it calls which section 114 * 115 * @var array 116 * @access private 117 */ 118 var $_calls = array(); 119 120 /** 121 * Notes for each section how often it was called by which section 122 * 123 * @var array 124 * @access private 125 */ 126 var $_callers = array(); 127 128 /** 129 * Auto-starts and stops profiler 130 * 131 * @var boolean 132 * @access private 133 */ 134 var $_auto = FALSE; 135 136 /** 137 * Max marker name length for non-html output 138 * 139 * @var integer 140 * @access private 141 */ 142 var $_maxStringLength = 0; 143 144 /** 145 * Constructor, starts profiling recording 146 * 147 * @access public 148 */ 149 function Benchmark_Profiler($auto = FALSE) { 150 $this->_auto = $auto; 151 152 if ($this->_auto) { 153 $this->start(); 154 } 155 156 $this->PEAR(); 157 } 158 159 /** 160 * Destructor, stops profiling recording 161 * 162 * @access private 163 */ 164 function _Benchmark_Profiler() { 165 if (isset($this->_auto) && $this->_auto) { 166 $this->stop(); 167 $this->display(); 168 } 169 } 170 171 /** 172 * Returns profiling informations for a given section. 173 * 174 * @param string $section 175 * @return array 176 * @access public 177 */ 178 function getSectionInformations($section = 'Global') { 179 if (isset($this->_sections[$section])) { 180 $calls = array(); 181 182 if (isset($this->_calls[$section])) { 183 $calls = $this->_calls[$section]; 184 } 185 186 $callers = array(); 187 188 if (isset($this->_callers[$section])) { 189 $callers = $this->_callers[$section]; 190 } 191 192 $informations = array(); 193 194 $informations['time'] = $this->_sections[$section]; 195 if (isset($this->_sections['Global'])) { 196 $informations['percentage'] = number_format(100 * $this->_sections[$section] / $this->_sections['Global'], 2, '.', ''); 197 } else { 198 $informations['percentage'] = 'N/A'; 199 } 200 $informations['calls'] = $calls; 201 $informations['num_calls'] = $this->_numberOfCalls[$section]; 202 $informations['callers'] = $callers; 203 204 if (isset($this->_subSectionsTime[$section])) { 205 $informations['netto_time'] = $this->_sections[$section] - $this->_subSectionsTime[$section]; 206 } else { 207 $informations['netto_time'] = $this->_sections[$section]; 208 } 209 210 return $informations; 211 } else { 212 $this->raiseError("The section '$section' does not exists.\n", NULL, PEAR_ERROR_TRIGGER, E_USER_WARNING); 213 } 214 } 215 216 /** 217 * Returns profiling informations for all sections. 218 * 219 * @return array 220 * @access public 221 */ 222 function getAllSectionsInformations() { 223 $informations = array(); 224 225 foreach($this->_sections as $section => $time) { 226 $informations[$section] = $this->getSectionInformations($section); 227 } 228 229 return $informations; 230 } 231 232 /** 233 * Returns formatted profiling information. 234 * 235 * @param string output format (auto, plain or html), default auto 236 * @see display() 237 * @access private 238 */ 239 function _getOutput($format) { 240 241 /* Quickly find out the maximun length: Ineffecient, but will do for now! */ 242 $informations = $this->getAllSectionsInformations(); 243 $names = array_keys($informations); 244 245 $maxLength = 0; 246 foreach ($names as $name) 247 { 248 if ($maxLength < strlen($name)) { 249 $maxLength = strlen($name); 250 } 251 } 252 $this->_maxStringLength = $maxLength; 253 254 if ($format == 'auto') { 255 if (function_exists('version_compare') && 256 version_compare(phpversion(), '4.1', 'ge')) { 257 $format = isset($_SERVER['SERVER_PROTOCOL']) ? 'html' : 'plain'; 258 } else { 259 global $HTTP_SERVER_VARS; 260 $format = isset($HTTP_SERVER_VARS['SERVER_PROTOCOL']) ? 'html' : 'plain'; 261 } 262 } 263 264 if ($format == 'html') { 265 $out = '<table style="border: 1px solid #000000; ">'."\n"; 266 $out .= 267 '<tr><td> </td><td align="center"><b>total ex. time</b></td>'. 268 '<td align="center"><b>netto ex. time</b></td>'. 269 '<td align="center"><b>#calls</b></td><td align="center"><b>%</b></td>'. 270 '<td align="center"><b>calls</b></td><td align="center"><b>callers</b></td></tr>'. 271 "\n"; 272 } else { 273 $dashes = $out = str_pad("\n", ($this->_maxStringLength + 75), '-', STR_PAD_LEFT); 274 $out .= str_pad('Section', $this->_maxStringLength + 10); 275 $out .= str_pad("Total Ex Time", 22); 276 $out .= str_pad("Netto Ex Time", 22); 277 $out .= str_pad("#Calls", 10); 278 $out .= "Percentage\n"; 279 $out .= $dashes; 280 } 281 282 foreach($informations as $name => $values) { 283 $percentage = $values['percentage']; 284 $calls_str = ""; 285 286 foreach($values['calls'] as $key => $val) { 287 if ($calls_str) { 288 $calls_str .= ", "; 289 } 290 291 $calls_str .= "$key ($val)"; 292 } 293 294 $callers_str = ""; 295 296 foreach($values['callers'] as $key => $val) { 297 if ($callers_str) { 298 $callers_str .= ", "; 299 } 300 301 $callers_str .= "$key ($val)"; 302 } 303 304 if ($format == 'html') { 305 $out .= "<tr><td><b>$name</b></td><td>{$values['time']}</td><td>{$values['netto_time']}</td><td>{$values['num_calls']}</td>"; 306 if (is_numeric($values['percentage'])) { 307 $out .= "<td align=\"right\">{$values['percentage']}%</td>\n"; 308 } else { 309 $out .= "<td align=\"right\">{$values['percentage']}</td>\n"; 310 } 311 $out .= "<td>$calls_str</td><td>$callers_str</td></tr>"; 312 } else { 313 $out .= str_pad($name, $this->_maxStringLength + 10); 314 $out .= str_pad($values['time'], 22); 315 $out .= str_pad($values['netto_time'], 22); 316 $out .= str_pad($values['num_calls'], 10); 317 if (is_numeric($values['percentage'])) { 318 $out .= str_pad($values['percentage']."%\n", 8, ' ', STR_PAD_LEFT); 319 } else { 320 $out .= str_pad($values['percentage']."\n", 8, ' ', STR_PAD_LEFT); 321 } 322 } 323 } 324 325 if ($format == 'html') { 326 return $out . '</table>'; 327 } else { 328 return $out; 329 } 330 } 331 332 /** 333 * Returns formatted profiling information. 334 * 335 * @param string output format (auto, plain or html), default auto 336 * @access public 337 */ 338 function display($format = 'auto') { 339 echo $this->_getOutput($format); 340 } 341 342 /** 343 * Enters "Global" section. 344 * 345 * @see enterSection(), stop() 346 * @access public 347 */ 348 function start() { 349 $this->enterSection('Global'); 350 } 351 352 /** 353 * Leaves "Global" section. 354 * 355 * @see leaveSection(), start() 356 * @access public 357 */ 358 function stop() { 359 $this->leaveSection('Global'); 360 } 361 362 /** 363 * Enters code section. 364 * 365 * @param string name of the code section 366 * @see start(), leaveSection() 367 * @access public 368 */ 369 function enterSection($name) { 370 if (count($this->_stack)) { 371 if (isset($this->_callers[$name][$this->_stack[count($this->_stack) - 1]["name"]])) { 372 $this->_callers[$name][$this->_stack[count($this->_stack) - 1]["name"]]++; 373 } else { 374 $this->_callers[$name][$this->_stack[count($this->_stack) - 1]["name"]] = 1; 375 } 376 377 if (isset($this->_calls[$this->_stack[count($this->_stack) - 1]["name"]][$name])) { 378 $this->_calls[$this->_stack[count($this->_stack) - 1]["name"]][$name]++; 379 } else { 380 $this->_calls[$this->_stack[count($this->_stack) - 1]["name"]][$name] = 1; 381 } 382 } else { 383 if ($name != 'Global') { 384 $this->raiseError("tried to enter section ".$name." but profiling was not started\n", NULL, PEAR_ERROR_DIE); 385 } 386 } 387 388 if (isset($this->_numberOfCalls[$name])) { 389 $this->_numberOfCalls[$name]++; 390 } else { 391 $this->_numberOfCalls[$name] = 1; 392 } 393 394 array_push($this->_stack, array("name" => $name, "time" => $this->_getMicrotime())); 395 } 396 397 /** 398 * Leaves code section. 399 * 400 * @param string name of the marker to be set 401 * @see stop(), enterSection() 402 * @access public 403 */ 404 function leaveSection($name) { 405 $microtime = $this->_getMicrotime(); 406 407 if (!count($this->_stack)) { 408 $this->raiseError("tried to leave section ".$name." but profiling was not started\n", NULL, PEAR_ERROR_DIE); 409 } 410 411 $x = array_pop($this->_stack); 412 413 if ($x["name"] != $name) { 414 $this->raiseError("reached end of section $name but expecting end of " . $x["name"]."\n", NULL, PEAR_ERROR_DIE); 415 } 416 417 if (isset($this->_sections[$name])) { 418 $this->_sections[$name] += $microtime - $x["time"]; 419 } else { 420 $this->_sections[$name] = $microtime - $x["time"]; 421 } 422 423 $parent = array_pop($this->_stack); 424 425 if (isset($parent)) { 426 if (isset($this->_subSectionsTime[$parent['name']])) { 427 $this->_subSectionsTime[$parent['name']] += $microtime - $x['time']; 428 } else { 429 $this->_subSectionsTime[$parent['name']] = $microtime - $x['time']; 430 } 431 432 array_push($this->_stack, $parent); 433 } 434 } 435 436 /** 437 * Wrapper for microtime(). 438 * 439 * @return float 440 * @access private 441 * @since 1.3.0 442 */ 443 function _getMicrotime() { 444 $microtime = explode(' ', microtime()); 445 return $microtime[1] . substr($microtime[0], 1); 446 } 447 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 14:08:00 2007 | par Balluche grâce à PHPXref 0.7 |