Как я могу измерить скорость кода, написанного на PHP? [закрыто]

118

Как я могу сказать, какой из многих классов (выполняющих одну и ту же работу) выполняется быстрее? есть программное обеспечение для измерения этого?

М.А. Кишави
источник

Ответы:

195

У вас есть (как минимум) два решения:

Довольно "наивный" метод - использовать микровремя (истина) до и после части кода, чтобы узнать, сколько времени прошло во время его выполнения; в других ответах говорилось об этом и уже приводились примеры, поэтому я не скажу больше.

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

Что-то вроде этого, так что, если вы хотите знать, сколько времени требуется для сериализации массива:

$before = microtime(true);

for ($i=0 ; $i<100000 ; $i++) {
    serialize($list);
}

$after = microtime(true);
echo ($after-$before)/$i . " sec/serialize\n";

Не идеально, но полезно и не требует много времени на настройку.



Другое решение, которое неплохо работает, если вы хотите определить, какая функция занимает много времени во всем скрипте, - это использовать:

  • Расширение Xdebug для генерации данных профилирования для скрипта.
  • Программное обеспечение, которое считывает данные профилирования и представляет вам что-то удобочитаемое. Я знаю троих из них:
    • Webgrind ; веб интерфейс ; должен работать на любом сервере Apache + PHP
    • WinCacheGrind ; только на окнах
    • KCacheGrind ; возможно только Linux и Linux-подобные; Это тот, который я предпочитаю, кстати

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

Обычно я не включаю профилировщик по умолчанию (он генерирует довольно большие файлы и замедляет работу) , а использую возможность отправки параметра, называемого XDEBUG_PROFILEданными GET, чтобы активировать профилирование только для нужной мне страницы.
Часть моего php.ini, связанная с профилированием, выглядит так:

xdebug.profiler_enable = 0              ; Profiling not activated by default
xdebug.profiler_enable_trigger = 1      ; Profiling activated when requested by the GET parameter
xdebug.profiler_output_dir = /tmp/ouput_directory
xdebug.profiler_output_name = files_names

(Прочтите документацию для получения дополнительной информации)

Этот снимок экрана взят из программы C ++ в KcacheGrind: (источник: sourceforge.net ) Вы получите точно такие же вещи и со сценариями PHP ;-) (Я имею в виду, что с KCacheGrind; WinCacheGrind не так хорош, как KCacheGrind ... )http://kcachegrind.sourceforge.net/html/pics/KcgShot3Large.gif



Это позволяет получить представление о том , что хорошем занимает много времени в вашем приложении - и он иногда определенно помогает найти в функцию, замедляя все вниз ^^

Обратите внимание, что Xdebug подсчитывает время процессора, затраченное PHP; когда PHP ожидает ответа от базы данных (например), он не работает; только ожидание. Так что Xdebug подумает, что запрос к БД не займет много времени!
Это должно быть профилировано на SQL-сервере, а не на PHP, поэтому ...


Надеюсь, это будет полезно :-)
Удачи!

Паскаль МАРТИН
источник
1
Существует сборка QCacheGrind для Windows :-) sourceforge.net/projects/qcachegrindwin
François Breton
43

Для быстрых вещей я делаю это (на PHP):

$startTime = microtime(true);
doTask(); // whatever you want to time
echo "Time:  " . number_format(( microtime(true) - $startTime), 4) . " Seconds\n";

Вы также можете использовать профилировщик, например http://xdebug.org/ .

Скотт Сондерс
источник
2
Для большей точности я бы предложил (а) использовать цикл и усреднить время и (б) использовать отдельные файлы для каждого объекта, который вы тестируете. Если у вас есть несколько таймингов в одном скрипте, их порядок иногда может иметь значение.
DisgruntledGoat
9

Я сделал простой класс времени, может быть, кому-то пригодится:

class TimingHelper {

    private $start;

    public function __construct() {
        $this->start = microtime(true);
    }

    public function start() {
        $this->start = microtime(true);
    }

    public function segs() {
        return microtime(true) - $this->start;
    }

    public function time() {
        $segs = $this->segs();
        $days = floor($segs / 86400);
        $segs -= $days * 86400;
        $hours = floor($segs / 3600);
        $segs -= $hours * 3600;
        $mins = floor($segs / 60);
        $segs -= $mins * 60;
        $microsegs = ($segs - floor($segs)) * 1000;
        $segs = floor($segs);

        return 
            (empty($days) ? "" : $days . "d ") . 
            (empty($hours) ? "" : $hours . "h ") . 
            (empty($mins) ? "" : $mins . "m ") . 
            $segs . "s " .
            $microsegs . "ms";
    }

}

Использование:

$th = new TimingHelper();
<..code being mesured..>
echo $th->time();
$th->start(); // if it's the case
<..code being mesured..>
echo $th->time();

// result: 4d 17h 34m 57s 0.00095367431640625ms 
Нельсон Тейшейра
источник
Вы ошиблись: это echo, а не$echo
вс,
9

Обновление 2020

Прошло много лет с тех пор, как я последний раз отвечал на эти вопросы, поэтому я подумал, что это заслуживает обновления в области APM.

  • Cisco купила AppDynamics, и учетная запись, которую они предлагали навсегда, была удалена с их веб-сайта.
  • NewRelic снизила свои цены со 149 долларов в месяц за хост до 25 долларов в месяц за хост, чтобы конкурировать с новичком на рынке APM, Datadog, который предлагает 31 доллар в месяц за хост.
  • Возможности Datadog APM по-прежнему невелики и оставляют желать лучшего. Однако я вижу, что они улучшают и улучшают их в течение следующего года.
  • Ruxit был куплен Dynatrace. Здесь нет ничего удивительного, поскольку Ruxit создан бывшими сотрудниками Dynatrace. Это позволило Dynatrace к лучшему преобразоваться в действительно модель SaaS. Попрощайтесь с громоздким Java-клиентом, если хотите.
  • Теперь есть бесплатные варианты с открытым исходным кодом. Оформить заказ Apache Skywalking, который очень популярен в Китае среди их ведущих технологических компаний, и PinPoint, который предлагает демоверсию, которую вы можете попробовать перед установкой. И то, и другое требует, чтобы вы управляли хостингом, поэтому будьте готовы развернуть несколько виртуальных машин и потратить некоторое время на установку и настройку.
  • Я не пробовал ни одно из этих решений APM с открытым исходным кодом, поэтому я не могу их рекомендовать, однако мне лично удалось развернуть все эти решения APM для нескольких организаций либо локально, либо в облаке для сотен приложений / microservices. Поэтому я могу с уверенностью сказать, что вы не ошибетесь с любым из поставщиков, если они соответствуют вашим требованиям.


Первоначальный ответ: октябрь 2015 г.

Вот прямой ответ на ваш вопрос

есть программное обеспечение для измерения этого?

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

Почему бы не использовать инструмент мониторинга производительности приложений (APM), который создан именно для этого и многого другого. Ознакомьтесь с NewRelic, AppDynamics, Ruxit (у всех есть бесплатная версия), чтобы отслеживать время выполнения, использование ресурсов, пропускную способность каждого приложения на уровне методов.

на-98
источник
6

Если вы хотите быстро проверить производительность фреймворка, вы можете поместить файл index.php

//at beginning
$milliseconds = round(microtime(true) * 1000);

//and at the end
echo round(microtime(true) * 1000) - $milliseconds;

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

tasmaniski
источник
5

В последнее время я использую XHProf http://pecl.php.net/package/xhprof . Первоначально он был разработан Facebook и имеет приличный веб-интерфейс.

Джейсон
источник
4

Я хотел бы поделиться с вами самодельной функцией, которую я использую для измерения скорости любой существующей функции до 10 аргументов:

function fdump($f_name='', $f_args=array()){

    $f_dump=array();
    $f_result='';

    $f_success=false;

    $f_start=microtime();
    $f_start=explode(' ', $f_start);
    $f_start=$f_start[1] + $f_start[0];

    if(function_exists($f_name)){

        if(isset($f_args[0])&&is_array($f_args[0])){
            if($f_result=$f_name($f_args)){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[1])){
            if($f_result=$f_name($f_args[0])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[2])){
            if($f_result=$f_name($f_args[0],$f_args[1])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[3])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[4])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[5])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[6])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[7])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[8])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6],$f_args[7])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[9])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6],$f_args[7],$f_args[8])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[10])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6],$f_args[7],$f_args[8],$f_args[9])){
                $f_success=true;
            }
        }
    }
    $f_end=microtime();
    $f_end=explode(' ', $f_end);
    $f_end=$f_end[1] + $f_end[0];

    $f_time=round(($f_end - $f_start), 4);
    $f_dump['f_success']=$f_success;
    $f_dump['f_time']=$f_time;
    $f_dump['f_result']=$f_result;

    var_dump($f_dump);exit;

    //return $f_result;

}

пример

function do_stuff($arg1='', $arg2=''){
    return $arg1.' '.$arg2;
}

fdump('do_stuff',array('hello', 'world'));

Возвращает

  array(3) {
    ["f_success"]=>
    bool(true)
    ["f_time"]=>
    float(0)            //too fast...
    ["f_result"]=>
    string(11) "hello world"
  }
RafaSashi
источник
3

Если это что-то, что можно протестировать вне веб-контекста, я просто использую команду Unix time.

хаос
источник
3

Zend Studio имеет встроенную поддержку профилирования с помощью XDebug или ZendDebugger. Он профилирует ваш код, сообщая вам, сколько времени заняла каждая функция. Это фантастический инструмент для определения ваших узких мест.

OverloadUT
источник
1

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

Alex
источник