From 9d4a7e4d7599afea40c373e97724e0179b724a60 Mon Sep 17 00:00:00 2001 From: Edward Chernenko Date: Sun, 17 Jun 2018 18:09:49 +0300 Subject: [PATCH] Xhprof: support tideways-xhprof extension 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 | 40 ++++++++---- includes/profiler/ProfilerXhprof.php | 8 +-- tests/phpunit/includes/libs/XhprofTest.php | 73 ++++++++++++++++++++++ 3 files changed, 105 insertions(+), 16 deletions(-) diff --git a/includes/libs/Xhprof.php b/includes/libs/Xhprof.php index e58d98fcc3..8175427d8d 100644 --- a/includes/libs/Xhprof.php +++ b/includes/libs/Xhprof.php @@ -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" ); } } diff --git a/includes/profiler/ProfilerXhprof.php b/includes/profiler/ProfilerXhprof.php index 2f2be4727a..55a5a1f43f 100644 --- a/includes/profiler/ProfilerXhprof.php +++ b/includes/profiler/ProfilerXhprof.php @@ -43,16 +43,16 @@ * ($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 { /** diff --git a/tests/phpunit/includes/libs/XhprofTest.php b/tests/phpunit/includes/libs/XhprofTest.php index 0ea132896d..ccad4a43d6 100644 --- a/tests/phpunit/includes/libs/XhprofTest.php +++ b/tests/phpunit/includes/libs/XhprofTest.php @@ -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; } -- 2.20.1