Skip to content

Commit e9f0329

Browse files
committed
Move peak_bytes calibration to integration test
1 parent c5a41dc commit e9f0329

2 files changed

Lines changed: 80 additions & 76 deletions

File tree

prover/src/auto_storage.rs

Lines changed: 3 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ const MEMORY_CELL_BYTES: u64 = 32;
4242
const INSTRUCTION_MAP_BYTES_PER_ROW: u64 = 32;
4343

4444
/// 9/10 budget headroom for OS, other processes, and allocator slack.
45-
const SAFETY_FRACTION_NUM: u64 = 9;
46-
const SAFETY_FRACTION_DEN: u64 = 10;
45+
pub const SAFETY_FRACTION_NUM: u64 = 9;
46+
pub const SAFETY_FRACTION_DEN: u64 = 10;
4747

4848
/// `(rows, main_cols, aux_cols, num_main_merkle_trees)` for a single table.
4949
type TableSpec = (u64, u64, u64, u64);
@@ -228,7 +228,7 @@ pub fn decide(lengths: &TableLengths, blowup_factor: u8) -> StorageMode {
228228
}
229229

230230
/// Peak RAM estimate in bytes for a proof whose trace shape matches `lengths`.
231-
fn peak_bytes(lengths: &TableLengths, blowup_factor: u8, table_parallelism: usize) -> u64 {
231+
pub fn peak_bytes(lengths: &TableLengths, blowup_factor: u8, table_parallelism: usize) -> u64 {
232232
let blowup = blowup_factor as u64;
233233
let k = table_parallelism.max(1);
234234
let specs = table_specs(lengths);
@@ -399,77 +399,4 @@ mod tests {
399399
let mode = select_storage_mode(peak_bytes(&empty_lengths(), 2, ALL_TABLES), None);
400400
assert_eq!(mode, StorageMode::Disk);
401401
}
402-
403-
/// Asserts predicted [`peak_bytes`] does not underestimate jemalloc-measured
404-
/// heap during a proof.
405-
mod calibration {
406-
use super::*;
407-
use crate::tables::MaxRowsConfig;
408-
use crate::tables::trace_builder::count_table_lengths;
409-
use crate::test_utils::{asm_elf_bytes, run_asm_elf};
410-
use stark::proof::options::GoldilocksCubicProofOptions;
411-
use std::sync::Arc;
412-
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
413-
use std::thread;
414-
use std::time::Duration;
415-
use tikv_jemalloc_ctl::{epoch, stats};
416-
417-
#[global_allocator]
418-
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
419-
420-
fn allocated_bytes() -> usize {
421-
epoch::advance().ok();
422-
stats::allocated::read().unwrap_or(0)
423-
}
424-
425-
#[test]
426-
fn peak_bytes_does_not_underestimate_measured_heap() {
427-
let (elf, logs, _) = run_asm_elf("fib_iterative_372k");
428-
let elf_bytes = asm_elf_bytes("fib_iterative_372k");
429-
430-
let max_rows = MaxRowsConfig::default();
431-
let lengths = count_table_lengths(&elf, &logs, &max_rows, &[])
432-
.expect("count_table_lengths succeeds");
433-
434-
let opts = GoldilocksCubicProofOptions::with_blowup(2).expect("blowup=2 is valid");
435-
let predicted = peak_bytes(&lengths, opts.blowup_factor, table_parallelism()) as usize;
436-
437-
drop(logs);
438-
439-
let baseline = allocated_bytes();
440-
let peak = Arc::new(AtomicUsize::new(baseline));
441-
let stop = Arc::new(AtomicBool::new(false));
442-
443-
let sampler = {
444-
let peak = Arc::clone(&peak);
445-
let stop = Arc::clone(&stop);
446-
thread::spawn(move || {
447-
while !stop.load(Ordering::Relaxed) {
448-
peak.fetch_max(allocated_bytes(), Ordering::Relaxed);
449-
thread::sleep(Duration::from_millis(10));
450-
}
451-
})
452-
};
453-
454-
let _proof = crate::prove_with_options_and_inputs(&elf_bytes, &[], &opts, &max_rows)
455-
.expect("proof succeeds");
456-
457-
stop.store(true, Ordering::Relaxed);
458-
sampler.join().expect("sampler joins");
459-
460-
let measured = peak.load(Ordering::Relaxed).saturating_sub(baseline);
461-
462-
eprintln!(
463-
"peak_bytes calibration: predicted={predicted} bytes, measured_heap={measured} bytes, ratio={:.2}",
464-
predicted as f64 / measured as f64
465-
);
466-
467-
let safety_num = SAFETY_FRACTION_NUM as usize;
468-
let safety_den = SAFETY_FRACTION_DEN as usize;
469-
assert!(
470-
predicted.saturating_mul(safety_den) >= measured.saturating_mul(safety_num),
471-
"peak_bytes underestimates measured heap: predicted={predicted}, measured={measured}"
472-
);
473-
}
474-
}
475402
}

prover/tests/calibration.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//! Asserts predicted `peak_bytes` does not underestimate jemalloc-measured
2+
//! heap during a proof. Lives in its own integration-test binary so that
3+
//! `#[global_allocator]` and `tikv_jemalloc_ctl::stats::allocated` reads are
4+
//! isolated from the rest of the prover test suite.
5+
6+
#![cfg(feature = "disk-spill")]
7+
8+
use lambda_vm_prover::auto_storage::{SAFETY_FRACTION_DEN, SAFETY_FRACTION_NUM, peak_bytes};
9+
use lambda_vm_prover::prove_with_options_and_inputs;
10+
use lambda_vm_prover::tables::MaxRowsConfig;
11+
use lambda_vm_prover::tables::trace_builder::count_table_lengths;
12+
use lambda_vm_prover::test_utils::{asm_elf_bytes, run_asm_elf};
13+
use stark::proof::options::GoldilocksCubicProofOptions;
14+
use stark::prover::table_parallelism;
15+
use std::sync::Arc;
16+
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
17+
use std::thread;
18+
use std::time::Duration;
19+
use tikv_jemalloc_ctl::{epoch, stats};
20+
21+
#[global_allocator]
22+
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
23+
24+
fn allocated_bytes() -> usize {
25+
epoch::advance().ok();
26+
stats::allocated::read().unwrap_or(0)
27+
}
28+
29+
#[test]
30+
fn peak_bytes_does_not_underestimate_measured_heap() {
31+
let (elf, logs, _) = run_asm_elf("fib_iterative_372k");
32+
let elf_bytes = asm_elf_bytes("fib_iterative_372k");
33+
34+
let max_rows = MaxRowsConfig::default();
35+
let lengths =
36+
count_table_lengths(&elf, &logs, &max_rows, &[]).expect("count_table_lengths succeeds");
37+
38+
let opts = GoldilocksCubicProofOptions::with_blowup(2).expect("blowup=2 is valid");
39+
let predicted = peak_bytes(&lengths, opts.blowup_factor, table_parallelism()) as usize;
40+
41+
drop(logs);
42+
43+
let baseline = allocated_bytes();
44+
let peak = Arc::new(AtomicUsize::new(baseline));
45+
let stop = Arc::new(AtomicBool::new(false));
46+
47+
let sampler = {
48+
let peak = Arc::clone(&peak);
49+
let stop = Arc::clone(&stop);
50+
thread::spawn(move || {
51+
while !stop.load(Ordering::Relaxed) {
52+
peak.fetch_max(allocated_bytes(), Ordering::Relaxed);
53+
thread::sleep(Duration::from_millis(10));
54+
}
55+
})
56+
};
57+
58+
let _proof =
59+
prove_with_options_and_inputs(&elf_bytes, &[], &opts, &max_rows).expect("proof succeeds");
60+
61+
stop.store(true, Ordering::Relaxed);
62+
sampler.join().expect("sampler joins");
63+
64+
let measured = peak.load(Ordering::Relaxed).saturating_sub(baseline);
65+
66+
eprintln!(
67+
"peak_bytes calibration: predicted={predicted} bytes, measured_heap={measured} bytes, ratio={:.2}",
68+
predicted as f64 / measured as f64
69+
);
70+
71+
let safety_num = SAFETY_FRACTION_NUM as usize;
72+
let safety_den = SAFETY_FRACTION_DEN as usize;
73+
assert!(
74+
predicted.saturating_mul(safety_den) >= measured.saturating_mul(safety_num),
75+
"peak_bytes underestimates measured heap: predicted={predicted}, measured={measured}"
76+
);
77+
}

0 commit comments

Comments
 (0)