Хак: Оптимизация инклудов в InstantCMS 2.0.1 (v.1)

+37
2.6K
Прекрасный по всем параметрам продукт InstantCMS 2 в версиях до 2.0.1 включительно имеет один недостаток, влияющий на производительность – неоптимизированные подключения файлов классов и библиотек. Например, при открытии главной страницы под админским логином выполняется более 800 попыток подключения по сути одних и тех же файлов.

Данный хак добавляет проверку на уже выполненное подключение перед вызовом подключений классов и библиотек. Это позволяет уменьшить время создания страницы более чем в полтора раза с полным сохранением функциональности сайта.

Можем сравнить увеличение скорости на разных компьютерах, если есть желание – пишите в каментах.
Например, время создания главной страницы сайта у меня уменьшилось с 375 до 231 мс для гостя и с 535 до 303 мс для входа под админом. То есть, стало в 1.6-1.7 раза быстрее.
Количество попыток инклудов уменьшилось, соответственно, с 645 до 89 и с 827 до 113.

Параметры тестирования:
версия с расширенной отладкой;
процессор Core i5 3.5 ГГц;
Указаны самые минимальные значения из всех полученных после пары десятков обновлений страницы.

Дальнейшее уменьшение количества подключений файлов возможно лишь за счёт исключения загрузки ненужных компонентов при старте ядра (а лишнее таки загружается, это можно увидеть при включении опции «Показывать инклуды» в расширенной отладке). Также, на мой взгляд, можно уменьшить количество инклудов и время работы PHP, если как-то организовать подключение всех (или большинства) классов через autoload. Но это уже вопросы r2, он знает внутренности системы и возможность такого варианта.
В любом случае, 300 мс на создание главной страницы в такой мощной и гибко настраиваемой CMS – шикарный результат. Спасибо разработчикам за прекрасную систему.

Изменяемые файлы:
\system\core\config.php
\system\core\core.php
\system\core\form.php
\system\core\eventsmanager.php
\system\core\mailer.php
\system\core\model.php
\system\controllers\typograph\hooks\html_filter.php

Изменённые файлы можно скачать одним архивом:

Для чистой версии 2.0.0 или 2.0.1

Для версии 2.0.0 или 2.0.1 с расширенной отладкой

Достаточно распаковать архивы в папку с установленным сайтом с заменой файлов.

В дальнейшем все новые версии Расширенной отладки будут уже со встроенной этой оптимизацией.

Для желающих разобраться в хаке поглубже или для варианта, когда у вас уже есть свои изменения в этих файлах, привожу полный список изменений для чистой версии (без расширенной отладки).


Для начала, если у вас версия без расширенной отладки, нужно вставить пару строк в файл index.php в корне сайта, чтобы увидеть время создания страниц. После проверки оптимизации эти строки можно будет закомментировать или удалить.

index.php
в самом начале файла, перед всеми строками
  1. $debug_start = microtime(TRUE);
в самом конце, после всех строк
  1. echo "Full time: ".round((microtime(TRUE) - $debug_start)*1000, 1)." ms";
После этого можно обновить страницу и внизу под страницей будет написано время её создания.
В версии с расширенной отладкой это и многое другое сразу отображается в таблице отладки. Есть смысл записать значения без оптимизации, чтобы потом посчитать ускорение.

А теперь, собственно, оптимизация.

\system\core\config.php

после строки 5 добавляем
  1. private static $mapping; // Для хранения массива ремапов на время работы скрипта
и меняем функцию getControllersMapping() на
  1. public static function getControllersMapping(){
  2.  
  3. if (!self::$mapping) {
  4.  
  5. self::$mapping = true;
  6.  
  7. $map_file = 'system/config/remap.php';
  8. $map_function = 'remap_controllers';
  9.  
  10. if (!cmsCore::includeFile($map_file)) { return false; }
  11.  
  12. if (!function_exists($map_function)){ return false; }
  13.  
  14. self::$mapping = call_user_func($map_function);
  15.  
  16. }
  17.  
  18. if (!is_array(self::$mapping)){ return false; }
  19.  
  20. return self::$mapping;
  21.  
  22. }

\system\core\core.php

после строки 5 добавляем
  1. private static $loadlanguage_include; // Массив уже подключённых файлов для функции loadLanguage
  2. private static $getfileslist_include; // Массив уже подключённых файлов для функции getFilesList
в функции getFilesList()
  1. if ($is_include) { include_once $file; }
меняем на
  1. if ($is_include) {
  2. if (!isset(self::$getfileslist_include[$file])) {
  3. include_once $file;
  4. self::$getfileslist_include[$file] = true;
  5. }
  6. }
в функции loadLanguage()
  1. return self::includeFile($lang_file);
меняем на
  1. if (!isset(self::$loadlanguage_include[$lang_file])) {
  2. self::$loadlanguage_include[$lang_file] = true;
  3. return self::includeFile($lang_file);
  4. } else {
  5. return true;
  6. }

в функции getController()
  1. include_once($ctrl_file);
меняем на
  1. if (!class_exists($controller_name, false)) include_once($ctrl_file);
и
  1. include_once($custom_file);
  2. $controller_class = $controller_name . '_custom';
меняем на
  1. $controller_class = $controller_name . '_custom';
  2. if (!class_exists($controller_class, false)) include_once($custom_file);
в функции runWidget()
  1. cmsCore::includeFile($file);
  2. cmsCore::loadWidgetLanguage($widget['name'], $widget['controller']);
  3.  
  4. $class = 'widget' .
  5. ($widget['controller'] ? string_to_camel('_', $widget['controller']) : '') .
  6. string_to_camel('_', $widget['name']);
меняем на
  1. $class = 'widget' .
  2. ($widget['controller'] ? string_to_camel('_', $widget['controller']) : '') .
  3. string_to_camel('_', $widget['name']);
  4.  
  5. if (!class_exists($class, false)) cmsCore::includeFile($file);
  6. cmsCore::loadWidgetLanguage($widget['name'], $widget['controller']);

\system\core\form.php

после строки 5 добавляем
  1. private static $fields_load; // Признак того, что классы полей уже загружены
и в функции getForm() меняем
  1. cmsForm::loadFormFields();
  2.  
  3. include_once $form_file;
  4.  
  5. $form_class = 'form' . string_to_camel('_', $form_name);
на
  1. if (!self::$fields_load) {
  2. cmsForm::loadFormFields();
  3. self::$fields_load = true;
  4. }
  5.  
  6. $form_class = 'form' . string_to_camel('_', $form_name);
  7.  
  8. if (!class_exists($form_class, false)) include_once $form_file;

\system\core\eventsmanager.php

после строки 2
  1. class cmsEventsManager {
добавляем
  1. private static $structure; // Для хранения структуры списка хуков
и меняем функцию
  1. public static function getEventListeners($event_name){
  2.  
  3. $listeners = array();
  4.  
  5. if (!self::$structure) self::$structure = self::getAllListeners();
  6.  
  7. if (isset(self::$structure[ $event_name ])){ $listeners = self::$structure[ $event_name ]; }
  8.  
  9. return $listeners;
  10.  
  11. }


\system\core\mailer.php

в строке 11
  1. cmsCore::loadLib('phpmailer/class.phpmailer');
меняем на
  1. if (!class_exists('PHPMailer', false)) cmsCore::loadLib('phpmailer/class.phpmailer');

\system\core\model.php

в строках 1376 и 1391
  1. cmsCore::loadLib('spyc.class');
меняем на
  1. if (!class_exists('Spyc', false)) cmsCore::loadLib('spyc.class');

\system\controllers\typograph\hooks\html_filter.php

в строке 27
  1. cmsCore::loadLib('jevix.class');
меняем на
  1. if (!class_exists('Jevix', false)) cmsCore::loadLib('jevix.class');
0
NeBox NeBox 9 лет назад #
Вот спасибо.

Инклуды с 842 уменьшились до 118 для админа(под юзером не смотрел)

Вообще у меня тормозят все локальные сайты на php >= 5.3
full time: с 1385.1 ms до 1310.1 ms - не особо поправило. На сервере лучше конечно будет.
+2
WebMan WebMan 9 лет назад #
А в итоговой таблице отладки что больше всего времени съедает? Возможно тормозит MySQL, тогда этот хак своё дело сделает, но принципиально не поможет.
0
Aryuts Aryuts 9 лет назад #
Не оптимальность некоторых моментов тоже смущает, но это только первые релизы, поэтому будем помогать автору довести систему до ума. WebMan спасибо за хак, буду тестировать. Если, что отпишусь.
+3
picaboo picaboo 9 лет назад #
Комментариев от администрации имеет смысл подождать?
-2
Dublic Dublic 9 лет назад #
На мой взгляд очень умный подход проверки, по принципу "если не нужно, не используем"
+4
WebMan WebMan 9 лет назад #
Согласен, это самый разумный подход. У классного движка InstantCMS 2 ещё есть запасы оптимизации по этому принципу.

Например, при открытии любой страницы с контентом (даже просто "О сайте" без каментов и виджетов под гостем) загружаются, компилируются и выполняются все 20 файлов с полями форм, независимо от их использования или не использования. Эта логика "зашита" в контроллер контента (\system\controllers\content\model.php). Я ещё не разбирался в ядре настолько глубоко, чтобы понять, как это обойти. Но думаю, что возможности есть. Даже только загрузка классов полей формы по требованию вместо полной загрузки при старте позволила бы уменьшить время создания страницы ещё на 15-20 мс. При открытии простой страницы типа "О сайте" на моём компе за 160 мс увеличение скорости было бы примерно на 10%. Тоже хороший плюс.

Или, например, загрузка классов кэширования происходит независимо от включения/выключения этого кэширования в настройках и реального использования кэша. Логика кода, в принципе, понятна: делать проверку включения кэширования только в самом классе кэширования для структурирования кода и более точного соответствия парадигме ООП. Но я бы от этого отказался ради производительности. Поскольку название параметра конфига 'cache_enabled' вряд ли будет меняться в будущем, то выгоднее в паре мест кода вне класса кэширования сделать проверку этого параметра и просто не загружать ничего, связанного с кэшированием, если оно выключено. Это даст выигрыш в 2-4 мс и дополнительную экономию памяти.

Где-то выиграть пару-тройку мс, где-то больше - можно ускорить движок ещё раза в полтора. joke

Предложеный мной вариант оптимизации из этого топика - делать проверку на уже выполненное подключение файлов - может быть тоже не самый лучший. Это просто оперативный хак. Возможно, если понять логику ядра, то можно вообще сделать так, чтобы не было этих сотен попыток и проверок, что ещё больше ускорит двиг и сократит потребление памяти. Но тут нужно потратить много времени на понимание всех связей. Да и не факт, что разработчиков это заинтересует.

И, кстати, о кэшировании. Оно сейчас сделано достаточно мягким и динамичным: кэшируются виджеты, небольшие блоки информации (списки событий) и т.д., а потом из этих кусочков кэша собирается страничка. Это увеличивает скорость сборки страницы всего процентов на 30 при использовании memcache, зато делает кэширование более динамичным. При этом всё равно загружается, компилируется и частично выполняется достаточно много лишнего кода - это следствие хорошей структурированности кода и следования ООП. Если добавить ещё один режим кэширования, более полный, когда, например, гостям будут отдаваться готовые страницы целиком из кэша, то можно генерить страницы раза в два и более быстрее даже без использования прокси. Можно будет разделять гостей и зарегистрированных пользователей, отдавая им сайт, соответственно, из кэша и без него. И это вообще будет полезно как в случае неожиданного пикового наплыва посетителей, так и для "обычных" сайтостроителей, не разбирающихся в особенностях вебсерверов, позволяя некоторое время прожить на старых серверах и тарифах.

В-общем, возможностей для оптимизации ещё много. Согласен с Aryuts, что движок молодой, его ещё можно и нужно совершенствовать во многих направлениях. Хотя по-честному, уже сейчас даже с минимальной оптимизацией InstantCMS 2 легко делает по удобству и функционалу другие популярные движки при не меньшей, а часто заметно лучшей производительности и меньшем потреблении памяти. Так что разработчики действительно постарались на славу. За что им большая благодарность!
0
Александр Александр 9 лет назад #
Спасибо! Все отлично работает. Скорость возросла в 2 раза!
0
leo748 leo748 9 лет назад #
Слайдер исчез только))
0
WebMan WebMan 9 лет назад #
У меня на нескольких тестовых локальных сайтах слайдер на месте и работает. И до Вас пока ни у кого такой ошибки не было. Давайте выясним.

Оптимизацию Вы делали накатом файлов из архива или ручками по списку изменений? У Вас до оптимизации уже были изменены какие-то из перечисленных в топике файлов? Или другие файлы были изменены - какие?
0
leo748 leo748 9 лет назад #
накатом файлов из первого архива. вроде не менял ничего-я чайник,в ядро не лезу. потом перезаписал папку system из инсталлятора инстанта -слайдер на месте.
0
WebMan WebMan 9 лет назад #
Трудно что-то сказать вслепую.
Попробуйте Класс расширенной отладки из этой ссылки. Во-первых, там уже есть все мои оптимизации на данный момент. Во-вторых, там есть отладка, которая может быть Вам полезна как для оценки скорости сайта, так и для других целей.
0
GoodNet GoodNet 9 лет назад #
Может кто то помочь с подобным хаком для 1.10.3
Просто куда не нужного кода показывается гостям. Готов заплатить.
0
zotak zotak 9 лет назад #
Для InstantCMS 2.1.1 актуально ?
0
oll oll 9 лет назад #
+ WEBMAN!
0
wcw2007 wcw2007 3 года назад #
А как обстоят дела с 2.13.1 ?
0
WebMan WebMan 3 года назад #
Замечательно обстоят. smile Вся эта оптимизация уже давно присутствует в дефолтном движке. И даже намного больше.

Еще от автора

Хуки-хухуки: Исключаем неактивных пользователей из списков
Как иногда начинают свой монолог неопытные стендаперы: «У всех в жизни было такое …
«Расширенная отладка» для InstantCMS 2.14.1 (v.14.1.2) – большое обновление для разработчиков
Новые возможности и удобства, облегчающие разработчикам отладку компонентов и шаблонов.
Использование расширенной отладки. Часть 11. Анализ ошибок 403/404 и редиректов
Одной из неудобных задач при отладке для меня является поиск причины ошибки 403/404.
Используя этот сайт, вы соглашаетесь с тем, что мы используем файлы cookie.