26.0.1
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
//! Small benchmark harness for the paranoia read path and sample index.
|
||||
//!
|
||||
//! Run with:
|
||||
//! cargo run --release --example bench_paranoia
|
||||
//! cargo run --release --example bench_paranoia -- 5000
|
||||
|
||||
use cdrustanoia_core::device::image::ImageDrive;
|
||||
use cdrustanoia_core::device::samples_to_bytes;
|
||||
use cdrustanoia_core::paranoia::sort::SortIndex;
|
||||
use cdrustanoia_core::paranoia::{Paranoia, PARANOIA_MODE_FULL};
|
||||
use std::collections::HashMap;
|
||||
use std::time::Instant;
|
||||
|
||||
fn make_samples(sectors: usize) -> Vec<i16> {
|
||||
let mut out = Vec::with_capacity(sectors * 1176);
|
||||
let mut x = 0x1234_5678_9abc_def0u64;
|
||||
for i in 0..sectors * 1176 {
|
||||
x ^= x << 13;
|
||||
x ^= x >> 7;
|
||||
x ^= x << 17;
|
||||
let v = if i % 5000 < 700 {
|
||||
0
|
||||
} else {
|
||||
(x as i16).wrapping_add((i as i16).wrapping_mul(11))
|
||||
};
|
||||
out.push(v);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn bench_index(samples: &[i16]) {
|
||||
let mut index = SortIndex::new(samples.len());
|
||||
let started = Instant::now();
|
||||
index.setup(samples, 0, 0, samples.len() as i64);
|
||||
let setup = started.elapsed();
|
||||
|
||||
let mut found = 0usize;
|
||||
let started = Instant::now();
|
||||
for i in 0..10_000i64 {
|
||||
let post = (i * 7919) % samples.len() as i64;
|
||||
let value = samples[post as usize];
|
||||
if index.getmatch(samples, post, 512, value).is_some() {
|
||||
found += 1;
|
||||
while index.nextmatch(samples).is_some() {
|
||||
found += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
let queries = started.elapsed();
|
||||
println!(
|
||||
"SortIndex: setup={:?} 10k queries={:?} matches={} ({} samples)",
|
||||
setup,
|
||||
queries,
|
||||
found,
|
||||
samples.len()
|
||||
);
|
||||
}
|
||||
|
||||
struct OldIndex {
|
||||
buckets: HashMap<i16, Vec<u32>>,
|
||||
size: usize,
|
||||
cursor: Option<(i16, usize, usize)>,
|
||||
}
|
||||
|
||||
impl OldIndex {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
buckets: HashMap::new(),
|
||||
size: 0,
|
||||
cursor: None,
|
||||
}
|
||||
}
|
||||
fn setup(&mut self, samples: &[i16]) {
|
||||
self.buckets.clear();
|
||||
self.size = samples.len();
|
||||
for (i, &sample) in samples.iter().enumerate() {
|
||||
self.buckets.entry(sample).or_default().push(i as u32);
|
||||
}
|
||||
}
|
||||
fn getmatch(&mut self, post: i64, overlap: i64, value: i16) -> Option<usize> {
|
||||
let post = post.clamp(0, self.size as i64);
|
||||
let lo = (post - overlap).max(0) as usize;
|
||||
let hi = ((post + overlap).min(self.size as i64)).max(0) as usize;
|
||||
self.cursor = None;
|
||||
let positions = self.buckets.get(&value)?;
|
||||
let idx = positions.partition_point(|p| (*p as usize) < lo);
|
||||
if idx >= positions.len() {
|
||||
return None;
|
||||
}
|
||||
let pos = positions[idx] as usize;
|
||||
if pos >= hi {
|
||||
return None;
|
||||
}
|
||||
self.cursor = Some((value, idx + 1, hi));
|
||||
Some(pos)
|
||||
}
|
||||
fn nextmatch(&mut self) -> Option<usize> {
|
||||
let (value, idx, hi) = self.cursor?;
|
||||
let positions = self.buckets.get(&value)?;
|
||||
if idx >= positions.len() {
|
||||
self.cursor = None;
|
||||
return None;
|
||||
}
|
||||
let pos = positions[idx] as usize;
|
||||
if pos >= hi {
|
||||
self.cursor = None;
|
||||
return None;
|
||||
}
|
||||
self.cursor = Some((value, idx + 1, hi));
|
||||
Some(pos)
|
||||
}
|
||||
}
|
||||
|
||||
fn bench_old_index(samples: &[i16]) {
|
||||
let mut index = OldIndex::new();
|
||||
let started = Instant::now();
|
||||
index.setup(samples);
|
||||
let setup = started.elapsed();
|
||||
let mut found = 0usize;
|
||||
let started = Instant::now();
|
||||
for i in 0..10_000i64 {
|
||||
let post = (i * 7919) % samples.len() as i64;
|
||||
let value = samples[post as usize];
|
||||
if index.getmatch(post, 512, value).is_some() {
|
||||
found += 1;
|
||||
while index.nextmatch().is_some() {
|
||||
found += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
let queries = started.elapsed();
|
||||
println!(
|
||||
"Old HashMap index: setup={:?} 10k queries={:?} matches={}",
|
||||
setup, queries, found
|
||||
);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let sectors: usize = std::env::args()
|
||||
.nth(1)
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(2000);
|
||||
let samples = make_samples(sectors);
|
||||
bench_index(&samples);
|
||||
bench_old_index(&samples);
|
||||
|
||||
let bytes = samples_to_bytes(&samples);
|
||||
let drive = ImageDrive::from_bytes(bytes);
|
||||
let mut p = Paranoia::new(Box::new(drive));
|
||||
p.modeset(PARANOIA_MODE_FULL);
|
||||
let mut cb = |_: i64, _: i32| {};
|
||||
let started = Instant::now();
|
||||
let mut got = 0usize;
|
||||
for _ in 0..sectors {
|
||||
let sector = p.read(&mut cb).expect("read sector");
|
||||
got += sector.len();
|
||||
}
|
||||
let elapsed = started.elapsed();
|
||||
let bytes_read = (got * 2) as f64;
|
||||
println!(
|
||||
"Read: {} sectors, {} samples, {:?}, {:.1} MB/s",
|
||||
sectors,
|
||||
got,
|
||||
elapsed,
|
||||
bytes_read / elapsed.as_secs_f64() / 1_000_000.0
|
||||
);
|
||||
assert_eq!(got, sectors * 1176);
|
||||
}
|
||||
Reference in New Issue
Block a user