some more careful caching prevention

This commit is contained in:
Florian Stecker 2024-02-23 01:04:49 -05:00
parent 874caff8b6
commit feadef4723
2 changed files with 66 additions and 64 deletions

View File

@ -1,90 +1,112 @@
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use rand::random; use rand::{Rng, thread_rng, random};
fn main() { fn main() {
for i in 1..400 { // generate 800MB of random data
let result = test_searches(500000 / i, i*2); let mut data: Vec<u64> = vec![0; 100*1024*1024];
println!("{} {} {}", thread_rng().fill(&mut data[..]);
result[0].as_nanos(), result[1].as_nanos(), result[2].as_nanos());
let mut metadata: Vec<(usize, usize)> = Vec::new();
let mut all_times: Vec<Vec<(u128, u128, u128)>> = Vec::new();
for run in 0..4 {
let mut run_times: Vec<(u128, u128, u128)> = Vec::with_capacity(200);
for i in 0..200 {
let runs = 10000000 / (i+1);
let items = (i+1)*2;
let result = test_searches(&data, runs, items);
if run == 0 {
metadata.push((runs, items));
}
run_times.push((result[0].as_nanos(), result[1].as_nanos(), result[2].as_nanos()));
}
all_times.push(run_times);
}
for i in 0..metadata.len() {
println!("{} {} {} {} {}",
metadata[i].0, metadata[i].1,
all_times.iter().map(|x|x[i].0).sum::<u128>(),
all_times.iter().map(|x|x[i].1).sum::<u128>(),
all_times.iter().map(|x|x[i].2).sum::<u128>());
} }
} }
fn test_searches(runs: usize, items: usize) -> Vec<Duration> { fn test_searches(data: &[u64], runs: usize, items: usize) -> Vec<Duration> {
let mut lists: Vec<Vec<u64>> = Vec::new(); let needle_offset = random::<u64>();
let mut needles: Vec<u64> = Vec::new(); // let offset_offset = random::<usize>();
let offset_offset = items;
for _ in 0..runs {
let mut current_list: Vec<u64> = Vec::new();
for _ in 0..items {
current_list.push(random::<u64>());
}
needles.push(current_list[0]);
current_list.sort();
lists.push(current_list);
}
flush_caches(); flush_caches();
let start_time = Instant::now(); let start_time = Instant::now();
for i in 0..runs { for i in 0..runs {
search_linear_functional(&lists[i], needles[i]); let offset = usize::wrapping_mul(i+1, offset_offset) % (data.len() - items);
let needle = u64::wrapping_mul((i+1) as u64, needle_offset);
search_linear_iter(&data[offset..offset+items], needle);
} }
let linear_functional_duration = Instant::now().duration_since(start_time); let linear_iter_duration = Instant::now().duration_since(start_time);
flush_caches(); flush_caches();
let start_time = Instant::now(); let start_time = Instant::now();
for i in 0..runs { for i in 0..runs {
search_linear_naive(&lists[i], needles[i]); let offset = usize::wrapping_mul(i+1, offset_offset) % (data.len() - items);
let needle = u64::wrapping_mul((i+1) as u64, needle_offset);
search_linear_loop(&data[offset..offset+items], needle);
} }
let linear_naive_duration = Instant::now().duration_since(start_time); let linear_loop_duration = Instant::now().duration_since(start_time);
flush_caches(); flush_caches();
let start_time = Instant::now(); let start_time = Instant::now();
for i in 0..runs { for i in 0..runs {
search_binary(&lists[i], needles[i]); let offset = usize::wrapping_mul(i+1, offset_offset) % (data.len() - items);
let needle = u64::wrapping_mul((i+1) as u64, needle_offset);
search_binary(&data[offset..offset+items], needle);
} }
let binary_duration = Instant::now().duration_since(start_time); let binary_duration = Instant::now().duration_since(start_time);
eprintln!("Tested {} runs of {} items each", runs, items); eprintln!("Tested {} runs of {} items each", runs, items);
vec![linear_functional_duration, linear_naive_duration, binary_duration] vec![linear_iter_duration, linear_loop_duration, binary_duration]
} }
fn flush_caches() { fn flush_caches() {
let mut rnd: Vec<u64> = Vec::new(); let mut data: Vec<u64> = vec![0; 1024*1024];
thread_rng().fill(&mut data[..]);
for _ in 0..10*1024*1024 { for i in 0..data.len() {
rnd.push(random::<u64>()); if data[i] == i as u64 {
}
for i in 0..10*1024*1024 {
if rnd[i] == i as u64 {
eprintln!("that's a strange coincidence!"); eprintln!("that's a strange coincidence!");
} }
} }
} }
fn search_binary(haystack: &[u64], needle: u64) { fn search_binary(haystack: &[u64], needle: u64) {
let index = haystack.binary_search(&needle).unwrap(); let index = haystack.binary_search(&needle).unwrap_or_else(|x|x);
if index as u64 == needle { if index as u64 == needle {
eprintln!("that's a strange coincidence!"); eprintln!("that's a strange coincidence!");
} }
} }
fn search_linear_functional(haystack: &[u64], needle: u64) { fn search_linear_iter(haystack: &[u64], needle: u64) {
let index = haystack.iter().enumerate().skip_while(|(_,x)|**x != needle).next().unwrap().0; let index = haystack.iter()
.enumerate()
.skip_while(|(_,x)|**x != needle)
.next()
.map(|x|x.0)
.unwrap_or_else(||haystack.len());
if index as u64 == needle { if index as u64 == needle {
eprintln!("that's a strange coincidence!"); eprintln!("that's a strange coincidence!");
} }
} }
fn search_linear_naive(haystack: &[u64], needle: u64) { fn search_linear_loop(haystack: &[u64], needle: u64) {
let mut index = 0; let mut index = 0;
for i in 0..haystack.len() { for i in 0..haystack.len() {
if haystack[i] == needle { if haystack[i] == needle {

View File

@ -1,35 +1,15 @@
set log x set log x
set log y set log y
set xrange [1:1000] set xrange [1:1000]
set yrange [1:1000] set yrange [1:3000]
set grid set grid
set terminal pngcairo size 1024, 1024 set terminal pngcairo size 1024, 1024
set output "times.png" set output "times.png"
# plot "data_new" using (($0+1)*2):($1*1.0/(500000/($0+1))) w l lw 2 lc 1 t "linear, iterator", \ plot "data_c8" using 2:($3/$1/4) w l lw 2 t "linear, iterator, consecutive", \
# "data_new" using (($0+1)*2):($2*1.0/(500000/($0+1))) w l lw 2 lc 2 t "linear, for loop", \ "" using 2:($4/$1/4) w l lw 2 t "linear, loop, consecutive", \
# "data_new" using (($0+1)*2):($3*1.0/(500000/($0+1))) w l lw 2 lc 3 t "binary", \ "" using 2:($5/$1/4) w l lw 2 t "binary, consecutive", \
# "data_new2" using (($0+1)*2):($1*1.0/(500000/($0+1))) w l lw 2 lc 1 t "", \ "data_c7" using 2:($3/$1/4) w l lw 2 t "linear, iterator, spread", \
# "data_new2" using (($0+1)*2):($2*1.0/(500000/($0+1))) w l lw 2 lc 2 t "", \ "" using 2:($4/$1/4) w l lw 2 t "linear, loop, spread", \
# "data_new2" using (($0+1)*2):($3*1.0/(500000/($0+1))) w l lw 2 lc 3 t "", \ "" using 2:($5/$1/4) w l lw 2 t "binary, spread"
# "data_new3" using (($0+1)*2):($1*1.0/(500000/($0+1))) w l lw 2 lc 1 t "", \
# "data_new3" using (($0+1)*2):($2*1.0/(500000/($0+1))) w l lw 2 lc 2 t "", \
# "data_new3" using (($0+1)*2):($3*1.0/(500000/($0+1))) w l lw 2 lc 3 t "", \
# "data_new4" using (($0+1)*2):($1*1.0/(500000/($0+1))) w l lw 2 lc 1 t "", \
# "data_new4" using (($0+1)*2):($2*1.0/(500000/($0+1))) w l lw 2 lc 2 t "", \
# "data_new4" using (($0+1)*2):($3*1.0/(500000/($0+1))) w l lw 2 lc 3 t "", \
plot "data_new_avg" using (($0+1)*2):($1) w l lw 2 lc 1 t "linear search, iterator", \
"data_new_avg" using (($0+1)*2):($2) w l lw 2 lc 2 t "linear search, loop", \
"data_new_avg" using (($0+1)*2):($3) w l lw 2 lc 3 t "binary search", \
# plot "data" using (($0+1)*1 ):($1/($0+1)/10000) w p pt 7 lc 1 t "linear functional", \
# "data" using (($0+1)*1 ):($2/($0+1)/10000) w p pt 7 lc 2 t "linear naive", \
# "data" using (($0+1)*1 ):($3/($0+1)/10000) w p pt 7 lc 3 t "binary", \
# "data_big" using (($0+1)*100):($1/($0+1)/1000000) w p pt 7 lc 1 t "", \
# "data_big" using (($0+1)*100):($2/($0+1)/1000000) w p pt 7 lc 2 t "", \
# "data_big" using (($0+1)*100):($3/($0+1)/1000000) w p pt 7 lc 3 t ""
# pause mouse keypress
# reread