Your IP : 3.19.241.182
<?php
function perfmonErrorHandler($errno, $errstr, $errfile, $errline)
{
global $perfmonErrors;
//if(count($perfmonErrors) > 100)
// return false;
static $arExclude = [
'/modules/main/classes/general/cache.php:150' => true,
];
$uni_file_name = str_replace('\\', '/', mb_substr($errfile, mb_strlen($_SERVER['DOCUMENT_ROOT'] . BX_ROOT)));
$bRecord = false;
switch ($errno)
{
case E_WARNING:
$bRecord = true;
break;
case E_NOTICE:
if (
(mb_strpos($errstr, 'Undefined index:') === false)
&& (mb_strpos($errstr, 'Undefined offset:') === false)
&& !array_key_exists($uni_file_name . ':' . $errline, $arExclude)
)
{
$bRecord = true;
}
break;
default:
break;
}
if ($bRecord)
{
$perfmonErrors[] = [
'ERRNO' => $errno,
'ERRSTR' => $errstr,
'ERRFILE' => $errfile,
'ERRLINE' => $errline,
];
}
//Continue with default handling
return false;
}
class CPerfomanceKeeper
{
public static function OnPageStart()
{
if (!defined('PERFMON_STOP'))
{
$end_time = COption::GetOptionInt('perfmon', 'end_time');
if (time() > $end_time)
{
CPerfomanceKeeper::SetActive(false);
if (COption::GetOptionString('perfmon', 'total_mark_value', '') == 'measure')
{
COption::SetOptionString('perfmon', 'total_mark_value', 'calc');
}
}
else
{
self::setDebugModeOn();
global $perfmonErrors;
$perfmonErrors = [];
if (COption::GetOptionString('perfmon', 'warning_log') === 'Y')
{
set_error_handler('perfmonErrorHandler');
}
}
}
}
public static function setDebugModeOn()
{
global $DB, $APPLICATION;
define('PERFMON_STARTED', $DB->ShowSqlStat . '|' . \Bitrix\Main\Data\Cache::getShowCacheStat() . '|' . $APPLICATION->ShowIncludeStat);
$DB->ShowSqlStat = true;
$application = \Bitrix\Main\Application::getInstance();
$application->getConnectionPool()->getConnection()->startTracker();
\Bitrix\Main\Data\Cache::setShowCacheStat(COption::GetOptionString('perfmon', 'cache_log') === 'Y');
$APPLICATION->ShowIncludeStat = true;
}
public static function restoreDebugMode()
{
global $DB, $APPLICATION;
$toRestore = explode('|', constant('PERFMON_STARTED'));
$DB->ShowSqlStat = $toRestore[0];
\Bitrix\Main\Data\Cache::setShowCacheStat($toRestore[1]);
$APPLICATION->ShowIncludeStat = $toRestore[2];
}
public static function OnEpilog()
{
if (defined('PERFMON_STARTED'))
{
self::restoreDebugMode();
}
}
public static function OnBeforeAfterEpilog()
{
if (defined('PERFMON_STARTED'))
{
global $DB;
$DB->ShowSqlStat = true;
}
}
public static function OnAfterAfterEpilog()
{
if (defined('PERFMON_STARTED'))
{
self::restoreDebugMode();
CPerfomanceKeeper::writeToDatabase();
}
}
public static function writeToDatabase()
{
$START_EXEC_CURRENT_TIME = microtime();
global $DB, $APPLICATION;
$pool = \Bitrix\Main\Application::getInstance()->getConnectionPool();
$connection = $pool->getConnection();
$connection->stopTracker();
$DB->ShowSqlStat = false;
if ($connection->getTracker())
{
$arQueryDebug = $connection->getTracker()->getQueries();
}
else
{
$arQueryDebug = [];
}
$arIncludeDebug = $APPLICATION->arIncludeDebug;
$cache_log = COption::GetOptionString('perfmon', 'cache_log') === 'Y';
$large_cache_log = COption::GetOptionString('perfmon', 'large_cache_log') === 'Y';
$large_cache_size = floatval(COption::GetOptionString('perfmon', 'large_cache_size')) * 1024;
$sql_log = COption::GetOptionString('perfmon', 'sql_log') === 'Y';
$slow_sql_log = COption::GetOptionString('perfmon', 'slow_sql_log') === 'Y';
$slow_sql_time = floatval(COption::GetOptionString('perfmon', 'slow_sql_time'));
if ($slow_sql_log)
{
self::removeQueries($arQueryDebug, $arIncludeDebug, $slow_sql_time, $cache_log);
}
$query_count = 0;
$query_time = 0.0;
if ($sql_log)
{
self::countQueries($query_count, $query_time, $arQueryDebug, $arIncludeDebug);
}
$comps_count = 0;
$comps_time = 0.0;
if ($sql_log || $cache_log)
{
self::countComponents($comps_count, $comps_time, $arIncludeDebug);
}
$cache_count = [];
/** @var \Bitrix\Main\Diag\CacheTracker $arCacheDebug */
$arCacheDebug = null;
if ($cache_log)
{
$arCacheDebug = \Bitrix\Main\Diag\CacheTracker::getCacheTracking();
if ($large_cache_log)
{
self::removeCaches($large_cache_size, $arCacheDebug, $arIncludeDebug);
}
self::countCache($arCacheDebug, $cache_count);
foreach ($arIncludeDebug as $ar)
{
if (array_key_exists('REL_PATH', $ar))
{
self::countCache($ar['CACHE'], $cache_count);
}
}
}
if ($_SERVER['SCRIPT_NAME'] == '/bitrix/urlrewrite.php' && isset($_SERVER['REAL_FILE_PATH']))
{
$SCRIPT_NAME = $_SERVER['REAL_FILE_PATH'];
}
elseif ($_SERVER['SCRIPT_NAME'] == '/404.php' && isset($_SERVER['REAL_FILE_PATH']))
{
$SCRIPT_NAME = $_SERVER['REAL_FILE_PATH'];
}
else
{
$SCRIPT_NAME = $_SERVER['SCRIPT_NAME'];
}
$arFields = [
'~DATE_HIT' => $DB->GetNowFunction(),
'IS_ADMIN' => defined('ADMIN_SECTION') ? 'Y' : 'N',
'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'] ?? '',
'SERVER_NAME' => $_SERVER['SERVER_NAME'] ?? '',
'SERVER_PORT' => $_SERVER['SERVER_PORT'] ?? '',
'SCRIPT_NAME' => $SCRIPT_NAME,
'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? '',
'INCLUDED_FILES' => function_exists('get_included_files') ? count(get_included_files()) : false,
'MEMORY_PEAK_USAGE' => function_exists('memory_get_peak_usage') ? memory_get_peak_usage() : false,
'CACHE_TYPE' => COption::GetOptionString('main', 'component_cache_on', 'Y') == 'Y' ? 'Y' : 'N',
'~CACHE_SIZE' => intval($GLOBALS['CACHE_STAT_BYTES']),
'~CACHE_COUNT_R' => intval($cache_count['R'] ?? 0),
'~CACHE_COUNT_W' => intval($cache_count['W'] ?? 0),
'~CACHE_COUNT_C' => intval($cache_count['C'] ?? 0),
'QUERIES' => $query_count,
'~QUERIES_TIME' => $query_time,
'SQL_LOG' => $sql_log ? 'Y' : 'N',
'COMPONENTS' => $comps_count,
'~COMPONENTS_TIME' => $comps_time,
'~MENU_RECALC' => $APPLICATION->_menu_recalc_counter,
];
CPerfomanceKeeper::SetPageTimes($START_EXEC_CURRENT_TIME, $arFields);
if ($query_count || $comps_count || $cache_count)
{
$HIT_ID = $DB->Add('b_perf_hit', $arFields);
}
else
{
$HIT_ID = false;
}
$NN = 0;
if ($HIT_ID && $cache_log)
{
self::saveCaches($HIT_ID, false, $arCacheDebug, $NN);
}
$MM = 0;
if ($HIT_ID && $sql_log)
{
if (is_array($arQueryDebug))
{
self::saveQueries($HIT_ID, false, $arQueryDebug, $MM);
}
}
if ($HIT_ID && ($sql_log || $cache_log))
{
foreach ($arIncludeDebug as $ii => $ar)
{
if (!array_key_exists('REL_PATH', $ar))
{
continue;
}
$cache_count = [];
if ($cache_log)
{
self::countCache($ar['CACHE'], $cache_count);
}
$arFields = [
'HIT_ID' => $HIT_ID,
'NN' => $ii,
'CACHE_TYPE' => $ar['CACHE_TYPE'],
'~CACHE_SIZE' => intval($ar['CACHE_SIZE']),
'~CACHE_COUNT_R' => intval($cache_count['R'] ?? 0),
'~CACHE_COUNT_W' => intval($cache_count['W'] ?? 0),
'~CACHE_COUNT_C' => intval($cache_count['C'] ?? 0),
'COMPONENT_TIME' => $ar['TIME'],
'QUERIES' => $ar['QUERY_COUNT'],
'QUERIES_TIME' => $ar['QUERY_TIME'],
'COMPONENT_NAME' => $ar['REL_PATH'],
];
$COMP_ID = $DB->Add('b_perf_component', $arFields);
if ($sql_log && is_array($ar['QUERIES']))
{
self::saveQueries($HIT_ID, $COMP_ID, $ar['QUERIES'], $MM);
}
if ($cache_log && is_array($ar['CACHE']))
{
self::saveCaches($HIT_ID, $COMP_ID, $ar['CACHE'], $NN);
}
}
}
global $perfmonErrors;
if ($HIT_ID && (count($perfmonErrors) > 0))
{
foreach ($perfmonErrors as $arError)
{
$arError['HIT_ID'] = $HIT_ID;
$DB->Add('b_perf_error', $arError);
}
}
}
public static function SetPageTimes($START_EXEC_CURRENT_TIME, &$arFields)
{
list($usec, $sec) = explode(' ', $START_EXEC_CURRENT_TIME);
$CURRENT_TIME = (float)$sec + (float)$usec;
if (defined('START_EXEC_PROLOG_BEFORE_1'))
{
$PROLOG_BEFORE_1 = (float)START_EXEC_PROLOG_BEFORE_1;
if (defined('START_EXEC_AGENTS_1') && defined('START_EXEC_AGENTS_2'))
{
$AGENTS_2 = (float)constant('START_EXEC_AGENTS_2');
$AGENTS_1 = (float)constant('START_EXEC_AGENTS_1');
$arFields['~AGENTS_TIME'] = $AGENTS_2 - $AGENTS_1;
}
else
{
$arFields['~AGENTS_TIME'] = 0;
}
if (defined('START_EXEC_EVENTS_1') && defined('START_EXEC_EVENTS_2'))
{
list($usec, $sec) = explode(' ', constant('START_EXEC_EVENTS_2'));
$EVENTS_2 = (float)$sec + (float)$usec;
list($usec, $sec) = explode(' ', constant('START_EXEC_EVENTS_1'));
$EVENTS_1 = (float)$sec + (float)$usec;
$arFields['~EVENTS_TIME'] = $EVENTS_2 - $EVENTS_1;
}
else
{
$arFields['~EVENTS_TIME'] = 0;
}
if (defined('START_EXEC_PROLOG_AFTER_1') && defined('START_EXEC_PROLOG_AFTER_2'))
{
$PROLOG_AFTER_1 = (float)START_EXEC_PROLOG_AFTER_1;
$PROLOG_AFTER_2 = (float)START_EXEC_PROLOG_AFTER_2;
$arFields['~PROLOG_AFTER_TIME'] = $PROLOG_AFTER_2 - $PROLOG_AFTER_1;
$arFields['~PROLOG_BEFORE_TIME'] = $PROLOG_AFTER_1 - $PROLOG_BEFORE_1;
$arFields['~PROLOG_TIME'] = round($PROLOG_AFTER_2 - $PROLOG_BEFORE_1 - $arFields['~AGENTS_TIME'], 4);
if (defined('START_EXEC_EPILOG_BEFORE_1'))
{
$EPILOG_BEFORE_1 = (float)START_EXEC_EPILOG_BEFORE_1;
$arFields['~WORK_AREA_TIME'] = $EPILOG_BEFORE_1 - $PROLOG_AFTER_2;
if (defined('START_EXEC_EPILOG_AFTER_1'))
{
$EPILOG_AFTER_1 = (float)START_EXEC_EPILOG_AFTER_1;
$arFields['~EPILOG_BEFORE_TIME'] = $EPILOG_AFTER_1 - $EPILOG_BEFORE_1;
$arFields['~EPILOG_AFTER_TIME'] = $CURRENT_TIME - $EPILOG_AFTER_1 - $arFields['~EVENTS_TIME'];
}
else
{
$arFields['~EPILOG_BEFORE_TIME'] = 0;
$arFields['~EPILOG_AFTER_TIME'] = 0;
}
$arFields['~EPILOG_TIME'] = $CURRENT_TIME - $EPILOG_BEFORE_1;
}
else
{
$arFields['~WORK_AREA_TIME'] = $CURRENT_TIME - $PROLOG_AFTER_2;
$arFields['~EPILOG_BEFORE_TIME'] = 0;
$arFields['~EPILOG_AFTER_TIME'] = 0;
$arFields['~EPILOG_TIME'] = 0;
}
}
$arFields['~PAGE_TIME'] = $CURRENT_TIME - $PROLOG_BEFORE_1;
}
else
{
$arFields['~PAGE_TIME'] = $CURRENT_TIME - START_EXEC_TIME;
}
}
public static function removeQueries(&$arQueryDebug, &$arIncludeDebug, $slow_sql_time, $preserveComponents = false)
{
if (is_array($arQueryDebug))
{
foreach ($arQueryDebug as $i => $arQueryInfo)
{
if ($arQueryInfo['TIME'] < $slow_sql_time)
{
unset($arQueryDebug[$i]);
}
}
}
if (is_array($arIncludeDebug))
{
foreach ($arIncludeDebug as $i => $ar)
{
if (array_key_exists('REL_PATH', $ar) && is_array($ar['QUERIES']))
{
foreach ($ar['QUERIES'] as $N => $arQueryInfo)
{
if ($arQueryInfo['TIME'] < $slow_sql_time)
{
unset($arIncludeDebug[$i]['QUERIES'][$N]);
}
}
if (!$preserveComponents)
{
if (empty($arIncludeDebug[$i]['QUERIES']))
{
unset($arIncludeDebug[$i]);
}
}
}
else
{
if (!$preserveComponents)
{
unset($arIncludeDebug[$i]);
}
}
}
}
}
public static function countQueries(&$query_count, &$query_time, $arQueryDebug, $arIncludeDebug)
{
$query_count = 0;
$query_time = 0.0;
if (is_array($arQueryDebug))
{
foreach ($arQueryDebug as $arQueryInfo)
{
$query_count++;
$query_time += $arQueryInfo['TIME'];
}
}
foreach ($arIncludeDebug as $ar)
{
if (array_key_exists('REL_PATH', $ar) && is_array($ar['QUERIES']))
{
foreach ($ar['QUERIES'] as $arQueryInfo)
{
$query_count++;
$query_time += $arQueryInfo['TIME'];
}
}
}
}
public static function countComponents(&$comps_count, &$comps_time, $arIncludeDebug)
{
$comps_count = 0;
$comps_time = 0.0;
foreach ($arIncludeDebug as $ar)
{
if (array_key_exists('REL_PATH', $ar))
{
$comps_count++;
$comps_time += $ar['TIME'];
}
}
}
public static function removeCaches($large_cache_size, &$arCacheDebug, &$arIncludeDebug)
{
if (is_array($arCacheDebug))
{
foreach ($arCacheDebug as $i => $arCacheInfo)
{
if (
(
$arCacheInfo['cache_size'] > 0
&& $arCacheInfo['cache_size'] < $large_cache_size
) || (
$arCacheInfo['operation'] != 'W'
&& $arCacheInfo['operation'] != 'R'
)
)
{
unset($arCacheDebug[$i]);
}
}
}
if (is_array($arIncludeDebug))
{
foreach ($arIncludeDebug as $i => $ar)
{
if (array_key_exists('REL_PATH', $ar) && isset($ar['CACHE']) && is_array($ar['CACHE']))
{
foreach ($ar['CACHE'] as $N => $arCacheInfo)
{
if (
(
$arCacheInfo['cache_size'] > 0
&& $arCacheInfo['cache_size'] < $large_cache_size
) || (
$arCacheInfo['operation'] != 'W'
&& $arCacheInfo['operation'] != 'R'
)
)
{
unset($arIncludeDebug[$i]['CACHE'][$N]);
}
}
}
}
}
}
public static function countCache($arCacheDebug, &$cache_count)
{
if (is_array($arCacheDebug))
{
foreach ($arCacheDebug as $arCacheInfo)
{
if (isset($cache_count[$arCacheInfo['operation']]))
{
$cache_count[$arCacheInfo['operation']]++;
}
else
{
$cache_count[$arCacheInfo['operation']] = 1;
}
}
}
}
public static function findCaller($trace, &$module_id, &$comp_id)
{
$module_id = false;
$comp_id = false;
foreach ($trace as $arCallInfo)
{
if (array_key_exists('file', $arCallInfo))
{
$file = mb_strtolower(str_replace('\\', '/', $arCallInfo['file']));
if (
!$module_id
&& !preg_match('/\\/(database|cache|managedcache)\\.php$/', $file)
)
{
$match = [];
if (preg_match('#.*/bitrix/modules/(.+?)/#', $file, $match))
{
$module_id = $match[1];
}
}
$match = [];
if (
!$comp_id
&& preg_match('#.*/(?:bitrix|install)/components/(.+?)/(.+?)/#', $file, $match)
)
{
$comp_id = $match[1] . ':' . $match[2];
}
if ($module_id && $comp_id)
{
break;
}
}
}
}
public static function saveQueries($HIT_ID, $COMP_ID, $arQueryDebug, &$NN)
{
global $DB;
foreach ($arQueryDebug as $arQueryInfo)
{
self::findCaller($arQueryInfo['TRACE'], $module_id, $comp_id);
$arFields = [
'HIT_ID' => $HIT_ID,
'COMPONENT_ID' => $COMP_ID,
'NN' => ++$NN,
'QUERY_TIME' => $arQueryInfo['TIME'],
'NODE_ID' => intval($arQueryInfo['NODE_ID']),
'MODULE_NAME' => $module_id,
'COMPONENT_NAME' => $comp_id,
'SQL_TEXT' => $arQueryInfo['QUERY'],
];
$SQL_ID = $DB->Add('b_perf_sql', $arFields, ['SQL_TEXT']);
if ($SQL_ID && COption::GetOptionString('perfmon', 'sql_backtrace') === 'Y')
{
$pl = mb_strlen(rtrim($_SERVER['DOCUMENT_ROOT'], '/'));
foreach ($arQueryInfo['TRACE'] as $i => $arCallInfo)
{
$DB->Add('b_perf_sql_backtrace', [
'ID' => 1,
'SQL_ID' => $SQL_ID,
'NN' => $i,
'FILE_NAME' => mb_substr($arCallInfo['file'], $pl),
'LINE_NO' => $arCallInfo['line'],
'CLASS_NAME' => $arCallInfo['class'],
'FUNCTION_NAME' => $arCallInfo['function'],
]);
}
}
}
}
public static function saveCaches($HIT_ID, $COMP_ID, $arCacheDebug, &$NN)
{
global $DB;
foreach ($arCacheDebug as $arCacheInfo)
{
self::findCaller($arCacheInfo['TRACE'], $module_id, $comp_id);
$arFields = [
'HIT_ID' => $HIT_ID,
'COMPONENT_ID' => $COMP_ID,
'NN' => ++$NN,
'CACHE_SIZE' => $arCacheInfo['cache_size'],
'OP_MODE' => $arCacheInfo['operation'],
'MODULE_NAME' => $module_id,
'COMPONENT_NAME' => $comp_id,
'BASE_DIR' => $arCacheInfo['basedir'],
'INIT_DIR' => $arCacheInfo['initdir'],
'FILE_NAME' => $arCacheInfo['filename'],
'FILE_PATH' => $arCacheInfo['path'],
];
$DB->Add('b_perf_cache', $arFields);
}
}
public static function IsActive()
{
$bActive = false;
foreach (GetModuleEvents('main', 'OnPageStart', true) as $arEvent)
{
if (isset($arEvent['TO_MODULE_ID']) && $arEvent['TO_MODULE_ID'] == 'perfmon')
{
$bActive = true;
break;
}
}
return $bActive;
}
public static function SetActive($bActive = false, $end_time = 0)
{
if ($bActive)
{
if (!CPerfomanceKeeper::IsActive())
{
RegisterModuleDependences('main', 'OnPageStart', 'perfmon', 'CPerfomanceKeeper', 'OnPageStart', '1');
RegisterModuleDependences('main', 'OnEpilog', 'perfmon', 'CPerfomanceKeeper', 'OnEpilog', '1000');
RegisterModuleDependences('main', 'OnAfterEpilog', 'perfmon', 'CPerfomanceKeeper', 'OnBeforeAfterEpilog', '1');
RegisterModuleDependences('main', 'OnAfterEpilog', 'perfmon', 'CPerfomanceKeeper', 'OnAfterAfterEpilog', '1000');
RegisterModuleDependences('main', 'OnLocalRedirect', 'perfmon', 'CPerfomanceKeeper', 'OnAfterAfterEpilog', '1000');
}
COption::SetOptionInt('perfmon', 'end_time', $end_time);
}
else
{
if (CPerfomanceKeeper::IsActive())
{
UnRegisterModuleDependences('main', 'OnPageStart', 'perfmon', 'CPerfomanceKeeper', 'OnPageStart');
UnRegisterModuleDependences('main', 'OnEpilog', 'perfmon', 'CPerfomanceKeeper', 'OnEpilog');
UnRegisterModuleDependences('main', 'OnAfterEpilog', 'perfmon', 'CPerfomanceKeeper', 'OnBeforeAfterEpilog');
UnRegisterModuleDependences('main', 'OnAfterEpilog', 'perfmon', 'CPerfomanceKeeper', 'OnAfterAfterEpilog');
UnRegisterModuleDependences('main', 'OnLocalRedirect', 'perfmon', 'CPerfomanceKeeper', 'OnAfterAfterEpilog');
}
}
}
}