/** * Основной метод получения экземпляра. * * @param type $silentOnDoubleTry - признак, стоит ли нам ругаться, если мы * обнаруживаем зацикливание при попытке получения экземпляра класса. * * Это нужно для классов, которые выполняют сложную логику в конструкторе, которая * может привести к повторному вызову ::inst() внутри этого конструктора. * * Классы, которые используют эту возможность: * @link DbChangeListener - менеджер прослушивания изменений в БД */ protected static function inst($silentOnDoubleTry = false) { $class = get_called_class(); if (array_key_exists($class, self::$_insts_)) { return self::$_insts_[$class]; } if (array_key_exists($class, self::$_instsrq_)) { if ($silentOnDoubleTry) { return null; } raise_error("Double try to get singleton of [{$class}]"); } self::$_instsrq_[$class] = true; //Создаём экземпляр $sec = Secundomer::startedInst("Creating singleton of {$class}"); self::$_insts_[$class] = new $class(); $sec->stop(); //Экземпляр успешно создан unset(self::$_instsrq_[$class]); //Теперь добавим в профайлер. Всё это нужно для защиты от зацикливания. PsProfiler::inst(__CLASS__)->add($class, $sec); //Добавим к глобальному секундомеру - текущий $SECUNDOMER = self::$_secundomer_ ? self::$_secundomer_ : (self::$_secundomer_ = Secundomer::inst()); $SECUNDOMER->addSecundomer($sec); //Отлогируем PsLogger::inst(__CLASS__)->info("+ {$class} ({$sec->getAverage()} / {$SECUNDOMER->getTotalTimeRounded()})"); return self::$_insts_[$class]; }
/** * Метод регистрирует новый секундомер для идентификатора * * @return Secundomer зарегистрированный идентификатор */ private final function registerSecundomer($ident) { if (!array_key_exists($ident, $this->secundomers)) { $this->secundomers[$ident] = Secundomer::inst($this->profilerId . '::' . $ident); } return $this->secundomers[$ident]; }
public static final function finalize(PsLoggerInterface $LOGGER, $CONTENT) { //Проверим на пустоту if (isEmpty($CONTENT)) { return $CONTENT; } $call = ++self::$call; //Создадим экземпляр финализатора и вызовем его $class = get_called_class(); $PROFILER = PsProfiler::inst($class); $inst = new $class($LOGGER, $PROFILER); $PROFILER->start(__FUNCTION__); $SECUNDOMER = Secundomer::startedInst(); $LOGGER->infoBox(">>> CALLED {$call}. {$class}"); try { $CONTENT = $inst->doFinalize($CONTENT); $PROFILER->stop(); $SECUNDOMER->stop(); } catch (Exception $ex) { $PROFILER->stop(false); $LOGGER->infoBox("Exception occured while calling {$class}::finalize. Message: " . $ex->getMessage()); throw $ex; } $LOGGER->infoBox("<<< CALL {$call}. {$class} FINISHED IN " . $SECUNDOMER->getAverage() . ' seconds'); return $CONTENT; }
function doTest() { global $HOST; global $TOTAL; global $HREFS; global $REQUESTS_CNT; $RESULTS = array(); $j = 0; foreach ($HREFS as $href => $name) { ++$j; $href = ensure_starts_with($href, '/'); $path = "http://{$HOST}{$href}"; $sec = Secundomer::inst(); for ($index = 0; $index <= $REQUESTS_CNT; $index++) { if ($index == 0) { //Пропустим первый вызов, на случай кеширования file_get_contents($path); continue; } $sec->start(); file_get_contents($path); $sec->stop(); ++$TOTAL; } dolog(pad_zero_left($j, 2) . '/' . count($HREFS) . " [{$path}] - " . $sec->getAverage() . ' (' . $sec->getTotalTime() . '/' . $sec->getCount() . ')'); $RESULTS[$path] = str_replace('.', ',', round($sec->getAverage(), 2)); } asort($RESULTS, SORT_DESC); $RESULTS = array_reverse($RESULTS, true); return $RESULTS; }
/** * Процесс строит скрипты для вставки ячеек в БД * * @param array $argv */ function executeProcess(array $argv) { $DM = DirManager::inst(array(__DIR__, 'output')); $customNum = $argv[1]; dolog('Processing mosaic demo, custom num={}', $customNum); /* @var $dir DirItem */ foreach ($DM->getDirContent(null, DirItemFilter::DIRS) as $dir) { if (is_inumeric($customNum) && $customNum != $dir->getName()) { continue; //---- } $imgDM = DirManager::inst($dir->getAbsPath()); $imgDI = end($imgDM->getDirContent(null, DirItemFilter::IMAGES)); $map = $imgDM->getDirItem(null, 'map', 'txt')->getFileAsProps(); $demoDM = DirManager::inst($imgDM->absDirPath(), 'demo'); $demoDM->clearDir(); dolog("Building map for: [{}].", $imgDI->getRelPath()); //CELLS BINDING $dim = $imgDM->getDirItem(null, 'settings', 'txt')->getFileAsProps(); $dim = $dim['dim']; $dim = explode('x', $dim); $cw = 1 * $dim[0]; $ch = 1 * $dim[1]; $sourceImg = SimpleImage::inst()->load($imgDI); $w = $sourceImg->getWidth(); $h = $sourceImg->getHeight(); $destImg = SimpleImage::inst()->create($w, $h, MosaicImage::BG_COLOR); dolog("Img size: [{$w} x {$h}]."); check_condition($w > 0 && !($w % $cw), 'Bad width'); check_condition($h > 0 && !($h % $ch), 'Bad height'); $totalCells = count($map); $lengtn = strlen("{$totalCells}"); //dolog("Cells cnt: [$xcells x $ycells], total: $totalCells."); //СТРОИМ КАРТИНКИ $secundomer = Secundomer::startedInst(); //$encoder = new PsGifEncoder(); for ($cellCnt = 0; $cellCnt <= $totalCells; $cellCnt++) { $name = pad_zero_left($cellCnt, $lengtn); $copyTo = $demoDM->absFilePath(null, $name, 'jpg'); if ($cellCnt > 0) { $cellParams = $map[$cellCnt]; $cellParams = explode('x', $cellParams); $xCell = $cellParams[0]; $yCell = $cellParams[1]; $x = ($xCell - 1) * $cw; $y = ($yCell - 1) * $ch; $destImg->copyFromAnother($sourceImg, $x, $y, $x, $y, $cw, $ch); } $destImg->save($copyTo); dolog("[{$totalCells}] {$copyTo}"); } //$encoder->saveToFile($demoDM->absFilePath(null, 'animation')); $secundomer->stop(); dolog('Execution time: ' . $secundomer->getTotalTime()); } }
/** * Вызов выполнения метода. Используется из ajax. */ public static function execute($method, array $params) { check_condition(array_key_exists($method, self::getMethodsList()), "Method TestManager::{$method} cannot be called"); PsUtil::startUnlimitedMode(); PsLogger::inst('TestManager')->info("Method TestManager::{$method} called with params: " . array_to_string($params)); $s = Secundomer::startedInst(); call_user_func_array(array(TestManager::inst(), $method), $params); $s->stop(); PsLogger::inst('TestManager')->info("Call done in {$s->getTotalTime()} seconds"); }
public static function testProductivity($callback, $count = 1000) { PsDefines::assertProductionOff(__CLASS__); check_condition(is_callable($callback), 'Передан некорректный callback для тестирования'); $s = Secundomer::inst(); for ($index = 0; $index < $count; $index++) { $s->start(); call_user_func($callback); $s->stop(); } return $s; }
/** * Перестраиваем и сохраняем classpath в файл. * Вынесли это действие в отдельный метод, чтобы можно было вывести classpath в файл (для дебага). * * @return AutoloadDir */ public function rebuild() { if (!$this->rebuilded) { $this->rebuilded = true; $s = Secundomer::startedInst(); $this->pathes = array(); PsCoreIncluder::loadClassPath($this->classesDir->getAbsPath(), $this->pathes, false); $this->classPathFile->saveArrayToFile($this->pathes); $this->classPathFile->getSibling($this->classPathFile->getName() . '_arr')->putToFile(print_r($this->pathes, true)); $this->LOGGER->info("{$this} rebuilded in {$s->stopAndGetAverage()} seconds."); } return $this; }
public function buildContent() { PsUtil::startUnlimitedMode(); $s = Secundomer::inst(); $data = array(); for ($num = 0; $num <= self::REQUESTS_COUNT; $num++) { $s->start(); file_get_contents($this->url); $s->stop(); $data[$num]['time'] = $s->getTime(); $data[$num]['total'] = $s->getTotalTime(); if ($num == 0) { //Запросим один раз, чтобы сработало кеширование, если оно включено $s->clear(); } } $params = array('url' => $this->url, 'data' => $data, 'average' => $s->getAverage()); echo $this->getFoldedEntity()->fetchTpl($params); }
public function closeAndWriteFinalLog() { $this->secundomer->stop(); $this->doWrite("Shell command execution finished in {$this->secundomer->getAverage()} seconds."); }
/** * Парсит файл профайлинга и возвращает массив вида: * ident=>Secundomer * Идентификатор здесь, это идентификатор профилируемой сущности, например - текст запроса. */ private function parseProfiler(DirItem $file) { $result = array(); $lines = $file->getFileLines(false); if (empty($lines)) { return $result; //--- } foreach ($lines as $line) { $tokens = explode('|', $line); if (count($tokens) != 3) { continue; } $ident = trim($tokens[0]); $count = trim($tokens[1]); $time = trim($tokens[2]); if (!$ident || !is_numeric($count) || !is_numeric($time)) { continue; } if (!array_key_exists($ident, $result)) { $result[$ident] = Secundomer::inst(); } $result[$ident]->add($count, $time); } return $result; }
/** * Метод выполняет дамп таблицы */ public static function dumpTable($idColumn, $table, array $where = array(), $order = null) { //Стартуем секундомер $secundomer = Secundomer::startedInst("Снятие дампа {$table}"); //Отключим ограничение по времени PsUtil::startUnlimitedMode(); //Получим экземпляр логгера $LOGGER = PsLogger::inst(__CLASS__); //Текущий пользователь $userId = AuthManager::getUserIdOrNull(); //Для логов, запросов и все остального $table = strtoupper(PsCheck::tableName($table)); //Макс кол-во записей $limit = PsDefines::getTableDumpPortion(); //Проверим наличие id $idColumn = PsCheck::tableColName($idColumn); $LOGGER->info('Dumping table {}. Id column: {}, limit: {}. User id: {}.', $table, $idColumn, $limit, $userId); //Получаем лок (без ожидания) $lockName = "DUMP table {$table}"; $locked = PsLock::lock($lockName, false); $LOGGER->info('Lock name: {}, locked ? {}.', $lockName, var_export($locked, true)); if (!$locked) { return false; //Не удалось получить лок } $zipDi = false; try { //ЗПРОСЫ: //1. Запрос на извлечение колва записей, подлежащих дампированию $queryCnt = Query::select("count({$idColumn}) as cnt", $table, $where); //2. Запрос на извлечение данных, подлежащих дампированию $queryDump = Query::select('*', $table, $where, null, $order, $limit); //3. Запрос на извлечение кодов дампируемых записей $selectIds = Query::select($idColumn, $table, $where, null, $order, $limit); //4. Запрос на удаление дампированных данных $queryDel = Query::delete($table, Query::plainParam("{$idColumn} in (select {$idColumn} from (" . $selectIds->build($delParams) . ') t )', $delParams)); //Выполним запрос для получения кол-ва записей, подлежащих дампу $cnt = PsCheck::int(array_get_value('cnt', PSDB::getRec($queryCnt, null, true))); $LOGGER->info('Dump recs count allowed: {}.', $cnt); if ($cnt < $limit) { $LOGGER->info('SKIP dumping table, count allowed ({}) < limit ({})...', $cnt, $limit); $LOGGER->info("Query for extract dump records count: {$queryCnt}"); PsLock::unlock($lockName); return false; } //Время дампа $date = PsUtil::fileUniqueTime(false); $time = time(); //Название файлов $zipName = $date . ' ' . $table; //Элемент, указывающий на zip архив $zipDi = DirManager::stuff(null, array(self::DUMPS_TABLE, $table))->getDirItem(null, $zipName, PsConst::EXT_ZIP); $LOGGER->info('Dump to: [{}].', $zipDi->getAbsPath()); if ($zipDi->isFile()) { $LOGGER->info('Dump file exists, skip dumping table...'); PsLock::unlock($lockName); return false; } //Комментарий к таблице $commentToken[] = "Date: {$date}"; $commentToken[] = "Time: {$time}"; $commentToken[] = "Table: {$table}"; $commentToken[] = "Manager: {$userId}"; $commentToken[] = "Recs dumped: {$limit}"; $commentToken[] = "Total allowed: {$cnt}"; $commentToken[] = "Query dump cnt: {$queryCnt}"; $commentToken[] = "Query dump data: {$queryDump}"; $commentToken[] = "Query dump ids: {$selectIds}"; $commentToken[] = "Query del dumped: {$queryDel}"; $comment = implode("\n", $commentToken); //Начинаем zip и сохраняем в него данные $zip = $zipDi->startZip(); $zip->addFromString($zipName, serialize(PSDB::getArray($queryDump))); $zip->setArchiveComment($comment); $zip->close(); $LOGGER->info('Data successfully dumped, zip comment:'); $LOGGER->info("[\n{$comment}\n]"); //Удалим те записи, дамп которых был снят $LOGGER->info('Clearing dumped table records...'); $affected = PSDB::update($queryDel); $LOGGER->info('Rows deleted: {}.', $affected); $LOGGER->info('Dumping is SUCCESSFULLY finished. Total time: {} sec.', $secundomer->stop()->getAverage()); } catch (Exception $ex) { PsLock::unlock($lockName); ExceptionHandler::dumpError($ex); $LOGGER->info('Error occured: {}', $ex->getMessage()); throw $ex; } return $zipDi; }
PsSecurity::set(new PsSecurityProviderCmd()); } else { /* * Автоматически подключаемся к БД */ PsConnectionPool::configure(PsConnectionParams::production()); } /* * Инициализируем окружение, если мы работаем под ним. * Подключаемое окружение может установить свой провайдер безопасности. * Важно! Вызов не перемещать в if, так как метод init должен быть вызван обязательно. */ PsEnvironment::init(); /* * Инициализируем подсистему безопасности */ PsSecurity::init(); //Зарегистрируем функцию, подключающую админские ресурсы function ps_admin_on($force = false) { if ($force || AuthManager::isAuthorizedAsAdmin()) { Autoload::inst()->registerAdminBaseDir(); } } //Ну и сразу попытаемся подключить админские ресурсы ps_admin_on(); //Подключаем файл глобальных настроек, если он существует и мы работаем в рамках проекта PsGlobals::init(); //Получим экземпляр профайлера, чтобы подписаться на PsShotdown, если профилирование включено PsProfiler::inst()->add('ScriptInit', Secundomer::inst()->add(1, microtime(true) - SCRIPT_EXECUTION_START));
$ch = 1 * $dim[1]; } //Скопируем свойства, с которыми она создавалась $outDm->getDirItem(null, 'settings', 'txt')->writeToFile('dim=' . $cw . 'x' . $ch); dolog("Cell dimensions: [{$cw} x {$ch}]."); $w = $img->getImageAdapter()->getWidth(); $h = $img->getImageAdapter()->getHeight(); dolog("Img size: [{$w} x {$h}]."); check_condition($w > 0 && !($w % $cw), 'Bad width'); check_condition($h > 0 && !($h % $ch), 'Bad height'); $xcells = $w / $cw; $ycells = $h / $ch; $totalCells = $xcells * $ycells; dolog("Cells cnt: [{$xcells} x {$ycells}], total: {$totalCells}."); $generator = new MosaicCellsGenerator($totalCells); $secundomer = Secundomer::startedInst(); $sqlDI = $outDm->getDirItem(null, 'fill', 'sql'); $mapDI = $outDm->getDirItem(null, 'map', 'txt'); $sqlImg = "delete from ps_img_mosaic_parts where id_img={$id};"; $sqlDI->writeLineToFile($sqlImg); $sqlImg = "delete from ps_img_mosaic_answers where id_img={$id};"; $sqlDI->writeLineToFile($sqlImg); $sqlImg = "delete from ps_img_mosaic where id_img={$id};"; $sqlDI->writeLineToFile($sqlImg); $sqlImg = "insert into ps_img_mosaic (id_img, w, h, cx, cy, cw, ch) values ({$id}, {$w}, {$h}, {$xcells}, {$ycells}, {$cw}, {$ch});"; $sqlDI->writeLineToFile($sqlImg); for ($cellCnt = 1; $cellCnt <= $totalCells; $cellCnt++) { $cellNum = $generator->getCellNum(); $xCell = $cellNum % $xcells; $xCell = $xCell == 0 ? $xcells : $xCell; $yCell = ($cellNum - $xCell) / $xcells + 1;
/** * Процесс строит скрипты для вставки ячеек в БД * * @param array $argv */ function executeProcess(array $argv) { $DM = DirManager::inst(__DIR__); //Перенесём картинки в директорию со всеми картинками /* @var $img DirItem */ foreach ($DM->getDirContent(null, DirItemFilter::IMAGES) as $img) { $img->copyTo($DM->absFilePath('source', $img->getName())); $img->remove(); } //Очистим директорию с выходными файлами $DM->clearDir('output'); $DM->makePath('output'); //Пробегаемся по картинкам, разбиваем их на ячейки и строим sql для вставки /* @var $img DirItem */ foreach ($DM->getDirContent('source', DirItemFilter::IMAGES) as $img) { $id = $img->getNameNoExt(); //Обрабатываем только картинки с целыми кодами if (is_inumeric($id)) { dolog("Processing img [{$img->getRelPath()}]."); $id = 1 * $id; } else { dolog("Skip img [{$img->getRelPath()}], name is not numeric."); continue; //--- } //Начало обработки $outDm = DirManager::inst(array(__DIR__, 'output'), $id); //Скопируем картинку $img->copyTo($outDm->absFilePath(null, $img->getName())); //Вычислим размеры ячейки $cw = 10; $ch = 10; $dim = $DM->getDirItem('source', $id, 'txt')->getFileAsProps(false); $dim = $dim['dim']; if ($dim) { $dim = explode('x', $dim); $cw = 1 * $dim[0]; $ch = 1 * $dim[1]; } //Скопируем свойства, с которыми она создавалась $outDm->getDirItem(null, 'settings', 'txt')->putToFile('dim=' . $cw . 'x' . $ch); dolog("Cell dimensions: [{$cw} x {$ch}]."); //Размеры картинки получим у самой картинки $w = $img->getImageAdapter()->getWidth(); $h = $img->getImageAdapter()->getHeight(); dolog("Img size: [{$w} x {$h}]."); check_condition($w > 0 && !($w % $cw), 'Bad width'); check_condition($h > 0 && !($h % $ch), 'Bad height'); $xcells = $w / $cw; $ycells = $h / $ch; $totalCells = $xcells * $ycells; dolog("Cells cnt: [{$xcells} x {$ycells}], total: {$totalCells}."); $generator = new MosaicCellsGenerator($totalCells); $secundomer = Secundomer::startedInst(); $sqlDI = $outDm->getDirItem(null, 'fill', 'sql'); $mapDI = $outDm->getDirItem(null, 'map', 'txt'); $sqlImg = "delete from ps_img_mosaic_parts where id_img={$id};"; $sqlDI->writeLineToFile($sqlImg); $sqlImg = "delete from ps_img_mosaic_answers where id_img={$id};"; $sqlDI->writeLineToFile($sqlImg); $sqlImg = "delete from ps_img_mosaic where id_img={$id};"; $sqlDI->writeLineToFile($sqlImg); $sqlImg = "insert into ps_img_mosaic (id_img, w, h, cx, cy, cw, ch) values ({$id}, {$w}, {$h}, {$xcells}, {$ycells}, {$cw}, {$ch});"; $sqlDI->writeLineToFile($sqlImg); for ($cellCnt = 1; $cellCnt <= $totalCells; $cellCnt++) { $cellNum = $generator->getCellNum(); $xCell = $cellNum % $xcells; $xCell = $xCell == 0 ? $xcells : $xCell; $yCell = ($cellNum - $xCell) / $xcells + 1; $sqlCell = "insert into ps_img_mosaic_parts (id_img, n_part, x_cell, y_cell) values ({$id}, {$cellCnt}, {$xCell}, {$yCell});"; $sqlDI->writeLineToFile($sqlCell); $mapDI->writeLineToFile($cellCnt . '=' . $xCell . 'x' . $yCell); } $secundomer->stop(); dolog('Execution time: ' . $secundomer->getTotalTime()); } }
private function doSolve($rebus) { $this->LOGGER->info("Обрабатываем ребус: [{$rebus}], пропускать первые символы={$this->SCIP_FIRST_CHARS}"); $this->COMBINATIONS = array(); check_condition($rebus, "Пустой ребус"); $eqCnt = substr_count($rebus, '='); check_condition($eqCnt == 1, "Знак равенства '=' встретился {$eqCnt} раз"); $this->LOGGER->info("Приведённый вид: [{$rebus}]"); $enCh = array(); $ruCh = array(); for ($i = 0; $i < ps_strlen($rebus); $i++) { //русский символ $letter = ps_charat($rebus, $i); if ($this->isRuChar($letter)) { if (!array_key_exists($letter, $ruCh)) { $ruCh[$letter] = null; } continue; } if ($this->isEnChar($letter)) { //английский символ if (!in_array($letter, $enCh)) { $enCh[] = $letter; } continue; } } $this->LOGGER->info('Русские символы: ' . print_r($ruCh, true)); $this->LOGGER->info('Английские символы: ' . print_r($enCh, true)); foreach ($ruCh as $ch => $value) { for ($i = 0; $i < strlen($this->EN); $i++) { $letter = substr($this->EN, $i, 1); if (!in_array($letter, $enCh)) { $enCh[] = $letter; $ruCh[$ch] = $letter; break; } } } $this->LOGGER->info('После привязки: '); $this->LOGGER->info('Русские символы: ' . print_r($ruCh, true)); $this->LOGGER->info('Английские символы: ' . print_r($enCh, true)); $enCharsCnt = count($enCh); check_condition($enCharsCnt > 0, 'Нет символов для перебора'); check_condition($enCharsCnt <= 10, "Слишком много переменных: {$enCharsCnt}"); $rebus = PsStrings::replaceMap($rebus, $ruCh); $this->LOGGER->info("Подготовленный ребус: [{$rebus}]"); $this->LOGGER->info("Всего символов для перебора: {$enCharsCnt}"); $this->LOGGER->info('Возможных комбинаций: ' . $this->variantsCnt($enCharsCnt)); $this->REBUS = $rebus; $this->EXPR = str_replace('=', '-', $rebus); $hasBefore = false; for ($i = 0; $i < strlen($rebus); $i++) { $char = substr($rebus, $i, 1); if ($this->isEnChar($char)) { //Символ перебора if (!$hasBefore) { $this->FIRST_CHARS[] = $char; $hasBefore = true; } } else { $hasBefore = false; } } $this->LOGGER->info('Начинаем перебор...'); $numbers = array(0 => false, 1 => false, 2 => false, 3 => false, 4 => false, 5 => false, 6 => false, 7 => false, 8 => false, 9 => false); $secundomer = Secundomer::startedInst(); for ($i = 0; $i <= 9; $i++) { $letter = reset($enCh); if ($this->isScip($i, $letter)) { continue; } $next = next($enCh); $numbers[$i] = $letter; $this->doCheckIteration($enCh, $next, $numbers); $numbers[$i] = false; } $secundomer->stop(); $parsed = DatesTools::inst()->parseSeconds(round($secundomer->getTotalTime())); $min = $parsed['mf']; $sec = pad_zero_left($parsed['s'], 2); $parsed = "{$min}:{$sec}"; $combCnt = count($this->COMBINATIONS); $this->LOGGER->info("Перебор закончен. Обработано операций: {$this->cnt}, найдено решений: {$combCnt}."); $this->LOGGER->info("Общее время обработки: {$parsed}."); return $this->COMBINATIONS; }