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( 'cache', 'Use servers from this $wgObjectCaches store', true, true );
42  $this->addOption( 'class', 'Override the store "class" parameter', false, true );
43  $this->addOption( 'i', 'Number of iterations', false, true );
44  $this->addArg( 'server[:port]', 'Cache server to test, with optional port', false );
45  }
46 
47  public function execute() {
49 
50  $cacheType = $this->getOption( 'cache', $wgMainCacheType );
51  $iterations = $this->getOption( 'i', 100 );
52  $classOverride = $this->getOption( 'class' );
53  $server = $this->getArg( 0 );
54 
55  if ( !isset( $wgObjectCaches[$cacheType] ) ) {
56  $this->fatalError( "No configured '$cacheType' cache" );
57  }
58 
59  if ( $classOverride !== null ) {
60  if ( !is_subclass_of( $classOverride, BagOStuff::class ) ) {
61  $this->fatalError( "Invalid class '$classOverride' for cache" );
62  }
63  $class = $classOverride;
64  } else {
65  $class = $wgObjectCaches[$cacheType]['class'];
66  }
67 
68  if ( $server !== null ) {
69  $servers = [ $server ];
70  } else {
71  // Note that some caches, like apcu, do not have a server list
72  $servers = $wgObjectCaches[$cacheType]['servers'] ?? [ null ];
73  }
74 
75  // Use longest server string for output alignment
76  $maxSrvLen = max( array_map( 'strlen', $servers ) );
77 
78  $this->output( "Warming up connections to cache servers..." );
80  $cacheByServer = [];
81  foreach ( $servers as $server ) {
82  $conf = $wgObjectCaches[$cacheType];
83  if ( $server !== null ) {
84  $conf['servers'] = [ $server ];
85  $host = $server;
86  } else {
87  $host = 'localhost';
88  }
89  $cacheByServer[$host] = new $class( $conf );
90  $cacheByServer[$host]->get( 'key' );
91  }
92  $this->output( "done\n" );
93  $this->output( "Single and batched operation profiling/test results:\n" );
94 
95  $valueByKey = [];
96  for ( $i = 1; $i <= $iterations; $i++ ) {
97  $valueByKey["test$i"] = 'S' . str_pad( (string)$i, 2048 );
98  }
99 
100  foreach ( $cacheByServer as $host => $mcc ) {
101  $this->output( str_pad( $host, $maxSrvLen ) . "\n" );
102  $this->benchmarkSingleKeyOps( $mcc, $valueByKey );
103  $this->benchmarkMultiKeyOpsImmediateBlocking( $mcc, $valueByKey );
104  $this->benchmarkMultiKeyOpsDeferredBlocking( $mcc, $valueByKey );
105  }
106  }
107 
112  private function benchmarkSingleKeyOps( BagOStuff $mcc, array $valueByKey ) {
113  $add = 0;
114  $set = 0;
115  $incr = 0;
116  $get = 0;
117  $delete = 0;
118 
119  $keys = array_keys( $valueByKey );
120  $count = count( $valueByKey );
121 
122  // Clear out any old values
123  $mcc->deleteMulti( $keys );
124 
125  $time_start = microtime( true );
126  foreach ( $valueByKey as $key => $value ) {
127  if ( $mcc->add( $key, $value ) ) {
128  $add++;
129  }
130  }
131  $addMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
132 
133  $time_start = microtime( true );
134  foreach ( $valueByKey as $key => $value ) {
135  if ( $mcc->set( $key, $value ) ) {
136  $set++;
137  }
138  }
139  $setMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
140 
141  $time_start = microtime( true );
142  foreach ( $valueByKey as $key => $value ) {
143  if ( $mcc->get( $key ) === $value ) {
144  $get++;
145  }
146  }
147  $getMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
148 
149  $time_start = microtime( true );
150  foreach ( $keys as $key ) {
151  if ( $mcc->delete( $key ) ) {
152  $delete++;
153  }
154  }
155  $delMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
156 
157  $time_start = microtime( true );
158  foreach ( $keys as $index => $key ) {
159  if ( $mcc->incrWithInit( $key, $mcc::TTL_INDEFINITE, $index ) === $index ) {
160  $incr++;
161  }
162  }
163  $incrMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
164 
165  $this->output(
166  " add: $add/$count {$addMs}ms " .
167  "set: $set/$count {$setMs}ms " .
168  "get: $get/$count ({$getMs}ms) " .
169  "delete: $delete/$count ({$delMs}ms) " .
170  "incr: $incr/$count ({$incrMs}ms)\n"
171  );
172  }
173 
178  private function benchmarkMultiKeyOpsImmediateBlocking( BagOStuff $mcc, array $valueByKey ) {
179  $keys = array_keys( $valueByKey );
180  $iterations = count( $valueByKey );
181 
182  $time_start = microtime( true );
183  $mSetOk = $mcc->setMulti( $valueByKey ) ? '✓' : '✗';
184  $mSetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
185 
186  $time_start = microtime( true );
187  $found = $mcc->getMulti( $keys );
188  $mGetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
189  $mGetOk = 0;
190  foreach ( $found as $key => $value ) {
191  $mGetOk += ( $value === $valueByKey[$key] );
192  }
193 
194  $time_start = microtime( true );
195  $mChangeTTLOk = $mcc->changeTTLMulti( $keys, 3600 ) ? '✓' : '✗';
196  $mChangeTTTMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
197 
198  $time_start = microtime( true );
199  $mDelOk = $mcc->deleteMulti( $keys ) ? '✓' : '✗';
200  $mDelMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
201 
202  $this->output(
203  " setMulti (IB): $mSetOk {$mSetMs}ms " .
204  "getMulti (IB): $mGetOk/$iterations {$mGetMs}ms " .
205  "changeTTLMulti (IB): $mChangeTTLOk {$mChangeTTTMs}ms " .
206  "deleteMulti (IB): $mDelOk {$mDelMs}ms\n"
207  );
208  }
209 
214  private function benchmarkMultiKeyOpsDeferredBlocking( BagOStuff $mcc, array $valueByKey ) {
215  $keys = array_keys( $valueByKey );
216  $iterations = count( $valueByKey );
217  $flags = $mcc::WRITE_BACKGROUND;
218 
219  $time_start = microtime( true );
220  $mSetOk = $mcc->setMulti( $valueByKey, 0, $flags ) ? '✓' : '✗';
221  $mSetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
222 
223  $time_start = microtime( true );
224  $found = $mcc->getMulti( $keys );
225  $mGetMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
226  $mGetOk = 0;
227  foreach ( $found as $key => $value ) {
228  $mGetOk += ( $value === $valueByKey[$key] );
229  }
230 
231  $time_start = microtime( true );
232  $mChangeTTLOk = $mcc->changeTTLMulti( $keys, 3600, $flags ) ? '✓' : '✗';
233  $mChangeTTTMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
234 
235  $time_start = microtime( true );
236  $mDelOk = $mcc->deleteMulti( $keys, $flags ) ? '✓' : '✗';
237  $mDelMs = intval( 1e3 * ( microtime( true ) - $time_start ) );
238 
239  $this->output(
240  " setMulti (DB): $mSetOk {$mSetMs}ms " .
241  "getMulti (DB): $mGetOk/$iterations {$mGetMs}ms " .
242  "changeTTLMulti (DB): $mChangeTTLOk {$mChangeTTTMs}ms " .
243  "deleteMulti (DB): $mDelOk {$mDelMs}ms\n"
244  );
245  }
246 }
247 
248 $maintClass = McTest::class;
249 require_once RUN_MAINTENANCE_IF_MAIN;
Class representing a cache/ephemeral data store.
Definition: BagOStuff.php:87
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Definition: Maintenance.php:66
addArg( $arg, $description, $required=true)
Add some args that are needed.
output( $out, $channel=null)
Throw some output to the user.
getArg( $argId=0, $default=null)
Get an argument.
addDescription( $text)
Set the description text.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
getOption( $name, $default=null)
Get an option, or return the default.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
Maintenance script that makes several 'set', 'incr' and 'get' requests on every memcached server and ...
Definition: mctest.php:33
benchmarkMultiKeyOpsImmediateBlocking(BagOStuff $mcc, array $valueByKey)
Definition: mctest.php:178
benchmarkMultiKeyOpsDeferredBlocking(BagOStuff $mcc, array $valueByKey)
Definition: mctest.php:214
__construct()
Default constructor.
Definition: mctest.php:34
execute()
Do the actual work.
Definition: mctest.php:47
benchmarkSingleKeyOps(BagOStuff $mcc, array $valueByKey)
Definition: mctest.php:112
$wgObjectCaches
Config variable stub for the ObjectCaches setting, for use by phpdoc and IDEs.
$wgMainCacheType
Config variable stub for the MainCacheType setting, for use by phpdoc and IDEs.
if( $help) $mcc
Definition: mcc.php:39
$maintClass
Definition: mctest.php:248