Простейший способ профилировать скрипт PHP

Какой самый простой способ профилировать PHP-скрипт?

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

Я пробовал экспериментировать с функцией microtime :

$then = microtime(); myFunc(); $now = microtime(); echo sprintf("Elapsed: %f", $now-$then); 

но это иногда дает мне отрицательные результаты. Плюс, это много хлопот, чтобы посыпать это по всему моему коду.

Расширение APC PECL используется следующим образом:

 <?php apd_set_pprof_trace(); //rest of the script ?> 

pprofp сгенерированный файл с помощью pprofp .

Пример вывода:

 Trace for /home/dan/testapd.php Total Elapsed Time = 0.00 Total System Time = 0.00 Total User Time = 0.00 Real User System secs/ cumm %Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage Name -------------------------------------------------------------------------------------- 100.0 0.00 0.00 0.00 0.00 0.00 0.00 1 0.0000 0.0009 0 main 56.9 0.00 0.00 0.00 0.00 0.00 0.00 1 0.0005 0.0005 0 apd_set_pprof_trace 28.0 0.00 0.00 0.00 0.00 0.00 0.00 10 0.0000 0.0000 0 preg_replace 14.3 0.00 0.00 0.00 0.00 0.00 0.00 10 0.0000 0.0000 0 str_replace 

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

Это потрясающе: D

Никаких расширений не требуется, просто используйте эти две функции для простого профилирования.

 // Call this at each point of interest, passing a descriptive string function prof_flag($str) { global $prof_timing, $prof_names; $prof_timing[] = microtime(true); $prof_names[] = $str; } // Call this when you're done and want to see the results function prof_print() { global $prof_timing, $prof_names; $size = count($prof_timing); for($i=0;$i<$size - 1; $i++) { echo "<b>{$prof_names[$i]}</b><br>"; echo sprintf("&nbsp;&nbsp;&nbsp;%f<br>", $prof_timing[$i+1]-$prof_timing[$i]); } echo "<b>{$prof_names[$size-1]}</b><br>"; } 

Вот пример, вызывающий prof_flag () с описанием на каждой контрольной точке и prof_print () в конце:

 prof_flag("Start"); include '../lib/database.php'; include '../lib/helper_func.php'; prof_flag("Connect to DB"); connect_to_db(); prof_flag("Perform query"); // Get all the data $select_query = "SELECT * FROM data_table"; $result = mysql_query($select_query); prof_flag("Retrieve data"); $rows = array(); $found_data=false; while($r = mysql_fetch_assoc($result)) { $found_data=true; $rows[] = $r; } prof_flag("Close DB"); mysql_close(); //close database connection prof_flag("Done"); prof_print(); 

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

Начало
0.004303
Подключение к БД
0.003518
Выполнить запрос
0.000308
Получение данных
0.000009
Закрыть БД
0.000049
Готово

Если вычесть микротимы дает отрицательные результаты, попробуйте использовать функцию с аргументом true ( microtime(true) ). С помощью true функция возвращает float вместо строки (как если бы она вызывается без аргументов).

Честно говоря, я собираюсь утверждать, что использование NewRelic для профилирования является лучшим.

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

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

скриншот одного из интерфейсов при профилировании

PECL XHPROF также выглядит как interensting. Он имеет интерактивный HTML-интерфейс для просмотра отчетов и довольно простой документации . Мне еще предстоит проверить его.

Мне нравится использовать phpDebug для профилирования. http://phpdebug.sourceforge.net/www/index.html

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

Для профилирования функций и классов я просто использую microtime() + get_memory_usage() + get_peak_memory_usage() .

Перекрестная отправка моей ссылки из бета-версии SO Documentation, которая отключается.

Профилирование с помощью XDebug

Расширение PHP под названием Xdebug доступно для профилирования приложений PHP , а также для отладки времени исполнения. При запуске профилировщика вывод записывается в файл в двоичном формате «cachegrind». Приложения доступны на каждой платформе для анализа этих файлов. Для выполнения этого профилирования необходимы изменения кода приложения узла.

Чтобы включить профилирование, установите расширение и настройте параметры php.ini. Некоторые дистрибутивы Linux поставляются со стандартными пакетами (например, пакет php-xdebug Ubuntu). В нашем примере мы будем запускать профиль по выбору на основе параметра запроса. Это позволяет нам сохранять статичные настройки и включать профилировщик только по мере необходимости.

 // 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" 

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

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

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

 /tmp/cachegrind.out.12345 

По умолчанию число в имени файла – это идентификатор процесса, который его написал. Это можно настроить с xdebug.profiler_output_name параметра xdebug.profiler_output_name .

Обратите внимание, что он будет писать один файл для каждого выполняемого PHP-запроса / процесса. Так, например, если вы хотите проанализировать сообщение формы, для запроса GET будет отображаться один профиль для отображения формы HTML. Параметр XDEBUG_PROFILE должен быть передан в последующий запрос POST для анализа второго запроса, который обрабатывает форму. Поэтому при профилировании иногда проще запускать завиток в POST-форму напрямую.

После написания кеш профиля может быть прочитан приложением, например KCachegrind.

KCachegrind

Это отобразит информацию, в том числе:

  • Выполненные функции
  • Время вызова, как самого, так и включающего последующие вызовы функций
  • Количество вызовов каждой функции
  • Графы вызова
  • Ссылки на исходный код

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

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

Примечание . Xdebug и, в частности, его профилирующие функции, очень ресурсоемкие и замедляют выполнение PHP. Рекомендуется не запускать их в среде производственного сервера.

Я бы демонстративно попросил BlackFire .

Есть этот виртуальный бокс, который я собрал с помощью puphpet , чтобы протестировать различные фрэш-фреймы , которые соответствуют BlackFire, пожалуйста, не стесняйтесь развивать и / или распространять при необходимости 🙂

https://github.com/webit4me/PHPFrameworks

Профили плохого человека, никаких расширений не требуется. Поддерживает вложенные профили и процент от общего числа:

 function p_open($flag) { global $p_times; if (null === $p_times) $p_times = []; if (! array_key_exists($flag, $p_times)) $p_times[$flag] = [ 'total' => 0, 'open' => 0 ]; $p_times[$flag]['open'] = microtime(true); } function p_close($flag) { global $p_times; if (isset($p_times[$flag]['open'])) { $p_times[$flag]['total'] += (microtime(true) - $p_times[$flag]['open']); unset($p_times[$flag]['open']); } } function p_dump() { global $p_times; $dump = []; $sum = 0; foreach ($p_times as $flag => $info) { $dump[$flag]['elapsed'] = $info['total']; $sum += $info['total']; } foreach ($dump as $flag => $info) { $dump[$flag]['percent'] = $dump[$flag]['elapsed']/$sum; } return $dump; } не function p_open($flag) { global $p_times; if (null === $p_times) $p_times = []; if (! array_key_exists($flag, $p_times)) $p_times[$flag] = [ 'total' => 0, 'open' => 0 ]; $p_times[$flag]['open'] = microtime(true); } function p_close($flag) { global $p_times; if (isset($p_times[$flag]['open'])) { $p_times[$flag]['total'] += (microtime(true) - $p_times[$flag]['open']); unset($p_times[$flag]['open']); } } function p_dump() { global $p_times; $dump = []; $sum = 0; foreach ($p_times as $flag => $info) { $dump[$flag]['elapsed'] = $info['total']; $sum += $info['total']; } foreach ($dump as $flag => $info) { $dump[$flag]['percent'] = $dump[$flag]['elapsed']/$sum; } return $dump; } 

Пример:

 <?php p_open('foo'); sleep(1); p_open('bar'); sleep(2); p_open('baz'); sleep(3); p_close('baz'); sleep(2); p_close('bar'); sleep(1); p_close('foo'); var_dump(p_dump()); 

Урожайность:

 array:3 [ "foo" => array:2 [ "elapsed" => 9.000766992569 "percent" => 0.4736904954747 ] "bar" => array:2 [ "elapsed" => 7.0004580020905 "percent" => 0.36841864946596 ] "baz" => array:2 [ "elapsed" => 3.0001420974731 "percent" => 0.15789085505934 ] ] 

Для бенчмаркинга, как и в вашем примере, я использую пакет Benchmark груши . Вы устанавливаете маркеры для измерения. Класс также предоставляет несколько помощников презентации, или вы можете обрабатывать данные по своему усмотрению.

Я на самом деле его завернул в другой класс с помощью метода __destruct. Когда сценарий завершается, выход регистрируется через log4php в syslog, поэтому у меня есть много данных о производительности, с которых можно работать.

XDebug нестабилен и не всегда доступен для конкретной версии php. Например, на некоторых серверах я все еще запускаю php-5.1.6, – это то, что поставляется с RedHat RHEL5 (и btw по-прежнему получает обновления для всех важных проблем), и недавний XDebug даже не компилируется с этим php. Таким образом, я закончил с переключением на отладчик DBG. Его бенчмаркинг по php обеспечивает синхронизацию функций, методов, модулей и даже строк.