Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages

Profiling.php

Go to the documentation of this file.
00001 <?php 00002 # This file is only included if profiling is enabled 00003 function wfProfileIn( $functionname ) 00004 { 00005 global $wgProfiler; 00006 $wgProfiler->profileIn( $functionname ); 00007 } 00008 00009 function wfProfileOut( $functionname = "missing" ) 00010 { 00011 global $wgProfiler; 00012 $wgProfiler->profileOut( $functionname ); 00013 } 00014 00015 function wfGetProfilingOutput( $start, $elapsed ) { 00016 global $wgProfiler; 00017 return $wgProfiler->getOutput( $start, $elapsed ); 00018 } 00019 00020 function wfProfileClose() 00021 { 00022 global $wgProfiler; 00023 $wgProfiler->close(); 00024 } 00025 00026 class Profiler 00027 { 00028 var $mStack = array(), $mWorkStack = array(), $mCollated = array(); 00029 var $mCalls = array(), $mTotals = array(); 00030 /* 00031 function Profiler() 00032 { 00033 $this->mProfileStack = array(); 00034 $this->mWorkStack = array(); 00035 $this->mCollated = array(); 00036 } 00037 */ 00038 00039 function profileIn( $functionname ) 00040 { 00041 global $wgDebugFunctionEntry; 00042 if ( $wgDebugFunctionEntry && function_exists( "wfDebug" ) ) { 00043 wfDebug( "Entering $functionname\n" ); 00044 } 00045 array_push( $this->mWorkStack, array($functionname, count( $this->mWorkStack ), microtime() ) ); 00046 } 00047 00048 function profileOut( $functionname) 00049 { 00050 global $wgDebugProfiling, $wgDebugFunctionEntry; 00051 00052 if ( $wgDebugFunctionEntry && function_exists( "wfDebug" ) ) { 00053 wfDebug( "Exiting $functionname\n" ); 00054 } 00055 00056 $bit = array_pop( $this->mWorkStack ); 00057 00058 if ( !$bit ) { 00059 wfDebug( "Profiling error, !\$bit: $functionname\n" ); 00060 } else { 00061 if ( $wgDebugProfiling ) { 00062 if ( $functionname == "close" ) { 00063 wfDebug( "Profile section ended by close(): {$bit[0]}\n" ); 00064 } elseif ( $bit[0] != $functionname ) { 00065 wfDebug( "Profiling error: in({$bit[0]}), out($functionname)\n" ); 00066 } 00067 } 00068 array_push( $bit, microtime() ); 00069 array_push( $this->mStack, $bit ); 00070 } 00071 } 00072 00073 function close() 00074 { 00075 while ( count( $this->mWorkStack ) ) { 00076 $this->profileOut( "close" ); 00077 } 00078 } 00079 00080 function getOutput( $scriptStart, $scriptElapsed ) 00081 { 00082 if( !count( $this->mStack ) ) { 00083 return "No profiling output\n"; 00084 } 00085 $this->close(); 00086 $width = 125; 00087 $format = "%-" . ($width - 28) . "s %6d %6.3f %6.3f %6.3f%%\n"; 00088 $titleFormat = "%-" . ($width - 28) . "s %9s %9s %9s %9s\n"; 00089 $prof = "\nProfiling data\n"; 00090 $prof .= sprintf( $titleFormat, "Name", "Calls", "Total", "Each", "%" ); 00091 $this->mCollated = array(); 00092 $this->mCalls = array(); 00093 00094 # Estimate profiling overhead 00095 $profileCount = count( $this->mStack ); 00096 wfProfileIn( "-overhead-total" ); 00097 for ($i=0; $i<$profileCount ; $i++) { 00098 wfProfileIn( "-overhead-internal" ); 00099 wfProfileOut( "-overhead-internal" ); 00100 } 00101 wfProfileOut( "-overhead-total" ); 00102 00103 # Collate 00104 foreach ( $this->mStack as $entry ) { 00105 $fname = $entry[0]; 00106 $thislevel = $entry[1]; 00107 $start = explode( " ", $entry[2]); 00108 $start = (float)$start[0] + (float)$start[1]; 00109 $end = explode( " ", $entry[3]); 00110 $end = (float)$end[0] + (float)$end[1]; 00111 $elapsed = $end - $start; 00112 00113 if ( !array_key_exists( $fname, $this->mCollated ) ) { 00114 $this->mCollated[$fname] = 0; 00115 $this->mCalls[$fname] = 0; 00116 } 00117 00118 $this->mCollated[$fname] += $elapsed; 00119 $this->mCalls[$fname] ++; 00120 } 00121 00122 $total = @$this->mCollated["-total"]; 00123 $overhead = $this->mCollated["-overhead-internal"] / $profileCount; 00124 $this->mCalls["-overhead-total"] = $profileCount; 00125 00126 # Output 00127 foreach ( $this->mCollated as $fname => $elapsed ) { 00128 $calls = $this->mCalls[$fname]; 00129 # Adjust for overhead 00130 if ( $fname[0] != "-" ) { 00131 $elapsed -= $overhead * $calls; 00132 } 00133 00134 $percent = $total ? 100. * $elapsed / $total : 0; 00135 $prof .= sprintf( $format, $fname, $calls, (float)($elapsed * 1000), 00136 (float)($elapsed * 1000) / $calls, $percent ); 00137 00138 global $wgProfileToDatabase; 00139 if( $wgProfileToDatabase ) { 00140 Profiler::logToDB( $fname, (float)($elapsed * 1000), $calls ); 00141 } 00142 } 00143 $prof .= "\nTotal: $total\n\n"; 00144 00145 return $prof; 00146 } 00147 00148 00149 /* static */ function logToDB($name, $timeSum, $eventCount) 00150 { 00151 $name = wfStrencode( $name ); 00152 $sql = "UPDATE profiling ". 00153 "SET pf_count=pf_count+{$eventCount}, ". 00154 "pf_time=pf_time + {$timeSum} ". 00155 "WHERE pf_name='{$name}'"; 00156 wfQuery($sql , DB_WRITE); 00157 00158 $rc = wfAffectedRows(); 00159 if( $rc == 0) { 00160 $sql = "INSERT IGNORE INTO profiling (pf_name,pf_count,pf_time) ". 00161 "VALUES ('{$name}', {$eventCount}, {$timeSum}) "; 00162 wfQuery($sql , DB_WRITE); 00163 $rc = wfAffectedRows(); 00164 } 00165 // When we upgrade to mysql 4.1, the insert+update 00166 // can be merged into just a insert with this construct added: 00167 // "ON DUPLICATE KEY UPDATE ". 00168 // "pf_count=pf_count + VALUES(pf_count), ". 00169 // "pf_time=pf_time + VALUES(pf_time)"; 00170 } 00171 00172 } 00173 00174 00175 $wgProfiler = new Profiler(); 00176 $wgProfiler->profileIn( "-total" ); 00177 ?>

Generated on Tue Jun 29 23:40:06 2004 for Mediawiki by doxygen 1.3.7