Як виміряти середній час виконання сценарію?


23

У мене є два сценарії, які кожен обчислює факторіал числа. Я хотів би знати, що швидше. timeКоманда дає мені мілісекунди і результат відрізняється час від часу:

piousbox@piousbox-laptop:~/projects/trash$ time ruby fac2.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.089s
user    0m0.052s
sys 0m0.028s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac1.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.091s
user    0m0.048s
sys 0m0.036s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac1.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.088s
user    0m0.048s
sys 0m0.040s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac2.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.088s
user    0m0.048s
sys 0m0.028s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac1.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.087s
user    0m0.064s
sys 0m0.028s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac2.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.089s
user    0m0.068s
sys 0m0.016s
piousbox@piousbox-laptop:~/projects/trash$ 

Як мені взяти середній час, необхідний для запуску сценарію? Я міг би проаналізувати та оцінити вихід 100 time-х, але я думаю, що є краще рішення?


Відповіді:


4

Ні, ваше уявлення про усереднення є правильним.

Виконання сценарію залежить від безлічі факторів, однак його слід розділити між часом установки (завантаження інтерпретатора в пам'яті, налаштування та, можливо, компіляція коду до байт-коду або машинного коду) та справжнім часом виконання.

Щоб краще зосередитись на внутрішньому часі виконання, ви робите цикл у самому скрипті (тобто замість того, щоб обчислити один факториал, ви обчислите його 100 разів за одне виконання сценарію. Сценарій буде встановлений один раз, а внутрішній режим виконає 100 разів).

Щоб зосередитись на загальному часі, ви виконаєте сценарій сто разів і середньо оцініть результати. В ідеалі вам слід розділити ці виконання достатньо, щоб система щоразу поверталася у "еталонний стан" (або не пов'язаний зі сценарієм). Наприклад, сам інтерпретатор буде кешований в пам'яті, так що саме перше виконання сценарію буде помітно повільніше, ніж наступні.

Щоб краще зрозуміти алгоритм, я вважаю, що найкращий спосіб - це щось подібне (на машині, що працює в режимі очікування):

  • оберніть алгоритм в одну єдину функцію.
  • у контрольній програмі:
    • викликати функцію один раз
    • отримайте системний ("настінний годинник") час і додайте 10 (або розумних N) секунд
    • введіть цикл і починайте рахувати ітерації
    • після кожного дзвінка до функції збільшуйте лічильник
    • якщо системний час нижче збереженого часу, зробіть інший цикл
    • отримати точний N, можливо плаваючу точку, від поточного часу настінного годинника
    • відобразити лічильник, розділений на N: це кількість ітерацій / секунди.

Додаток запускається лише один раз, усі налаштування та грунтовка виконуються за допомогою першої необмеженої ітерації, тому це повинно мінімізувати накладні витрати (за винятком, можливо, для виклику часу).

Якщо функція отримує вхід, ви б добре поставити їй випадкову послідовність входів, використовуючи PRNG, засіяний фіксованим значенням, щоб гарантувати, що обидві версії тестованої функції отримують однакові значення. Це дозволяє уникнути виконання однієї функції, мабуть, кращою завдяки «щасливим числам» (наприклад, я пам’ятаю варіацію алгоритму Гіллсорта, яка виконувалась помірно краще, якщо кількість елементів для сортування була у формі 2 k -1 з малим k s).


Правильно, дякую. Я помітив, що наступні дзвінки десь скорочуються. Я запускаю цикл всередині сценаріїв і виявив, що один алгоритм, безумовно, швидший, ніж інший.
Віктор Піубокс

39

Ви можете запускати ітерації програми в циклі; і розділити загальний час на кількість ітерацій:

time for i in {1..10}; do sleep 1; done
real    0m10.052s
user    0m0.005s
sys 0m0.018s

2
Супер просто, люблю це. Я також ніколи {1..10}раніше не бачив, і я здивований, що це працює, не можу знайти його в посібнику по баш. Сумно лише те, що ви не знаєте поширення своїх результатів (мінімум та максимум часу).
w00t

@ w00t:man -P 'less +/Brace\ Expansion' bash
user2683246

Дякуємо @ user2683246! Потім я також виявив це на gnu.org/software/bash/manual/bash.html#Brace-Expansion - приємне використання меншої кількості btw. Тепер мені також цікаво, коли це з'явилося в
басі

1
Ага, версія 3, через 10 років після того, як я почав використовувати bash :) tldp.org/LDP/abs/html/bashver3.html
w00t

2
Якщо це не працює для приїзду Googlers, це може бути тому, що ви не працюєте bash. Спробуйте запустити /bin/bashперед цим.
Cory Klein

14

є інструмент під назвою мультиморф, який робить саме це: запускає команду кілька разів, вимірює, скільки часу потрібно (реальний / користувач / система із середнім, мінімальним / макс та середнім часом автоматично обчислюється)

Наприклад, для вимірювання подібного сценарію 100 разів:

multitime -q -n 100 "fact1.sh"
===> multitime results
1: -q fact1.sh
            Mean        Std.Dev.    Min         Median      Max
real        0.122       0.032       0.086       0.116       0.171       
user        0.148       0.044       0.096       0.137       0.223       
sys         0.023       0.019       0.000       0.014       0.061 

12

Це старе, але воно вийшло так високо в google, коли я шукав команду, яку раніше використовував, але не зміг знайти. У будь-якому випадку, мій кращий спосіб зробити це:

perf stat -r 10 -B sleep 1

Це дає досить багато деталей, включаючи середній час виконання в кінці:

1.002248382 seconds time elapsed                   ( +-  0.01% )


1

Hyperfine - це ще один варіант.

Використання зразка:

hyperfine --warmup 3 'ruby fac1.rb'

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