Merge "Exclude redirects from Special:Fewestrevisions"
[lhc/web/wiklou.git] / maintenance / mctest.php
index 513edf3..9548d6b 100644 (file)
@@ -37,6 +37,7 @@ class McTest extends Maintenance {
                        . " memcached server and shows a report" );
                $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 +67,177 @@ class McTest extends Maintenance {
                # find out the longest server string to nicely align output later on
                $maxSrvLen = $servers ? max( array_map( 'strlen', $servers ) ) : 0;
 
+               $type = $this->getOption( 'driver', 'php' );
+               if ( $type === 'php' ) {
+                       $class = MemcachedPhpBagOStuff::class;
+               } elseif ( $type === 'pecl' ) {
+                       $class = MemcachedPeclBagOStuff::class;
+               } else {
+                       $this->fatalError( "Invalid driver type '$type'" );
+               }
+
                foreach ( $servers as $server ) {
-                       $this->output(
-                               str_pad( $server, $maxSrvLen ),
-                               $server # output channel
-                       );
+                       $this->output( str_pad( $server, $maxSrvLen ) . "\n" );
 
-                       $mcc = new MemcachedClient( [
-                               'persistant' => true,
+                       /** @var BagOStuff $mcc */
+                       $mcc = new $class( [
+                               'servers' => [ $server ],
+                               'persistent' => true,
                                '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++;
-                               }
+
+                       $this->benchmarkSingleKeyOps( $mcc, $iterations );
+                       $this->benchmarkMultiKeyOpsImmediateBlocking( $mcc, $iterations );
+                       $this->benchmarkMultiKeyOpsDeferredBlocking( $mcc, $iterations );
+               }
+       }
+
+       /**
+        * @param BagOStuff $mcc
+        * @param int $iterations
+        */
+       private function benchmarkSingleKeyOps( $mcc, $iterations ) {
+               $add = 0;
+               $set = 0;
+               $incr = 0;
+               $get = 0;
+               $delete = 0;
+
+               $keys = [];
+               for ( $i = 1; $i <= $iterations; $i++ ) {
+                       $keys[] = "test$i";
+               }
+
+               // Clear out any old values
+               $mcc->deleteMulti( $keys );
+
+               $time_start = microtime( true );
+               foreach ( $keys as $key ) {
+                       if ( $mcc->add( $key, $i ) ) {
+                               $add++;
                        }
-                       for ( $i = 1; $i <= $iterations; $i++ ) {
-                               if ( !is_null( $mcc->incr( "test$i", $i ) ) ) {
-                                       $incr++;
-                               }
+               }
+               $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++ ) {
-                               $value = $mcc->get( "test$i" );
-                               if ( $value == $i * 2 ) {
-                                       $get++;
-                               }
+               }
+               $incrMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
+
+               $time_start = microtime( true );
+               foreach ( $keys as $key ) {
+                       $value = $mcc->get( $key );
+                       if ( $value == $i * 2 ) {
+                               $get++;
                        }
-                       $exectime = microtime( true ) - $time_start;
+               }
+               $getMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
 
-                       $this->output( " set: $set   incr: $incr   get: $get time: $exectime", $server );
+               $time_start = microtime( true );
+               foreach ( $keys as $key ) {
+                       if ( $mcc->delete( $key ) ) {
+                               $delete++;
+                       }
                }
+               $delMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
+
+               $this->output(
+                       " add: $add/$iterations {$addMs}ms   " .
+                       "set: $set/$iterations {$setMs}ms   " .
+                       "incr: $incr/$iterations {$incrMs}ms   " .
+                       "get: $get/$iterations ({$getMs}ms)   " .
+                       "delete: $delete/$iterations ({$delMs}ms)\n"
+               );
+       }
+
+       /**
+        * @param BagOStuff $mcc
+        * @param int $iterations
+        */
+       private function benchmarkMultiKeyOpsImmediateBlocking( $mcc, $iterations ) {
+               $keysByValue = [];
+               for ( $i = 1; $i <= $iterations; $i++ ) {
+                       $keysByValue["test$i"] = 'S' . str_pad( $i, 2048 );
+               }
+               $keyList = array_keys( $keysByValue );
+
+               $time_start = microtime( true );
+               $mSetOk = $mcc->setMulti( $keysByValue ) ? 'S' : 'F';
+               $mSetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
+
+               $time_start = microtime( true );
+               $found = $mcc->getMulti( $keyList );
+               $mGetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
+               $mGetOk = 0;
+               foreach ( $found as $key => $value ) {
+                       $mGetOk += ( $value === $keysByValue[$key] );
+               }
+
+               $time_start = microtime( true );
+               $mChangeTTLOk = $mcc->changeTTLMulti( $keyList, 3600 ) ? 'S' : 'F';
+               $mChangeTTTMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
+
+               $time_start = microtime( true );
+               $mDelOk = $mcc->deleteMulti( $keyList ) ? 'S' : 'F';
+               $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"
+               );
+       }
+
+       /**
+        * @param BagOStuff $mcc
+        * @param int $iterations
+        */
+       private function benchmarkMultiKeyOpsDeferredBlocking( $mcc, $iterations ) {
+               $flags = $mcc::WRITE_BACKGROUND;
+               $keysByValue = [];
+               for ( $i = 1; $i <= $iterations; $i++ ) {
+                       $keysByValue["test$i"] = 'A' . str_pad( $i, 2048 );
+               }
+               $keyList = array_keys( $keysByValue );
+
+               $time_start = microtime( true );
+               $mSetOk = $mcc->setMulti( $keysByValue, 0, $flags ) ? 'S' : 'F';
+               $mSetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
+
+               $time_start = microtime( true );
+               $found = $mcc->getMulti( $keyList );
+               $mGetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
+               $mGetOk = 0;
+               foreach ( $found as $key => $value ) {
+                       $mGetOk += ( $value === $keysByValue[$key] );
+               }
+
+               $time_start = microtime( true );
+               $mChangeTTLOk = $mcc->changeTTLMulti( $keyList, 3600, $flags ) ? 'S' : 'F';
+               $mChangeTTTMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
+
+               $time_start = microtime( true );
+               $mDelOk = $mcc->deleteMulti( $keyList, $flags ) ? 'S' : 'F';
+               $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"
+               );
        }
 }