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