Профилирование php. Профилирование и отладка php-приложений с помощью xhprof & FirePHP

Рассказывалось о том, как установить и настроить xdebug, описывались некоторые простейшие возможности, такие как улучшение вывода функции var_dump() или вывод трассировки стека вызовов при получении сообщения об ошибке. Во второй части мы рассмотрели такую возможность xdebug как трассировку. Трассировка содержит все вызовы функций и методов в программе, время запуска, опционально размер памяти, передаваемые и возвращаемые параметры. Лог трассировки может помочь вам понять пути выполнения сложной программы. Вместо того чтобы вставлять отладочный код внутрь программы, вы включаете или выключаете трассировку в тем места где нужно, а потом используете утилиты подобные grep или собственно написанные приложения на PHP для анализа лог файла.

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

Создания профайлинг-лога

Ниже короткая выдержка из профайлинг-лога, созданного xdebug:

fl=php:internal
fn=php::define
106 3

Fl=C:\www\drupal\includes\bootstrap.inc
fn=require_once::C:\www\drupal\includes\bootstrap.inc
1 648
cfn=php::define
calls=1 0 0
13 6
cfn=php::define
calls=1 0 0
18 4
cfn=php::define
calls=1 0 0
23 2


Как вы видите, профайлинг-лог не возможно читать напрямую. Мы будем использовать дополнительный инструменты для визуализации и анализа полученных данных. Итак, профайлинг показывает как много раз запущена была та или иная строчка и сколько времени занял запуск.
Создание профайлинг-лога сильно ухудшает производительность, подобно создания лога трассировки, потому что надо описать прохождение каждой строчки. Поэтому также как и в случае трассировки, не запускаете профайлинг на боевых серверах… Однако существуют случаи, когда профайлинг необходимо запустить на live-системе. В этом случае будьте осторожны в одновременном запуске xdebug с дроугими расширениями Zend, такими как загрузчики, оптимизаторы или кэши.
Для того, чтобы xdebug начал записывать профайлинг-лог добавьте

Пожалуйста, отметьте, что вы не можете запустить профайлинг во время запуска путем запуска команды.
Так как профайлинг-лог предназначен для чтения программами-анализаторами, не существует дополнительных настроек, которые позволяют отображать дополнительную информацию, как в случае лога трассировки. Однако есть некоторые настройки, которые позволяют настроить профайлинг, похожие на те, которые мы использовали при настройке трассировки.
Во-первых, xdebug по умолчанию пишет профайлинг-лог в каталог /tmp. Если вы используете Windows, необходимо исправить php.ini, например так:
xdebug.profiler_output_dir=«c:\traces»

По умолчанию xdebug перезаписывает существующий профайлинг-лог. Вы можете настроить, чтобы он дополнял существующий, для чего добавьте следующую команду

в php.ini. Есть такие случаи, когда вы не хотите создавать профайлинг-лог для всех файлов, в тоже время активация профайлинга во время выполнения проблематична. Вместо периодического включения и выключения профайлинга, добавьте команду
xdebug.profiler_enable_trigger=On

в php.ini. Теперь вы можете включать и выключать профайлинг, передавая специальный GET или POST параметр XDEBUG_PROFILE в PHP-скрипт. Это включит профайлинг только для данного PHP-скрипта. Необязательно устанавливать значение этого параметра, не забудьте только добавить этот параметр в адрес test.php?XDEBUG_PROFILE.

Название профайлинг-лога

Имя, которое по умолчания xdebug присваивает профайлинг-логу «cachegrind.out.» плюч идентификатор процесса. Также как и в случае лога трассировки можно изменить названия лога, добавляя в php.ini соответствующие настройки. Название параметра xdebug.profiler_output_name. Аргументом является строка. которая может содержать различные модификаторы. Самые важные ниже:

  • %p – идентификатор процесса
  • %r – случайное число
  • %u - время
  • %H – значение $_SERVER["HTTP_HOST"]
  • %R – значение $_SERVER["REQUEST_URI"]
  • %s – имя, включающее полный путь, слеши конвертируются в знаки подчеркивания
Пожалуйста, отметьте, что модификатор %s используется только для xdebug.profiler_output_name. Если вы хотите узнать название профайлинг-лога, вы можете вызвать функцию xdebug_get_profiler_filename().

Анализ профайлинг-лога
Как уже говорилось выше, для анализа профайлинг-лога необходимы дополнительные программы для визуализации данных. Все профайлинг-логи, которые создает xdebug, находятся в формате похожем на Cachegrind-формат. Cachegrind это профайлер, который является частью более мощной программы под названием Valgrind , программы для отладки и профайлинга программного обеспечения для Linux. Cachegrind был предназначен для анализа статистик кэшей, использования памяти и команд программы. Другой инструмент программы Valgrind, Callgrind рисует графы вызовов. В отношении PHP, мы можем использовать это приложение для визуализации и анализа профайлинг-лога.
Инструмент, который обычно используется для анализа профайлинг-лога, созданного xdebug, называется . KCachegrind – это свободное программное обеспечение доступное по лицензии GPL (работает только на Unix-системах). Однако, есть простенькая программка и для Windows - , которая также бесплатна. Давайте рассмотрим сначала Windows-версию.

WinCacheGrind: анализ профайлинг-логов в Windows

Текущая версия (на момент написания автором данной статьи) WinCachegrind - 1.0.0.12. Эта версия датирована далеким 2005, что говорит о том, что WinCachegrind давно не разрабатывается. Если посмотреть на примечания к релизу release notes, авторы пишут, что в программе есть ошибки, которые иногда делают ее поведение странным.
Поэтому я рекомендую использовать KCachegrind, запущенной на основе виртуальной машигы на последнем дистрибутиве Линукса, например Ubuntu (примечание переводчика, вообще говоря странная рекомендация, я бы рекомендовал в этом случае просто поставить линукс, а не городить огород виртуальных машин). Существует огромное количество виртуальных машин, доступных под Windows. Если не возможно использовать Unix или виртуальную машину по каким-либо причинам, вы можете продолжать использовать WinCachegrind для простого анализа профайлинг-лога. WinCachegrind не рисует графы вызовов в отличие от KCachegrind.
Установка Wincachegrind чрезвычайно проста. Запустите установщик, нажмите на кнопочку согласиться с лицензией и установка завершена. Теперь вы можете запустить программу, открыть в ней один из cachegrind профайлинг-логов, созданных xdebug.

Кликая на часики или иконку сигмы, вы можете переключаться между выводом информации в абсолютных значениях и процентах. Процентное отображение показывает, сколько времени в процентах от общего времени занимает вызов функции в данном блоке.
Две полезные настройки Profiler -> Hide Fast Functions и Profiler -> Hide Library Functions. Первый переключатель скрывает функции, временной вклад которых в общее время выполнения программы незначителен.
Вторая настройка, Profiler -> Hide Library Functions скрывает из общего анализа встроенные в PHP функции. Когда включены обе эти настройки, вы видите меньше данных, вследствие чего можно сфокусироваться на тех участках кода, которые требуют оптимизации.
Главное окно содержит две вкладки: Line by line и Overall. Обе вкладки показывают одинаковую информацию, однако вкладка Overall агрегирует информацию для лучшенго представления. Self time отображает время запуска кода в текущем блоке, в то время как Cumulative time (Cum.) показывает общее время запуска функций в данном блоке.

KCacheGrind: анализ профайлинг-логов в Unix

Unix версия KCachegrind предоставляет больше функциональности, чем WinCachegrind. KCachegrind визуализирует данные и строит граф вызовов.
Для начала использования необходимо установить KCachegrind. Текущая версия . Более новая версия (0.10.1) доступна, однакак она является частью пакета Valgrind.
Если выозможно используйте менеджер пакетов для установки пакета KCachegrind. KCachegrind использует GraphViz для рисования графов вызова, поэтому необходимо также установить пакет GraphViz, если ваш менеджер пакетов автоматически не устанавливает зависимые пакеты.
Если вы не нашли бинарный пакет KCachegrind, необходимо скомпилировать KCachegrind самостоятельно. После загрузки исходников, запустите

./configure --prefix=/opt/kde3
make
make install

Как вы можете отметить, необходимо прописать путь к текущей установке KDE-библиотеки. Если вы не знаете, где в вашей системе находятся библиотеки KDE, используйте

для отображения пути к библиотекам KDE.
После установки, вы можете запустить KCacheGrind из командной строки

Табличное отображение данных в KCachegrind очень похоже на WinCachegrind. Вы также можете переключаться между абсолютными и процентными значениями. Некоторые возможности KCachegrind не предназначены для PHP. На картинке внизу показан граф вызовов программы phpMyAdmin:


Как вы можете видеть, большая часть времени запуска прошла внутри common.inc.php. Следующий скриншот показывает визуализацию вызовов функций внутри common.inc.php:

В этом блоке кода запускаются два require_once, которые составляют половину времени запуска common.inc.php. Кликнув дважды на любой прямоугольник, вы опуститесь глубже в анализ данных.

Оптимизация кода на основании данных профайлинга

Всегда профилируйте ваши приложения до начала оптимизации. Вы можете сами начать оптимизацию, в том месте, где вам кажется, что эта оптимизация принесет эффект, однако это не всегда верно. Оптимизация, главным образом, имеет эффект лишь в тех частях, которые занимают, больше всего времени в процессе выполнения.
Если запускается множество копий программы одновременно, все равно может возникнуть необходимость оптимизации той части вашей программы, которая занимает большую часть времени выполнения. В этом случае оптимизация не сделает обслуживание одного индивидуального запроса быстрее, но позволит вашему серверу выдерживать высокую нагрузку, потребляя меньше ресурсов для обслуживания подобные запросы.
Когда вы смотрите на продолжительность запуска по данным профайлера, имейте ввиду, что абсолютные значения мене важны, чем относительные. Измеренные на разных системах, абсолютные значения могут быть различными. Однако до того как приступить к оптимизации кода, рассмотрите следующие вещи.
Важное правило в оптимизации – сокращение количества операций ввода/вывода. Некоторые операции ввода/вывода требуют очень много времени по сравнению с вычислениями. Уменьшение таких операций может быть очень эффективным путем ускорения вашей программы. Удаление одного вызова I/O может дать более эффективное улучшение, чем куча часов оптимизации кода. Поэтому вы должны сфокусироваться вначале на операциях I/O до того как вы приступите к коду.
Также перед оптимизацией вы можете увеличить количество ваших серверов. Вы можете купить огромный, что позволит вам ненамного увеличить производительность. Время разработки более дорогое, чем цена нового сервера. И если вы увеличите количество железа, вы можете быть уверены, что вы получите увеличение сразу же без какого-либо воздействия на PHP код. Когда разработчик проводит один или два дня над оптимизацией код, вы никогда не скажете, на сколько увеличится производительность. И в конце концов, вы уже не можете быть уверены в том, что оптимизация не принесет никаких ошибок.
Преобразование некоторых страниц в статические – это один из путей достичь большей производительности. Допустим, есть сайт с большим трафиком, где PHP скрипт на каждый запрос создает первую страницу, выбирая информацию из базы данных или XML-файла. Если данные на странице изменяются достаточно часто, то вы можете пересоздавать ее статическую копию. Если преобразование в статический вид для страницы не возможно (на странице выводится какая-то персональная информация), вы можете преобразовывать в статику некоторые блоки.
Другой уровень оптимизации не требует изменения кода PHP. Как мы знаем PHP это интерпретируемый язык. Это значит, что его команды транслируются во время выполнения в промежуточный код. Трансляция повторяется каждый раз, когда запускается скрипт. Это делает PHP медленнее по сравнению с такими языками как C или Java, которые не требуют разбора код каждый раз при запуске. Для PHP, вы можете использовать кэши промежуточного представления (смотри мой перевод ….) для сохранения и повторного использования промежуточного кода, это делает запуск и выполнение быстрее.
Все это не говорит о том, что не время и не место оптимизировать PHP-код. Некоторые оптимизации кода могут очень сильно увеличить производительность. Однако всегда помните, что изменение кода всегда несет риск внесения дополнительных ошибок и проблем безопасности. Также не забывайте, что оптимизация кода делает его менее читаемым.

Заключение

Создание и визуализация профайлинг-лога это одна из важных условий для оптимизации PHP-кода. Вы должны знать, какие места в программе требуют больше всего времени, и именно там начать оптимизацию.
В следующей статье мы рассмотрим отладку, используя xdebug. xdebug может предоставить вам возможность для удаленной отладки. Используя клиент, в котором реализована такая возможность, например Eclipse PDT, вы можете производить отладку вашего кода, не изменяя его, устанавливать breakpoints, перескакивать через участки кода, смотреть, как и где переменные изменяют значения.


Иногда ошибки ViewProfile.swf и другие системные ошибки SWF могут быть связаны с проблемами в реестре Windows. Несколько программ может использовать файл ViewProfile.swf, но когда эти программы удалены или изменены, иногда остаются "осиротевшие" (ошибочные) записи реестра SWF.

В принципе, это означает, что в то время как фактическая путь к файлу мог быть изменен, его неправильное бывшее расположение до сих пор записано в реестре Windows. Когда Windows пытается найти файл по этой некорректной ссылке (на расположение файлов на вашем компьютере), может возникнуть ошибка ViewProfile.swf. Кроме того, заражение вредоносным ПО могло повредить записи реестра, связанные с Bioshock 2. Таким образом, эти поврежденные записи реестра SWF необходимо исправить, чтобы устранить проблему в корне.

Редактирование реестра Windows вручную с целью удаления содержащих ошибки ключей ViewProfile.swf не рекомендуется, если вы не являетесь специалистом по обслуживанию ПК. Ошибки, допущенные при редактировании реестра, могут привести к неработоспособности вашего ПК и нанести непоправимый ущерб вашей операционной системе. На самом деле, даже одна запятая, поставленная не в том месте, может воспрепятствовать загрузке компьютера!

В связи с подобным риском мы настоятельно рекомендуем использовать надежные инструменты очистки реестра, такие как WinThruster (разработанный Microsoft Gold Certified Partner), чтобы просканировать и исправить любые проблемы, связанные с ViewProfile.swf. Используя очистку реестра , вы сможете автоматизировать процесс поиска поврежденных записей реестра, ссылок на отсутствующие файлы (например, вызывающих ошибку ViewProfile.swf) и нерабочих ссылок внутри реестра. Перед каждым сканированием автоматически создается резервная копия, позволяющая отменить любые изменения одним кликом и защищающая вас от возможного повреждения компьютера. Самое приятное, что устранение ошибок реестра может резко повысить скорость и производительность системы.


Предупреждение: Если вы не являетесь опытным пользователем ПК, мы НЕ рекомендуем редактирование реестра Windows вручную. Некорректное использование Редактора реестра может привести к серьезным проблемам и потребовать переустановки Windows. Мы не гарантируем, что неполадки, являющиеся результатом неправильного использования Редактора реестра, могут быть устранены. Вы пользуетесь Редактором реестра на свой страх и риск.

Перед тем, как вручную восстанавливать реестр Windows, необходимо создать резервную копию, экспортировав часть реестра, связанную с ViewProfile.swf (например, Bioshock 2):

  1. Нажмите на кнопку Начать .
  2. Введите "command " в строке поиска... ПОКА НЕ НАЖИМАЙТЕ ENTER !
  3. Удерживая клавиши CTRL-Shift на клавиатуре, нажмите ENTER .
  4. Будет выведено диалоговое окно для доступа.
  5. Нажмите Да .
  6. Черный ящик открывается мигающим курсором.
  7. Введите "regedit " и нажмите ENTER .
  8. В Редакторе реестра выберите ключ, связанный с ViewProfile.swf (например, Bioshock 2), для которого требуется создать резервную копию.
  9. В меню Файл выберите Экспорт .
  10. В списке Сохранить в выберите папку, в которую вы хотите сохранить резервную копию ключа Bioshock 2.
  11. В поле Имя файла введите название файла резервной копии, например "Bioshock 2 резервная копия".
  12. Убедитесь, что в поле Диапазон экспорта выбрано значение Выбранная ветвь .
  13. Нажмите Сохранить .
  14. Файл будет сохранен с расширением.reg .
  15. Теперь у вас есть резервная копия записи реестра, связанной с ViewProfile.swf.

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

FirePHP - это расширение для firebug, которое в связке со своим маленьким php-классом, позволяет транслировать в консоль firebug"а данные от php, например всякие var_dump и прочую отладочную информацию. Главный плюс этого расширения в том, что вся трансляция отладочной информации происходит через заголовки и не замусоривает страницы и вообще никак не ломает логику работы приложения. Официальный сайт: http://firephp.org/ .

Основная идея.

Общий алгоритм профилирования заключается в следующем:
  1. В начале страницы включаем профайлинг с помощью xhprof_enable()
  2. В конце страницы выключаем профайлинг с помощью xhprof_disable() и сохраняем собранные данные с помощью save_run()
  3. Далее с помощью php-класса firephp передаем ссылку на данные профайлинга на клиентскую часть
  4. В консоли firebug"а открываем нужную нам информацию
  5. Радуемся:)
Еще хочется сказать, что, конечно, ручное добавление этих функций в свои php-скрипты - это здорово. Но хочется, чтобы эта информация всегда была под рукой во время разработки, и при этом не попадала на боевые сервера. Мы решаем эту задачу следующим образом:

В наших проектах почти во всех скриптах в начале подключается рабочий файлик с загрузчиком классов, подключением функций и прочими нужными штуками. Поэтому включение профайлинга мы вынесли в этот файл. А для того, чтобы иметь возможность включать/выключать отладочный режим по своему желанию добавили проверку на конфигурационную константу, плюс обернули эти проверки в некие мета-тэги, которые автоматически удаляются при сборке проекта. Тоже самое относится и к выключению профайлинга и записывании информации в заголовки с помощью firephp - эти задачи решает одна функция, которая вызывается в конце каждого php-скрипта и так же обернута в мета-тэги. Выглядит это примерно так:

// В конфиг-файле приложения прописаны вот такие константы

/** Режим работы среды окружения * */
define("APPLICATION_ENV" , "dev" ); // dev - отладка | pro - продакшин
/** Путь до профайлера */
define("XHPROF_ROOT" , __DIR__ . "/ExtProcs/debug/xhprof-0.9.2" );

/***************************************************************************************
* Далее в файлике, который подгружается в начале каждого скрипта запускаем профайлинг
* DEV_START и DEV_END - это наши мета-тэги, все что между ними вырезается при сборке
***************************************************************************************/

//-- DEV_START
//-- в режиме отладки подключаем debug библиотеки

// Подгружаем firephp
require_once(__DIR__ . "/includes/ExtProcs/debug/firephp/FirePHP.class.php" );
//-- подгружаем профайлер
"/xhprof_lib/utils/xhprof_lib.php" );
require_once (XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php" );
// Инициализируем профайлинг с нужными флагами. Подробное описание флагов
// можно найти на php.net/manual/ru/xhprof.constants.php
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
}
//-- DEV_END

// Ну и вот такая функция вызывается в конце каждого скрипта
// Ее вызов так же обернут в DEV_START и DEV_END

/**
* Создаем ссылку на результат профайлинга и выводим это в консоль
*/
function dev_boot_Down() {
if (APPLICATION_ENV === "dev" ) {
// Инициализируем экземпляр firephp
$firephp = FirePHP::getInstance(true );
// Выключаем профайлинг и сохраняем данные
$xhprof_data = xhprof_disable();
$xhprof_runs = new XHProfRuns_Default();
$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_testing" );
// Формируем ссылку на данные профайлинга и записываем ее в консоль
$link = "http://" . $_SERVER["HTTP_HOST" ] . "/includes/ExtProcs/debug/xhprof-0.9.2/xhprof_html/index.php?run={$run_id}&source=xhprof_testing\n" ;
$firephp->info($link, "profiling data" );
}
}


* This source code was highlighted with Source Code Highlighter .

Не буду вдаваться в подробности установки данных расширений, ибо тут все просто. Скажу только про некоторые моменты настройки. В xhproof предусмотрена всего одна конфигурационная переменная - xhprof.output_dir, которая указывает на папку, куда будут сохраняться данные профайлинга. Поэтому убедитесь, что в указанную директорию у пользователя, из-под которого выполняются php-скрипты есть права на запись. Так что пропишите в свой php.ini что-то вроде этого:


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

Так же не плохо поставить что-то типа dot или Graphviz для рисования графов вызовов. У меня под MacOS X стоит Graphviz.

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

An extension to PHP called Xdebug is available to assist in profiling PHP applications , as well as runtime debugging. When running the profiler, the output is written to a file in a binary format called "cachegrind". Applications are available on each platform to analyze these files. No application code changes are necessary to perform this profiling.

To enable profiling, install the extension and adjust php.ini settings. Some Linux distributions come with standard packages (e.g. Ubuntu"s php-xdebug package). In our example we will run the profile optionally based on a request parameter. This allows us to keep settings static and turn on the profiler only as needed.

# php.ini settings # Set to 1 to turn it on for every request xdebug.profiler_enable = 0 # Let"s use a GET/POST parameter to turn on the profiler xdebug.profiler_enable_trigger = 1 # The GET/POST value we will pass; empty for any value xdebug.profiler_enable_trigger_value = "" # Output cachegrind files to /tmp so our system cleans them up later xdebug.profiler_output_dir = "/tmp" xdebug.profiler_output_name = "cachegrind.out.%p"

Next use a web client to make a request to your application"s URL you wish to profile, e.g.

Http://example.com/article/1?XDEBUG_PROFILE=1

As the page processes it will write to a file with a name similar to

/tmp/cachegrind.out.12345

By default the number in the filename is the process id which wrote it. This is configurable with the xdebug.profiler_output_name setting.

Note that it will write one file for each PHP request / process that is executed. So, for example, if you wish to analyze a form post, one profile will be written for the GET request to display the HTML form. The XDEBUG_PROFILE parameter will need to be passed into the subsequent POST request to analyze the second request which processes the form. Therefore when profiling it is sometimes easier to run curl to POST a form directly.

Analyzing the Output

Once written the profile cache can be read by an application such as or Webgrind . PHPStorm, a popular PHP IDE, can also display this profiling data .

KCachegrind, for example, will display information including:

  • Functions executed
  • Call time, both itself and inclusive of subsequent function calls
  • Number of times each function is called
  • Call graphs
  • Links to source code

What to Look For

Obviously performance tuning is very specific to each application"s use cases. In general it"s good to look for:

  • Repeated calls to the same function you wouldn"t expect to see. For functions that process and query data these could be prime opportunities for your application to cache.
  • Slow-running functions. Where is the application spending most of its time? the best payoff in performance tuning is focusing on those parts of the application which consume the most time.

Note : Xdebug, and in particular its profiling features, are very resource intensive and slow down PHP execution. It is recommended to not run these in a production server environment.

С помощью систем для профилирования можно собрать информацию о том, какие функции в php-коде потребляют больше процессорного времени и оперативной памяти, то есть выявить наиболее медленные и требовательные к памяти места в программе на php.

xhprof

XHProf - PHP profiler разработанный в Facebook.

Установка:

Aptitude install php-pear pecl install xhprof-0.9.4 echo "extension=xhprof.so" > /etc/php5/mods-available/xhprof.ini ln -s /etc/php5/mods-available/xhprof.ini /etc/php5/conf.d/xhprof.ini apachectl restart

Необходимые для работы файлы расположены в директории /usr/share/php . Однако не все, а только c php-кодом. Для нормального отображения отчетов требуется jquery и css. Их можно заполучить из репозитория на github:

Git clone https://github.com/facebook/xhprof.git

После этого в код php-скрипта в месте, откуда должен начаться сбор данных добавляем строку:

Xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);

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

$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://domain.tld/xhprof_html/index.php?run=$run_id&source=xhprof_test"; echo "\n";

В строке $run_id в кавычках указано название профиля, которое можно задать произвольно.

Результат в обработанном виде выглядит следующим образом:

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

В таблице представлена следующая информация:

Calls - количество вызовов функции,
Wall Time - общее время работы функции вклчая время ожидания ответа от внешних ресурсов,
CPU - сколько времени было затарчено на обработку функций,
MemUse - сколько оперативной памяти было задействовано,
PeakMemUse - пиковое потребление памяти.

В качестве модификаторов выступают:

Incl - inclusive - с учетом вызовов других функций из этой функции,
Excl - exclusive - без учета вызовов функций.

Кроме того, над таблицей представлена информация о суммарных времени обработки, использованной памяти и количестве вызовов функций.

Также XHProf позволяет строить разностные отчеты между двумя запусками, которые обозначаются красным и зеленым цветами. С помощью таких отчетов можно получить ясную картину улучшений после каждого изменения кода.

Для получения подобного отчета нужно воспользоваться ссылкой вида:

http://domain.tld/xhprof_html/index.php?run1=run_id1&run2=run_id2&source=xhprof_test

где run_id1 и run_id2 - идентификаторы запусков.

Если установить Graphviz :

Aptitude install graphviz

Также для php profiler xhprof существуют сторонние веб-интерфейсы использующие базы данных:

xDebug

xDebug - дебаггер PHP-кода с возможностью профилирования (profiling), написанный Дериком Ретансом (Derick Rethans).

Установка:

Yum install php5-xdebug

Затем редактируем конфиг:

Nano /etc/php5/mods-available/xdebug.ini

добавляя в него строки:

Xdebug.profiler_enable = 1 xdebug.profiler_aggregate = On xdebug.profiler_output_dir = /tmp

Здесь включаем PHP профайлер и указываем директорию в которую складывать профили. Профили создаются с именами вида cachegrind.out.*

Существует веб-клиент webgrind: https://github.com/jokkedk/webgrind . Работает он не слишком быстро, но позволяет оперативно просмотреть небольшие профили. Фактически это код на PHP, который нужно склонировать с github:

Git clone https://github.com/jokkedk/webgrind.git

создастся директория webgrind , которую нужно скопировать в директорию любого сайта и обратиться к ней из браузера. Далее, чтобы в Debian заработало построение графиков в конфигурационном файле config.php нужно поправить путь до исполняемого файла graphviz . Должно получиться так:

Static $dotExecutable = "/usr/bin/dot";

Кроме того, можно подправить часовой пояс:

Static $defaultTimezone = "Europe/Moscow";

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

График может выглядеть следующим образом:

Обратите внимание, что webgrind не стоит использовать на производственных серверах, так как какая-либо авторизация не предусмотрена, но при этом есть доступ к коду файлов на php. В случае необходимости используйте хотя бы базовую авторизацию Apache.

Также существуют программы для анализа профилей как под Linux:

О профилировании

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

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

К примеру, если вы используете фреймворк, то использование некоторых функций фреймворка может вести к вызову нескольких базовых функций. Если вы читаете некоторые данные несколько раз, то, возможно, стоит сохранить результат в переменную.

Также профайлер может помочь понять где стоит использовать кэширование PHP-кода, к примеру, с помощью APCu или memcached .

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

При обнаружении следующих ситуаций стоит подумать о кэшировании:

  • Неизменяемые функции вызываются внутри цикла,
  • Некое содержимое генерируется дважды,
  • Содержимое, которое не изменяется генерируется каждый раз,
  • Содержимое генерируется, даже если не используется.

Не стоит кэшировать все подряд, так как память тоже ценный ресурс. Кэшируйте те данные, к которым обращаетесь постоянно. Также кэширование имеет мало смысла в случае если кэширование тратит больше ресурсов, чем экономит.

Кроме кэширования в коде не стоит забывать о кэшировании с помощью веб-сервера (), а также на стороне клиента. Если использовать правильные заголовки, то многие запросы могут быть разрешены еще до поступления на сервер.