wiki.techinc.nl/includes/Profiling.php
Tim Starling ac549401d4 * Support for table name prefixes throughout the code. No support yet for converting static SQL, which also means no installation. But it has been tested by creating the tables in the ordinary way and then renaming them
* DB_WRITE now called DB_MASTER, DB_READ now called DB_SLAVE
* Converted to use SQL wrapper functions instead of direct SQL in various places
* Experimental method for preserving the chronological order of events when slave servers are used. Untested.
* Fixes to the new post-parse existence test feature
* Some.. other stuff
2004-07-18 08:48:43 +00:00

182 lines
4.7 KiB
PHP
Executable file

<?php
# This file is only included if profiling is enabled
function wfProfileIn( $functionname )
{
global $wgProfiler;
$wgProfiler->profileIn( $functionname );
}
function wfProfileOut( $functionname = "missing" )
{
global $wgProfiler;
$wgProfiler->profileOut( $functionname );
}
function wfGetProfilingOutput( $start, $elapsed ) {
global $wgProfiler;
return $wgProfiler->getOutput( $start, $elapsed );
}
function wfProfileClose()
{
global $wgProfiler;
$wgProfiler->close();
}
class Profiler
{
var $mStack = array(), $mWorkStack = array(), $mCollated = array();
var $mCalls = array(), $mTotals = array();
/*
function Profiler()
{
$this->mProfileStack = array();
$this->mWorkStack = array();
$this->mCollated = array();
}
*/
function profileIn( $functionname )
{
global $wgDebugFunctionEntry;
if ( $wgDebugFunctionEntry && function_exists( "wfDebug" ) ) {
wfDebug( str_repeat( " ", count( $this->mWorkStack ) ) . "Entering $functionname\n" );
}
array_push( $this->mWorkStack, array($functionname, count( $this->mWorkStack ), microtime() ) );
}
function profileOut( $functionname)
{
global $wgDebugProfiling, $wgDebugFunctionEntry;
if ( $wgDebugFunctionEntry && function_exists( "wfDebug" ) ) {
wfDebug( str_repeat( " ", count( $this->mWorkStack ) - 1 ) . "Exiting $functionname\n" );
}
$bit = array_pop( $this->mWorkStack );
if ( !$bit ) {
wfDebug( "Profiling error, !\$bit: $functionname\n" );
} else {
if ( $wgDebugProfiling ) {
if ( $functionname == "close" ) {
wfDebug( "Profile section ended by close(): {$bit[0]}\n" );
} elseif ( $bit[0] != $functionname ) {
wfDebug( "Profiling error: in({$bit[0]}), out($functionname)\n" );
}
}
array_push( $bit, microtime() );
array_push( $this->mStack, $bit );
}
}
function close()
{
while ( count( $this->mWorkStack ) ) {
$this->profileOut( "close" );
}
}
function getOutput()
{
global $wgDebugFunctionEntry;
$wgDebugFunctionEntry = false;
if( !count( $this->mStack ) ) {
return "No profiling output\n";
}
$this->close();
$width = 125;
$format = "%-" . ($width - 28) . "s %6d %6.3f %6.3f %6.3f%%\n";
$titleFormat = "%-" . ($width - 28) . "s %9s %9s %9s %9s\n";
$prof = "\nProfiling data\n";
$prof .= sprintf( $titleFormat, "Name", "Calls", "Total", "Each", "%" );
$this->mCollated = array();
$this->mCalls = array();
# Estimate profiling overhead
$profileCount = count( $this->mStack );
wfProfileIn( "-overhead-total" );
for ($i=0; $i<$profileCount ; $i++) {
wfProfileIn( "-overhead-internal" );
wfProfileOut( "-overhead-internal" );
}
wfProfileOut( "-overhead-total" );
# Collate
foreach ( $this->mStack as $entry ) {
$fname = $entry[0];
$thislevel = $entry[1];
$start = explode( " ", $entry[2]);
$start = (float)$start[0] + (float)$start[1];
$end = explode( " ", $entry[3]);
$end = (float)$end[0] + (float)$end[1];
$elapsed = $end - $start;
if ( !array_key_exists( $fname, $this->mCollated ) ) {
$this->mCollated[$fname] = 0;
$this->mCalls[$fname] = 0;
}
$this->mCollated[$fname] += $elapsed;
$this->mCalls[$fname] ++;
}
$total = @$this->mCollated["-total"];
$overhead = $this->mCollated["-overhead-internal"] / $profileCount;
$this->mCalls["-overhead-total"] = $profileCount;
# Output
foreach ( $this->mCollated as $fname => $elapsed ) {
$calls = $this->mCalls[$fname];
# Adjust for overhead
if ( $fname[0] != "-" ) {
$elapsed -= $overhead * $calls;
}
$percent = $total ? 100. * $elapsed / $total : 0;
$prof .= sprintf( $format, $fname, $calls, (float)($elapsed * 1000),
(float)($elapsed * 1000) / $calls, $percent );
global $wgProfileToDatabase;
if( $wgProfileToDatabase ) {
Profiler::logToDB( $fname, (float)($elapsed * 1000), $calls );
}
}
$prof .= "\nTotal: $total\n\n";
return $prof;
}
/* static */ function logToDB($name, $timeSum, $eventCount)
{
$dbw =& wfGetDB( DB_MASTER );
$profiling = $dbw->tableName( 'profiling' );
$name = $dbw->strencode( $name );
$sql = "UPDATE $profiling ".
"SET pf_count=pf_count+{$eventCount}, ".
"pf_time=pf_time + {$timeSum} ".
"WHERE pf_name='{$name}'";
$dbw->query($sql);
$rc = $dbw->affectedRows();
if( $rc == 0) {
$sql = "INSERT IGNORE INTO $profiling (pf_name,pf_count,pf_time) ".
"VALUES ('{$name}', {$eventCount}, {$timeSum}) ";
$dbw->query($sql , DB_MASTER);
}
// When we upgrade to mysql 4.1, the insert+update
// can be merged into just a insert with this construct added:
// "ON DUPLICATE KEY UPDATE ".
// "pf_count=pf_count + VALUES(pf_count), ".
// "pf_time=pf_time + VALUES(pf_time)";
}
}
$wgProfiler = new Profiler();
$wgProfiler->profileIn( "-total" );
?>