You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					193 lines
				
				5.5 KiB
			
		
		
			
		
	
	
					193 lines
				
				5.5 KiB
			| 
											14 years ago
										 | <?php
 | ||
|  | /**
 | ||
|  |  * @link http://www.yiiframework.com/
 | ||
|  |  * @copyright Copyright © 2008-2011 Yii Software LLC
 | ||
|  |  * @license http://www.yiiframework.com/license/
 | ||
|  |  */
 | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * CProfileLogRoute displays the profiling results in Web page.
 | ||
|  |  *
 | ||
|  |  * The profiling is done by calling {@link YiiBase::beginProfile()} and {@link YiiBase::endProfile()},
 | ||
|  |  * which marks the begin and end of a code block.
 | ||
|  |  *
 | ||
|  |  * CProfileLogRoute supports two types of report by setting the {@link setReport report} property:
 | ||
|  |  * <ul>
 | ||
|  |  * <li>summary: list the execution time of every marked code block</li>
 | ||
|  |  * <li>callstack: list the mark code blocks in a hierarchical view reflecting their calling sequence.</li>
 | ||
|  |  * </ul>
 | ||
|  |  *
 | ||
|  |  * @author Qiang Xue <qiang.xue@gmail.com>
 | ||
| 
											14 years ago
										 |  * @since 2.0
 | ||
| 
											14 years ago
										 |  */
 | ||
|  | class CProfileLogRoute extends CWebLogRoute
 | ||
|  | {
 | ||
|  | 	/**
 | ||
|  | 	 * @var boolean whether to aggregate results according to profiling tokens.
 | ||
|  | 	 * If false, the results will be aggregated by categories.
 | ||
|  | 	 * Defaults to true. Note that this property only affects the summary report
 | ||
|  | 	 * that is enabled when {@link report} is 'summary'.
 | ||
|  | 	 */
 | ||
|  | 	public $groupByToken = true;
 | ||
|  | 	/**
 | ||
|  | 	 * @var string type of profiling report to display
 | ||
|  | 	 */
 | ||
|  | 	private $_report = 'summary';
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * Initializes the route.
 | ||
|  | 	 * This method is invoked after the route is created by the route manager.
 | ||
|  | 	 */
 | ||
|  | 	public function init()
 | ||
|  | 	{
 | ||
|  | 		$this->levels = CLogger::LEVEL_PROFILE;
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * @return string the type of the profiling report to display. Defaults to 'summary'.
 | ||
|  | 	 */
 | ||
|  | 	public function getReport()
 | ||
|  | 	{
 | ||
|  | 		return $this->_report;
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * @param string $value the type of the profiling report to display. Valid values include 'summary' and 'callstack'.
 | ||
|  | 	 */
 | ||
|  | 	public function setReport($value)
 | ||
|  | 	{
 | ||
|  | 		if ($value === 'summary' || $value === 'callstack')
 | ||
|  | 			$this->_report = $value;
 | ||
|  | 		else
 | ||
| 
											13 years ago
										 | 			throw new CException(Yii::t('yii', 'CProfileLogRoute.report "{report}" is invalid. Valid values include "summary" and "callstack".',
 | ||
| 
											14 years ago
										 | 				array('{report}' => $value)));
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * Displays the log messages.
 | ||
|  | 	 * @param array $logs list of log messages
 | ||
|  | 	 */
 | ||
|  | 	public function processLogs($logs)
 | ||
|  | 	{
 | ||
| 
											13 years ago
										 | 		$app = \Yii::$app;
 | ||
| 
											14 years ago
										 | 		if (!($app instanceof CWebApplication) || $app->getRequest()->getIsAjaxRequest())
 | ||
|  | 			return;
 | ||
|  | 
 | ||
|  | 		if ($this->getReport() === 'summary')
 | ||
|  | 			$this->displaySummary($logs);
 | ||
|  | 		else
 | ||
|  | 			$this->displayCallstack($logs);
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * Displays the callstack of the profiling procedures for display.
 | ||
|  | 	 * @param array $logs list of logs
 | ||
|  | 	 */
 | ||
|  | 	protected function displayCallstack($logs)
 | ||
|  | 	{
 | ||
|  | 		$stack = array();
 | ||
|  | 		$results = array();
 | ||
|  | 		$n = 0;
 | ||
|  | 		foreach ($logs as $log)
 | ||
|  | 		{
 | ||
| 
											14 years ago
										 | 			if ($log[1] !== CLogger::LEVEL_PROFILE) {
 | ||
| 
											14 years ago
										 | 				continue;
 | ||
| 
											14 years ago
										 | 			}
 | ||
| 
											14 years ago
										 | 			$message = $log[0];
 | ||
| 
											14 years ago
										 | 			if (!strncasecmp($message, 'begin:', 6)) {
 | ||
| 
											14 years ago
										 | 				$log[0] = substr($message, 6);
 | ||
|  | 				$log[4] = $n;
 | ||
|  | 				$stack[] = $log;
 | ||
|  | 				$n++;
 | ||
| 
											14 years ago
										 | 			} elseif (!strncasecmp($message, 'end:', 4)) {
 | ||
| 
											14 years ago
										 | 				$token = substr($message, 4);
 | ||
| 
											14 years ago
										 | 				if (($last = array_pop($stack)) !== null && $last[0] === $token) {
 | ||
| 
											14 years ago
										 | 					$delta = $log[3] - $last[3];
 | ||
|  | 					$results[$last[4]] = array($token, $delta, count($stack));
 | ||
| 
											14 years ago
										 | 				} else
 | ||
| 
											14 years ago
										 | 				{
 | ||
| 
											13 years ago
										 | 					throw new CException(Yii::t('yii', 'CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
 | ||
| 
											14 years ago
										 | 						array('{token}' => $token)));
 | ||
| 
											14 years ago
										 | 				}
 | ||
| 
											14 years ago
										 | 			}
 | ||
|  | 		}
 | ||
|  | 		// remaining entries should be closed here
 | ||
|  | 		$now = microtime(true);
 | ||
| 
											14 years ago
										 | 		while (($last = array_pop($stack)) !== null) {
 | ||
| 
											14 years ago
										 | 			$results[$last[4]] = array($last[0], $now - $last[3], count($stack));
 | ||
| 
											14 years ago
										 | 		}
 | ||
| 
											14 years ago
										 | 		ksort($results);
 | ||
|  | 		$this->render('profile-callstack', $results);
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * Displays the summary report of the profiling result.
 | ||
|  | 	 * @param array $logs list of logs
 | ||
|  | 	 */
 | ||
|  | 	protected function displaySummary($logs)
 | ||
|  | 	{
 | ||
|  | 		$stack = array();
 | ||
|  | 		foreach ($logs as $log)
 | ||
|  | 		{
 | ||
|  | 			if ($log[1] !== CLogger::LEVEL_PROFILE)
 | ||
|  | 				continue;
 | ||
|  | 			$message = $log[0];
 | ||
|  | 			if (!strncasecmp($message, 'begin:', 6))
 | ||
|  | 			{
 | ||
|  | 				$log[0] = substr($message, 6);
 | ||
|  | 				$stack[] = $log;
 | ||
| 
											14 years ago
										 | 			} elseif (!strncasecmp($message, 'end:', 4))
 | ||
| 
											14 years ago
										 | 			{
 | ||
|  | 				$token = substr($message, 4);
 | ||
|  | 				if (($last = array_pop($stack)) !== null && $last[0] === $token)
 | ||
|  | 				{
 | ||
|  | 					$delta = $log[3] - $last[3];
 | ||
|  | 					if (!$this->groupByToken)
 | ||
|  | 						$token = $log[2];
 | ||
|  | 					if (isset($results[$token]))
 | ||
|  | 						$results[$token] = $this->aggregateResult($results[$token], $delta);
 | ||
|  | 					else
 | ||
|  | 						$results[$token] = array($token, 1, $delta, $delta, $delta);
 | ||
| 
											14 years ago
										 | 				} else
 | ||
| 
											13 years ago
										 | 					throw new CException(Yii::t('yii', 'CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
 | ||
| 
											14 years ago
										 | 						array('{token}' => $token)));
 | ||
|  | 			}
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		$now = microtime(true);
 | ||
|  | 		while (($last = array_pop($stack)) !== null)
 | ||
|  | 		{
 | ||
|  | 			$delta = $now - $last[3];
 | ||
|  | 			$token = $this->groupByToken ? $last[0] : $last[2];
 | ||
|  | 			if (isset($results[$token]))
 | ||
|  | 				$results[$token] = $this->aggregateResult($results[$token], $delta);
 | ||
|  | 			else
 | ||
|  | 				$results[$token] = array($token, 1, $delta, $delta, $delta);
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		$entries = array_values($results);
 | ||
| 
											13 years ago
										 | 		$func = create_function('$a,$b', 'return $a[4] < $b[4] ? 1 : 0;');
 | ||
| 
											14 years ago
										 | 		usort($entries, $func);
 | ||
|  | 
 | ||
|  | 		$this->render('profile-summary', $entries);
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * Aggregates the report result.
 | ||
|  | 	 * @param array $result log result for this code block
 | ||
|  | 	 * @param float $delta time spent for this code block
 | ||
|  | 	 * @return array
 | ||
|  | 	 */
 | ||
|  | 	protected function aggregateResult($result, $delta)
 | ||
|  | 	{
 | ||
|  | 		list($token, $calls, $min, $max, $total) = $result;
 | ||
|  | 		if ($delta < $min)
 | ||
|  | 			$min = $delta;
 | ||
|  | 		elseif ($delta > $max)
 | ||
|  | 			$max = $delta;
 | ||
|  | 		$calls++;
 | ||
|  | 		$total += $delta;
 | ||
|  | 		return array($token, $calls, $min, $max, $total);
 | ||
|  | 	}
 | ||
| 
											13 years ago
										 | }
 |