Профилирование кода позволяет выявить медленные участки в коде, что позволит в случае необходимости устранить их.
Новый PHP профайлер XHprof от компании Facebook – это альтернатива Xdebug (PHP профайлер Xdebug). XHprof был разработан специально для Facebook и начиная с март 2009 года его исходный код стал доступен для скачивания.
Как работает XHprof?
XHProf работает по принципу декомпозиции системы на вызовы функций (методов) и построения статистики в разрезе их ресурсопотребления. В результате получаем информацию: количество выделяемой памяти, количество вызовов функций, время исполнения и т.д.
Установка XHProf
С марта 2009 года XHprof доступен как пакет PECL, поэтому его установка не составит особого труда. Для Windows пакет не доступен.
# pecl search xhprof Retrieving data...0% Matched packages, channel pecl.php.net: ======================================= Package Stable/(Latest) Local xhprof 0.9.2 (beta) XHProf: A Hierarchical Profiler for PHP
Т.к. пакет xhprof находится в стадии beta, то нужно разрешить его установку:
# pecl config-get preferred_state stable # pecl config-set preferred_state beta # pecl config-get preferred_state beta
Если попытаться установить пакет через PECL, то получим ошибку:
# pecl install xhprof downloading xhprof-0.9.2.tar ... Starting to download xhprof-0.9.2.tar (Unknown size) ....................................................................done: 1,506,816 bytes 11 source files, building running: phpize Cannot find config.m4. Make sure that you run '/usr/local/bin/phpize' in the top level source directory of the module ERROR: `phpize' failed
Поэтому выполняем следующие шаги:
# wget http://pecl.php.net/get/xhprof-0.9.2.tgz # tar xvf xhprof-0.9.2.tgz # cd ./xhprof-0.9.2/extension/ # phpize # ./configure --with-php-config=/usr/local/bin/php-config # make # make install Installing shared extensions: /usr/local/lib/php/20060613/ # make test
Удалять папку xhprof-0.9.2 не следует, т.к. там содержатся утилиты GUI для визуального представления информации профайлера.
Подключаем модуль xhprof к PHP – редактируем файл php.ini (добавляем в конец файла):
[xhprof] extension=xhprof.so xhprof.output_dir="/var/tmp/xhprof"
Для папки “/var/tmp/xhprof” должен быть доступ на запись, т.к. туда будут сохраняться результаты профайлинга.
Перезагрузите Apache. При вызове phpinfo() появится информация, что подключен модуль xhprof – значит все работает.
Настройка XHProf UI (GUI)
В пакет XHprof входит очень удобный интерфейс для анализа отчетов профилирования. XHprof позволяет строить отчеты, как в текстовом так и графическом ввиде.
В установочной папке xhprof-0.9.2 Вы найдете папку xhprof_html и xhprof_lib, которые нам понадобятся:
• xhprof_html – доступ к GUI
• xhprof_lib – библиотека для отображения и анализа кода (computing flat profile info, computing diffs, aggregating data from multiple runs, etc.).
Папку xhprof_lib размещаем в /usr/local/share/php/ или /usr/local/lib/php/ в зависимости от ОС. Таким образом будет доступ к библиотеки будет глобальный. В нашем случае получится: /usr/local/share/php/xhprof_lib/. Или как вариант папку xhprof_lib можно положить в наш проект.
В зависимости от того как Вы настроете доступ к GUI xhprof, нужно положить xhprof_html в соответствующее место. К примеру, можно создать субдомен http://xhprof.project/ или положить в корень проекта http://xhprof/.
Небольшой пример использования
В качестве примера взят пример с сайта highload.com.ua:
function user_array_intersect( $a, $b ) {
$res = array();
foreach ( $a as $k => $v )
{
if ( in_array($v, $b) )
{
$res[] = $v;
}
}
return $res;
}
function execute()
{
$a = range(rand(100, 300), rand(700, 900));
$b = range(rand(100, 300), rand(700, 900));
$r1 = user_array_intersect($a, $b);
$r2 = array_intersect($a, $b);
}
# Инициализируем профайлер - будем считать и процессорное время и потребление памяти
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
# Выполняем "программу"
execute();
# Останавливаем профайлер
$xhprof_data = xhprof_disable();
# Сохраняем отчет и генерируем ссылку для его просмотра
include_once "xhprof_lib/utils/xhprof_lib.php";
include_once "xhprof_lib/utils/xhprof_runs.php";
$xhprof_runs = new XHProfRuns_Default();
$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_test");
echo "Report: http://xhprof/index.php?run=$run_id&source=xhprof_test"; # Хост, который Вы настроили ранее на GUI профайлера
echo "\n";
В этом скрипте мы сравним отличие в эффективности работы встроенной функции array_intersect и ее самописного клона user_array_intersect. После описания функций мы подключили профайлер для генерации и сохранения отчета. Посмотрим на отчет:

Из отчета видно, что эффективность собственной реализации функции array_intersect в два раза меньше встроенной (еще одно напоминание об использовании стандартных средств прежде всего!). Небольшая справка по терминологии отчетов:
• Incl[usive] Time – время, потраченное на функцию и на все функции, вызванные из нее
• Excl[usive] Time – время, потраченное на функцию без учета времени на вложенные функции
На скриншоте показана только часть отчета, кроме этих показателей отчет также содержит статистику по процессорным затратам и использованной памяти.
Графические отчеты
XHprof позволяет строить графические отчеты. Для построения он использует внешний инструмент Graphviz, поэтому убедитесь, что он установлен. Графический отчет вышеуказанного скрипта выглядит так:

Графический отчет позволяет визуально оценить ресурсоемкость каждой функции (красный должен привлечь внимание!). Как видим, в примере самой затратной функцией для ресурсов стала in_array(), которая сама по себе не является проблемой но говорит о плохом техническом решении.
Профилирование production проектов
XHprof позволяет профилировать не только отдельные участки кода но и production проекты. Т.к. профилирование проектов в среде production процесс ресурсоемкий, то главный тут критерий – производительность. И XHprof тут прекрасно справляется, т.к. создан он был именно для таких целей. Во-первых XHprof написан на C, во-вторых имеет ряд настроек:
• Таймер CPU на Linux системах имеет большой оверхед, поэтому разработчики рекомендуют использовать профайлер в режиме “elapsed time + memory”:
// elapsed time profiling (default) + memory profiling xhprof_enable(XHPROF_FLAGS_MEMORY);
• Сбор данных профайлера будет весьма точно отражать реальную картину, если его запускать не каждый раз, а случайно и равнораспределенно, например для запуска каждый сотый раз:
if (mt_rand(1, 100) == 1) {
xhprof_enable(XHPROF_FLAGS_MEMORY);
$xhprof_on = true;
}
...
if ($xhprof_on) {
$xhprof_data = xhprof_disable();
}
• Режим Lightweight Sampling – в этом режиме профилирование выполняется в течении короткого промежутка во времени (сэмплами) – 0.1 секунды
Пример профилирования production проекта
В качестве примера используем проект на Yii – Hello World!
Наш проект http://project/.
GUI нашего профайлера (содержимое папки xhprof_html) http://xhprof/.
xhprof_lib находится в “/usr/local/share/php/xhprof_lib”.
Создаем 2 файла (header.php и footer.php).
header.php
<?php
if (extension_loaded('xhprof')) {
// Способ 1 - файлы лежат в проекте
// include_once '/usr/local/share/php/xhprof_lib/utils/xhprof_lib.php';
// include_once '/usr/local/share/php/xhprof_lib/utils/xhprof_runs.php';
// Способ 2 - файлы лежат в /usr/local/share/php/xhprof_lib
include_once dirname(__FILE__) . '/xhprof_lib/utils/xhprof_lib.php';
include_once dirname(__FILE__) . '/xhprof_lib/utils/xhprof_runs.php';
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
}
footer.php
<?php
if (extension_loaded('xhprof')) {
$profiler_namespace = 'myapp'; // namespace for your application
$xhprof_data = xhprof_disable();
$xhprof_runs = new XHProfRuns_Default();
$run_id = $xhprof_runs->save_run($xhprof_data, $profiler_namespace);
// url to the XHProf UI libraries (change the host name and path)
$profiler_url = sprintf('http://' . $_SERVER['SERVER_NAME'] . '/xhprof/index.php?run=%s&source=%s', $run_id, $profiler_namespace);
// Можем сделать защиту по айпи, или добавить $_GET параметр
if (in_array($_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1')))
{
// На нашей странице появится ссылка "Profiler output", которая ведет на GUI XHprof с уникальными идентификатором отчета
echo '<br/><br/><a href="'. $profiler_url .'" target="_blank">Profiler output</a>';
}
}
Для внедрения профайлера в наш проект есть 2 способа:
1) Создаем файл .htaccess
php_value auto_prepend_file ../xhprof/header.php php_value auto_append_file ../xhprof/footer.php
2) Добавляем вызов в файла в наш index.php
<?php
include('xhprof/header.php');
// include Yii bootstrap file
require_once(dirname(__FILE__).'/framework/yii.php');
// create a Web application instance and run
Yii::createWebApplication()->run();
include('xhprof/footer.php');
Загружаем страницу сайта. Внизу страницы появляется ссылка “Profiler output”, которая ведет на GUI XHprof с уникальными идентификатором отчета. Каждый раз, когда мы обновляем страницу отчет перегенирируется и идентификатор изменится.
Получаем отчет:

Показатели:
• Total Incl. Wall Time (microsec): 18,710 microsecs (время затраченное на выполнение функций с учетом ожидания ответов от сокетов, файловой системы и других ресурсов )
• Total Incl. CPU (microsecs): 16,309 microsecs (время затраченное на выполнение функций)
• Total Incl. MemUse (bytes): 527,604 bytes (использование памяти)
• Total Incl. PeakMemUse (bytes): 529,428 bytes (пиковое использование памяти)
• Number of Function Calls: 179 (количество вызовов функций)
Что почитать:
• XHProf Documentation
• Pecl: xhprof
• Profiling with XHProf
• XHprof – профилирование PHP от Facebook
• Профилирование PHP-кода


