Подтвердить что ты не робот

Программы бенчмаркинга в Rust

Как можно тестировать программы в Rust? Например, как мне получить время выполнения программы за считанные секунды?

4b9b3361

Ответ 1

  Этот ответ устарел! Пожалуйста, ознакомьтесь с ответами ниже для получения актуальной информации.


Вы можете попробовать синхронизировать отдельные компоненты в программе, используя временной ящик.

Ответ 2

Возможно, стоит отметить 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

Ссылки:

Ответ 3

Если вы просто хотите рассчитать время выполнения кода, вы можете использовать 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));

Полный пример

Cargo.toml

[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 = "*"

rust.rs

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);
}

Ответ 4

Для измерения времени без добавления сторонних зависимостей вы можете использовать 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 в ваши собственные функции, чтобы их можно было написать в менее подробном виде. путь.

Ответ 5

Быстрый способ узнать время выполнения программы, независимо от языка реализации, - запустить time prog в командной строке. Например:

~$ time sleep 4

real    0m4.002s
user    0m0.000s
sys     0m0.000s

Самое интересное измерение обычно user, которое измеряет фактический объем работы, выполняемой программой, независимо от того, что происходит в системе (sleep - довольно скучная программа для тестирования). real измеряет фактическое время, прошедшее, и sys измеряет объем работы, выполняемой ОС от имени программы.

Ответ 6

В настоящее время нет интерфейса ни с одной из следующих функций 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 зависит от доступности отладочной информации в программе. Возможно, он не работает.

Ответ 7

Я создал для этого небольшой ящик (measure_time), который регистрирует или печатает время до конца области.

#[macro_use]
extern crate measure_time;
fn main() {
    print_time!("measure function");
    do_stuff();
}

Ответ 8

Есть несколько способов сравнить вашу программу 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 (только ночью)

В 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.
  • Повторите рабочую нагрузку: запускать рабочую нагрузку один раз почти всегда бесполезно. Есть много вещей, которые могут повлиять на ваше время: общая загрузка системы, выполнение операционной системы, регулирование ЦП, кеширование файловой системы и так далее. Поэтому повторяйте свою работу как можно чаще. Например, Criterion запускает все тесты в течение как минимум 5 секунд (даже если рабочая нагрузка занимает всего несколько наносекунд). Затем можно проанализировать все измеренные времена, при этом среднее и стандартное отклонение являются стандартными инструментами.
  • Убедитесь, что ваш тест не полностью удален.: тесты очень искусственные по своей природе. Обычно результат вашей рабочей нагрузки не проверяется, так как вы хотите только измерить продолжительность. Однако это означает, что хороший оптимизатор может удалить весь ваш тест, потому что у него нет побочных эффектов (ну, кроме времени). Таким образом, чтобы обмануть оптимизатор, вы должны каким-то образом использовать свое значение результата, чтобы ваша рабочая нагрузка не могла быть удалена. Самый простой способ - распечатать результат. Лучшее решение - что-то вроде black_box. Эта функция в основном скрывает значение от LLVM, так как LLVM не может знать, что произойдет со значением. Ничего не происходит, но LLVM не знает. В этом суть.

    Хорошие тестовые рамки используют блок-блок в нескольких ситуациях. Например, замыкание, данное методу iter (как для встроенного, так и для критерия Bencher), может возвращать значение. Это значение автоматически передается в black_box.

  • Остерегайтесь постоянных значений: аналогично приведенному выше пункту, если вы указываете постоянные значения в бенчмарке, оптимизатор может сгенерировать код специально для этого значения. В крайних случаях вся ваша рабочая нагрузка может быть постоянно объединена в одну константу, что означает, что ваш тест бесполезен. Пропустите все постоянные значения через black_box, чтобы избежать слишком агрессивной оптимизации LLVM.
  • Остерегайтесь накладных расходов на измерения: измерение длительности занимает само время. Обычно это только десятки наносекунд, но они могут влиять на ваши измеренные времена. Таким образом, для всех рабочих нагрузок, которые превышают несколько десятков наносекунд, вам не следует измерять каждое время выполнения индивидуально. Вы можете выполнить свою рабочую нагрузку 100 раз и измерить, сколько времени заняли все 100 выполнений. Разделив это на 100, вы получите среднее время. Упомянутые выше рамки сравнительного анализа также используют этот прием. Критерий также имеет несколько методов измерения очень коротких рабочих нагрузок, которые имеют побочные эффекты (например, что-то мутировав).
  • Многие другие вещи: к сожалению, я не могу перечислить все трудности здесь. Если вы хотите написать серьезные тесты, прочитайте больше онлайн-ресурсов.