Xhprof: support tideways-xhprof extension
authorEdward Chernenko <edwardspec@gmail.com>
Sun, 17 Jun 2018 15:09:49 +0000 (18:09 +0300)
committerKrinkle <krinklemail@gmail.com>
Tue, 19 Jun 2018 14:43:40 +0000 (14:43 +0000)
The "tideways" extension was renamed by their developers, see
https://tideways.com/profiler/blog/releasing-new-tideways-xhprof-extension

While doing so, they also renamed enable/disable functions:
tideways_enable -> tideways_xhprof_enable
tideways_disable -> tideways_xhprof_disable

Change-Id: I63bc97dba461dd46241a094dfc59439c0d28a219

includes/libs/Xhprof.php
includes/profiler/ProfilerXhprof.php
tests/phpunit/includes/libs/XhprofTest.php

index e58d98f..8175427 100644 (file)
@@ -54,13 +54,14 @@ class Xhprof {
                        throw new Exception( 'Profiling is already enabled.' );
                }
                self::$enabled = true;
-               if ( function_exists( 'xhprof_enable' ) ) {
-                       xhprof_enable( $flags, $options );
-               } elseif ( function_exists( 'tideways_enable' ) ) {
-                       tideways_enable( $flags, $options );
-               } else {
-                       throw new Exception( "Neither xhprof nor tideways are installed" );
-               }
+               self::callAny(
+                       [
+                               'xhprof_enable',
+                               'tideways_enable',
+                               'tideways_xhprof_enable'
+                       ],
+                       [ $flags, $options ]
+               );
        }
 
        /**
@@ -71,12 +72,27 @@ class Xhprof {
        public static function disable() {
                if ( self::isEnabled() ) {
                        self::$enabled = false;
-                       if ( function_exists( 'xhprof_disable' ) ) {
-                               return xhprof_disable();
-                       } else {
-                               // tideways
-                               return tideways_disable();
+                       return self::callAny( [
+                               'xhprof_disable',
+                               'tideways_disable',
+                               'tideways_xhprof_disable'
+                       ] );
+               }
+       }
+
+       /**
+        * Call the first available function from $functions.
+        * @param array $functions
+        * @param array $args
+        * @throws Exception
+        */
+       protected static function callAny( array $functions, array $args = [] ) {
+               foreach ( $functions as $func ) {
+                       if ( function_exists( $func ) ) {
+                               return $func( ...$args );
                        }
                }
+
+               throw new Exception( "Neither xhprof nor tideways are installed" );
        }
 }
index 2f2be47..55a5a1f 100644 (file)
  * ($wgProfiler['exclude']) containing an array of function names.
  * Shell-style patterns are also accepted.
  *
- * It is also possible to use the Tideways PHP extension, which is mostly
- * a drop-in replacement for Xhprof. Just change the XHPROF_FLAGS_* constants
- * to TIDEWAYS_FLAGS_*.
+ * This also supports Tideways-XHProf PHP extension, which is mostly a drop-in
+ * replacement for Xhprof (replace XHPROF_FLAGS_* with XHPROF_TIDEWAYS_FLAGS_*),
+ * as well as the older (discontinued) Tideways extension (TIDEWAYS_FLAGS_*).
  *
  * @copyright © 2014 Wikimedia Foundation and contributors
  * @ingroup Profiler
  * @see Xhprof
  * @see https://php.net/xhprof
  * @see https://github.com/facebook/hhvm/blob/master/hphp/doc/profiling.md
- * @see https://github.com/tideways/php-profiler-extension
+ * @see https://github.com/tideways/php-xhprof-extension
  */
 class ProfilerXhprof extends Profiler {
        /**
index 0ea1328..ccad4a4 100644 (file)
@@ -37,4 +37,77 @@ class XhprofTest extends PHPUnit\Framework\TestCase {
                $enabled->setValue( true );
                $xhprof->getMethod( 'enable' )->invoke( null );
        }
+
+       /**
+        * callAny() calls the first function of the list.
+        *
+        * @covers Xhprof::callAny
+        * @dataProvider provideCallAny
+        */
+       public function testCallAny( array $functions, array $args, $expectedResult ) {
+               $xhprof = new ReflectionClass( Xhprof::class );
+               $callAny = $xhprof->getMethod( 'callAny' );
+               $callAny->setAccessible( true );
+
+               $this->assertEquals( $expectedResult,
+                       $callAny->invoke( null, $functions, $args ) );
+       }
+
+       /**
+        * Data provider for testCallAny().
+       */
+       public function provideCallAny() {
+               return [
+                       [
+                               [ 'wfTestCallAny_func1', 'wfTestCallAny_func2', 'wfTestCallAny_func3' ],
+                               [ 3, 4 ],
+                               12
+                       ],
+                       [
+                               [ 'wfTestCallAny_nosuchfunc1', 'wfTestCallAny_func2', 'wfTestCallAny_func3' ],
+                               [ 3, 4 ],
+                               7
+                       ],
+                       [
+                               [ 'wfTestCallAny_nosuchfunc1', 'wfTestCallAny_nosuchfunc2', 'wfTestCallAny_func3' ],
+                               [ 3, 4 ],
+                               -1
+                       ]
+
+               ];
+       }
+
+       /**
+        * callAny() throws an exception when all functions are unavailable.
+        *
+        * @expectedException        Exception
+        * @expectedExceptionMessage Neither xhprof nor tideways are installed
+        * @covers Xhprof::callAny
+        */
+       public function testCallAnyNoneAvailable() {
+               $xhprof = new ReflectionClass( Xhprof::class );
+               $callAny = $xhprof->getMethod( 'callAny' );
+               $callAny->setAccessible( true );
+
+               $callAny->invoke( $xhprof, [
+                       'wfTestCallAny_nosuchfunc1',
+                       'wfTestCallAny_nosuchfunc2',
+                       'wfTestCallAny_nosuchfunc3'
+               ] );
+       }
+}
+
+/** Test function #1 for XhprofTest::testCallAny */
+function wfTestCallAny_func1( $a, $b ) {
+       return $a * $b;
+}
+
+/** Test function #2 for XhprofTest::testCallAny */
+function wfTestCallAny_func2( $a, $b ) {
+       return $a + $b;
+}
+
+/** Test function #3 for XhprofTest::testCallAny */
+function wfTestCallAny_func3( $a, $b ) {
+       return $a - $b;
 }