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

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

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

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

$then = microtime();
myFunc();
$now = microtime();

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

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

Ответ 1

Расширение 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

Предупреждение: последняя версия APD датирована 2004 годом, расширение больше не поддерживается и имеет различные проблемы с совместимостью (см. Комментарии).

Ответ 2

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

Это скалы, серьезно: D

Ответ 3

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

// 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
Подключение к DB
  0.003518
Выполните запрос
  0.000308
Получить данные
  0.00009
Закрыть БД
  0.000049
Готово

Ответ 4

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

Ответ 5

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

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

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

screenshot of one of the interfaces when profiling

Ответ 6

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

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

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

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

# php.ini settings
# Set to 1 to turn it on for every request
xdebug.profiler_enable = 0
# Let 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 или Webgrind. PHPStorm, популярная PHP IDE, также может отображать данные профилирования.

KCachegrind

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

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

Что искать

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

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

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

Ответ 8

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

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

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

Ответ 9

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

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
  ]
]

Ответ 10

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

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

https://github.com/webit4me/PHPFrameworks

Ответ 11

Для бенчмаркинга, как и в вашем примере, я использую пакет

Ответ 12

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