* @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;
+ // 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;
}
*/
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 );
}
/**
$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] ) ) {
$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.
*
$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;
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
+ }
}