#![cfg(target_os = "linux")]
use lineprior::{BuildConfig, build_prior_book_from_reader};
use std::io::Read;
struct SyntheticJsonl {
next: u64,
total: u64,
unique_pairs: u64,
buf: Vec<u8>,
pos: usize,
}
impl SyntheticJsonl {
fn new(total: u64, unique_pairs: u64) -> Self {
Self {
next: 0,
total,
unique_pairs,
buf: Vec::new(),
pos: 0,
}
}
}
impl Read for SyntheticJsonl {
fn read(&mut self, out: &mut [u8]) -> std::io::Result<usize> {
if self.pos >= self.buf.len() {
if self.next >= self.total {
return Ok(0);
}
let pair = self.next % self.unique_pairs;
self.buf = format!(
"{{\"sequence_id\":\"s{}\",\"step\":0,\"state\":\"state_{pair}\",\"action\":\"action_{pair}\",\"outcome\":\"success\",\"weight\":1.0}}\n",
self.next,
)
.into_bytes();
self.pos = 0;
self.next += 1;
}
let n = (self.buf.len() - self.pos).min(out.len());
out[..n].copy_from_slice(&self.buf[self.pos..self.pos + n]);
self.pos += n;
Ok(n)
}
}
fn vm_hwm_kb() -> u64 {
let status = std::fs::read_to_string("/proc/self/status").expect("read /proc/self/status");
for line in status.lines() {
if let Some(rest) = line.strip_prefix("VmHWM:") {
return rest
.trim()
.trim_end_matches("kB")
.trim()
.parse()
.expect("parse VmHWM value");
}
}
panic!("VmHWM not found in /proc/self/status");
}
struct SyntheticContextJsonl {
next_sequence: u64,
total_sequences: u64,
unique_pairs: u64,
step: u32,
buf: Vec<u8>,
pos: usize,
}
impl SyntheticContextJsonl {
fn new(total_sequences: u64, unique_pairs: u64) -> Self {
Self {
next_sequence: 0,
total_sequences,
unique_pairs,
step: 0,
buf: Vec::new(),
pos: 0,
}
}
}
impl Read for SyntheticContextJsonl {
fn read(&mut self, out: &mut [u8]) -> std::io::Result<usize> {
if self.pos >= self.buf.len() {
if self.next_sequence >= self.total_sequences {
return Ok(0);
}
let pair = self.next_sequence % self.unique_pairs;
let state = if self.step == 0 { "state_a" } else { "state_b" };
self.buf = format!(
"{{\"sequence_id\":\"seq{}\",\"step\":{},\"state\":\"{state}\",\"action\":\"action_{pair}\",\"outcome\":\"success\",\"weight\":1.0}}\n",
self.next_sequence, self.step,
)
.into_bytes();
self.pos = 0;
if self.step == 0 {
self.step = 1;
} else {
self.step = 0;
self.next_sequence += 1;
}
}
let n = (self.buf.len() - self.pos).min(out.len());
out[..n].copy_from_slice(&self.buf[self.pos..self.pos + n]);
self.pos += n;
Ok(n)
}
}
#[test]
fn streaming_build_with_context_order_keeps_peak_memory_bounded_by_unique_tuples() {
const TOTAL_SEQUENCES: u64 = 1_500_000; const UNIQUE_PAIRS: u64 = 100;
let before_kb = vm_hwm_kb();
let reader = SyntheticContextJsonl::new(TOTAL_SEQUENCES, UNIQUE_PAIRS);
let config = BuildConfig {
context_order: 1,
..Default::default()
};
let output = build_prior_book_from_reader(reader, false, &config).unwrap();
let after_kb = vm_hwm_kb();
let delta_kb = after_kb.saturating_sub(before_kb);
let total_actions: u64 = output.book.entries.values().map(Vec::len).sum::<usize>() as u64;
assert_eq!(total_actions, 2 * UNIQUE_PAIRS);
let total_context_actions: u64 = output
.book
.context_entries
.values()
.map(Vec::len)
.sum::<usize>() as u64;
assert_eq!(total_context_actions, UNIQUE_PAIRS);
assert!(
delta_kb < 150_000,
"peak memory grew by {delta_kb}KB while processing {} observations across only \
{UNIQUE_PAIRS} unique (context, state, action) tuples -- this suggests \
context_order > 0 is no longer streaming",
TOTAL_SEQUENCES * 2,
);
}
#[test]
fn streaming_build_keeps_peak_memory_bounded_by_unique_pairs_not_total_observations() {
const TOTAL_OBSERVATIONS: u64 = 3_000_000;
const UNIQUE_PAIRS: u64 = 100;
let before_kb = vm_hwm_kb();
let reader = SyntheticJsonl::new(TOTAL_OBSERVATIONS, UNIQUE_PAIRS);
let output = build_prior_book_from_reader(reader, false, &BuildConfig::default()).unwrap();
let after_kb = vm_hwm_kb();
let delta_kb = after_kb.saturating_sub(before_kb);
let total_actions: u64 = output.book.entries.values().map(Vec::len).sum::<usize>() as u64;
assert_eq!(total_actions, UNIQUE_PAIRS);
assert!(
delta_kb < 100_000,
"peak memory grew by {delta_kb}KB while processing {TOTAL_OBSERVATIONS} observations \
across only {UNIQUE_PAIRS} unique pairs -- this suggests build_prior_book_from_reader \
is no longer streaming (e.g. a Vec<Observation> got reintroduced somewhere)"
);
}