MediaWiki  master
mctest.php
Go to the documentation of this file.
1 <?php
25 require_once __DIR__ . '/Maintenance.php';
26 
33 class McTest extends Maintenance {
34  public function __construct() {
35  parent::__construct();
36  $this->addDescription(
37  "Makes several operation requests on every cache server and shows a report.\n" .
38  "This tests both per-key and batched *Multi() methods as well as WRITE_BACKGROUND.\n" .
39  "\"IB\" means \"immediate blocking\" and \"DB\" means \"deferred blocking.\""
40  );
41  $this->addOption( 'i', 'Number of iterations', false, true );
42  $this->addOption( 'cache', 'Use servers from this $wgObjectCaches store', false, true );
43  $this->addOption( 'driver', 'Either "php" or "pecl"', false, true );
44  $this->addArg( 'server[:port]', 'Memcached server to test, with optional port', false );
45  }
46 
47  public function execute() {
49 
50  $memcachedTypes = [ CACHE_MEMCACHED, 'memcached-php', 'memcached-pecl' ];
51 
52  $cache = $this->getOption( 'cache' );
53  $iterations = $this->getOption( 'i', 100 );
54  if ( $cache ) {
55  if ( !isset( $wgObjectCaches[$cache] ) ) {
56  $this->fatalError( "MediaWiki isn't configured with a cache named '$cache'" );
57  }
58  $servers = $wgObjectCaches[$cache]['servers'];
59  } elseif ( $this->hasArg( 0 ) ) {
60  $servers = [ $this->getArg( 0 ) ];
61  } elseif ( in_array( $wgMainCacheType, $memcachedTypes, true ) ) {
62  global $wgMemCachedServers;
63  $servers = $wgMemCachedServers;
64  } elseif ( isset( $wgObjectCaches[$wgMainCacheType]['servers'] ) ) {
65  $servers = $wgObjectCaches[$wgMainCacheType]['servers'];
66  } else {
67  $this->fatalError( "MediaWiki isn't configured for Memcached usage" );
68  }
69 
70  # find out the longest server string to nicely align output later on
71  $maxSrvLen = $servers ? max( array_map( 'strlen', $servers ) ) : 0;
72 
73  $type = $this->getOption( 'driver', 'php' );
74  if ( $type === 'php' ) {
75  $class = MemcachedPhpBagOStuff::class;
76  } elseif ( $type === 'pecl' ) {
77  $class = MemcachedPeclBagOStuff::class;
78  } else {
79  $this->fatalError( "Invalid driver type '$type'" );
80  }
81 
82  $this->output( "Warming up connections to cache servers..." );
83  $mccByServer = [];
84  foreach ( $servers as $server ) {
86  $mccByServer[$server] = new $class( [
87  'servers' => [ $server ],
88  'persistent' => true,
89  'allow_tcp_nagle_delay' => false,
90  'timeout' => $wgMemCachedTimeout
91  ] );
92  $mccByServer[$server]->get( 'key' );
93  }
94  $this->output( "done\n" );
95  $this->output( "Single and batched operation profiling/test results:\n" );
96 
97  $valueByKey = [];
98  for ( $i = 1; $i <= $iterations; $i++ ) {
99  $valueByKey["test$i"] = 'S' . str_pad( $i, 2048 );
100  }
101 
102  foreach ( $mccByServer as $server => $mcc ) {
103  $this->output( str_pad( $server, $maxSrvLen ) . "\n" );
104  $this->benchmarkSingleKeyOps( $mcc, $valueByKey );
105  $this->benchmarkMultiKeyOpsImmediateBlocking( $mcc, $valueByKey );
106  $this->benchmarkMultiKeyOpsDeferredBlocking( $mcc, $valueByKey );
107  }
108  }
109 
114  private function benchmarkSingleKeyOps( BagOStuff $mcc, array $valueByKey ) {
115  $add = 0;
116  $set = 0;
117  $incr = 0;
118  $get = 0;
119  $delete = 0;
120 
121  $i = count( $valueByKey );
122  $keys = array_keys( $valueByKey );
123 
124  // Clear out any old values
125  $mcc->deleteMulti( $keys );
126 
127  $time_start = microtime( true );
128  foreach ( $keys as $key ) {
129  if ( $mcc->add( $key, $i ) ) {
130  $add++;
131  }
132  }
133  $addMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
134 
135  $time_start = microtime( true );
136  foreach ( $keys as $key ) {
137  if ( $mcc->set( $key, $i ) ) {
138  $set++;
139  }
140  }
141  $setMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
142 
143  $time_start = microtime( true );
144  foreach ( $keys as $key ) {
145  if ( !is_null( $mcc->incr( $key, $i ) ) ) {
146  $incr++;
147  }
148  }
149  $incrMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
150 
151  $time_start = microtime( true );
152  foreach ( $keys as $key ) {
153  $value = $mcc->get( $key );
154  if ( $value == $i * 2 ) {
155  $get++;
156  }
157  }
158  $getMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
159 
160  $time_start = microtime( true );
161  foreach ( $keys as $key ) {
162  if ( $mcc->delete( $key ) ) {
163  $delete++;
164  }
165  }
166  $delMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
167 
168  $this->output(
169  " add: $add/$i {$addMs}ms " .
170  "set: $set/$i {$setMs}ms " .
171  "incr: $incr/$i {$incrMs}ms " .
172  "get: $get/$i ({$getMs}ms) " .
173  "delete: $delete/$i ({$delMs}ms)\n"
174  );
175  }
176 
181  private function benchmarkMultiKeyOpsImmediateBlocking( BagOStuff $mcc, array $valueByKey ) {
182  $keys = array_keys( $valueByKey );
183  $iterations = count( $valueByKey );
184 
185  $time_start = microtime( true );
186  $mSetOk = $mcc->setMulti( $valueByKey ) ? '✓' : '✗';
187  $mSetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
188 
189  $time_start = microtime( true );
190  $found = $mcc->getMulti( $keys );
191  $mGetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
192  $mGetOk = 0;
193  foreach ( $found as $key => $value ) {
194  $mGetOk += ( $value === $valueByKey[$key] );
195  }
196 
197  $time_start = microtime( true );
198  $mChangeTTLOk = $mcc->changeTTLMulti( $keys, 3600 ) ? '✓' : '✗';
199  $mChangeTTTMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
200 
201  $time_start = microtime( true );
202  $mDelOk = $mcc->deleteMulti( $keys ) ? '✓' : '✗';
203  $mDelMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
204 
205  $this->output(
206  " setMulti (IB): $mSetOk {$mSetMs}ms " .
207  "getMulti (IB): $mGetOk/$iterations {$mGetMs}ms " .
208  "changeTTLMulti (IB): $mChangeTTLOk {$mChangeTTTMs}ms " .
209  "deleteMulti (IB): $mDelOk {$mDelMs}ms\n"
210  );
211  }
212 
217  private function benchmarkMultiKeyOpsDeferredBlocking( BagOStuff $mcc, array $valueByKey ) {
218  $keys = array_keys( $valueByKey );
219  $iterations = count( $valueByKey );
220  $flags = $mcc::WRITE_BACKGROUND;
221 
222  $time_start = microtime( true );
223  $mSetOk = $mcc->setMulti( $valueByKey, 0, $flags ) ? '✓' : '✗';
224  $mSetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
225 
226  $time_start = microtime( true );
227  $found = $mcc->getMulti( $keys );
228  $mGetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
229  $mGetOk = 0;
230  foreach ( $found as $key => $value ) {
231  $mGetOk += ( $value === $valueByKey[$key] );
232  }
233 
234  $time_start = microtime( true );
235  $mChangeTTLOk = $mcc->changeTTLMulti( $keys, 3600, $flags ) ? '✓' : '✗';
236  $mChangeTTTMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
237 
238  $time_start = microtime( true );
239  $mDelOk = $mcc->deleteMulti( $keys, $flags ) ? '✓' : '✗';
240  $mDelMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
241 
242  $this->output(
243  " setMulti (DB): $mSetOk {$mSetMs}ms " .
244  "getMulti (DB): $mGetOk/$iterations {$mGetMs}ms " .
245  "changeTTLMulti (DB): $mChangeTTLOk {$mChangeTTTMs}ms " .
246  "deleteMulti (DB): $mDelOk {$mDelMs}ms\n"
247  );
248  }
249 }
250 
251 $maintClass = McTest::class;
252 require_once RUN_MAINTENANCE_IF_MAIN;
deleteMulti(array $keys, $flags=0)
Batch deletion.
getArg( $argId=0, $default=null)
Get an argument.
const RUN_MAINTENANCE_IF_MAIN
Definition: Maintenance.php:39
getOption( $name, $default=null)
Get an option, or return the default.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Definition: Maintenance.php:86
add( $key, $value, $exptime=0, $flags=0)
Insert an item if it does not already exist.
__construct()
Definition: mctest.php:34
$maintClass
Definition: mctest.php:251
benchmarkSingleKeyOps(BagOStuff $mcc, array $valueByKey)
Definition: mctest.php:114
const CACHE_MEMCACHED
Definition: Defines.php:84
hasArg( $argId=0)
Does a given argument exist?
incr( $key, $value=1, $flags=0)
Increase stored value of $key by $value while preserving its TTL.
set( $key, $value, $exptime=0, $flags=0)
Set an item.
$wgMainCacheType
Main cache type.
getMulti(array $keys, $flags=0)
Get an associative array containing the item for each of the keys that have items.
addDescription( $text)
Set the description text.
$cache
Definition: mcc.php:33
addArg( $arg, $description, $required=true)
Add some args that are needed.
delete( $key, $flags=0)
Delete an item.
output( $out, $channel=null)
Throw some output to the user.
benchmarkMultiKeyOpsDeferredBlocking(BagOStuff $mcc, array $valueByKey)
Definition: mctest.php:217
get( $key, $flags=0)
Get an item with the given key.
setMulti(array $data, $exptime=0, $flags=0)
Batch insertion/replace.
changeTTLMulti(array $keys, $exptime, $flags=0)
Change the expiration of multiple keys that exist.
if( $help) $mcc
Definition: mcc.php:39
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
$wgMemCachedServers
The list of MemCached servers and port numbers.
$wgObjectCaches
Advanced object cache configuration.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
benchmarkMultiKeyOpsImmediateBlocking(BagOStuff $mcc, array $valueByKey)
Definition: mctest.php:181
execute()
Definition: mctest.php:47
Maintenance script that makes several &#39;set&#39;, &#39;incr&#39; and &#39;get&#39; requests on every memcached server and ...
Definition: mctest.php:33
$wgMemCachedTimeout
Read/write timeout for MemCached server communication, in microseconds.