X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fprofiler%2FProfilerMwprof.php;h=af3c7741c7eec366124f2c3132b142b932641a90;hb=91f7c1996d5169ac7d712ddc070fd0113ce9afb6;hp=e81c6ecc8c858a1b1b6df8d22c649b23bd550738;hpb=55da056f08df570e7a893edf5c9607b819f511df;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/profiler/ProfilerMwprof.php b/includes/profiler/ProfilerMwprof.php index e81c6ecc8c..af3c7741c7 100644 --- a/includes/profiler/ProfilerMwprof.php +++ b/includes/profiler/ProfilerMwprof.php @@ -33,21 +33,22 @@ * @since 1.23 */ class ProfilerMwprof extends Profiler { + /** @var array Queue of open profile calls with start data */ + protected $mWorkStack = array(); - // Message types + /** @var array Map of (function name => aggregate data array) */ + protected $mCollated = array(); + /** @var array Cache of a standard broken collation entry */ + protected $mErrorEntry; - const TYPE_SINGLE = 1; + // Message types + const TYPE_SINGLE = 1; const TYPE_RUNNING = 2; - /** - * Indicate that this Profiler subclass is persistent. - * - * Called by Parser::braceSubstitution. If true, the parser will not - * generate per-title profiling sections, to avoid overloading the - * profiling data collector. - * - * @return bool true - */ + public function isStub() { + return false; + } + public function isPersistent() { return true; } @@ -62,18 +63,7 @@ class ProfilerMwprof extends Profiler { */ public function profileIn( $inName ) { $this->mWorkStack[] = array( $inName, count( $this->mWorkStack ), - $this->getTime(), $this->getTime( 'cpu' ) ); - } - - /** - * Produce an empty function report. - * - * ProfileMwprof does not provide a function report. - * - * @return string Empty string. - */ - public function getFunctionReport() { - return ''; + $this->getTime(), $this->getTime( 'cpu' ), 0 ); } /** @@ -90,24 +80,24 @@ class ProfilerMwprof extends Profiler { // Check for unbalanced profileIn / profileOut calls. // Bad entries are logged but not sent. if ( $inName !== $outName ) { - wfDebugLog( 'ProfilerUnbalanced', json_encode( array( $inName, $outName ) ) ); + $this->debugGroup( 'ProfilerUnbalanced', json_encode( array( $inName, $outName ) ) ); return; } $elapsedCpu = $this->getTime( 'cpu' ) - $inCpu; $elapsedWall = $this->getTime() - $inWall; - $this->updateEntry( $outName, $elapsedCpu, $elapsedWall ); - $this->updateTrxProfiling( $outName, $elapsedWall ); + $this->updateRunningEntry( $outName, $elapsedCpu, $elapsedWall ); + $this->trxProfiler->recordFunctionCompletion( $outName, $elapsedWall ); } /** * Update an entry with timing data. * * @param string $name Section name - * @param float $elapsedCpu elapsed CPU time - * @param float $elapsedWall elapsed wall-clock time + * @param float $elapsedCpu Elapsed CPU time + * @param float $elapsedWall Elapsed wall-clock time */ - public function updateEntry( $name, $elapsedCpu, $elapsedWall ) { + public function updateRunningEntry( $name, $elapsedCpu, $elapsedWall ) { // If this is the first measurement for this entry, store plain values. // Many profiled functions will only be called once per request. if ( !isset( $this->mCollated[$name] ) ) { @@ -138,6 +128,65 @@ class ProfilerMwprof extends Profiler { $entry['wall']->push( $elapsedWall ); } + /** + * @return array + */ + public function getRawData() { + // This method is called before shutdown in the footer method on Skins. + // If some outer methods have not yet called wfProfileOut(), work around + // that by clearing anything in the work stack to just the "-total" entry. + if ( count( $this->mWorkStack ) > 1 ) { + $oldWorkStack = $this->mWorkStack; + $this->mWorkStack = array( $this->mWorkStack[0] ); // just the "-total" one + } else { + $oldWorkStack = null; + } + $this->close(); + // If this trick is used, then the old work stack is swapped back afterwards. + // This means that logData() will still make use of all the method data since + // the missing wfProfileOut() calls should be made by the time it is called. + if ( $oldWorkStack ) { + $this->mWorkStack = $oldWorkStack; + } + + $totalWall = 0.0; + $profile = array(); + foreach ( $this->mCollated as $fname => $data ) { + if ( $data['count'] == 1 ) { + $profile[] = array( + 'name' => $fname, + 'calls' => $data['count'], + 'elapsed' => $data['wall'] * 1000, + 'memory' => 0, // not supported + 'min' => $data['wall'] * 1000, + 'max' => $data['wall'] * 1000, + 'overhead' => 0, // not supported + 'periods' => array() // not supported + ); + $totalWall += $data['wall']; + } else { + $profile[] = array( + 'name' => $fname, + 'calls' => $data['count'], + 'elapsed' => $data['wall']->n * $data['wall']->getMean() * 1000, + 'memory' => 0, // not supported + 'min' => $data['wall']->min * 1000, + 'max' => $data['wall']->max * 1000, + 'overhead' => 0, // not supported + 'periods' => array() // not supported + ); + $totalWall += $data['wall']->n * $data['wall']->getMean(); + } + } + $totalWall = $totalWall * 1000; + + foreach ( $profile as &$item ) { + $item['percent'] = $totalWall ? 100 * $item['elapsed'] / $totalWall : 0; + } + + return $profile; + } + /** * Serialize profiling data and send to a profiling data aggregator. * @@ -151,6 +200,10 @@ class ProfilerMwprof extends Profiler { $this->close(); + if ( !function_exists( 'socket_create' ) ) { + return; // avoid fatal + } + $sock = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP ); socket_connect( $sock, $wgUDPProfilerHost, $wgUDPProfilerPort ); $bufferLength = 0; @@ -187,4 +240,17 @@ class ProfilerMwprof extends Profiler { socket_send( $sock, $buffer, $bufferLength, 0 ); } } + + /** + * Close opened profiling sections + */ + public function close() { + while ( count( $this->mWorkStack ) ) { + $this->profileOut( 'close' ); + } + } + + public function getOutput() { + return ''; // no report + } }