Какой самый простой способ профилировать 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(" %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, которая отключается.
Расширение 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.
Это отобразит информацию, в том числе:
Очевидно, что настройка производительности очень специфична для случаев использования каждого приложения. В общем, полезно искать:
Примечание . Xdebug и, в частности, его профилирующие функции, очень ресурсоемкие и замедляют выполнение PHP. Рекомендуется не запускать их в среде производственного сервера.
Я бы демонстративно попросил BlackFire .
Есть этот виртуальный бокс, который я собрал с помощью puphpet , чтобы протестировать различные фрэш-фреймы , которые соответствуют BlackFire, пожалуйста, не стесняйтесь развивать и / или распространять при необходимости 🙂
Профили плохого человека, никаких расширений не требуется. Поддерживает вложенные профили и процент от общего числа:
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 обеспечивает синхронизацию функций, методов, модулей и даже строк.