Як я можу виміряти швидкість коду, написаного на 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-подібні; Це я вважаю за краще, btw

Щоб отримати файли з профілюванням, потрібно встановити та налаштувати Xdebug; дивіться на сторінку Профілювання PHP-скриптів документації.

Що я зазвичай роблю, це не включати профайлер за замовчуванням (він генерує досить великі файли та уповільнює роботу) , але використовує можливість для надсилання параметра, який називається XDEBUG_PROFILEGET data, для активації профілювання для потрібної мені сторінки.
Частина мого 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 подумає, що запит DB не потребує багато часу!
Це має бути профільовано на сервері SQL, а не на PHP, тому ...


Сподіваюся, це корисно :-)
Весело!


1
Існує версія Windows QCacheGrind :-) 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
Для додаткової точності я б запропонував (а) використовувати цикл та усереднювати час та (б) використовувати окремі файли для кожної тестуваної речі. Якщо у вас є кілька таймінгів в межах одного сценарію, їх порядок іноді може змінитися.
НезадоволенеЗаключення

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
SuN

9

Оновлення 2020 року

Минуло багато років, як я востаннє відповів на це питання, тому я подумав, що це заслуговує на оновлення щодо пейзажу APM.

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


Оригінально відповів на жовтень 2015 року

Ось пряма відповідь на ваше запитання

чи є програмне забезпечення для вимірювання цього?

Так, є. Мені цікаво, чому хтось ще цього не згадував. Хоча відповіді, запропоновані вище, здаються чудовими для швидкої перевірки, але не підлягають масштабуванню в довгостроковій перспективі або для більшого проекту.

Чому б не використовувати інструмент моніторингу продуктивності додатків (APM), який будується саме для цього та багато іншого. Ознайомтеся з NewRelic, AppDynamics, Ruxit (усі мають безкоштовну версію), щоб контролювати час виконання, використання ресурсів, пропускну здатність кожної програми до рівня методу.


6

Якщо ви хочете швидко перевірити працездатність рамки, ви можете помістити файл index.php

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

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

Кожен раз, коли ви отримуватимете час виконання у мілісекундах . Тому що мікросекунди не надто корисні для тестування рамкового випадку.



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

3

Якщо це те, що можна перевірити за межами веб-контексту, я просто використовую команду Unix time.


3

Zend Studio має вбудовану підтримку для профілювання за допомогою XDebug або ZendDebugger. Він буде профілювати ваш код, точно повідомляючи, скільки часу займає кожна функція. Це фантастичний інструмент для з'ясування, де ваші вузькі місця.


1

Ви можете використовувати основні речі, такі як зберігання часових позначок або мікрочасу () до і після операції, щоб обчислити необхідний час. Це легко зробити, але не дуже точно. Можливо, краще рішення - Xdebug , я ніколи з ним не працював, але, здається, це найвідоміший налагоджувач / профілер PHP, який я можу знайти.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.