hyperfine — это инструмент для тестирования производительности из командной строки, который многократно запускает ваши команды, собирает данные о времени выполнения за несколько прогонов и предоставляет статистически достоверные результаты с указанием среднего значения, минимума, максимума и стандартного отклонения, что делает его гораздо более точным, чем однократное измерение времени.
Я всегда измерял время выполнения команд с помощью команды time, и она обманывала — не потому, что time не работает, а потому, что однократный запуск фиксирует только один момент времени, который может резко повышаться или понижаться в зависимости от состояния кэша, загрузки ЦП или планирования ядра.
Если вы выбираете между двумя скриптами, двумя инструментами сжатия или двумя запросами к базе данных, вам нужна средняя величина по десяткам запусков, а не одно удачное измерение.
hyperfine решает эту проблему, запуская каждую команду настраиваемое количество раз, отбрасывая прогоны «разогрева» и предоставляя вам надёжную статистику.
Инструмент hyperfine протестирован на Ubuntu и Rocky Linux, но он работает на любом современном дистрибутиве Linux, который поддерживает установку через пакетный менеджер или бинарный файл из репозитория github.
Установка hyperfine в Linux
Чтобы установить hyperfine в Linux, используйте следующую команду, соответствующую вашему конкретному дистрибутиву Linux.
sudo apt install hyperfine [On Debian, Ubuntu and Mint] sudo dnf install hyperfine [On RHEL/CentOS/Fedora and Rocky/AlmaLinux] sudo apk add hyperfine [On Alpine Linux] sudo pacman -S hyperfine [On Arch Linux] sudo zypper install hyperfine [On OpenSUSE] sudo pkg install hyperfine [On FreeBSD]
В других дистрибутивах Linux, если пакета нет в репозиториях по умолчанию, загрузите последнюю версию бинарного файла с GitHub:
wget https://github.com/sharkdp/hyperfine/releases/download/v1.20.0/hyperfine-v1.20.0-x86_64-unknown-linux-musl.tar.gz tar xzf hyperfine-v1.20.0-x86_64-unknown-linux-musl.tar.gz sudo mv hyperfine-v1.20.0-x86_64-unknown-linux-musl/hyperfine /usr/local/bin/
Проверьте установку во всех дистрибутивах с помощью:
hyperfine --version
В простейшем варианте ваша команда помещается в кавычки после hyperfine:
hyperfine 'command to benchmark'
По умолчанию hyperfine выполняет не менее 10 итераций с измерением времени и 3 прогона для прогрева перед подсчетом результатов. Прогоны для прогрева позволяют кэшу файловой системы стабилизироваться, чтобы аномалии холодного кэша не искажали ваши результаты.
Пример 1: Тестирование производительности одной команды
Измерьте, сколько времени занимает у команды find Сканирование вашего домашнего каталога на наличие .log файлов.
hyperfine 'find ~ -name "*.log"'
Вывод:
Benchmark 1: find ~ -name "*.log" Time (mean ± σ): 143.2 ms ± 8.4 ms [User: 62.1 ms, Sys: 80.7 ms] Range (min … max): 133.5 ms … 161.3 ms 10 runs
Вывод показывает среднее время (143,2 мс), стандартное отклонение (σ = 8.4ms, которое указывает на степень стабильности результатов) и полный диапазон. Высокое значение σ по отношению к среднему означает, что на результаты влияют внешние факторы, что само по себе является полезным сигналом.
Пример 2: Сравнение двух команд
Именно здесь hyperfine показывает свою полезность: он может сравнить команду grep с ripgrep при поиске строки в каталоге, заполненном файлами журналов.
hyperfine 'grep -r "error" /var/log/' 'rg "error" /var/log/'
Вывод:
Benchmark 1: grep -r "error" /var/log/ Time (mean ± σ): 1.243 s ± 0.051 s [User: 0.891 s, Sys: 0.351 s] Range (min … max): 1.181 s … 1.334 s 10 runs Benchmark 2: rg "error" /var/log/ Time (mean ± σ): 189.4 ms ± 12.3 ms [User: 312.1 ms, Sys: 98.7 ms] Range (min … max): 173.2 ms … 217.6 ms 10 runs Summary rg "error" /var/log/ ran 6.56 ± 0.58 times faster than grep -r "error" /var/log/
Строка Summary внизу вычисляет соотношение за вас. Это соотношение 6,56x — цифра, которую вы можете использовать в обсуждении с командой или в pull-запросе.
Пример 3: Управление количеством запусков с помощью –runs
Для медленных команд, таких как дампы баз данных или сжатие больших файлов, 10 запусков — это перебор, поэтому используйте --runs, чтобы установить меньшее количество.
hyperfine --runs 5 'tar -czf /tmp/backup.tar.gz /var/www/html'
Вывод:
Benchmark 1: tar -czf /tmp/backup.tar.gz /var/www/html Time (mean ± σ): 4.312 s ± 0.198 s [User: 3.891 s, Sys: 0.421 s] Range (min … max): 4.073 s … 4.591 s 5 runs
Для очень быстрых команд, которые завершаются за миллисекунды, поступите наоборот и увеличьте количество запусков до 50 или 100, чтобы статистика стабилизировалась. Один миллисекундный шум имеет большое значение, когда ваше среднее значение составляет 5 мс.
Пример 4: Запуски для прогрева с помощью –warmup
Если ваша команда читает с диска и вы хотите протестировать производительность с «горячим» кэшем (насколько быстро она работает после того, как ОС кэшировала данные), увеличьте количество прогонов для прогрева.
hyperfine --warmup 5 'wc -l /var/log/syslog'
Вывод:
Benchmark 1: wc -l /var/log/syslog Time (mean ± σ): 4.7 ms ± 0.6 ms [User: 2.1 ms, Sys: 2.5 ms] Range (min … max): 3.8 ms … 5.9 ms 10 runs
Если же вы тестируете производительность с «холодным» кэшем, применяется обратный подход: запустите:
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
Перед каждым тестом, чтобы очистить файловый кэш ОС. Это даст более реалистичную картину того, что происходит при свежей загрузке или на сервере, который не обращался к этому файлу в последнее время.
Пример 5: Экспорт результатов в JSON
Когда вы сравниваете несколько инструментов в рамках скрипта или конвейера CI, простого вывода в терминал недостаточно, поэтому экспортируйте результаты в JSON с помощью --export-json и передавайте их далее по конвейеру.
hyperfine --export-json results.json 'gzip -k testfile.bin' 'zstd -k testfile.bin'
Вывод:
Benchmark 1: gzip -k testfile.bin Time (mean ± σ): 621.4 ms ± 18.3 ms [User: 611.2 ms, Sys: 9.9 ms] Range (min … max): 598.3 ms … 651.7 ms 10 runs Benchmark 2: zstd -k testfile.bin Time (mean ± σ): 87.6 ms ± 4.1 ms [User: 77.3 ms, Sys: 10.1 ms] Range (min … max): 81.2 ms … 95.4 ms 10 runs
Файл results.json содержит время выполнения каждого отдельного запуска наряду с сводной статистикой, что означает, что вы можете строить графики распределений, отслеживать регрессии между релизами или передавать данные в дашборд. Флаг --export-markdown предоставляет вам отформатированную таблицу, которую можно вставить прямо в задачи GitHub или документацию.
Наиболее полезные флаги hyperfine
Ниже приведены наиболее полезные флаги hyperfine.
--runs <N>устанавливает точное количество итераций с измерением времени.--warmup <N>задает количество прогонов, которые будут выполнены до начала измерения времени.--export-json <file>сохраняет полные результаты в формате JSON.--export-markdown <file>сохраняет результаты в виде таблицы markdown.--prepare <cmd>запускает команду настройки перед каждой итерацией теста, что полезно для сброса состояния.--shell noneотключает оболочку для тестов необработанных двоичных файлов, что исключает время запуска оболочки из измерений.--ignore-failureпродолжает тестирование, даже если команда возвращает ненулевой код завершения.
Заключение
Вы увидели, как hyperfine выходит за рамки измерения времени одного запуска, собирая статистику по нескольким итерациям, запуская прогоны для прогрева, чтобы нормализовать состояние кэша, сравнивая команды бок о бок с чётким сводным соотношением и экспортируя результаты в машиночитаемые форматы для автоматизации.
Конкретное задание, которое можно выполнить прямо сейчас: выберите 2 команды, которые вы уже регулярно запускаете, например, два способа сжатия резервных копий или два метода поиска в логах, и запустите:
hyperfine cmd1 cmd2
на реальных данных из вашей системы. Соотношение в строке Summary даст вам конкретную информацию, на основе которой вы сможете принять меры.
Комментарии (2)