PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/www/shop/engine/Library/Enlight/Extensions/Benchmark/Bootstrap.php

https://bitbucket.org/weberlars/sot-shopware
PHP | 331 lines | 178 code | 32 blank | 121 comment | 14 complexity | 04165b7091811a0977fc1ab8fb70c49c MD5 | raw file
Possible License(s): AGPL-3.0, MIT, BSD-3-Clause, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /**
  3. * Enlight
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://enlight.de/license
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@shopware.de so we can send you a copy immediately.
  14. *
  15. * @category Enlight
  16. * @package Enlight_Extensions
  17. * @copyright Copyright (c) 2011, shopware AG (http://www.shopware.de)
  18. * @license http://enlight.de/license New BSD License
  19. * @version $Id$
  20. * @author Heiner Lohaus
  21. * @author $Author$
  22. */
  23. /**
  24. * Enlight benchmark extension to benchmark database queries, controller actions and template rendering.
  25. *
  26. * The Enlight_Extensions_Benchmark_Bootstrap allows the timekeeping, memory measurement.
  27. * It writes the benchmark data into the log. Support the benchmarking of database request,
  28. * template rendering and controller events.
  29. *
  30. * @category Enlight
  31. * @package Enlight_Extensions
  32. * @copyright Copyright (c) 2011, shopware AG (http://www.shopware.de)
  33. * @license http://enlight.de/license New BSD License
  34. */
  35. class Enlight_Extensions_Benchmark_Bootstrap extends Enlight_Plugin_Bootstrap_Config
  36. {
  37. /**
  38. * @var Enlight_Components_Log Contains an instance of the Enlight_Components_Log
  39. */
  40. protected $log;
  41. /**
  42. * @var array Contains all measured events.
  43. */
  44. protected $results = array();
  45. /**
  46. * @var null Contains the start time of the Benchmarking
  47. */
  48. protected $startTime;
  49. /**
  50. * @var null Contains the start memory size of the Benchmarking
  51. */
  52. protected $startMemory;
  53. /**
  54. * Install benchmark plugin.
  55. * Subscribes the Enlight_Controller_Front_StartDispatch event to start the benchmarking and
  56. * the Enlight_Controller_Front_DispatchLoopShutdown to stop the benchmarking.
  57. *
  58. */
  59. public function install()
  60. {
  61. $this->subscribeEvent(
  62. 'Enlight_Controller_Front_StartDispatch',
  63. 'onStartDispatch',
  64. 100
  65. );
  66. $this->subscribeEvent(
  67. 'Enlight_Controller_Front_DispatchLoopShutdown',
  68. 'onDispatchLoopShutdown',
  69. 100
  70. );
  71. }
  72. /**
  73. * Returns the instance of the enlight configuration. If no configuration is set,
  74. * the logDb, logTemplate and the logController flags will be set to true.
  75. *
  76. * @return Enlight_Config
  77. */
  78. public function Config()
  79. {
  80. $config = parent::Config();
  81. if (count($config) === 0) {
  82. $config->merge(new Enlight_Config(array(
  83. 'logDb' => true,
  84. 'logTemplate' => true,
  85. 'logController' => true,
  86. )));
  87. }
  88. return $this->config;
  89. }
  90. /**
  91. * Listener method of the Enlight_Controller_Front_StartDispatch event.
  92. * Set the instance of the application log resource into the internal property.
  93. * Enables the database profiler if the logDb flag in the configuration is set to true.
  94. * Activate the template debugging if the logTemplate flag in the configuration is set to true.
  95. * Register the listeners to log the controllers if the logController flag in the configuration is set to true.
  96. *
  97. * On Dispatch start activate db profiling
  98. *
  99. * @param Enlight_Event_EventArgs $args
  100. * @return void
  101. */
  102. public function onStartDispatch(Enlight_Event_EventArgs $args)
  103. {
  104. $this->log = $this->Application()->Log();
  105. if ($this->log === null) {
  106. return;
  107. }
  108. if (!empty($this->Config()->logDb)) {
  109. $this->Application()->Db()->getProfiler()->setEnabled(true);
  110. }
  111. if (!empty($this->Config()->logTemplate)) {
  112. $this->Application()->Template()->setDebugging(true);
  113. $this->Application()->Template()->debug_tpl = 'string:';
  114. }
  115. if (!empty($this->Config()->logController)) {
  116. $this->Application()->Events()->registerSubscriber($this->getListeners());
  117. }
  118. }
  119. /**
  120. * Listener method of the Enlight_Controller_Front_DispatchLoopShutdown event.
  121. * On Dispatch Shutdown collect sql performance results, template results and controller results
  122. * and dump to log component.
  123. *
  124. * @param Enlight_Event_EventArgs $args
  125. */
  126. public function onDispatchLoopShutdown(Enlight_Event_EventArgs $args)
  127. {
  128. if ($this->log === null) {
  129. return;
  130. }
  131. if (!empty($this->Config()->logDb)) {
  132. $this->logDb();
  133. }
  134. if (!empty($this->Config()->logTemplate)) {
  135. $this->logTemplate();
  136. }
  137. if (!empty($this->Config()->logController)) {
  138. $this->logController();
  139. }
  140. }
  141. /**
  142. * Logs all database process to the internal log object.
  143. * Iterates all queries of the query profiler and writes the query,
  144. * the parameter and the elapsed seconds for the query into a new row of the log.
  145. *
  146. * @return void
  147. */
  148. public function logDb()
  149. {
  150. /** @var $profiler Zend_Db_Profiler */
  151. $profiler = $this->Application()->Db()->getProfiler();
  152. $rows = array(array('time', 'count', 'sql', 'params'));
  153. $counts = array(10000);
  154. $total_time = 0;
  155. $queryProfiles = $profiler->getQueryProfiles();
  156. if (!$queryProfiles) {
  157. return;
  158. }
  159. /** @var $query Zend_Db_Profiler_Query */
  160. foreach ($queryProfiles as $query) {
  161. $id = md5($query->getQuery());
  162. $total_time += $query->getElapsedSecs();
  163. if (!isset($rows[$id])) {
  164. $rows[$id] = array(
  165. number_format($query->getElapsedSecs(), 5, '.', ''),
  166. 1,
  167. $query->getQuery(),
  168. $query->getQueryParams()
  169. );
  170. $counts[$id] = $query->getElapsedSecs();
  171. } else {
  172. $rows[$id][1]++;
  173. $counts[$id] += $query->getElapsedSecs();
  174. $rows[$id][0] = number_format($counts[$id], 5, '.', '');
  175. }
  176. }
  177. array_multisort($counts, SORT_NUMERIC, SORT_DESC, $rows);
  178. $rows = array_values($rows);
  179. $total_time = round($total_time, 5);
  180. $total_count = $profiler->getTotalNumQueries();
  181. $label = "Database Querys ($total_count @ $total_time sec)";
  182. $table = array($label, $rows);
  183. $this->Application()->Log()->table($table);
  184. }
  185. /**
  186. * Logs all controller events into the internal log object.
  187. * Each logged events contains the event name, the execution time and the allocated peak of memory.
  188. *
  189. * @param Enlight_Event_EventArgs $args
  190. * @return void
  191. */
  192. public function onBenchmarkEvent(Enlight_Event_EventArgs $args)
  193. {
  194. if (empty($this->results)) {
  195. $this->results[] = array('name', 'memory', 'time');
  196. $this->startTime = microtime(true);
  197. $this->startMemory = memory_get_peak_usage(true);
  198. }
  199. $this->results[] = array(
  200. 0 => str_replace('Enlight_Controller_', '', $args->getName()),
  201. 1 => $this->formatMemory(memory_get_peak_usage(true) - $this->startMemory),
  202. 2 => $this->formatTime(microtime(true) - $this->startTime)
  203. );
  204. }
  205. /**
  206. * Logs all rendered templates into the internal log object.
  207. * Each logged template contains the template name, the required compile time,
  208. * the required render time and the required cache time.
  209. *
  210. * @return void
  211. */
  212. public function logTemplate()
  213. {
  214. $rows = array(array('name', 'compile_time', 'render_time', 'cache_time'));
  215. $total_time = 0;
  216. foreach (Smarty_Internal_Debug::$template_data as $template_file) {
  217. $total_time += $template_file['render_time'];
  218. $total_time += $template_file['cache_time'];
  219. $template_file['name'] = str_replace($this->Application()->CorePath(), '', $template_file['name']);
  220. $template_file['name'] = str_replace($this->Application()->AppPath(), '', $template_file['name']);
  221. $template_file['compile_time'] = $this->formatTime($template_file['compile_time']);
  222. $template_file['render_time'] = $this->formatTime($template_file['render_time']);
  223. $template_file['cache_time'] = $this->formatTime($template_file['cache_time']);
  224. unset($template_file['start_time']);
  225. $rows[] = array_values($template_file);
  226. }
  227. $total_time = round($total_time, 5);
  228. $total_count = count($rows) - 1;
  229. $label = "Benchmark Template ($total_count @ $total_time sec)";
  230. $table = array($label, $rows);
  231. $this->log->table($table);
  232. }
  233. /**
  234. * Get total execution time in controller
  235. *
  236. * @return void
  237. */
  238. public function logController()
  239. {
  240. $total_time = $this->formatTime(microtime(true) - $this->startTime);
  241. $label = "Benchmark Controller ($total_time sec)";
  242. $table = array($label, $this->results);
  243. $this->Application()->Log()->table($table);
  244. }
  245. /**
  246. * Monitor execution time and memory on specified event points in application
  247. *
  248. * @return Enlight_Event_Subscriber_Array
  249. */
  250. public function getListeners()
  251. {
  252. $events = array(
  253. 'Enlight_Controller_Front_RouteStartup',
  254. 'Enlight_Controller_Front_RouteShutdown',
  255. 'Enlight_Controller_Front_DispatchLoopStartup',
  256. 'Enlight_Controller_Front_PreDispatch',
  257. 'Enlight_Controller_Front_PostDispatch',
  258. 'Enlight_Controller_Front_DispatchLoopShutdown',
  259. 'Enlight_Controller_Action_Init',
  260. 'Enlight_Controller_Action_PreDispatch',
  261. 'Enlight_Controller_Action_PostDispatch',
  262. 'Enlight_Plugins_ViewRenderer_PreRender',
  263. 'Enlight_Plugins_ViewRenderer_PostRender'
  264. );
  265. $listeners = new Enlight_Event_Subscriber_Array();
  266. foreach ($events as $event) {
  267. $listeners->registerListener(
  268. new Enlight_Event_Handler_Default(
  269. $event, array($this, 'onBenchmarkEvent'), -99
  270. )
  271. );
  272. }
  273. return $listeners;
  274. }
  275. /**
  276. * Format memory in a proper way
  277. *
  278. * @param $size
  279. * @return string
  280. */
  281. public static function formatMemory($size)
  282. {
  283. if (empty($size)) {
  284. return '0.00 b';
  285. }
  286. $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
  287. return @number_format($size / pow(1024, ($i = floor(log($size, 1024)))), 2, '.', '') . ' ' . $unit[$i];
  288. }
  289. /**
  290. * Format time for human readable
  291. *
  292. * @param $time
  293. * @return string
  294. */
  295. public static function formatTime($time)
  296. {
  297. return number_format($time, 5, '.', '');
  298. }
  299. }