I've been comparing the performance of simple methods to access an array and came across something weird. The performance of the iterator-, while-unchecked, for-unchecked,slice-iter-methods is the same for the standard step of one. However, when I use a skip of 4. The iterator method falls behind the slice iterator method and the get_unchecked method with a for loop falls behind its while-loop counterpart. Why is this so?? (compiled in release mode)
To clarify: The program builds a vector of the given size and iterates over it - switching entries with the number of repetitions.
Here are my results:
Enter length:
1000000
Enter repetitions:
1000
Index:
Average time: 325.859µs, Best time: 286.5µs
Unchecked with range:
Average time: 355.375µs, Best time: 311.4µs
Get with range:
Average time: 400.481µs, Best time: 358µs
Unchecked with while:
Average time: 135.6µs, Best time: 116.1µs
Iterator:
Average time: 227.038µs, Best time: 199.8µs
Slice:
Average time: 145.709µs, Best time: 115.2µs
Press enter to exist...
And the code:
use std::io;
use std::time::{Duration, Instant};
fn main() {
println!("Enter length:");
let mut inp = String::new();
io::stdin().read_line(&mut inp);
let len = inp.trim().parse().unwrap();
let mut test = vec![0; len];
println!("Enter repetitions:");
inp.clear();
io::stdin().read_line(&mut inp);
let num = inp.trim().parse().unwrap();
{
println!("Index:");
test.iter_mut().for_each(|x| { *x = 0 });
let mut times = Vec::new();
for _ in 0..num {
let start = Instant::now();
{
for idx in (0..len).step_by(4) {
test[idx] = num;
}
}
times.push(start.elapsed());
}
let mut median: Duration = times.iter().sum();
median /= times.len() as u32;
let best = *times.iter().min().unwrap();
println!("Average time: {:?}, Best time: {:?}", median, best);
}
{
println!("Unchecked with range:");
test.iter_mut().for_each(|x| { *x = 0 });
let mut times = Vec::new();
for _ in 0..num {
let start = Instant::now();
{
for idx in (0..len).step_by(4) {
unsafe {
*test.get_unchecked_mut(idx) = num;
}
}
}
times.push(start.elapsed());
}
let mut median: Duration = times.iter().sum();
median /= times.len() as u32;
let best = *times.iter().min().unwrap();
println!("Average time: {:?}, Best time: {:?}", median, best);
}
{
println!("Get with range:");
test.iter_mut().for_each(|x| { *x = 0 });
let mut times = Vec::new();
for _ in 0..num {
let start = Instant::now();
{
for idx in (0..len).step_by(4) {
if let Some(item) = test.get_mut(idx) {
*item = num;
}
}
}
times.push(start.elapsed());
}
let mut median: Duration = times.iter().sum();
median /= times.len() as u32;
let best = *times.iter().min().unwrap();
println!("Average time: {:?}, Best time: {:?}", median, best);
}
{
println!("Unchecked with while:");
test.iter_mut().for_each(|x| { *x = 0 });
let mut times = Vec::new();
for _ in 0..num {
let start = Instant::now();
{
let mut idx = 0;
while idx < len {
unsafe {
*test.get_unchecked_mut(idx) = num;
}
idx += 4;
}
}
times.push(start.elapsed());
}
let mut median: Duration = times.iter().sum();
median /= times.len() as u32;
let best = *times.iter().min().unwrap();
println!("Average time: {:?}, Best time: {:?}", median, best);
}
{
println!("Iterator:");
test.iter_mut().for_each(|x| { *x = 0 });
let mut times = Vec::new();
for _ in 0..num {
let start = Instant::now();
{
for item in test.iter_mut().step_by(4) {
*item = num;
}
}
times.push(start.elapsed());
}
let mut median: Duration = times.iter().sum();
median /= times.len() as u32;
let best = *times.iter().min().unwrap();
println!("Average time: {:?}, Best time: {:?}", median, best);
}
{
println!("Slice:");
test.iter_mut().for_each(|x| { *x = 0 });
let mut times = Vec::new();
for _ in 0..num {
let start = Instant::now();
{
test[..].iter_mut().step_by(4).for_each(|item| {
*item = num;
});
}
times.push(start.elapsed());
}
let mut median: Duration = times.iter().sum();
median /= times.len() as u32;
let best = *times.iter().min().unwrap();
println!("Average time: {:?}, Best time: {:?}", median, best);
}
println!("Press enter to exist...");
io::stdin().read_line(&mut String::new()).unwrap();
}