#[cfg(feature = "mimalloc_bench")]
use mimalloc::MiMalloc;
#[cfg(feature = "mimalloc_bench")]
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use std::hint::black_box;
use std::process::Command;
use std::time::Instant;
use mnemo_engine::{Mnemo, RecallRequest, ScoreWeights};
#[path = "../benches/corpus.rs"]
mod corpus;
use corpus::{gen_clustered_vectors, setup_cached_corpus, DIMENSIONS, PASSPHRASE};
const OPEN_LOOPS: usize = 50;
const ALLOCATOR_BANNER: &str = if cfg!(feature = "mimalloc_bench") {
"mimalloc (variant 4)"
} else {
"system default (variant 1/2/3 depending on env + --pressure-relief)"
};
#[cfg(target_os = "macos")]
mod purge {
#[link(name = "System", kind = "dylib")]
extern "C" {
fn malloc_zone_pressure_relief(zone: *mut std::ffi::c_void, goal: usize) -> usize;
}
pub fn pressure_relief() -> usize {
unsafe { malloc_zone_pressure_relief(std::ptr::null_mut(), 0) }
}
}
#[cfg(not(target_os = "macos"))]
mod purge {
pub fn pressure_relief() -> usize {
0
}
}
fn rss_kb() -> u64 {
let pid = std::process::id();
let out = Command::new("ps")
.args(["-o", "rss=", "-p", &pid.to_string()])
.output();
out.ok()
.and_then(|o| {
String::from_utf8(o.stdout)
.ok()
.and_then(|s| s.trim().parse::<u64>().ok())
})
.unwrap_or(0)
}
fn one_iteration(
path: &std::path::Path,
q: &[f32],
read_only: bool,
pressure_relief: bool,
) -> (f64, u64, u64) {
let mut db = if read_only {
Mnemo::open_read_only(path, PASSPHRASE).expect("open_read_only")
} else {
Mnemo::open(path, PASSPHRASE).expect("open")
};
let req = RecallRequest::new(q.to_vec())
.top_k(10)
.track_access(false)
.weights(ScoreWeights::default());
let start = Instant::now();
let hits = db.recall(&req).expect("recall");
let elapsed = start.elapsed();
black_box(hits);
drop(db);
let released = if pressure_relief {
purge::pressure_relief() as u64
} else {
0
};
let rss = rss_kb();
(elapsed.as_secs_f64() * 1_000.0, rss, released)
}
fn percentile(sorted: &[f64], pct: f64) -> f64 {
if sorted.is_empty() {
return 0.0;
}
let idx = ((pct / 100.0) * (sorted.len() as f64 - 1.0)).round() as usize;
sorted[idx.min(sorted.len() - 1)]
}
fn median(sorted: &[f64]) -> f64 {
percentile(sorted, 50.0)
}
struct Args {
corpus: usize,
loops: usize,
pressure_relief: bool,
read_only_phase: bool,
}
fn parse_args() -> Args {
let mut args = Args {
corpus: 100_000,
loops: OPEN_LOOPS,
pressure_relief: false,
read_only_phase: false,
};
let mut it = std::env::args().skip(1).peekable();
while let Some(a) = it.next() {
match a.as_str() {
"--corpus" => {
args.corpus = it
.next()
.and_then(|v| v.parse().ok())
.expect("--corpus needs a positive integer");
}
"--loops" => {
args.loops = it
.next()
.and_then(|v| v.parse().ok())
.expect("--loops needs a positive integer");
}
"--pressure-relief" => args.pressure_relief = true,
"--read-only" => args.read_only_phase = true,
other => panic!("unknown arg: {other}"),
}
}
args
}
fn main() {
let args = parse_args();
println!("mnemo PR MEM-1 open_rss harness");
println!(" pid : {}", std::process::id());
println!(
" corpus size : {} memories, {}-dim vectors",
args.corpus, DIMENSIONS
);
println!(" loops : {}", args.loops);
println!(
" phase : {}",
if args.read_only_phase {
"read-only"
} else {
"read-write"
}
);
println!(
" pressure_relief : {}",
if args.pressure_relief {
"on (variant 3)"
} else {
"off"
}
);
println!(" allocator : {ALLOCATOR_BANNER}");
println!(
" macOS env : MallocSpaceEfficient={} MallocAggressiveMadvise={}",
std::env::var("MallocSpaceEfficient").unwrap_or_else(|_| "unset".into()),
std::env::var("MallocAggressiveMadvise").unwrap_or_else(|_| "unset".into()),
);
let cached = setup_cached_corpus(args.corpus, DIMENSIONS);
let queries = gen_clustered_vectors(args.loops, DIMENSIONS, 100, 0xDEAD_BEEF);
println!("rss_kb at start: {}\n", rss_kb());
println!(
"{:>4} {:>14} {:>14} {:>14}",
"iter", "first_recall_ms", "rss_kb_after", "released_kb"
);
let mut ms_log = Vec::with_capacity(args.loops);
let mut rss_log = Vec::with_capacity(args.loops);
for i in 0..args.loops {
let q = &queries[i % queries.len()];
let (ms, rss, released) =
one_iteration(&cached, q, args.read_only_phase, args.pressure_relief);
println!("{i:>4} {ms:>14.3} {rss:>14} {:>14}", released / 1024);
ms_log.push(ms);
rss_log.push(rss);
}
let mut sorted = ms_log.clone();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
println!("\n== summary ==");
println!(
"first-recall ms: median {:.3}, p95 {:.3}",
median(&sorted),
percentile(&sorted, 95.0),
);
let start = *rss_log.first().unwrap_or(&0);
let end = *rss_log.last().unwrap_or(&0);
let peak = *rss_log.iter().max().unwrap_or(&0);
println!(
"rss_kb: start {start}, end {end}, peak {peak}, delta {}",
end as i64 - start as i64
);
let slope = {
if rss_log.len() < 4 {
0.0
} else {
let half = rss_log.len() / 2;
let last_half = &rss_log[half..];
let first = *last_half.first().unwrap_or(&0) as f64;
let last = *last_half.last().unwrap_or(&0) as f64;
(last - first) / (last_half.len() as f64 - 1.0)
}
};
println!("rss_kb slope (second half): {:.2} kB/iter", slope);
}