Merge "Make a hidden form field to keep the language code"
[lhc/web/wiklou.git] / includes / profiler / ProfilerMwprof.php
index 5ecfc21..af3c774 100644 (file)
  * @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 );
        }
 
        /**
@@ -96,18 +86,18 @@ class ProfilerMwprof extends Profiler {
 
                $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
+       }
 }