mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-12 23:14:18 +01:00
Reviewed the instrumentation to help in tuning the performance
SVN:trunk[2916]
This commit is contained in:
@@ -28,34 +28,170 @@ class ExecutionKPI
|
||||
{
|
||||
static protected $m_bEnabled_Duration = false;
|
||||
static protected $m_bEnabled_Memory = false;
|
||||
static protected $m_sAllowedUser = '*';
|
||||
|
||||
static protected $m_aStats = array();
|
||||
static protected $m_aStats = array(); // Recurrent operations
|
||||
static protected $m_aExecData = array(); // One shot operations
|
||||
|
||||
protected $m_fStarted = null;
|
||||
protected $m_iInitialMemory = null;
|
||||
|
||||
static public function EnableDuration()
|
||||
static public function EnableDuration($iLevel)
|
||||
{
|
||||
self::$m_bEnabled_Duration = true;
|
||||
if ($iLevel > 0)
|
||||
{
|
||||
self::$m_bEnabled_Duration = true;
|
||||
}
|
||||
}
|
||||
|
||||
static public function EnableMemory()
|
||||
static public function EnableMemory($iLevel)
|
||||
{
|
||||
self::$m_bEnabled_Memory = true;
|
||||
if ($iLevel > 0)
|
||||
{
|
||||
self::$m_bEnabled_Memory = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string sUser A user login or * for all users
|
||||
*/
|
||||
static public function SetAllowedUser($sUser)
|
||||
{
|
||||
self::$m_sAllowedUser = $sUser;
|
||||
}
|
||||
|
||||
static public function ReportStats()
|
||||
{
|
||||
if (self::$m_sAllowedUser != '*')
|
||||
{
|
||||
if (UserRights::GetUser() != self::$m_sAllowedUser)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
global $fItopStarted;
|
||||
$sExecId = microtime(); // id to differentiate the hrefs!
|
||||
|
||||
$aBeginTimes = array();
|
||||
foreach (self::$m_aExecData as $aOpStats)
|
||||
{
|
||||
$aBeginTimes[] = $aOpStats['time_begin'];
|
||||
}
|
||||
array_multisort($aBeginTimes, self::$m_aExecData);
|
||||
|
||||
$sTableStyle = 'background-color: #ccc; margin: 10px;';
|
||||
|
||||
self::Report("<hr/>");
|
||||
self::Report("<div style=\"background-color: grey; padding: 10px;\">");
|
||||
self::Report("<h3><a name=\"".md5($sExecId)."\">KPIs</a> - ".$_SERVER['REQUEST_URI']." (".$_SERVER['REQUEST_METHOD'].")</h3>");
|
||||
self::Report("<p>".date('Y-m-d H:i:s', $fItopStarted)."</p>");
|
||||
self::Report("<p>log_kpi_user_id: ".MetaModel::GetConfig()->Get('log_kpi_user_id')."</p>");
|
||||
self::Report("<div>");
|
||||
self::Report("<table border=\"1\" style=\"$sTableStyle\">");
|
||||
self::Report("<thead>");
|
||||
self::Report(" <th>Operation</th><th>Begin</th><th>End</th><th>Duration</th><th>Memory start</th><th>Memory end</th><th>Memory peak</th>");
|
||||
self::Report("</thead>");
|
||||
foreach (self::$m_aExecData as $aOpStats)
|
||||
{
|
||||
$sOperation = $aOpStats['op'];
|
||||
$sBegin = $sEnd = $sDuration = $sMemBegin = $sMemEnd = $sMemPeak = '?';
|
||||
|
||||
$sBegin = round($aOpStats['time_begin'], 3);
|
||||
$sEnd = round($aOpStats['time_end'], 3);
|
||||
$fDuration = $aOpStats['time_end'] - $aOpStats['time_begin'];
|
||||
$sDuration = round($fDuration, 3);
|
||||
|
||||
if (isset($aOpStats['mem_begin']))
|
||||
{
|
||||
$sMemBegin = self::MemStr($aOpStats['mem_begin']);
|
||||
$sMemEnd = self::MemStr($aOpStats['mem_end']);
|
||||
if (isset($aOpStats['mem_peak']))
|
||||
{
|
||||
$sMemPeak = self::MemStr($aOpStats['mem_peak']);
|
||||
}
|
||||
}
|
||||
|
||||
self::Report("<tr>");
|
||||
self::Report(" <td>$sOperation</td><td>$sBegin</td><td>$sEnd</td><td>$sDuration</td><td>$sMemBegin</td><td>$sMemEnd</td><td>$sMemPeak</td>");
|
||||
self::Report("</tr>");
|
||||
}
|
||||
self::Report("</table>");
|
||||
self::Report("</div>");
|
||||
|
||||
$aConsolidatedStats = array();
|
||||
foreach (self::$m_aStats as $sOperation => $aOpStats)
|
||||
{
|
||||
echo "<h2>KPIs for $sOperation</h2>\n";
|
||||
$fTotalOp = 0;
|
||||
$iTotalOp = 0;
|
||||
$fMinOp = null;
|
||||
$fMaxOp = 0;
|
||||
echo "<ul>\n";
|
||||
$sMaxOpArguments = null;
|
||||
foreach ($aOpStats as $sArguments => $aEvents)
|
||||
{
|
||||
foreach ($aEvents as $fDuration)
|
||||
{
|
||||
$fTotalOp += $fDuration;
|
||||
$iTotalOp++;
|
||||
|
||||
$fMinOp = is_null($fMinOp) ? $fDuration : min($fMinOp, $fDuration);
|
||||
if ($fDuration > $fMaxOp)
|
||||
{
|
||||
$sMaxOpArguments = $sArguments;
|
||||
$fMaxOp = $fDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
$aConsolidatedStats[$sOperation] = array(
|
||||
'count' => $iTotalOp,
|
||||
'duration' => $fTotalOp,
|
||||
'min' => $fMinOp,
|
||||
'max' => $fMaxOp,
|
||||
'avg' => $fTotalOp / $iTotalOp,
|
||||
'max_args' => $sMaxOpArguments
|
||||
);
|
||||
}
|
||||
|
||||
self::Report("<div>");
|
||||
self::Report("<table border=\"1\" style=\"$sTableStyle\">");
|
||||
self::Report("<thead>");
|
||||
self::Report(" <th>Operation</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th><th>Avg</th>");
|
||||
self::Report("</thead>");
|
||||
foreach ($aConsolidatedStats as $sOperation => $aOpStats)
|
||||
{
|
||||
$sOperation = '<a href="#'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
|
||||
$sCount = $aOpStats['count'];
|
||||
$sDuration = round($aOpStats['duration'], 3);
|
||||
$sMin = round($aOpStats['min'], 3);
|
||||
$sMax = '<a href="#'.md5($sExecId.$aOpStats['max_args']).'">'.round($aOpStats['max'], 3).'</a>';
|
||||
$sAvg = round($aOpStats['avg'], 3);
|
||||
|
||||
self::Report("<tr>");
|
||||
self::Report(" <td>$sOperation</td><td>$sCount</td><td>$sDuration</td><td>$sMin</td><td>$sMax</td><td>$sAvg</td>");
|
||||
self::Report("</tr>");
|
||||
}
|
||||
self::Report("</table>");
|
||||
self::Report("</div>");
|
||||
|
||||
self::Report("</div>");
|
||||
|
||||
// Report operation details
|
||||
foreach (self::$m_aStats as $sOperation => $aOpStats)
|
||||
{
|
||||
$sOperationHtml = '<a name="'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
|
||||
self::Report("<h4>$sOperationHtml</h4>");
|
||||
self::Report("<p><a href=\"#".md5($sExecId)."\">Back to page stats</a></p>");
|
||||
self::Report("<table border=\"1\" style=\"$sTableStyle\">");
|
||||
self::Report("<thead>");
|
||||
self::Report(" <th>Operation details</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>");
|
||||
self::Report("</thead>");
|
||||
foreach ($aOpStats as $sArguments => $aEvents)
|
||||
{
|
||||
$sHtmlArguments = '<a name="'.md5($sExecId.$sArguments).'">'.$sArguments.'</a>';
|
||||
if ($aConsolidatedStats[$sOperation]['max_args'] == $sArguments)
|
||||
{
|
||||
$sHtmlArguments = '<span style="color: red;">'.$sHtmlArguments.'</span>';
|
||||
}
|
||||
$fTotalInter = 0;
|
||||
$fMinInter = null;
|
||||
$fMaxInter = 0;
|
||||
@@ -64,34 +200,17 @@ class ExecutionKPI
|
||||
$fTotalInter += $fDuration;
|
||||
$fMinInter = is_null($fMinInter) ? $fDuration : min($fMinInter, $fDuration);
|
||||
$fMaxInter = max($fMaxInter, $fDuration);
|
||||
|
||||
$fMinOp = is_null($fMinOp) ? $fDuration : min($fMinOp, $fDuration);
|
||||
$fMaxOp = max($fMaxOp, $fDuration);
|
||||
}
|
||||
$fTotalOp += $fTotalInter;
|
||||
$iTotalOp++;
|
||||
|
||||
$iCountInter = count($aEvents);
|
||||
$sTotalInter = round($fTotalInter, 3)."s";
|
||||
if ($iCountInter > 1)
|
||||
{
|
||||
$sMinInter = round($fMinInter, 3)."s";
|
||||
$sMaxInter = round($fMaxInter, 3)."s";
|
||||
$sTimeDesc = "$sTotalInter (from $sMinInter to $sMaxInter) in $iCountInter times";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sTimeDesc = "$sTotalInter";
|
||||
}
|
||||
echo "<li>Spent $sTimeDesc, on: <span style=\"font-size:60%\">$sArguments</span></li>\n";
|
||||
$sTotalInter = round($fTotalInter, 3);
|
||||
$sMinInter = round($fMinInter, 3);
|
||||
$sMaxInter = round($fMaxInter, 3);
|
||||
self::Report("<tr>");
|
||||
self::Report(" <td>$sHtmlArguments</td><td>$iCountInter</td><td>$sTotalInter</td><td>$sMinInter</td><td>$sMaxInter</td>");
|
||||
self::Report("</tr>");
|
||||
}
|
||||
echo "</ul>\n";
|
||||
echo "<ul>Sumary for $sOperation\n";
|
||||
echo "<li>Total: $iTotalOp (".round($fTotalOp, 3).")</li>\n";
|
||||
echo "<li>Min: ".round($fMinOp, 3)."</li>\n";
|
||||
echo "<li>Max: ".round($fMaxOp, 3)."</li>\n";
|
||||
echo "<li>Avg: ".round($fTotalOp / $iTotalOp, 3)."</li>\n";
|
||||
echo "</ul>\n";
|
||||
self::Report("</table>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,25 +224,43 @@ class ExecutionKPI
|
||||
//
|
||||
public function ComputeAndReport($sOperationDesc)
|
||||
{
|
||||
global $fItopStarted;
|
||||
|
||||
$aNewEntry = null;
|
||||
|
||||
if (self::$m_bEnabled_Duration)
|
||||
{
|
||||
$fStopped = MyHelpers::getmicrotime();
|
||||
$fDuration = $fStopped - $this->m_fStarted;
|
||||
$this->Report($sOperationDesc.' / duration: '.round($fDuration, 3));
|
||||
$aNewEntry = array(
|
||||
'op' => $sOperationDesc,
|
||||
'time_begin' => $this->m_fStarted - $fItopStarted,
|
||||
'time_end' => $fStopped - $fItopStarted,
|
||||
);
|
||||
// Reset for the next operation (if the object is recycled)
|
||||
$this->m_fStarted = $fStopped;
|
||||
}
|
||||
|
||||
if (self::$m_bEnabled_Memory)
|
||||
{
|
||||
$iMemory = self::memory_get_usage();
|
||||
$iMemoryUsed = $iMemory - $this->m_iInitialMemory;
|
||||
$this->Report($sOperationDesc.' / memory: '.self::MemStr($iMemoryUsed).' (Total: '.self::MemStr($iMemory).')');
|
||||
$iCurrentMemory = self::memory_get_usage();
|
||||
if (is_null($aNewEntry))
|
||||
{
|
||||
$aNewEntry = array('op' => $sOperationDesc);
|
||||
}
|
||||
$aNewEntry['mem_begin'] = $this->m_iInitialMemory;
|
||||
$aNewEntry['mem_end'] = $iCurrentMemory;
|
||||
if (function_exists('memory_get_peak_usage'))
|
||||
{
|
||||
$iMemoryPeak = memory_get_peak_usage();
|
||||
$this->Report($sOperationDesc.' / memory peak: '.self::MemStr($iMemoryPeak));
|
||||
$aNewEntry['mem_peak'] = memory_get_peak_usage();
|
||||
}
|
||||
// Reset for the next operation (if the object is recycled)
|
||||
$this->m_iInitialMemory = $iCurrentMemory;
|
||||
}
|
||||
|
||||
if (!is_null($aNewEntry))
|
||||
{
|
||||
self::$m_aExecData[] = $aNewEntry;
|
||||
}
|
||||
$this->ResetCounters();
|
||||
}
|
||||
|
||||
@@ -150,9 +287,11 @@ class ExecutionKPI
|
||||
}
|
||||
}
|
||||
|
||||
protected function Report($sText)
|
||||
const HtmlReportFile = 'log/kpi.html';
|
||||
|
||||
static protected function Report($sText)
|
||||
{
|
||||
echo "$sText<br/>\n";
|
||||
file_put_contents(APPROOT.self::HtmlReportFile, "$sText\n", FILE_APPEND | LOCK_EX);
|
||||
}
|
||||
|
||||
static protected function MemStr($iMemory)
|
||||
@@ -204,13 +343,3 @@ class ExecutionKPI
|
||||
}
|
||||
}
|
||||
|
||||
class ApplicationStartupKPI extends ExecutionKPI
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
global $fItopStarted;
|
||||
$this->m_fStarted = $fItopStarted;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user