BxProfiler.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup Profiler Profiler
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. define ('BX_PROFILER', true);
  12. define ('BX_PROFILER_DISPLAY', 1);
  13. require_once(BX_DIRECTORY_PATH_MODULES . 'boonex/profiler/install/config.php');
  14. $GLOBALS['bx_profiler_module'] = array (
  15. 'type' => BX_DOL_MODULE_TYPE_MODULE,
  16. 'name' => 'bx_profiler',
  17. 'title' => $aConfig['title'],
  18. 'vendor' => $aConfig['vendor'],
  19. 'path' => $aConfig['home_dir'],
  20. 'uri' => $aConfig['home_uri'],
  21. 'class_prefix' => $aConfig['class_prefix'],
  22. 'db_prefix' => $aConfig['db_prefix'],
  23. );
  24. bx_import('Template', $GLOBALS['bx_profiler_module']);
  25. bx_import('Config', $GLOBALS['bx_profiler_module']);
  26. class BxProfiler extends BxDol
  27. {
  28. protected $oConfig, $oTemplate, $oTemplateAdmin;
  29. protected $aConf = [];
  30. protected $_iTimeStart = 0;
  31. protected $_aQueries = [];
  32. protected $_sQueryIndex = 0;
  33. protected $_aModules = [];
  34. protected $_aModulesNames = [];
  35. protected $_aModulesLevel = 0;
  36. protected $_aAlerts = [];
  37. protected $_iAlertsLevel = 0;
  38. protected $_aInjections = [];
  39. protected $_sInjectionIndex = 0;
  40. protected $_sLogDateFormat = "Y-m-d H:i:s";
  41. protected $_sLogMaxArgLength = 64;
  42. protected $_sLogFilename = 64;
  43. protected $_aTemplates = [];
  44. protected $_aTemplateIndexes = [];
  45. protected $_aPages = [];
  46. protected $_sPageIndex = '';
  47. protected $_sPageBlockIndex = 0;
  48. protected $_aPagesBlocks = [];
  49. protected $_aMenus = [];
  50. function __construct($iTimeStart)
  51. {
  52. parent::__construct();
  53. $this->oConfig = new BxProfilerConfig ($GLOBALS['bx_profiler_module']);
  54. $this->oTemplate = new BxProfilerTemplate ($this->oConfig);
  55. $this->oTemplateAdmin = BxDolStudioTemplate::getInstance();
  56. if (getParam ('bx_profiler_long_sql_queries_log'))
  57. $this->aConf['long_query'] = getParam ('bx_profiler_long_sql_queries_time');
  58. if (getParam ('bx_profiler_long_module_query_log'))
  59. $this->aConf['long_module'] = getParam ('bx_profiler_long_module_query_time');
  60. if (getParam ('bx_profiler_long_page_log'))
  61. $this->aConf['long_page'] = getParam ('bx_profiler_long_page_time');
  62. $this->_iTimeStart = $iTimeStart;
  63. }
  64. // output profiler debug panel
  65. function output ()
  66. {
  67. $iPageTime = $this->_getCurrentDelay ();
  68. if (isset($this->aConf['long_page']) && $iPageTime > $this->aConf['long_page'])
  69. $this->logPageOpen ($iPageTime);
  70. switch (getParam('bx_profiler_show_debug_panel')) {
  71. case 'all':
  72. break;
  73. case 'admins':
  74. if (!isset($GLOBALS['logged']) || !$GLOBALS['logged']['admin'])
  75. return;
  76. break;
  77. case 'none':
  78. default:
  79. return;
  80. }
  81. $aCss = array (
  82. 'profiler.css',
  83. BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'jush/|jush.css',
  84. );
  85. $aJs = array (
  86. 'jquery.tablesorter.min.js',
  87. 'profiler.js',
  88. 'jush/jush.js',
  89. );
  90. $sJsCss = '';
  91. foreach ($aCss as $sCssPath)
  92. $sJsCss .= $this->oTemplate->addCss($sCssPath, 1);
  93. foreach ($aJs as $sJsPath)
  94. $sJsCss .= $this->oTemplate->addJs($sJsPath, 1);
  95. $sPlanks = $this->_plankMain ();
  96. $sPlanks .= $this->_plankMenus ();
  97. $sPlanks .= $this->_plankTemplates ();
  98. $sPlanks .= $this->_plankInjections ();
  99. $sPlanks .= $this->_plankPagesBlocks ();
  100. $sPlanks .= $this->_plankSql ();
  101. $sPlanks .= $this->_plankModules ();
  102. $sPlanks .= $this->_plankAlerts ();
  103. echo ob_get_clean();
  104. $sContentType = $this->oTemplate->getHeaderContentType();
  105. if ('text/html' == $sContentType) {
  106. echo $sJsCss . $sPlanks;
  107. }
  108. else if ('application/json' == $sContentType) {
  109. echo $sPlanks;
  110. }
  111. }
  112. function _logBegin ($s)
  113. {
  114. $sDate = date ($this->_sLogDateFormat);
  115. return "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" . $sDate . " " . $s . "\n" .
  116. (getLoggedId() ? "User ID: " . getLoggedId() . "\n" : '') .
  117. "User role: " . (!empty($GLOBALS['logged']['admin']) ? 'admin' : (!empty($GLOBALS['logged']['member']) ? 'member' : 'guest')) . "\n";
  118. }
  119. function _logEnd ()
  120. {
  121. return "\n";
  122. }
  123. function _appendToLog ($s)
  124. {
  125. bx_log('bx_profiler', $s, BX_LOG_INFO);
  126. }
  127. function logSqlQuery ($iTime, $aSqlQuery, &$oStmt)
  128. {
  129. $s = $this->_logBegin ('LONG SQL QUERY: ' . $aSqlQuery['time']);
  130. $s .= "Rows: " . $aSqlQuery['rows'] . "\n";
  131. $s .= "Affected: " . $aSqlQuery['affected'] . "\n";
  132. $s .= "Query: " . $aSqlQuery['sql'] . "\n";
  133. if (getParam('bx_profiler_long_sql_queries_debug'))
  134. $s .= "Backtrace: \n" . $this->_debugBackTrace (3);
  135. $s .= $this->_logEnd();
  136. $this->_appendToLog ($s);
  137. }
  138. function logModuleQuery ($iTime, $aModuleQuery)
  139. {
  140. $s = $this->_logBegin ('LONG MODULE QUERY: ' . $aModuleQuery['time']);
  141. $s .= "Module name: " . $aModuleQuery['name'] . "\n";
  142. $s .= "Query type: " . $aModuleQuery['type'] . "\n";
  143. $s .= "Class/file: " . $aModuleQuery['class/file'] . "\n";
  144. $s .= "Method: " . $aModuleQuery['method'] . "\n";
  145. if (getParam('bx_profiler_long_module_query_debug'))
  146. $s .= "Backtrace: \n" . $this->_debugBackTrace (3);
  147. $s .= $this->_logEnd();
  148. $this->_appendToLog ($s);
  149. }
  150. function logPageOpen ($iTime)
  151. {
  152. $s = $this->_logBegin ('LONG PAGE OPEN: ' . $this->_formatTime($iTime));
  153. if (isset($_SERVER['REQUEST_METHOD']))
  154. $s .= "Request method: " . $_SERVER['REQUEST_METHOD'] . "\n";
  155. if (isset($_SERVER['QUERY_STRING']))
  156. $s .= "Query string: " . $_SERVER['QUERY_STRING'] . "\n";
  157. if (isset($_SERVER['REQUEST_URI']))
  158. $s .= "Request URI: " . $_SERVER['REQUEST_URI'] . "\n";
  159. if (isset($_SERVER['SCRIPT_NAME']))
  160. $s .= "Script name: " . $_SERVER['SCRIPT_NAME'] . "\n";
  161. if (isset($_SERVER['PHP_SELF']))
  162. $s .= "PHP self: " . $_SERVER['PHP_SELF'] . "\n";
  163. if (getParam('bx_profiler_long_page_debug'))
  164. $s .= "All server vars: \n" . print_r ($_SERVER, true);
  165. $s .= $this->_logEnd();
  166. $this->_appendToLog ($s);
  167. }
  168. function beginModule($sType, $sHash, &$aModule, $sClassFile, $sMethod = '' )
  169. {
  170. ++$this->_aModulesLevel;
  171. $this->_aModulesNames[$aModule['title']] = isset($this->_aModulesNames[$aModule['title']]) ? $this->_aModulesNames[$aModule['title']] + 1 : 1;
  172. $this->_aModules[$sHash] = array (
  173. 'name' => str_repeat("--", $this->_aModulesLevel-1) . $aModule['title'],
  174. 'type' => $sType,
  175. 'class/file' => $sClassFile,
  176. 'method' => $sMethod,
  177. 'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
  178. 'sql' => 0,
  179. 'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
  180. 'kb' => 0,
  181. 'begin' => microtime (),
  182. 'time' => -1,
  183. );
  184. }
  185. function endModule($sType, $sHash)
  186. {
  187. --$this->_aModulesLevel;
  188. $iTime = $this->_calcTime ($this->_aModules[$sHash]['begin']);
  189. unset ($this->_aModules[$sHash]['begin']);
  190. $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aModules[$sHash]['sql_counter'];
  191. unset ($this->_aModules[$sHash]['sql_counter']);
  192. $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aModules[$sHash]['kb_counter']: 0;
  193. unset ($this->_aModules[$sHash]['kb_counter']);
  194. $this->_aModules[$sHash]['sql'] = $iSqlCounter;
  195. $this->_aModules[$sHash]['kb'] = $this->_formatKb($iMemCounter);
  196. $this->_aModules[$sHash]['time'] = $this->_formatTime($iTime);
  197. $this->_aModules[$sHash]['raw_time'] = $iTime;
  198. if (isset($this->aConf['long_module']) && $iTime > $this->aConf['long_module'])
  199. $this->logModuleQuery ($iTime, $this->_aModules[$sHash]);
  200. }
  201. function beginAlert($sUnit, $sAction, $sHandler)
  202. {
  203. $sHash = md5($sUnit . $sAction . $sHandler . $this->_iAlertsLevel);
  204. ++$this->_iAlertsLevel;
  205. $this->_aAlerts[$sHash] = array (
  206. 'name' => str_repeat("--", $this->_iAlertsLevel-1) . $sHandler,
  207. 'unit' => $sUnit,
  208. 'action' => $sAction,
  209. 'handler' => $sHandler,
  210. 'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
  211. 'sql' => 0,
  212. 'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
  213. 'kb' => 0,
  214. 'begin' => microtime (),
  215. 'time' => -1,
  216. );
  217. }
  218. function endAlert($sUnit, $sAction, $sHandler)
  219. {
  220. --$this->_iAlertsLevel;
  221. $sHash = md5($sUnit . $sAction . $sHandler . $this->_iAlertsLevel);
  222. $iTime = $this->_calcTime ($this->_aAlerts[$sHash]['begin']);
  223. unset ($this->_aAlerts[$sHash]['begin']);
  224. $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aAlerts[$sHash]['sql_counter'];
  225. unset ($this->_aAlerts[$sHash]['sql_counter']);
  226. $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aAlerts[$sHash]['kb_counter']: 0;
  227. unset ($this->_aAlerts[$sHash]['kb_counter']);
  228. $this->_aAlerts[$sHash]['sql'] = $iSqlCounter;
  229. $this->_aAlerts[$sHash]['kb'] = $this->_formatKb($iMemCounter);
  230. $this->_aAlerts[$sHash]['time'] = $this->_formatTime($iTime);
  231. $this->_aAlerts[$sHash]['raw_time'] = $iTime;
  232. }
  233. function beginInjection ($sId)
  234. {
  235. $this->_sInjectionIndex = $sId;
  236. $this->_aInjections[$sId] = [
  237. 'begin' => microtime (),
  238. 'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
  239. 'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
  240. ];
  241. }
  242. function endInjection ($sId, $aInjection)
  243. {
  244. if (!isset($this->_aInjections[$sId]))
  245. return;
  246. $iTime = $this->_calcTime ($this->_aInjections[$sId]['begin']);
  247. unset ($this->_aInjections[$sId]['begin']);
  248. $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aInjections[$sId]['sql_counter'];
  249. unset ($this->_aInjections[$sId]['sql_counter']);
  250. $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aInjections[$sId]['kb_counter']: 0;
  251. unset ($this->_aInjections[$sId]['kb_counter']);
  252. $this->_aInjections[$sId]['name'] = isset($aInjection['name']) ? $aInjection['name'] : 'no-name';
  253. $this->_aInjections[$sId]['key'] = $aInjection['key'];
  254. $this->_aInjections[$sId]['replace'] = $aInjection['replace'] ? 'yes' : 'no';
  255. $this->_aInjections[$sId]['sql'] = $iSqlCounter;
  256. $this->_aInjections[$sId]['kb'] = $this->_formatKb($iMemCounter);
  257. $this->_aInjections[$sId]['time'] = $this->_formatTime($iTime);
  258. $this->_aInjections[$sId]['raw_time'] = $iTime;
  259. }
  260. function beginPageBlock ($sName, $iBlockId)
  261. {
  262. $this->_sPageBlockIndex = $iBlockId;
  263. $this->_aPagesBlocks[$this->_sPageBlockIndex] = [
  264. 'name' => $sName,
  265. 'begin' => microtime (),
  266. 'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
  267. 'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
  268. ];
  269. }
  270. function endPageBlock ($iBlockId, $isEmpty, $isCached)
  271. {
  272. if (!$this->_sPageBlockIndex)
  273. return;
  274. $iTime = $this->_calcTime ($this->_aPagesBlocks[$this->_sPageBlockIndex]['begin']);
  275. unset ($this->_aPagesBlocks[$this->_sPageBlockIndex]['begin']);
  276. $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aPagesBlocks[$this->_sPageBlockIndex]['sql_counter'];
  277. unset ($this->_aPagesBlocks[$this->_sPageBlockIndex]['sql_counter']);
  278. $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aPagesBlocks[$this->_sPageBlockIndex]['kb_counter']: 0;
  279. unset ($this->_aPagesBlocks[$this->_sPageBlockIndex]['kb_counter']);
  280. $this->_aPagesBlocks[$this->_sPageBlockIndex]['cached'] = $isCached ? 'yes' : 'no';
  281. $this->_aPagesBlocks[$this->_sPageBlockIndex]['empty'] = $isEmpty ? 'yes' : 'no';
  282. $this->_aPagesBlocks[$this->_sPageBlockIndex]['sql'] = $iSqlCounter;
  283. $this->_aPagesBlocks[$this->_sPageBlockIndex]['kb'] = $this->_formatKb($iMemCounter);
  284. $this->_aPagesBlocks[$this->_sPageBlockIndex]['time'] = $this->_formatTime($iTime);
  285. $this->_aPagesBlocks[$this->_sPageBlockIndex]['raw_time'] = $iTime;
  286. }
  287. function beginPage ($sName)
  288. {
  289. $this->_sPageIndex = md5 ($sName.time().rand());
  290. $this->_aPages[$this->_sPageIndex] = [
  291. 'name' => $sName,
  292. 'begin' => microtime (),
  293. 'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
  294. 'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
  295. ];
  296. }
  297. function endPage (&$sContent)
  298. {
  299. if (!$this->_sPageIndex || !isset($this->_aPages[$this->_sPageIndex]['begin']))
  300. return;
  301. $iTime = $this->_calcTime ($this->_aPages[$this->_sPageIndex]['begin']);
  302. unset ($this->_aPages[$this->_sPageIndex]['begin']);
  303. $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aPages[$this->_sPageIndex]['sql_counter'];
  304. unset ($this->_aPages[$this->_sPageIndex]['sql_counter']);
  305. $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aPages[$this->_sPageIndex]['kb_counter']: 0;
  306. unset ($this->_aPages[$this->_sPageIndex]['kb_counter']);
  307. $this->_aPages[$this->_sPageIndex]['sql'] = $iSqlCounter;
  308. $this->_aPages[$this->_sPageIndex]['kb'] = $this->_formatKb($iMemCounter);
  309. $this->_aPages[$this->_sPageIndex]['time'] = $this->_formatTime($iTime);
  310. $this->_aPages[$this->_sPageIndex]['raw_time'] = $iTime;
  311. }
  312. function beginTemplate ($sName, $sRand)
  313. {
  314. $this->_aTemplateIndexes[$sName.$sRand] = 1;
  315. $this->_aTemplates[$sName.$sRand] = [
  316. 'name' => $sName,
  317. 'begin' => microtime (),
  318. 'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
  319. 'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
  320. ];
  321. }
  322. function endTemplate ($sName, $sRand, &$sContent, $isCached)
  323. {
  324. if (!isset($this->_aTemplateIndexes[$sName.$sRand]))
  325. return;
  326. $iTime = $this->_calcTime ($this->_aTemplates[$sName.$sRand]['begin']);
  327. unset ($this->_aTemplates[$sName.$sRand]['begin']);
  328. $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aTemplates[$sName.$sRand]['sql_counter'];
  329. unset ($this->_aTemplates[$sName.$sRand]['sql_counter']);
  330. $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aTemplates[$sName.$sRand]['kb_counter']: 0;
  331. unset ($this->_aTemplates[$sName.$sRand]['kb_counter']);
  332. $this->_aTemplates[$sName.$sRand]['sql'] = $iSqlCounter;
  333. $this->_aTemplates[$sName.$sRand]['kb'] = $this->_formatKb($iMemCounter);
  334. $this->_aTemplates[$sName.$sRand]['cached'] = $isCached ? 'yes' : 'no';
  335. $this->_aTemplates[$sName.$sRand]['time'] = $this->_formatTime($iTime);
  336. $this->_aTemplates[$sName.$sRand]['raw_time'] = $iTime;
  337. }
  338. function beginQuery ($sSql)
  339. {
  340. $this->_sQueryIndex = md5 ($sSql.time().rand());
  341. $this->_aQueries[$this->_sQueryIndex] = [
  342. 'sql' => $sSql,
  343. 'begin' => microtime (),
  344. 'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
  345. ];
  346. }
  347. function endQuery (&$oStmt)
  348. {
  349. if (!$this->_sQueryIndex)
  350. return;
  351. $iTime = $this->_calcTime ($this->_aQueries[$this->_sQueryIndex]['begin']);
  352. unset ($this->_aQueries[$this->_sQueryIndex]['begin']);
  353. $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aQueries[$this->_sQueryIndex]['kb_counter']: 0;
  354. unset ($this->_aQueries[$this->_sQueryIndex]['kb_counter']);
  355. $this->_aQueries[$this->_sQueryIndex]['time'] = $this->_formatTime($iTime);
  356. $this->_aQueries[$this->_sQueryIndex]['raw_time'] = $iTime;
  357. $this->_aQueries[$this->_sQueryIndex]['rows'] = $oStmt ? BxDolDb::getInstance()->getNumRows($oStmt) : '';
  358. $this->_aQueries[$this->_sQueryIndex]['affected'] = $oStmt ? BxDolDb::getInstance()->getAffectedRows($oStmt) : '';
  359. $this->_aQueries[$this->_sQueryIndex]['kb'] = $this->_formatKb($iMemCounter);
  360. if (isset($this->aConf['long_query']) && $iTime > $this->aConf['long_query'])
  361. $this->logSqlQuery ($iTime, $this->_aQueries[$this->_sQueryIndex], $oStmt);
  362. }
  363. function isMenu($sName)
  364. {
  365. return isset($this->_aMenus[$sName]);
  366. }
  367. function beginMenu ($sName)
  368. {
  369. $this->_aMenus[$sName] = [
  370. 'name' => $sName,
  371. 'begin' => microtime (),
  372. 'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
  373. 'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
  374. ];
  375. }
  376. function endMenu ($sName, $sCacheType = '', $bCacheUsed = false)
  377. {
  378. if (!isset($this->_aMenus[$sName]))
  379. return;
  380. $iTime = $this->_calcTime ($this->_aMenus[$sName]['begin']);
  381. unset ($this->_aMenus[$sName]['begin']);
  382. $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aMenus[$sName]['sql_counter'];
  383. unset ($this->_aMenus[$sName]['sql_counter']);
  384. $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aMenus[$sName]['kb_counter']: 0;
  385. unset ($this->_aMenus[$sName]['kb_counter']);
  386. $this->_aMenus[$sName]['sql'] = $iSqlCounter;
  387. $this->_aMenus[$sName]['kb'] = $this->_formatKb($iMemCounter);
  388. $this->_aMenus[$sName]['time'] = $this->_formatTime($iTime);
  389. $this->_aMenus[$sName]['raw_time'] = $iTime;
  390. $this->_aMenus[$sName]['cache type'] = $sCacheType;
  391. $this->_aMenus[$sName]['cache used'] = $bCacheUsed ? 'yes' : 'no';
  392. }
  393. function _getCurrentDelay ()
  394. {
  395. $i1 = explode(' ', microtime ());
  396. $i2 = explode(' ', $this->_iTimeStart);
  397. return ($i1[0]+$i1[1]) - ($i2[0]+$i2[1]);
  398. }
  399. function _plankMain ()
  400. {
  401. $sTime = $this->_formatTime($this->_getCurrentDelay (), 3);
  402. if (function_exists('memory_get_usage'))
  403. $sMemory = $this->_formatBytes(memory_get_usage(true)) . ' of ' . ini_get('memory_limit') . ' allowed';
  404. $aLoad = sys_getloadavg();
  405. $sLoad = implode(',', array_map(function ($f) {
  406. return round ($f, 2);
  407. }, $aLoad));
  408. return $this->oTemplate->plank(
  409. $this->oTemplate->nameValue('Time:', $sTime) .
  410. (function_exists('memory_get_usage') ? $this->oTemplate->nameValue('Memory:', $sMemory) : '') .
  411. $this->oTemplate->nameValue('PHP:', phpversion()) .
  412. $this->oTemplate->nameValue('SAPI:', php_sapi_name()) .
  413. $this->oTemplate->nameValue('OS:', php_uname('s')) .
  414. $this->oTemplate->nameValue('Avg load:', $sLoad)
  415. );
  416. }
  417. function _plankTemplates ()
  418. {
  419. if (empty($GLOBALS['bx_profiler']->_aPages) && empty($GLOBALS['bx_profiler']->_aTemplates))
  420. return;
  421. $sPages = '';
  422. if (!empty($GLOBALS['bx_profiler']->_aPages)) {
  423. $iTimePages = 0;
  424. foreach ($GLOBALS['bx_profiler']->_aPages as $k => $r) {
  425. if (!isset($r['raw_time']))
  426. continue;
  427. $iTimePages += $r['raw_time'];
  428. unset ($GLOBALS['bx_profiler']->_aPages[$k]['raw_time']);
  429. }
  430. $sPages = count($GLOBALS['bx_profiler']->_aPages) . ' (' . $this->_formatTime($iTimePages, 3) . ')';
  431. }
  432. $sTemplatesCached = '';
  433. $sTemplatesNotCached = '';
  434. if ($GLOBALS['bx_profiler']->_aTemplates) {
  435. $iTimeTemplatesCached = 0;
  436. $iTimeTemplatesNotCached = 0;
  437. $sTemplatesCached = 0;
  438. $sTemplatesNotCached = 0;
  439. foreach ($GLOBALS['bx_profiler']->_aTemplates as $k => $r) {
  440. if (!isset($r['raw_time']))
  441. continue;
  442. if ('yes' == $r['cached']) {
  443. $iTimeTemplatesCached += $r['raw_time'];
  444. ++$sTemplatesCached;
  445. } else {
  446. $iTimeTemplatesNotCached += $r['raw_time'];
  447. ++$sTemplatesNotCached;
  448. }
  449. unset ($GLOBALS['bx_profiler']->_aTemplates[$k]['raw_time']);
  450. }
  451. if ($sTemplatesCached)
  452. $sTemplatesCached .= ' (' . $this->_formatTime($iTimeTemplatesCached, 3) . ')';
  453. if ($sTemplatesNotCached)
  454. $sTemplatesNotCached .= ' (' . $this->_formatTime($iTimeTemplatesNotCached, 3) . ')';
  455. }
  456. return $this->oTemplate->plank(
  457. ($sPages ? $this->oTemplate->nameValue('Pages:', $sPages) : '') .
  458. ($sTemplatesCached ? $this->oTemplate->nameValue('Templates Cached:', $sTemplatesCached) : '') .
  459. ($sTemplatesNotCached ? $this->oTemplate->nameValue('Templates Not Cached:', $sTemplatesNotCached) : ''),
  460. $this->oTemplate->table($GLOBALS['bx_profiler']->_aTemplates)
  461. );
  462. }
  463. function _plankInjections ()
  464. {
  465. if (!$GLOBALS['bx_profiler']->_aInjections)
  466. return;
  467. $iTimeInjections = 0;
  468. foreach ($GLOBALS['bx_profiler']->_aInjections as $k => $r) {
  469. if (!isset($r['raw_time']))
  470. continue;
  471. $iTimeInjections += $r['raw_time'];
  472. unset ($GLOBALS['bx_profiler']->_aInjections[$k]['raw_time']);
  473. }
  474. $sInjections = count($GLOBALS['bx_profiler']->_aInjections) . ' injection (' . $this->_formatTime($iTimeInjections, 3) . ')';
  475. return $this->oTemplate->plank(
  476. $this->oTemplate->nameValue('Injections:', $sInjections),
  477. $this->oTemplate->table($GLOBALS['bx_profiler']->_aInjections)
  478. );
  479. }
  480. function _plankPagesBlocks ()
  481. {
  482. if (empty($GLOBALS['bx_profiler']->_aPagesBlocks))
  483. return;
  484. $iTimeBlocks = 0;
  485. $iTimeBlocksCached = 0;
  486. $iTimeBlocksNotCached = 0;
  487. $iTimeBlocksEmpty = 0;
  488. $iTimeBlocksNotEmpty = 0;
  489. $iCountBlocksCached = 0;
  490. $iCountBlocksNotCached = 0;
  491. $iCountBlocksEmpty = 0;
  492. $iCountBlocksNotEmpty = 0;
  493. foreach ($GLOBALS['bx_profiler']->_aPagesBlocks as $k => $r) {
  494. if (!isset($r['raw_time']))
  495. continue;
  496. $iTimeBlocks += $r['raw_time'];
  497. if ($r['cached'] == 'yes') {
  498. $iTimeBlocksCached += $r['raw_time'];
  499. ++$iCountBlocksCached;
  500. } else {
  501. $iTimeBlocksNotCached += $r['raw_time'];
  502. ++$iCountBlocksNotCached;
  503. }
  504. if ($r['empty'] == 'yes') {
  505. $iTimeBlocksEmpty += $r['raw_time'];
  506. ++$iCountBlocksEmpty;
  507. } else {
  508. $iTimeBlocksNotEmpty += $r['raw_time'];
  509. ++$iCountBlocksNotEmpty;
  510. }
  511. unset ($GLOBALS['bx_profiler']->_aPagesBlocks[$k]['raw_time']);
  512. }
  513. $sBlocks = count($GLOBALS['bx_profiler']->_aPagesBlocks) . ' (' . $this->_formatTime($iTimeBlocks, 3) . ')';
  514. if ($iCountBlocksCached)
  515. $sBlocksCached = $iCountBlocksCached . ' (' . $this->_formatTime($iTimeBlocksCached, 3) . ')';
  516. if ($iCountBlocksNotCached)
  517. $sBlocksNotCached = $iCountBlocksNotCached . ' (' . $this->_formatTime($iTimeBlocksNotCached, 3) . ')';
  518. if ($iCountBlocksEmpty)
  519. $sBlocksEmpty = $iCountBlocksEmpty . ' (' . $this->_formatTime($iTimeBlocksEmpty, 3) . ')';
  520. if ($iCountBlocksNotEmpty)
  521. $sBlocksNotEmpty = $iCountBlocksNotEmpty . ' (' . $this->_formatTime($iTimeBlocksNotEmpty, 3) . ')';
  522. return $this->oTemplate->plank(
  523. $this->oTemplate->nameValue('Pages Blocks:', $sBlocks) .
  524. ($iCountBlocksCached ? $this->oTemplate->nameValue('Cached:', $sBlocksCached) : '') .
  525. ($iCountBlocksNotCached ? $this->oTemplate->nameValue('Not Cached:', $sBlocksNotCached) : '') .
  526. ($iCountBlocksEmpty ? $this->oTemplate->nameValue('Empty:', $sBlocksEmpty) : '') .
  527. ($iCountBlocksNotEmpty ? $this->oTemplate->nameValue('Not Empty:', $sBlocksNotEmpty) : ''),
  528. $this->oTemplate->table($GLOBALS['bx_profiler']->_aPagesBlocks)
  529. );
  530. }
  531. function _plankMenus ()
  532. {
  533. if (empty($GLOBALS['bx_profiler']->_aMenus))
  534. return;
  535. $iTimeMenus = 0;
  536. foreach ($GLOBALS['bx_profiler']->_aMenus as $k => $r) {
  537. if (!isset($r['raw_time']))
  538. continue;
  539. $iTimeMenus += $r['raw_time'];
  540. unset ($GLOBALS['bx_profiler']->_aMenus[$k]['raw_time']);
  541. }
  542. $sMenus = count($GLOBALS['bx_profiler']->_aMenus) . ' menus (' . $this->_formatTime($iTimeMenus, 3) . ')';
  543. return $this->oTemplate->plank(
  544. $this->oTemplate->nameValue('Menus:', $sMenus),
  545. $this->oTemplate->table($GLOBALS['bx_profiler']->_aMenus)
  546. );
  547. }
  548. function _plankSql ()
  549. {
  550. if (empty($GLOBALS['bx_profiler']->_aQueries))
  551. return;
  552. $iTimeQueries = 0;
  553. foreach ($GLOBALS['bx_profiler']->_aQueries as $k => $r) {
  554. if (!isset($r['raw_time']))
  555. continue;
  556. $iTimeQueries += $r['raw_time'];
  557. unset ($GLOBALS['bx_profiler']->_aQueries[$k]['raw_time']);
  558. }
  559. $sQueries = count($GLOBALS['bx_profiler']->_aQueries) . ' queries (' . $this->_formatTime($iTimeQueries, 3) . ')';
  560. return $this->oTemplate->plank(
  561. $this->oTemplate->nameValue('SQL:', $sQueries),
  562. $this->oTemplate->table($GLOBALS['bx_profiler']->_aQueries, 'sql')
  563. );
  564. }
  565. function _plankModules ()
  566. {
  567. if (empty($GLOBALS['bx_profiler']->_aModules))
  568. return;
  569. $iTimeModules = 0;
  570. foreach ($GLOBALS['bx_profiler']->_aModules as $k => $r) {
  571. if (!isset($r['raw_time']))
  572. continue;
  573. $iTimeModules += $r['raw_time'];
  574. unset ($GLOBALS['bx_profiler']->_aModules[$k]['raw_time']);
  575. }
  576. $sModules = count($GLOBALS['bx_profiler']->_aModulesNames) . ' modules loaded';
  577. $sModulesQueries = count($GLOBALS['bx_profiler']->_aModules) . ' modules queries (' . $this->_formatTime($iTimeModules, 3) . ')';
  578. return $this->oTemplate->plank(
  579. $this->oTemplate->nameValue('Modules:', $sModules) .
  580. $this->oTemplate->nameValue('Modules Queries:', $sModulesQueries),
  581. $this->oTemplate->table($GLOBALS['bx_profiler']->_aModules)
  582. );
  583. }
  584. function _plankAlerts ()
  585. {
  586. if (empty($GLOBALS['bx_profiler']->_aAlerts))
  587. return;
  588. $iTimeAlerts = 0;
  589. foreach ($GLOBALS['bx_profiler']->_aAlerts as $k => $r) {
  590. if (!isset($r['raw_time']))
  591. continue;
  592. $iTimeAlerts += $r['raw_time'];
  593. unset ($GLOBALS['bx_profiler']->_aAlerts[$k]['raw_time']);
  594. }
  595. $sAlerts = count($GLOBALS['bx_profiler']->_aAlerts) . ' alerts responses (' . $this->_formatTime($iTimeAlerts, 3) . ')';
  596. return $this->oTemplate->plank(
  597. $this->oTemplate->nameValue('Alerts:', $sAlerts),
  598. $this->oTemplate->table($GLOBALS['bx_profiler']->_aAlerts)
  599. );
  600. }
  601. function _formatTime ($i, $iPrecision = 4)
  602. {
  603. return round($i, $iPrecision) . ' sec';
  604. }
  605. function _formatBytes ($i)
  606. {
  607. return bx_format_bytes($i);
  608. }
  609. function _formatKb ($i)
  610. {
  611. $s = round($i / 1024, 0);
  612. return $s == '-0' ? '0' : $s;
  613. }
  614. function _isProfilerDisabled()
  615. {
  616. if (isset($GLOBALS['bx_profiler_disable']) || isset($_GET['bx_profiler_disable']) || defined('BX_API'))
  617. return true;
  618. return false;
  619. }
  620. function _calcTime ($begin)
  621. {
  622. $i1 = explode(' ', microtime ());
  623. $i2 = explode(' ', $begin);
  624. return ($i1[0]+$i1[1]) - ($i2[0]+$i2[1]);
  625. }
  626. function _debugPrintArray ($mixed)
  627. {
  628. $sArgs .= 'Array(';
  629. foreach ($mixed as $mixed2)
  630. $sArgs .= (is_object($mixed2) ? $this->_debugPrintObject($mixed2) : $this->_debugPrintAny($mixed2)) . ',';
  631. $sArgs = substr($sArgs, 0, -1);
  632. $sArgs .= ')';
  633. return $sArgs;
  634. }
  635. function _debugPrintObject ($mixed)
  636. {
  637. return get_class($mixed) . ' instance';
  638. }
  639. function _debugPrintAny ($mixed)
  640. {
  641. if (is_string($mixed))
  642. return "'" . (strlen($mixed) > $this->_sLogMaxArgLength ? substr($mixed, 0, $this->_sLogMaxArgLength) . '...' : $mixed) . "'";
  643. else
  644. return $mixed;
  645. }
  646. function _debugBackTrace ($iShifts = 0)
  647. {
  648. $a = debug_backtrace();
  649. while (--$iShifts > -1)
  650. array_shift($a);
  651. $s = '';
  652. foreach ($a as $r) {
  653. $sArgs = '';
  654. foreach ($r['args'] as $mixed) {
  655. switch (true) {
  656. case is_array($mixed):
  657. $sArgs .= $this->_debugPrintArray($mixed);
  658. break;
  659. case is_object($mixed):
  660. $sArgs .= $this->_debugPrintObject($mixed);
  661. break;
  662. default:
  663. $sArgs .= $this->_debugPrintAny($mixed);
  664. }
  665. $sArgs .= ',';
  666. }
  667. $sArgs = substr($sArgs, 0, -1);
  668. $s .= "--------------------------------------\n";
  669. $s .= "{$r['line']} {$r['file']}\n";
  670. $s .= "{$r['class']}{$r['type']}{$r['function']} ({$sArgs});\n";
  671. }
  672. return $s;
  673. }
  674. }
  675. $GLOBALS['bx_profiler'] = new BxProfiler(BX_DOL_START);
  676. if (!$GLOBALS['bx_profiler']->_isProfilerDisabled())
  677. register_shutdown_function (array ($GLOBALS['bx_profiler'], 'output'));
  678. /** @} */