This commit is contained in:
tux
2026-11-03 22:13:16 +01:00
parent 158e115242
commit 8012e912ec
19 changed files with 975 additions and 208 deletions
+168
View File
@@ -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);
}