Adding basic profiler sampling support and restored the --profiler script option
authorAaron Schulz <aschulz@wikimedia.org>
Fri, 21 Nov 2014 22:54:57 +0000 (14:54 -0800)
committerAaron Schulz <aschulz@wikimedia.org>
Fri, 21 Nov 2014 23:14:18 +0000 (15:14 -0800)
* Also enforce that the profiler is normally off in CLI mode

Change-Id: I35faedff818af2ad459b544c9ad50e77b54b378e

StartProfiler.sample
includes/profiler/Profiler.php
maintenance/Maintenance.php

index b72d5d5..d20c0e1 100644 (file)
  * maintenance/archives/patch-profiling.sql to your database.
  *
  * For a rudimentary sampling profiler:
- *   if ( !mt_rand( 0, 100 ) ) {
- *       $wgProfiler['class'] = 'ProfilerStandard';
- *       $wgProfiler['output'] = array( 'db' );
- *   }
+ *   $wgProfiler['class'] = 'ProfilerStandard';
+ *   $wgProfiler['output'] = array( 'db' );
+ *   $wgProfiler['sampling'] = 50; // one every 50 requests
+ * This will use ProfilerStub for non-sampled cases.
+ *
+ * For performance, the profiler is always disabled for CLI scripts
+ * as they could be long running and the data would accumulate. Use
+ * the --profiler parameter of maintenance scripts to override this.
  */
index f2bdc84..2b3b616 100644 (file)
@@ -72,10 +72,10 @@ abstract class Profiler {
                if ( self::$__instance === null ) {
                        global $wgProfiler;
                        if ( is_array( $wgProfiler ) ) {
-                               if ( !isset( $wgProfiler['class'] ) ) {
+                               $class = isset( $wgProfiler['class'] ) ? $wgProfiler['class'] : 'ProfilerStub';
+                               $factor = isset( $wgProfiler['sampling'] ) ? $wgProfiler['sampling'] : 1;
+                               if ( PHP_SAPI === 'cli' || mt_rand( 0, $factor - 1 ) != 0 ) {
                                        $class = 'ProfilerStub';
-                               } else {
-                                       $class = $wgProfiler['class'];
                                }
                                self::$__instance = new $class( $wgProfiler );
                        } else {
@@ -85,6 +85,21 @@ abstract class Profiler {
                return self::$__instance;
        }
 
+       /**
+        * Replace the current profiler with $profiler if no non-stub profiler is set
+        *
+        * @param Profiler $profiler
+        * @throws MWException
+        * @since 1.25
+        */
+       final public static function replaceStubInstance( Profiler $profiler ) {
+               if ( self::$__instance && !( self::$__instance instanceof ProfilerStub ) ) {
+                       throw new MWException( 'Could not replace non-stub profiler instance.' );
+               } else {
+                       self::$__instance = $profiler;
+               }
+       }
+
        /**
         * Return whether this a stub profiler
         *
@@ -144,8 +159,7 @@ abstract class Profiler {
         * @since 1.25
         */
        public function logData() {
-               $output = isset( $this->params['output'] ) ?
-                       $this->params['output'] : null;
+               $output = isset( $this->params['output'] ) ? $this->params['output'] : null;
 
                if ( !$output || $this->isStub() ) {
                        // return early when no output classes defined or we're a stub
index 3f8f6e8..1d558d2 100644 (file)
@@ -446,6 +446,7 @@ abstract class Maintenance {
                $this->addOption( 'server', "The protocol and server name to use in URLs, e.g. " .
                        "http://en.wikipedia.org. This is sometimes necessary because " .
                        "server name detection may fail in command line scripts.", false, true );
+               $this->addOption( 'profiler', 'Profiler output format (usually "text")', false, true );
 
                # Save generic options to display them separately in help
                $this->mGenericParameters = $this->mParams;
@@ -596,6 +597,23 @@ abstract class Maintenance {
                }
        }
 
+       /**
+        * Activate the profiler (assuming $wgProfiler is set)
+        */
+       protected function activateProfiler() {
+               global $wgProfiler;
+
+               $output = $this->getOption( 'profiler' );
+               if ( $output && is_array( $wgProfiler ) ) {
+                       $class = $wgProfiler['class'];
+                       $profiler = new $class(
+                               array( 'sampling' => 1, 'output' => $output ) + $wgProfiler
+                       );
+                       $profiler->setTemplated( true );
+                       Profiler::replaceStubInstance( $profiler );
+               }
+       }
+
        /**
         * Clear all params and arguments.
         */
@@ -919,6 +937,9 @@ abstract class Maintenance {
                        LBFactory::destroyInstance();
                }
 
+               // Per-script profiling; useful for debugging
+               $this->activateProfiler();
+
                $this->afterFinalSetup();
 
                $wgShowSQLErrors = true;