use std::fs;
use std::hint::black_box;
use std::mem::size_of;
use std::net::IpAddr;
use libmaxminddb_rs::{Error, Reader};
use serde::Serialize;
use super::million::{Fixture, LABEL, Record, Result};
#[derive(Debug, Serialize)]
pub struct Snapshot {
pub rss_bytes: u64,
pub peak_rss_bytes: u64,
pub anonymous_rss_bytes: u64,
pub file_rss_bytes: u64,
}
impl Snapshot {
pub fn read() -> Result<Self> {
if !cfg!(target_os = "linux") {
return Err(
"RSS scenarios require Linux /proc/self/status; no measurement available".into(),
);
}
Self::parse(&fs::read_to_string("/proc/self/status")?)
}
pub fn parse(status: &str) -> Result<Self> {
fn kib(status: &str, key: &str) -> Result<u64> {
let line = status
.lines()
.find(|line| line.starts_with(key))
.ok_or_else(|| format!("missing {key} in /proc/self/status"))?;
let mut fields = line.split_whitespace().skip(1);
let value = fields.next().ok_or("missing RSS value")?.parse::<u64>()?;
if fields.next() != Some("kB") {
return Err("unexpected RSS unit".into());
}
value.checked_mul(1024).ok_or_else(|| "RSS overflow".into())
}
Ok(Self {
rss_bytes: kib(status, "VmRSS:")?,
peak_rss_bytes: kib(status, "VmHWM:")?,
anonymous_rss_bytes: kib(status, "RssAnon:")?,
file_rss_bytes: kib(status, "RssFile:")?,
})
}
}
#[derive(Debug, Serialize)]
pub struct Measurement {
pub family: String,
pub opening: String,
pub pid: u32,
pub entries: usize,
pub lookups: usize,
pub database_bytes: u64,
pub auxiliary_capacity_bytes: usize,
pub before_auxiliary: Snapshot,
pub before_open: Snapshot,
pub after_open: Snapshot,
pub after_lookups: Snapshot,
}
pub fn measure(fixture: &Fixture, mode: &str) -> Result<Measurement> {
if !fixture.cached() {
return Err("memory worker requires a prepared fixture".into());
}
let before_auxiliary = Snapshot::read()?;
let hits = fixture.queries("hits")?;
let misses = fixture.queries("misses")?;
let auxiliary_capacity_bytes = (hits.capacity() + misses.capacity()) * size_of::<IpAddr>();
let before_open = Snapshot::read()?;
let reader = match mode {
"owned" => Reader::open(fixture.database())?,
"mmap" => {
unsafe { Reader::open_mmap(fixture.database())? }
}
_ => return Err(format!("unknown opening mode: {mode}").into()),
};
let after_open = Snapshot::read()?;
for (id, (&hit, &miss)) in hits.iter().zip(&misses).enumerate() {
let record: Record<'_> = reader.lookup_borrowed(black_box(hit))?;
if record.id != id as u32 || record.label != LABEL {
return Err("invalid memory-workload hit".into());
}
black_box(record);
match reader.lookup_borrowed::<Record<'_>>(black_box(miss)) {
Err(Error::NotFound) => {
black_box(false);
}
Ok(_) => return Err("invalid memory-workload miss".into()),
Err(error) => return Err(error.into()),
}
}
let after_lookups = Snapshot::read()?;
black_box((&reader, &hits, &misses));
Ok(Measurement {
family: fixture.family.name().into(),
opening: mode.into(),
pid: std::process::id(),
entries: fixture.count,
lookups: hits.len() + misses.len(),
database_bytes: fixture.manifest()?.database_bytes,
auxiliary_capacity_bytes,
before_auxiliary,
before_open,
after_open,
after_lookups,
})
}