Ответ 1
Этот ответ устарел! Пожалуйста, ознакомьтесь с ответами ниже для получения актуальной информации.
Вы можете попробовать синхронизировать отдельные компоненты в программе, используя временной ящик.
Как можно тестировать программы в Rust? Например, как мне получить время выполнения программы за считанные секунды?
Этот ответ устарел! Пожалуйста, ознакомьтесь с ответами ниже для получения актуальной информации.
Вы можете попробовать синхронизировать отдельные компоненты в программе, используя временной ящик.
Возможно, стоит отметить 2 года спустя (чтобы помочь будущим программистам Rust, которые наткнулись на эту страницу), что теперь есть инструменты для сравнения кода Rust как части одного набора тестов.
(Из приведенной ниже ссылки на руководство). Используя атрибут #[bench]
, можно использовать стандартный инструментарий Rust для сравнения методов в их коде.
extern crate test;
use test::Bencher;
#[bench]
fn bench_xor_1000_ints(b: &mut Bencher) {
b.iter(|| {
// use 'test::black_box' to prevent compiler optimizations from disregarding
// unused values
test::black_box(range(0u, 1000).fold(0, |old, new| old ^ new));
});
}
Для командного cargo bench
это выводит что-то вроде:
running 1 test
test bench_xor_1000_ints ... bench: 375 ns/iter (+/- 148)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
Ссылки:
Если вы просто хотите рассчитать время выполнения кода, вы можете использовать time
ящик. время тем временем устарело, хотя. Ящик для последующей проверки: chrono
.
Добавьте time = "*"
к Cargo.toml
.
Добавить
extern crate time;
use time::PreciseTime;
перед вашей основной функцией и
let start = PreciseTime::now();
// whatever you want to do
let end = PreciseTime::now();
println!("{} seconds for whatever you did.", start.to(end));
[package]
name = "hello_world" # the name of the package
version = "0.0.1" # the current version, obeying semver
authors = [ "[email protected]" ]
[[bin]]
name = "rust"
path = "rust.rs"
[dependencies]
rand = "*" # Or a specific version
time = "*"
extern crate rand;
extern crate time;
use rand::Rng;
use time::PreciseTime;
fn main() {
// Creates an array of 10000000 random integers in the range 0 - 1000000000
//let mut array: [i32; 10000000] = [0; 10000000];
let n = 10000000;
let mut array = Vec::new();
// Fill the array
let mut rng = rand::thread_rng();
for _ in 0..n {
//array[i] = rng.gen::<i32>();
array.push(rng.gen::<i32>());
}
// Sort
let start = PreciseTime::now();
array.sort();
let end = PreciseTime::now();
println!("{} seconds for sorting {} integers.", start.to(end), n);
}
Для измерения времени без добавления сторонних зависимостей вы можете использовать std::time::Instant
fn my_function() {
use std::time::Instant;
let now = Instant::now();
{
my_function_to_measure();
}
let elapsed = now.elapsed();
let sec = (elapsed.as_secs() as f64) + (elapsed.subsec_nanos() as f64 / 1000_000_000.0);
println!("Seconds: {}", sec);
}
fn main() {
my_function();
}
Конечно, если вы делаете это часто, вы захотите обобщить преобразование, или использовать ящик, который предоставляет утилиты для этого, или оберните Instant
и Duration
в ваши собственные функции, чтобы их можно было написать в менее подробном виде. путь.
Быстрый способ узнать время выполнения программы, независимо от языка реализации, - запустить time prog
в командной строке. Например:
~$ time sleep 4
real 0m4.002s
user 0m0.000s
sys 0m0.000s
Самое интересное измерение обычно user
, которое измеряет фактический объем работы, выполняемой программой, независимо от того, что происходит в системе (sleep
- довольно скучная программа для тестирования). real
измеряет фактическое время, прошедшее, и sys
измеряет объем работы, выполняемой ОС от имени программы.
В настоящее время нет интерфейса ни с одной из следующих функций Linux:
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)
getrusage
times
(manpage: man 2 times
)Доступные способы измерения времени процессора и горячих точек программы Rust на Linux:
/usr/bin/time program
perf stat program
perf record --freq 100000 program; perf report
valgrind --tool=callgrind program; kcachegrind callgrind.out.*
Вывод perf report
и valgrind
зависит от доступности отладочной информации в программе. Возможно, он не работает.
Я создал для этого небольшой ящик (measure_time), который регистрирует или печатает время до конца области.
#[macro_use]
extern crate measure_time;
fn main() {
print_time!("measure function");
do_stuff();
}
Есть несколько способов сравнить вашу программу Rust. Для большинства реальных эталонных тестов вы должны использовать правильную структуру эталонных тестов, так как они помогают с несколькими вещами, которые легко испортить (включая статистический анализ). Читайте также раздел "Почему писать тесты сложно" в самом низу!
Instant
и Duration
из стандартной библиотекиЧтобы быстро проверить, как долго выполняется фрагмент кода, вы можете использовать типы в std::time
. Модуль довольно минимальный, но он подходит для простых измерений времени. Вы должны использовать Instant
вместо SystemTime
, так как первые - это монотонно увеличивающиеся часы, а вторые - нет. Пример (Детская площадка):
use std::time::Instant;
let before = Instant::now();
workload();
println!("Elapsed time: {:.2?}", before.elapsed());
Точность std Instant
, к сожалению, не указана в документации, но во всех основных операционных системах она использует наилучшую точность, которую может обеспечить платформа (обычно она составляет около 20 нс).
Если std::time
не предлагает достаточно функций для вашего случая, вы можете взглянуть на chrono
. Однако для измерения длительности вряд ли вам понадобится этот внешний ящик.
Использование фреймворков часто является хорошей идеей, потому что они пытаются предотвратить определенные ошибки.
В Rust есть удобная встроенная функция бенчмаркинга, которая, к сожалению, все еще нестабильна на 2019-07 годы. Вы должны добавить атрибут #[bench]
к вашей функции и заставить его принять один аргумент &mut test::Bencher
:
#![feature(test)]
extern crate test;
use test::Bencher;
#[bench]
fn bench_workload(b: &mut Bencher) {
b.iter(|| workload());
}
Выполнение cargo bench
напечатает:
running 1 test
test bench_workload ... bench: 78,534 ns/iter (+/- 3,606)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out
Ящик criterion
- это фреймворк, работающий на стабильной основе, но он немного сложнее, чем встроенное решение. Он выполняет более сложный статистический анализ, предлагает более богатый API, производит больше информации и может даже автоматически генерировать графики.
Подробнее о том, как использовать критерий, см. в разделе "Быстрый запуск".
Есть много подводных камней при написании тестов. Одна ошибка может сделать ваши результаты тестов бессмысленными. Вот список распространенных ошибок:
rustc -O3
или cargo build --release
. Когда вы выполняете свои тесты с помощью cargo bench
, Cargo автоматически включает оптимизацию. Этот шаг важен, поскольку часто существует большая разница в производительности между оптимизированным и неоптимизированным кодом Rust.Убедитесь, что ваш тест не полностью удален.: тесты очень искусственные по своей природе. Обычно результат вашей рабочей нагрузки не проверяется, так как вы хотите только измерить продолжительность. Однако это означает, что хороший оптимизатор может удалить весь ваш тест, потому что у него нет побочных эффектов (ну, кроме времени). Таким образом, чтобы обмануть оптимизатор, вы должны каким-то образом использовать свое значение результата, чтобы ваша рабочая нагрузка не могла быть удалена. Самый простой способ - распечатать результат. Лучшее решение - что-то вроде black_box
. Эта функция в основном скрывает значение от LLVM, так как LLVM не может знать, что произойдет со значением. Ничего не происходит, но LLVM не знает. В этом суть.
Хорошие тестовые рамки используют блок-блок в нескольких ситуациях. Например, замыкание, данное методу iter
(как для встроенного, так и для критерия Bencher
), может возвращать значение. Это значение автоматически передается в black_box
.
black_box
, чтобы избежать слишком агрессивной оптимизации LLVM.