@TicSo

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

В приведенном коде создал тестовый пример обработки массива vec01.
Задавая количество повторов такой обработки смотрю на время выполнения.
Не понимаю, почему бывает расхождение более чем в три раза, например,
time_min = 41200 time_max = 145000.
Комп 6 ядер 12 потоков ничем не нагружен. Если не накосячил с кодом, а так
захватывается периодически ресурс потоков компа, то как такое решить
и получать расхождение в пределах 20%?
код

use rand::Rng;
use std::time::Instant;

fn main() {
   //
   const RING: usize = 300;                   // задаём кол-во повторов 
   const ELEM: usize = 1000;                  // кол-во елементов vec_01
   //
   let mut vec_01: Vec<u8> = vec![];
   //
   let mut i: usize = 0;
   loop {
      if i == ELEM {break};
      let mut rng = rand::thread_rng();
      let n: u8 = rng.gen();
      vec_01.push(n);
      i = i + 1;
   }   
   i = 0; // ^_ заполнил массив `vec_01` произвольными элементами типа u8.
   //   
   let len_01: usize = vec_01.len();
   //
   let mut count_chet: usize = 0; 
   let mut count_nech: usize = 0; 
   let mut j: usize = 0;
   //
   let mut vec_chet: Vec<u8> = Vec::with_capacity(len_01 * RING);
   let mut vec_nech: Vec<u8> = Vec::with_capacity(len_01 * RING);
   let mut t01: u64 = 0;   
   let mut t02: u64 = 10_000_000_000;   // задал заведомо бОльшее значение (моё дефолтное);
   //
   loop {
      if j == RING {break};
      let start = Instant::now();                                                            // момент начала измерения выполнения кода;
      //
      loop {
         if i == len_01 {break};
         if vec_01[i] % 2 == 0 {
            vec_chet.push(vec_01[i]);
            count_chet = count_chet + 1;
         }else{
            vec_nech.push(vec_01[i]);
            count_nech = count_nech + 1;
         }
         i = i + 1;
      }
      //
      i = 0;
   //
   j = j + 1;
   let duration = start.elapsed();
   // println!("{:?}. время выполнения цикла = {:?} наносек. = {:?}", j, duration, duration.subsec_nanos() as u64);
   //
   if (duration.subsec_nanos() as u64) > t01 {
      t01 = duration.subsec_nanos() as u64;
   }
   if (duration.subsec_nanos() as u64) < t02 {
      t02 = duration.subsec_nanos() as u64;
   }
   //
   }
   //
   println!("кол-во элементов массива `vec_01`, которые обрабатываю в цикле = {:?}", len_01);
   println!("кол-во повторов = {:?}", RING);
   println!("count_chet = {:?}", count_chet);
   println!("count_nech = {:?}\n", count_nech);
   println!("time_min = {:?} time_max = {:?}", t02, t01);
}


_play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=537d0482efc78c4a05a2174015c2291c
статистика времени выполнения

кол-во элементов массива `vec_01`, которые обрабатываю в цикле = 1000
кол-во повторов = 300
count_chet = 154500
count_nech = 145500
time_min = 31400 time_max = 36800

кол-во элементов массива `vec_01`, которые обрабатываю в цикле = 1000
кол-во повторов = 300
count_chet = 150600
count_nech = 149400
time_min = 74000 time_max = 198600

кол-во элементов массива `vec_01`, которые обрабатываю в цикле = 1000
кол-во повторов = 300
count_chet = 139200
count_nech = 160800
time_min = 41200 time_max = 145000

кол-во элементов массива `vec_01`, которые обрабатываю в цикле = 1000
кол-во повторов = 300
count_chet = 152100
count_nech = 147900
time_min = 45700 time_max = 70400
  • Вопрос задан
  • 133 просмотра
Пригласить эксперта
Ответы на вопрос 3
vabka
@vabka Куратор тега Rust
Не скажу ничего про алгоритм и корректность замеров, но время t01 и t02 ты точно измеряешь неправильно

subsec_nanos
Returns the fractional part of this Duration, in nanoseconds.

This method does not return the length of the duration when represented by nanoseconds. The returned number always represents a fractional portion of a second (i.e., it is less than one billion).
https://doc.rust-lang.org/std/time/struct.Duration...

У структуры Duration есть операторы для сравнения, так что тебе не обязательно знать конкретное число, пока ты не выводишь его в консоль

let mut t01 = Duration::MIN;
let mut t02 = Duration::MAX;
if duration> t01 {
      t01 = duration; // здесь
   }
   if duration< t02 {
      t02 = duration; // и здесь
   }


UPD:


Комп 6 ядер 12 потоков ничем не нагружен. Если не накосячил с кодом, а так
захватывается периодически ресурс потоков компа, то как такое решить
и получать расхождение в пределах 20%?

1. Такой разброс, как у тебя показан - это норма. Нужно смотреть не на минимум/максимум, а на распределение (в комментах скинул график - там тоже минимум и максимум сильно различаются, но прогонов с таким временем мало)
2. Я не увидел в вопросе описания того, как происходит запуск. Хотябы в --release компилировал?
3. У тебя данные вполне статичные, так что компилятор при желании мог очень много наоптимизировать, что даст тебе некорректные результаты, но на распределение это влиять не должно.
Ответ написан
@historydev
Валера, настало твоё время
Возможно OC выдала вторичный поток - частично лечится повышением приоритета процесса или выставлением определённого ядра, например через process lasso.

Лучше создай массив вне цикла для хранения времени каждой итерации цикла и записывай туда, желательно не в куче [f32; N].

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

А сейчас ты записываешь лишь последний результат.

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

И учти коммент: mayton2019
Сейчас ты меряешь какой-то случайный процесс который в общей своей массе длиннее
чем твой изучаемый алгоритм.
Ответ написан
@TicSo Автор вопроса
2. Я не увидел в вопросе описания того, как происходит запуск. Хотябы в --release компилировал?

спасибо за помощь разобраться
да, > cargo run --release
в отличие от debug даёт общее ускорение выполнения, но между повторами сохраняется иногда двукратное расхождение времени выполнения, например для массива на 10к элементов и 30 повторов:
10к/30
кол-во элементов массива `vec_01`, которые обрабатываю в цикле = 10000
кол-во повторов = 30
count_chet = 151950
count_nech = 148050
time_min = 59600 time_max = 110500


При значительном увеличении кол-ва элементов в массиве, например, до 10кк:
10кк/30
кол-во элементов массива `vec_01`, которые обрабатываю в цикле = 10000000
кол-во повторов = 30
count_chet = 150007770
count_nech = 149992230
time_min = 44812400 time_max = 88239600
-
кол-во элементов массива `vec_01`, которые обрабатываю в цикле = 10000000
кол-во повторов = 30
count_chet = 149946630
count_nech = 150053370
time_min = 45137500 time_max = 89361300

вот гуляет время от 45 ms до 89 ms на одинаковых условиях и наборе данных и думаю, что это не нормально (случайные служебные процессы), а косяк кода. Поэтому задал вопрос.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы