Runtime Comparison для PHP приложений

Очень часто в моей работе приходится сравнивать время выполнения того или иного кода с целью выбора наиболее оптимального решения, и каждый раз я писал небольшой обработчик с расчётом микровремени (microtime), после чего заносил все результаты в какую-нибудь таблицу Excel и вручную рассчитывал минимальное, максимальное и среднее время выполнения…

74170dcd724211c514eba23ca75dfcbf.png

Для решения этой тривиальной задачи был выпущен пакет «Runtime Comparison», позволяющий сравнивать время выполнения кода без лишних затрат на разработку — просто устанавливаете зависимость и вызываете метод сравнения, передавая проверяемые варианты в качестве аргументов.

Установка

Проще всего установить пакет при помощи пакетного менеджера Composer:

composer require dragon-code/runtime-comparison --dev

И всё, пакет готов к работе.

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

Так как вся нужная информация выводится в консоль, то лучше вызывать данный код через консоль хоть через команды используемого Вами фреймворка, хоть напрямую через вызов файла, например, php handler.php.

use DragonCode\RuntimeComparison\Comparator;

(new Comparator())->compare(
    fn () => /* some code */,
    fn () => /* some code */,
);

(new Comparator())->compare([
    fn () => /* some code */,
    fn () => /* some code */,
]);

(new Comparator())->compare([
    'foo' => fn () => /* some code */,
    'bar' => fn () => /* some code */,
]);

Передавать можно неограниченное количество аргументов.

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

Пример результата выполнения

----- ------------------- ------------------- 
 #     0                   1                  
----- ------------------- ------------------- 
 1     0.011713027954102   0.015522003173828  
 2     0.014931917190552   0.015424013137817  
 3     0.015513896942139   0.014975070953369  
 4     0.015083789825439   0.014898061752319  
 5     0.014750003814697   0.014961004257202  
 6     0.015435934066772   0.015391111373901  
 7     0.015177965164185   0.014806985855103  
 8     0.014681816101074   0.01552677154541   
 9     0.014717102050781   0.015773057937622  
 10    0.015694856643677   0.014908075332642  
----- ------------------- ------------------- 
 min   0.011713027954102   0.014806985855103  
 max   0.015694856643677   0.015773057937622  
 avg   0.014770030975342   0.015218615531921  
----- ------------------- ------------------- 
       winner              loser              
----- ------------------- ------------------- 

Количество итераций

По-умолчанию каждый колбэк проходит 10 итераций, но Вы можете задать своё количество вызывав метод iterations:

use DragonCode\RuntimeComparison\Comparator;

(new Comparator())
    ->iterations(5)
    ->compare(
        fn () => /* some code */,
        fn () => /* some code */,
    );

В случае если переданное значение будет меньше единицы, то скрипт будет использовать значение »1».

Пример результата выполнения

 ----- ------------------- ------------------- 
  #     0                   1                  
 ----- ------------------- ------------------- 
  1     0.011653184890747   0.01565408706665   
  2     0.015084981918335   0.015007972717285  
  3     0.015398025512695   0.014491081237793  
  4     0.015589952468872   0.015861034393311  
  5     0.014101028442383   0.015037059783936  
 ----- ------------------- ------------------- 
  min   0.011653184890747   0.014491081237793  
  max   0.015589952468872   0.015861034393311  
  avg   0.014365434646606   0.015210247039795  
 ----- ------------------- ------------------- 
        winner              loser              
 ----- ------------------- ------------------- 

Округление значений

По-умолчанию скрипт не округляет результаты замеров, но Вы можете указать количество символов после запятой, до которых может производиться округление:

use DragonCode\RuntimeComparison\Comparator;

(new Comparator())
    ->roundPrecision(4)
    ->compare(
        fn () => /* some code */,
        fn () => /* some code */,
    );

Пример результата выполнения

----- -------- -------- 
 #     0        1       
----- -------- -------- 
 1     0.0112   0.015   
 2     0.0147   0.0155  
 3     0.0153   0.0153  
 4     0.0157   0.015   
 5     0.0154   0.0158  
----- -------- -------- 
 min   0.0112   0.015   
 max   0.0157   0.0158  
 avg   0.0144   0.0153  
----- -------- -------- 
       winner   loser   
----- -------- -------- 

Вывод только итоговой информации

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

use DragonCode\RuntimeComparison\Comparator;

(new Comparator())
    ->withoutData()
    ->compare([
        'foo' => fn () => /* some code */,
        'bar' => fn () => /* some code */,
    ]);

Пример результата выполнения

 ----- ------------------- ------------------- 
  #     0                   1                  
 ----- ------------------- ------------------- 
  min   0.011653184890747   0.014491081237793  
  max   0.015589952468872   0.015861034393311  
  avg   0.014365434646606   0.015210247039795  
 ----- ------------------- ------------------- 
        winner              loser              
 ----- ------------------- -------------------

Расчёт победителей

Победители рассчитываются в следующем порядке:

  1. Если среди средних арифметических значений есть отличия, то победитель определяется по нему, иначе:

  2. Если среди максимальных значений есть отличия, то победитель определяется по нему, иначе:

  3. Если среди минимальных значений есть отличия, то победитель определяется по нему, иначе:

  4. Все элементы отмечаются победителями.

Заключение

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

© Habrahabr.ru