Files
wy/ZeedFramework/library/Zeed/Benchmark.php

344 lines
12 KiB
PHP
Raw Normal View History

2026-01-07 11:40:41 +08:00
<?php
/**
* Zeed Platform Project
* Based on Zeed Framework & Zend Framework.
*
* BTS - Billing Transaction Service
* CAS - Central Authentication Service
*
* LICENSE
* http://www.zeed.com.cn/license/
*
* @category Zeed
* @package Zeed_Benchmark
* @copyright Copyright (c) 2010 Zeed Technologies PRC Inc. (http://www.zeed.com.cn)
* @author Zeed Team (http://blog.zeed.com.cn)
* @since 2010-6-30
* @version SVN: $Id: Benchmark.php 13049 2012-06-15 17:11:04Z xsharp $
*/
class Zeed_Benchmark
{
/**
* Benchmark timestamps
*
* @var array
*/
private static $marks;
private static $_resetThisCounter = false;
/**
* 重置开始时间
*
* @param string $name
* @param boolean $resetAll 如果设置为 false,那么只清除上一次开始时间,并且下次结束时间也不做统计
*/
public static function reset($name, $resetAll = true)
{
if (isset(self::$marks[$name])) {
if ($resetAll) {
self::$marks[$name] = array();
} else {
if (! empty(self::$marks[$name])) {
array_shift(self::$marks[$name]);
self::$_resetThisCounter = true;
}
}
}
}
/**
* Set a benchmark start point.
*
* @param string benchmark name
* @return void
*/
public static function start($name)
{
if (! isset(self::$marks[$name])) {
self::$marks[$name] = array();
}
$mark = array(
'start' => microtime(TRUE),
'stop' => FALSE,
'memory_start' => self::memory_usage(),
'memory_stop' => FALSE);
array_unshift(self::$marks[$name], $mark);
}
/**
* Set a benchmark stop point.
*
* @param string benchmark name
* @return void
*/
public static function stop($name)
{
if (self::$_resetThisCounter) {
self::$_resetThisCounter = false;
return;
}
if (isset(self::$marks[$name]) and self::$marks[$name][0]['stop'] === FALSE) {
self::$marks[$name][0]['stop'] = microtime(TRUE);
self::$marks[$name][0]['memory_stop'] = self::memory_usage();
}
}
/**
* Get the elapsed time between a start and stop.
*
* @param string benchmark name, TRUE for all
* @param integer number of decimal places to count to
* @return array
*/
public static function get($name, $decimals = 4)
{
if ($name === TRUE) {
$times = array();
$names = array_keys(self::$marks);
foreach ($names as $name) {
// Get each mark recursively
$times[$name] = self::get($name, $decimals);
}
// Return the array
return $times;
}
if (! isset(self::$marks[$name]))
return FALSE;
if (empty(self::$marks[$name])) {
return array('time' => 0, 'memory' => 0, 'count' => 0);
}
if (self::$marks[$name][0]['stop'] === FALSE) {
// Stop the benchmark to prevent mis-matched results
self::stop($name);
}
// Return a string version of the time between the start and stop points
// Properly reading a float requires using number_format or sprintf
$time = $memory = 0;
$count = count(self::$marks[$name]);
for ($i = 0; $i < $count; $i ++) {
$time += self::$marks[$name][$i]['stop'] - self::$marks[$name][$i]['start'];
$memory += self::$marks[$name][$i]['memory_stop'] - self::$marks[$name][$i]['memory_start'];
}
return array(
'time' => number_format($time, $decimals),
'memory' => number_format(($memory / 1024 / 1024), 4),
'count' => $count);
}
/**
* Dump marks to log file.(Testing)
*
* @return array
*/
public static function dump()
{
if (! count(self::$marks)) {
return false;
}
$marks = Zeed_Benchmark::get(true);
$logFile = ZEED_PATH_DATA . 'log/Benchmark-' . date('Y-m-d') . '.log';
$clientIP = Zeed_Util::clientIP();
$clientName = 'xsharp' . rand(1, 8);
$time = time();
if (false != $handle = fopen($logFile, 'a')) {
$logContent = '';
foreach ($marks as $name => $mark) {
$time += rand(1, 8);
//$logContent .= $clientIP . ' ' . $clientName . ' [' . date('m/M/Y:H:i:s +0800') . '] "GET ' . $name . ' HTTP/1.1" ' . $mark['time'] . ' ' . $mark['memory'] . ' ' . $mark['count'] . "\n";
$logContent .= $clientIP . ' - ' . $clientName . ' [' . date('m/M/Y:H:i:s +0800', $time) . '] "GET /' . $name . ' HTTP/1.1" 200 ' . (int) ($mark['time'] * 1000000) . "\r\n";
}
fwrite($handle, $logContent);
fclose($handle);
}
}
/**
* Returns the current memory usage. This is only possible if the
* memory_get_usage function is supported in PHP.
*
* @return integer
*/
private static function memory_usage()
{
static $func = NULL;
if ($func === NULL) {
// Test if memory usage can be seen
$func = function_exists('memory_get_usage');
}
return $func ? memory_get_usage() : 0;
}
/**
* Colorful print_r()
*
* @param Array|String|Mixed $var
* @param String $memo
*/
public static function print_r($var, $memo = null)
{
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$color_bg = "RGB(" . rand(100, 255) . "," . rand(100, 255) . "," . rand(100, 255) . ")";
if (! is_null($memo)) {
$prefix = '<FIELDSET STYLE="FONT-SIZE:12PX;FONT-FAMILY:COURIER NEW;"><LEGEND STYLE="PADDING:5PX;">' . (is_string($memo)? $memo : print_r($memo, true)) . '</LEGEND>';
$postfix = '</FIELDSET>';
} else {
$prefix = $postfix = "";
}
echo $prefix . '<PRE STYLE="FONT-SIZE:12PX;PADDING:5PX;BORDER-LEFT:5PX SOLID #0066CC;FONT-FAMILY:COURIER NEW;COLOR:BLACK;TEXT-ALIGN:LEFT;BACKGROUND-COLOR:' . $color_bg . '">' . "\n";
print_r($var);
echo "\n</PRE>\n" . $postfix;
} else {
if (! is_null($memo)) {
if (is_string($memo)) {
echo $memo;
} else {
print_r($memo);
}
echo " - - - - -\n";
}
print_r($var);
echo "\n";
}
}
public static function println($str, $flush = true)
{
if (isset($_SERVER['HTTP_USER_AGENT'])) {
echo $str . '<br />';
} else {
echo $str . "\n";
}
if ($flush) {
Zeed_Util::flush();
}
}
/**
*
*/
public static function sql()
{
if (class_exists('Fit_Db', false)) {
$dbInstances = & Fit_Db::$instances;
} elseif (class_exists('Zeed_Db', false)) {
$dbInstances = & Zeed_Db::$instances;
} else {
return null;
}
if (empty($dbInstances)) {
return null;
}
$totalTime = 0;
$queryCount = 0;
$longestTime = 0;
$longestQuery = null;
$sqlAll = array();
$i = 0;
foreach ($dbInstances as $name => $dbAdapter) {
$profiler = $dbAdapter->getProfiler();
$_cQueryCount = $profiler->getTotalNumQueries();
if ($_cQueryCount < 1) {
continue;
} else {
$totalTime += $profiler->getTotalElapsedSecs();
$queryCount += $profiler->getTotalNumQueries();
}
foreach ($profiler->getQueryProfiles() as $_qp) {
$_es = $_qp->getElapsedSecs();
$_q = $_qp->getQuery();
$sqlAll["$_es"] = array('sql' => $_q, 'time' => $_es, 'id' => $i, 'con' => $name);
if ($_qp->getQueryType() == Zend_Db_Profiler::SELECT) {
$sqlAll["$_es"]['explain'] = $dbAdapter->query('EXPLAIN ' . $_q)->fetchAll();
}
if ($_es > $longestTime) {
$longestTime = $_es;
$longestQuery = $_q;
}
$i ++;
}
}
if ($queryCount < 1) {
return null;
}
echo '<a href="#showsql" name="showsql" style="text-decoration:none;" onclick="(document.getElementById(\'queryProfiler\').style.display == \'none\') ? (document.getElementById(\'queryProfiler\').style.display = \'block\') : (document.getElementById(\'queryProfiler\').style.display = \'none\')">+</a>';
echo '<div id="queryProfiler" style="display:none; text-align:left; padding-left:2px; line-height:130%; color:#003366; font-size:11px; font-family:Courier New; margin:0; background-color:#FAF8C5; border:1px dotted #666;">';
if (count($sqlAll) > 0) {
ksort($sqlAll);
reset($sqlAll);
$perIn = (int) (255 / $queryCount);
$fColor = 0;
foreach ($sqlAll as $val) {
$fColor += $perIn;
$bColor = 255 - $fColor;
$val['fColor'] = $fColor;
$val['bColor'] = $bColor;
$sqlAll2[$val['id']] = $val;
}
ksort($sqlAll2);
reset($sqlAll2);
unset($sqlAll);
foreach ($sqlAll2 as $val) {
$val['time'] = $val['time'] * 1000;
$val['time'] = (string) sprintf('%f', $val['time']) . 'ms';
echo sprintf('%02d', $val['id']) . '.<span style="border-left: 10px solid rgb(255,' . $val['bColor'] . ',' . $val['bColor'] . '); ;border-bottom: 1px solid rgb(255,' . $val['bColor'] . ',' . $val['bColor'] . '); line-height:21px;">' . $val['sql'] . '</span> (' . $val['con'] . ') ... ' . $val['time'] . '<br />';
if (! isset($val['explain'])) {
continue;
}
$explain = '<span style="padding-left: 30px ;">';
foreach ($val['explain'] as $_val) {
$explain .= ' <strong>Table:</strong> ' . $_val['table'];
if ($_val['key'] != '') {
$explain .= ' <strong>Key:</strong> ' . $_val['key'];
}
if ($_val['Extra'] != '') {
if (preg_match("/temporary|filesort/i", $_val['Extra'])) {
$eColor = 'red';
} else {
$eColor = 'green';
}
$explain .= ' <strong>Extra:</strong> <span = style="background-color:' . $eColor . '; color: white;">' . $_val['Extra'] . '</span>';
}
}
echo $explain . '</span><br>';
}
}
echo '<div style="padding-left:1px; margin-top:5px;">';
echo 'Executed ' . $queryCount . ' queries in ' . $totalTime . ' seconds' . "<br />\n";
echo 'Average query length: ' . $totalTime / $queryCount . ' seconds' . "<br />\n";
echo 'Queries per second: ' . $queryCount / $totalTime . "<br />\n";
echo 'Longest query length: ' . $longestTime . "<br />\n";
echo "Longest query: \n" . $longestQuery . "<br />\n";
echo '</div>';
echo '</div>';
}
}
// End ^ LF ^ UTF-8