MediaWiki  master
Benchmarker.php
Go to the documentation of this file.
1 <?php
31 
32 // @codeCoverageIgnoreStart
33 require_once __DIR__ . '/../Maintenance.php';
34 // @codeCoverageIgnoreEnd
35 
41 abstract class Benchmarker extends Maintenance {
42  protected $defaultCount = 100;
43  private $lang;
44 
45  public function __construct() {
46  parent::__construct();
47  $this->addOption( 'count', 'How many times to run a benchmark', false, true );
48  $this->addOption( 'verbose', 'Verbose logging of resource usage', false, false, 'v' );
49  }
50 
51  public function bench( array $benchs ) {
52  $this->lang = MediaWikiServices::getInstance()->getLanguageFactory()->getLanguage( 'en' );
53 
54  $this->startBench();
55  $count = $this->getOption( 'count', $this->defaultCount );
56  $verbose = $this->hasOption( 'verbose' );
57 
58  // Normalise
59  $normBenchs = [];
60  foreach ( $benchs as $key => $bench ) {
61  // Shortcut for simple functions
62  if ( is_callable( $bench ) ) {
63  $bench = [ 'function' => $bench ];
64  }
65 
66  // Default to no arguments
67  if ( !isset( $bench['args'] ) ) {
68  $bench['args'] = [];
69  }
70 
71  // Name defaults to name of called function
72  if ( is_string( $key ) ) {
73  $name = $key;
74  } else {
75  if ( is_array( $bench['function'] ) ) {
76  $name = get_class( $bench['function'][0] ) . '::' . $bench['function'][1];
77  } else {
78  $name = strval( $bench['function'] );
79  }
80  $name = sprintf( "%s(%s)",
81  $name,
82  implode( ', ', $bench['args'] )
83  );
84  }
85 
86  $normBenchs[$name] = $bench;
87  }
88 
89  foreach ( $normBenchs as $name => $bench ) {
90  // Optional setup called outside time measure
91  if ( isset( $bench['setup'] ) ) {
92  call_user_func( $bench['setup'] );
93  }
94 
95  // Run benchmarks
96  $stat = new RunningStat();
97  for ( $i = 0; $i < $count; $i++ ) {
98  // Setup outside of time measure for each loop
99  if ( isset( $bench['setupEach'] ) ) {
100  $bench['setupEach']();
101  }
102  $t = microtime( true );
103  call_user_func_array( $bench['function'], $bench['args'] );
104  $t = ( microtime( true ) - $t ) * 1000;
105  if ( $verbose ) {
106  $this->verboseRun( $i );
107  }
108  $stat->addObservation( $t );
109  }
110 
111  $this->addResult( [
112  'name' => $name,
113  'count' => $stat->getCount(),
114  // Get rate per second from mean (in ms)
115  'rate' => $stat->getMean() == 0 ? INF : ( 1.0 / ( $stat->getMean() / 1000.0 ) ),
116  'total' => $stat->getMean() * $stat->getCount(),
117  'mean' => $stat->getMean(),
118  'max' => $stat->max,
119  'stddev' => $stat->getStdDev(),
120  'usage' => [
121  'mem' => memory_get_usage( true ),
122  'mempeak' => memory_get_peak_usage( true ),
123  ],
124  ] );
125  }
126  }
127 
128  public function startBench() {
129  $this->output(
130  sprintf( "Running PHP version %s (%s) on %s %s %s\n\n",
131  phpversion(),
132  php_uname( 'm' ),
133  php_uname( 's' ),
134  php_uname( 'r' ),
135  php_uname( 'v' )
136  )
137  );
138  }
139 
140  public function addResult( $res ) {
141  $ret = sprintf( "%s\n %' 6s: %d\n",
142  $res['name'],
143  'count',
144  $res['count']
145  );
146  $ret .= sprintf( " %' 6s: %8.1f/s\n",
147  'rate',
148  $res['rate']
149  );
150  foreach ( [ 'total', 'mean', 'max', 'stddev' ] as $metric ) {
151  $ret .= sprintf( " %' 6s: %8.2fms\n",
152  $metric,
153  $res[$metric]
154  );
155  }
156 
157  foreach ( [
158  'mem' => 'Current memory usage',
159  'mempeak' => 'Peak memory usage'
160  ] as $key => $label ) {
161  $ret .= sprintf( "%' 20s: %s\n",
162  $label,
163  $this->lang->formatSize( $res['usage'][$key] )
164  );
165  }
166 
167  $this->output( "$ret\n" );
168  }
169 
170  protected function verboseRun( $iteration ) {
171  $this->output( sprintf( "#%3d - memory: %-10s - peak: %-10s\n",
172  $iteration,
173  $this->lang->formatSize( memory_get_usage( true ) ),
174  $this->lang->formatSize( memory_get_peak_usage( true ) )
175  ) );
176  }
177 
183  protected function loadFile( $file ) {
184  $content = file_get_contents( $file );
185  // Detect GZIP compression header
186  if ( substr( $content, 0, 2 ) === "\037\213" ) {
187  $content = gzdecode( $content );
188  }
189  return $content;
190  }
191 }
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
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
hasOption( $name)
Checks to see if a particular option exists.
bench(array $benchs)
Definition: Benchmarker.php:51
addResult( $res)
output( $out, $channel=null)
Throw some output to the user.
loadFile( $file)
Base class for benchmark scripts.
Definition: Benchmarker.php:41
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
$content
Definition: router.php:78
verboseRun( $iteration)