Base for a static organization website

BenchmarkShell.php 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  10. * @link http://cakephp.org CakePHP(tm) Project
  11. * @since DebugKit 1.0
  12. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  13. */
  14. App::uses('String', 'Utility');
  15. /**
  16. * Benchmark Shell Class
  17. *
  18. * Provides basic benchmarking of application requests
  19. * functionally similar to Apache AB
  20. *
  21. * @since DebugKit 1.0
  22. * @todo Print/export time detail information
  23. * @todo Export/graphing of data to .dot format for graphviz visualization
  24. * @todo Make calculated results round to leading significant digit position of std dev.
  25. */
  26. class BenchmarkShell extends Shell {
  27. /**
  28. * Main execution of shell
  29. *
  30. * @return void
  31. */
  32. public function main() {
  33. $url = $this->args[0];
  34. $defaults = array('t' => 100, 'n' => 10);
  35. $options = array_merge($defaults, $this->params);
  36. $times = array();
  37. $this->out(String::insert(__d('debug_kit', '-> Testing :url'), compact('url')));
  38. $this->out("");
  39. for ($i = 0; $i < $options['n']; $i++) {
  40. if (floor($options['t'] - array_sum($times)) <= 0 || $options['n'] <= 1) {
  41. break;
  42. }
  43. $start = microtime(true);
  44. file_get_contents($url);
  45. $stop = microtime(true);
  46. $times[] = $stop - $start;
  47. }
  48. $this->_results($times);
  49. }
  50. /**
  51. * Prints calculated results
  52. *
  53. * @param array $times Array of time values
  54. * @return void
  55. */
  56. protected function _results($times) {
  57. $duration = array_sum($times);
  58. $requests = count($times);
  59. $this->out(String::insert(__d('debug_kit', 'Total Requests made: :requests'), compact('requests')));
  60. $this->out(String::insert(__d('debug_kit', 'Total Time elapsed: :duration (seconds)'), compact('duration')));
  61. $this->out("");
  62. $this->out(String::insert(__d('debug_kit', 'Requests/Second: :rps req/sec'), array(
  63. 'rps' => round($requests / $duration, 3)
  64. )));
  65. $this->out(String::insert(__d('debug_kit', 'Average request time: :average-time seconds'), array(
  66. 'average-time' => round($duration / $requests, 3)
  67. )));
  68. $this->out(String::insert(__d('debug_kit', 'Standard deviation of average request time: :std-dev'), array(
  69. 'std-dev' => round($this->_deviation($times, true), 3)
  70. )));
  71. $this->out(String::insert(__d('debug_kit', 'Longest/shortest request: :longest sec/:shortest sec'), array(
  72. 'longest' => round(max($times), 3),
  73. 'shortest' => round(min($times), 3)
  74. )));
  75. $this->out("");
  76. }
  77. /**
  78. * One-pass, numerically stable calculation of population variance.
  79. *
  80. * Donald E. Knuth (1998).
  81. * The Art of Computer Programming, volume 2: Seminumerical Algorithms, 3rd edn.,
  82. * p. 232. Boston: Addison-Wesley.
  83. *
  84. * @param array $times Array of values
  85. * @param boolean $sample If true, calculates an unbiased estimate of the population
  86. * variance from a finite sample.
  87. * @return float Variance
  88. */
  89. protected function _variance($times, $sample = true) {
  90. $n = $mean = $M2 = 0;
  91. foreach ($times as $time) {
  92. $n += 1;
  93. $delta = $time - $mean;
  94. $mean = $mean + $delta / $n;
  95. $M2 = $M2 + $delta * ($time - $mean);
  96. }
  97. if ($sample) {
  98. $n -= 1;
  99. }
  100. return $M2 / $n;
  101. }
  102. /**
  103. * Calculate the standard deviation.
  104. *
  105. * @param array $times Array of values
  106. * @param boolean $sample
  107. * @return float Standard deviation
  108. */
  109. protected function _deviation($times, $sample = true) {
  110. return sqrt($this->_variance($times, $sample));
  111. }
  112. public function getOptionParser() {
  113. $parser = parent::getOptionParser();
  114. $parser->description(__d('debug_kit',
  115. 'Allows you to obtain some rough benchmarking statistics' .
  116. 'about a fully qualified URL.'
  117. ))
  118. ->addArgument('url', array(
  119. 'help' => __d('debug_kit', 'The URL to request.'),
  120. 'required' => true
  121. ))
  122. ->addOption('n', array(
  123. 'default' => 10,
  124. 'help' => __d('debug_kit', 'Number of iterations to perform.')
  125. ))
  126. ->addOption('t', array(
  127. 'default' => 100,
  128. 'help' => __d('debug_kit', 'Maximum total time for all iterations, in seconds.' .
  129. 'If a single iteration takes more than the timeout, only one request will be made'
  130. )
  131. ))
  132. ->epilog(__d('debug_kit',
  133. 'Example Use: `cake benchmark --n 10 --t 100 http://localhost/testsite`. ' .
  134. '<info>Note:</info> this benchmark does not include browser render times.'
  135. ));
  136. return $parser;
  137. }
  138. }