| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- <?php
- /**
- * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://cakephp.org CakePHP(tm) Project
- * @since DebugKit 1.0
- * @license http://www.opensource.org/licenses/mit-license.php MIT License
- */
-
- App::uses('String', 'Utility');
-
- /**
- * Benchmark Shell Class
- *
- * Provides basic benchmarking of application requests
- * functionally similar to Apache AB
- *
- * @since DebugKit 1.0
- * @todo Print/export time detail information
- * @todo Export/graphing of data to .dot format for graphviz visualization
- * @todo Make calculated results round to leading significant digit position of std dev.
- */
- class BenchmarkShell extends Shell {
-
- /**
- * Main execution of shell
- *
- * @return void
- */
- public function main() {
- $url = $this->args[0];
- $defaults = array('t' => 100, 'n' => 10);
- $options = array_merge($defaults, $this->params);
- $times = array();
-
- $this->out(String::insert(__d('debug_kit', '-> Testing :url'), compact('url')));
- $this->out("");
- for ($i = 0; $i < $options['n']; $i++) {
- if (floor($options['t'] - array_sum($times)) <= 0 || $options['n'] <= 1) {
- break;
- }
-
- $start = microtime(true);
- file_get_contents($url);
- $stop = microtime(true);
-
- $times[] = $stop - $start;
- }
- $this->_results($times);
- }
-
- /**
- * Prints calculated results
- *
- * @param array $times Array of time values
- * @return void
- */
- protected function _results($times) {
- $duration = array_sum($times);
- $requests = count($times);
-
- $this->out(String::insert(__d('debug_kit', 'Total Requests made: :requests'), compact('requests')));
- $this->out(String::insert(__d('debug_kit', 'Total Time elapsed: :duration (seconds)'), compact('duration')));
-
- $this->out("");
-
- $this->out(String::insert(__d('debug_kit', 'Requests/Second: :rps req/sec'), array(
- 'rps' => round($requests / $duration, 3)
- )));
-
- $this->out(String::insert(__d('debug_kit', 'Average request time: :average-time seconds'), array(
- 'average-time' => round($duration / $requests, 3)
- )));
-
- $this->out(String::insert(__d('debug_kit', 'Standard deviation of average request time: :std-dev'), array(
- 'std-dev' => round($this->_deviation($times, true), 3)
- )));
-
- $this->out(String::insert(__d('debug_kit', 'Longest/shortest request: :longest sec/:shortest sec'), array(
- 'longest' => round(max($times), 3),
- 'shortest' => round(min($times), 3)
- )));
-
- $this->out("");
- }
-
- /**
- * One-pass, numerically stable calculation of population variance.
- *
- * Donald E. Knuth (1998).
- * The Art of Computer Programming, volume 2: Seminumerical Algorithms, 3rd edn.,
- * p. 232. Boston: Addison-Wesley.
- *
- * @param array $times Array of values
- * @param boolean $sample If true, calculates an unbiased estimate of the population
- * variance from a finite sample.
- * @return float Variance
- */
- protected function _variance($times, $sample = true) {
- $n = $mean = $M2 = 0;
-
- foreach ($times as $time) {
- $n += 1;
- $delta = $time - $mean;
- $mean = $mean + $delta / $n;
- $M2 = $M2 + $delta * ($time - $mean);
- }
-
- if ($sample) {
- $n -= 1;
- }
-
- return $M2 / $n;
- }
-
- /**
- * Calculate the standard deviation.
- *
- * @param array $times Array of values
- * @param boolean $sample
- * @return float Standard deviation
- */
- protected function _deviation($times, $sample = true) {
- return sqrt($this->_variance($times, $sample));
- }
-
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- $parser->description(__d('debug_kit',
- 'Allows you to obtain some rough benchmarking statistics' .
- 'about a fully qualified URL.'
- ))
- ->addArgument('url', array(
- 'help' => __d('debug_kit', 'The URL to request.'),
- 'required' => true
- ))
- ->addOption('n', array(
- 'default' => 10,
- 'help' => __d('debug_kit', 'Number of iterations to perform.')
- ))
- ->addOption('t', array(
- 'default' => 100,
- 'help' => __d('debug_kit', 'Maximum total time for all iterations, in seconds.' .
- 'If a single iteration takes more than the timeout, only one request will be made'
- )
- ))
- ->epilog(__d('debug_kit',
- 'Example Use: `cake benchmark --n 10 --t 100 http://localhost/testsite`. ' .
- '<info>Note:</info> this benchmark does not include browser render times.'
- ));
- return $parser;
- }
- }
|