use std::time::Instant;
use crate::preflight::system_check;
pub use tacet_core::adaptive::{Calibration, CalibrationConfig, CalibrationError};
pub fn calibrate(
baseline_samples: &[u64],
sample_samples: &[u64],
ns_per_tick: f64,
config: &CalibrationConfig,
) -> Result<Calibration, CalibrationError> {
let start = Instant::now();
let n = baseline_samples.len().min(sample_samples.len());
let mut calibration = tacet_core::adaptive::calibrate(
baseline_samples,
sample_samples,
ns_per_tick,
config,
1_000_000.0, )?;
let elapsed = start.elapsed().as_secs_f64();
if elapsed > 0.0 {
calibration.samples_per_second = n as f64 / elapsed;
}
if !config.skip_preflight {
for warning in system_check() {
let _ = warning; }
}
Ok(calibration)
}
#[allow(dead_code)]
pub fn estimate_samples_for_mde(current_mde: f64, target_mde: f64, current_n: usize) -> usize {
if target_mde >= current_mde || target_mde <= 0.0 {
return current_n;
}
let scale = (current_mde / target_mde).powi(2);
((current_n as f64) * scale).ceil() as usize
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_estimate_samples_for_mde() {
let estimate = estimate_samples_for_mde(10.0, 5.0, 1000);
assert_eq!(estimate, 4000);
let estimate = estimate_samples_for_mde(10.0, 2.5, 1000);
assert_eq!(estimate, 16000);
}
#[test]
fn test_estimate_samples_target_already_met() {
let estimate = estimate_samples_for_mde(5.0, 10.0, 1000);
assert_eq!(estimate, 1000); }
#[test]
fn test_calibration_config_default() {
let config = CalibrationConfig::default();
assert_eq!(config.calibration_samples, 5000);
assert_eq!(config.bootstrap_iterations, 200);
}
#[test]
fn test_calibration_basic() {
let baseline: Vec<u64> = (0..1000).map(|i| 1000 + (i % 10)).collect();
let sample: Vec<u64> = (0..1000).map(|i| 1005 + (i % 10)).collect();
let config = CalibrationConfig {
calibration_samples: 1000,
bootstrap_iterations: 50, timer_resolution_ns: 1.0,
theta_ns: 100.0,
alpha: 0.01,
seed: 42,
skip_preflight: true, force_discrete_mode: false,
};
let result = calibrate(&baseline, &sample, 1.0, &config);
assert!(
result.is_ok(),
"Calibration should succeed: {:?}",
result.err()
);
let cal = result.unwrap();
assert!(
cal.sigma_rate.trace() > 0.0,
"Sigma rate should be positive"
);
assert!(cal.block_length >= 1, "Block length should be at least 1");
assert!(
cal.prior_cov_marginal[(0, 0)] > 0.0,
"Prior marginal variance should be positive"
);
assert!(cal.sigma_t > 0.0, "Sigma t should be positive");
assert!(
cal.samples_per_second > 0.0,
"Throughput should be positive"
);
}
#[test]
fn test_calibration_too_few_samples() {
let baseline: Vec<u64> = vec![1000, 1001, 1002];
let sample: Vec<u64> = vec![1005, 1006, 1007];
let config = CalibrationConfig::default();
let result = calibrate(&baseline, &sample, 1.0, &config);
assert!(matches!(
result,
Err(CalibrationError::TooFewSamples { .. })
));
}
}