X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=maintenance%2Fmctest.php;h=6b1cdc39a7e091095b9088fb8878818e5673ae66;hb=101493a70783b15656daa0686d404ac1a7a6976b;hp=513edf391120c52313261442464812ea4c429eb8;hpb=7bdfadde3fe1b14ff633ff740f77d74585b8e00a;p=lhc%2Fweb%2Fwiklou.git diff --git a/maintenance/mctest.php b/maintenance/mctest.php index 513edf3911..6b1cdc39a7 100644 --- a/maintenance/mctest.php +++ b/maintenance/mctest.php @@ -33,10 +33,14 @@ require_once __DIR__ . '/Maintenance.php'; class McTest extends Maintenance { public function __construct() { parent::__construct(); - $this->addDescription( "Makes several 'set', 'incr' and 'get' requests on every" - . " memcached server and shows a report" ); + $this->addDescription( + "Makes several operation requests on every cache server and shows a report.\n" . + "This tests both per-key and batched *Multi() methods as well as WRITE_BACKGROUND.\n" . + "\"IB\" means \"immediate blocking\" and \"DB\" means \"deferred blocking.\"" + ); $this->addOption( 'i', 'Number of iterations', false, true ); $this->addOption( 'cache', 'Use servers from this $wgObjectCaches store', false, true ); + $this->addOption( 'driver', 'Either "php" or "pecl"', false, true ); $this->addArg( 'server[:port]', 'Memcached server to test, with optional port', false ); } @@ -66,41 +70,181 @@ class McTest extends Maintenance { # find out the longest server string to nicely align output later on $maxSrvLen = $servers ? max( array_map( 'strlen', $servers ) ) : 0; - foreach ( $servers as $server ) { - $this->output( - str_pad( $server, $maxSrvLen ), - $server # output channel - ); + $type = $this->getOption( 'driver', 'php' ); + if ( $type === 'php' ) { + $class = MemcachedPhpBagOStuff::class; + } elseif ( $type === 'pecl' ) { + $class = MemcachedPeclBagOStuff::class; + } else { + $this->fatalError( "Invalid driver type '$type'" ); + } - $mcc = new MemcachedClient( [ - 'persistant' => true, + $this->output( "Warming up connections to cache servers..." ); + $mccByServer = []; + foreach ( $servers as $server ) { + /** @var BagOStuff $mcc */ + $mccByServer[$server] = new $class( [ + 'servers' => [ $server ], + 'persistent' => true, + 'allow_tcp_nagle_delay' => false, 'timeout' => $wgMemCachedTimeout ] ); - $mcc->set_servers( [ $server ] ); - $set = 0; - $incr = 0; - $get = 0; - $time_start = microtime( true ); - for ( $i = 1; $i <= $iterations; $i++ ) { - if ( $mcc->set( "test$i", $i ) ) { - $set++; - } + $mccByServer[$server]->get( 'key' ); + } + $this->output( "done\n" ); + $this->output( "Single and batched operation profiling/test results:\n" ); + + $valueByKey = []; + for ( $i = 1; $i <= $iterations; $i++ ) { + $valueByKey["test$i"] = 'S' . str_pad( $i, 2048 ); + } + + foreach ( $mccByServer as $server => $mcc ) { + $this->output( str_pad( $server, $maxSrvLen ) . "\n" ); + $this->benchmarkSingleKeyOps( $mcc, $valueByKey ); + $this->benchmarkMultiKeyOpsImmediateBlocking( $mcc, $valueByKey ); + $this->benchmarkMultiKeyOpsDeferredBlocking( $mcc, $valueByKey ); + } + } + + /** + * @param BagOStuff $mcc + * @param array $valueByKey + */ + private function benchmarkSingleKeyOps( BagOStuff $mcc, array $valueByKey ) { + $add = 0; + $set = 0; + $incr = 0; + $get = 0; + $delete = 0; + + $i = count( $valueByKey ); + $keys = array_keys( $valueByKey ); + + // Clear out any old values + $mcc->deleteMulti( $keys ); + + $time_start = microtime( true ); + foreach ( $keys as $key ) { + if ( $mcc->add( $key, $i ) ) { + $add++; + } + } + $addMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $time_start = microtime( true ); + foreach ( $keys as $key ) { + if ( $mcc->set( $key, $i ) ) { + $set++; + } + } + $setMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $time_start = microtime( true ); + foreach ( $keys as $key ) { + if ( !is_null( $mcc->incr( $key, $i ) ) ) { + $incr++; } - for ( $i = 1; $i <= $iterations; $i++ ) { - if ( !is_null( $mcc->incr( "test$i", $i ) ) ) { - $incr++; - } + } + $incrMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $time_start = microtime( true ); + foreach ( $keys as $key ) { + $value = $mcc->get( $key ); + if ( $value == $i * 2 ) { + $get++; } - for ( $i = 1; $i <= $iterations; $i++ ) { - $value = $mcc->get( "test$i" ); - if ( $value == $i * 2 ) { - $get++; - } + } + $getMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $time_start = microtime( true ); + foreach ( $keys as $key ) { + if ( $mcc->delete( $key ) ) { + $delete++; } - $exectime = microtime( true ) - $time_start; + } + $delMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $this->output( + " add: $add/$i {$addMs}ms " . + "set: $set/$i {$setMs}ms " . + "incr: $incr/$i {$incrMs}ms " . + "get: $get/$i ({$getMs}ms) " . + "delete: $delete/$i ({$delMs}ms)\n" + ); + } + + /** + * @param BagOStuff $mcc + * @param array $valueByKey + */ + private function benchmarkMultiKeyOpsImmediateBlocking( BagOStuff $mcc, array $valueByKey ) { + $keys = array_keys( $valueByKey ); + $iterations = count( $valueByKey ); + + $time_start = microtime( true ); + $mSetOk = $mcc->setMulti( $valueByKey ) ? '✓' : '✗'; + $mSetMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $time_start = microtime( true ); + $found = $mcc->getMulti( $keys ); + $mGetMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + $mGetOk = 0; + foreach ( $found as $key => $value ) { + $mGetOk += ( $value === $valueByKey[$key] ); + } + + $time_start = microtime( true ); + $mChangeTTLOk = $mcc->changeTTLMulti( $keys, 3600 ) ? '✓' : '✗'; + $mChangeTTTMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $time_start = microtime( true ); + $mDelOk = $mcc->deleteMulti( $keys ) ? '✓' : '✗'; + $mDelMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $this->output( + " setMulti (IB): $mSetOk {$mSetMs}ms " . + "getMulti (IB): $mGetOk/$iterations {$mGetMs}ms " . + "changeTTLMulti (IB): $mChangeTTLOk {$mChangeTTTMs}ms " . + "deleteMulti (IB): $mDelOk {$mDelMs}ms\n" + ); + } - $this->output( " set: $set incr: $incr get: $get time: $exectime", $server ); + /** + * @param BagOStuff $mcc + * @param array $valueByKey + */ + private function benchmarkMultiKeyOpsDeferredBlocking( BagOStuff $mcc, array $valueByKey ) { + $keys = array_keys( $valueByKey ); + $iterations = count( $valueByKey ); + $flags = $mcc::WRITE_BACKGROUND; + + $time_start = microtime( true ); + $mSetOk = $mcc->setMulti( $valueByKey, 0, $flags ) ? '✓' : '✗'; + $mSetMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $time_start = microtime( true ); + $found = $mcc->getMulti( $keys ); + $mGetMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + $mGetOk = 0; + foreach ( $found as $key => $value ) { + $mGetOk += ( $value === $valueByKey[$key] ); } + + $time_start = microtime( true ); + $mChangeTTLOk = $mcc->changeTTLMulti( $keys, 3600, $flags ) ? '✓' : '✗'; + $mChangeTTTMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $time_start = microtime( true ); + $mDelOk = $mcc->deleteMulti( $keys, $flags ) ? '✓' : '✗'; + $mDelMs = intval( 1e3 * ( microtime( true ) - $time_start ) ); + + $this->output( + " setMulti (DB): $mSetOk {$mSetMs}ms " . + "getMulti (DB): $mGetOk/$iterations {$mGetMs}ms " . + "changeTTLMulti (DB): $mChangeTTLOk {$mChangeTTTMs}ms " . + "deleteMulti (DB): $mDelOk {$mDelMs}ms\n" + ); } }