Блог о программировании

Профилирование PHP7 кода с использованием xhprof

 2 июля 2017 г. 20:05

Со временем любой PHP-программист сталкивается с проблемой низкой производительности своего приложения. Это может быть медленная загрузка конкретной страницы или слишком долгий ответ от API. И порой достаточно сложно понять, в чем причина тормозов? Порой случаются более сложные ситуации: на боевом сервере api сильно тормозит, но на стенде, где происходит разработка, - все хорошо. И пойди разберись, что идет не так. Производить отладку на рабочем сервере - это крайняя степень безысходности, до которой, конечно, лучше не доводить.

Именно для таких ситуаций и были придуманы специальные инструменты, называемые профилировщиками приложений. В мире PHP эту роль выполняют xDebug, а также xhprof. xhprof является более легковесным, простым и гибким инструментом, поэтому его использование более предпочтительно. Что интересно, xhprof был разработан в facebook еще в 2009 году, однако до сих пор от них нет официальной поддержки php7 и больше не будет, поскольку facebook перешел на HHVM. Однако, благодаря обширному сообществу php-разработчиков, появился форк, поддерживающий php7, установка которого не вызывает каких-либо сложностей.

Установка

Для начала нужно, собственно, установить xhprof:

git clone https://github.com/longxinH/xhprof xhprof
cd xhprof/extension
phpize
./configure --with-php-config=/usr/bin/php-config
sudo make && sudo make install
mkdir /var/tmp/xhprof

Далее прописать настройки в php.ini:

[xhprof]
extension=xhprof.so
xhprof.output_dir="/var/tmp/xhprof"

Для папки /var/tmp/xhprof должен быть доступ на запись, т.к. туда будут сохраняться результаты профайлинга.

Можно перезагрузить PHP-FPM и проверить, установилось ли расширение. Банально, это можно сделать с помощью вывода функции phpinfo();

xhprof installed

xhprof установлен, можно им пользоваться. В пакет xhprof входит очень удобный интерфейс для анализа отчетов профилирования. xhprof позволяет строить отчеты, как в текстовом так и графическом виде. В установочной папке xhprof находятся xhprof_html и xhprof_lib, которые нам понадобятся. Папка xhprof_html — предоставляет доступ к GUI. xhprof_lib — библиотека для отображения и анализа кода. Всю папку xhprof целесообразно перенести в /var/www/xhprof и настроить для нее виртуальный хост, например xhprof.loc. Пример для nginx:

server {
  listen 80;

  server_name xhprof.loc;
  charset utf-8;

  root /var/www/xhprof/xhprof_html;
  index index.php;

  location / {
    try_files $uri $uri/ /index.php?q=$uri&$args;
  }

  location ~ \.php {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
  }
}

Также необходимо не забыть обновить файл hosts. Теперь при введении в браузерe URL xhprof.loc мы будем попадать на веб-интерфейс профилировщика, где будут доступы сгенерированные им файлы.

Теперь можно приступить непосредственно к профилированию кода.

Для включения профилировщика используется функция xhprof_enable(), которая на вход принимает следующие флаги:

  • XHPROF_FLAGS_CPU - для фиксирования статистики процессора;
  • XHPROF_FLAGS_MEMORY — для памяти;
  • XHPROF_FLAGS_NO_BUILTINS — для игнорирования встроенных функций.

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

header.php:
if (extension_loaded('xhprof')) {
    include_once '/var/www/xhprof/xhprof_lib/utils/xhprof_lib.php';
    include_once '/var/www/xhprof/xhprof_lib/utils/xhprof_runs.php';
     
    xhprof_enable(XHPROF_FLAGS_CPU);
}
footer.php:
if (extension_loaded('xhprof')) {
     $profilerNamespace = 'ЗДЕСЬ_ИМЯ_ПРОФИЛИРУЕМОГО_СКРИПТА';
     $xhprofData = xhprof_disable();
     $xhprofRuns = new XHProfRuns_Default();
     $runId = $xhprofRuns->save_run($xhprofData, $profilerNamespace);
 }

Использование

Подключив header.php и footer.php к профилируемому скриту, можно начинать: при выполнении профилируемого скрипта сгенерируется файл, который сохранится в директории /var/tmp/xhprof, содержащий информацию о работе скрипта. При открытии веб-интерфейса xhprof.loc, будет доступен этот сгенерированный файл:

xhprof profiler

При открытии файла профилирования появляется детальная информация о работе приложения, весь стек вызовов:

xhprof profiling

Что значат столбцы:

  • Calls — количество и процентное соотношение вызовов функции;
  • Incl. Wall Time — время выполнения функции с вложенными функциями;
  • Excl. Wall Time — время выполнения функции без вложенных функций;
  • Incl. CPU — процессорное время с вложенными функциями;
  • Excl. CPU — процессорное время без вложенных функций;
  • Incl. MemUse — потребление памяти с вложенными функциями;
  • Excl. MemUse — потребление памяти без вложенных функций;
  • Incl. PeakMemUse — максимальное потребление памяти с вложенными функциями;
  • Excl. PeakMemUse — максимальное потребление памяти без вложенных функций.

Если перейти по ссылке [View Full Callgraph], то отобразится прекрасное дерево вызовов с визуальной индикацией наиболее тормознутого кода. Если же этого не произошло, то скорее всего нужно установить библиотеку graphviz:

apt-get install graphviz

Пример построенного графика:

xhprof graph vizualization

В моем случае самое узкое место — это взаимодействие с БД.


Использование xhprof на боевом сервере

Изначально xhprof разрабатывался именно с целью профилирования кода в бою, на production серверах. Другого бесплатного и эффективного инструмента профилирования php7-кода в бою по-просту нет, поэтому у xhprof нет конкурентов. Конкретно у меня есть опыт использования xhprof на production сервере, который обрабатывает миллион запросов в сутки. Там используется php7, и проблем пока не было обнаружено. Однако, xhprof не запускается для каждого запроса — генерировалось бы слишком много файлов профилирования. У меня профилировщик запускается только в том случае, если в запросе указан заголовок «XHPROF_ENABLE» и он установлен в true. Также можно использовать и другую стратегию, например, запускать профилировщик случайно с вероятностью, скажем, в 1/1000. Тогда тоже будет достаточно ясная картина.


Вывод

Даже несмотря на то, что xhprof официально не поддерживается для php7, он по-прежнему остается незаменимым инструментом для php-разработчика.

Теги:  php  xhprof  php7 

Поделиться статьей

Оставить комментарий