use super::ring_state::RingOccupancy;
pub const RUNTIME_IO_EVIDENCE_SCHEMA_VERSION: u32 = 1;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuntimeEvidenceMetricFamily {
Ring,
Control,
Copy,
Residency,
}
impl RuntimeEvidenceMetricFamily {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Ring => "ring",
Self::Control => "control",
Self::Copy => "copy",
Self::Residency => "residency",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct RuntimeEvidenceMetricCoverage {
pub ring: bool,
pub control: bool,
pub copy: bool,
pub residency: bool,
}
impl RuntimeEvidenceMetricCoverage {
#[must_use]
pub const fn complete() -> Self {
Self {
ring: true,
control: true,
copy: true,
residency: true,
}
}
#[must_use]
pub fn missing_families(self) -> Vec<RuntimeEvidenceMetricFamily> {
let mut missing = Vec::new();
if !self.ring {
missing.push(RuntimeEvidenceMetricFamily::Ring);
}
if !self.control {
missing.push(RuntimeEvidenceMetricFamily::Control);
}
if !self.copy {
missing.push(RuntimeEvidenceMetricFamily::Copy);
}
if !self.residency {
missing.push(RuntimeEvidenceMetricFamily::Residency);
}
missing
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ResidentRuntimeEvidence {
pub schema_version: u32,
pub resident_device_bytes: u64,
pub host_copy_bytes: u64,
pub host_copy_avoided_bytes: u64,
pub ring_occupancy: RingOccupancy,
pub control_decode_ns: u64,
pub ring_decode_ns: u64,
pub coverage: RuntimeEvidenceMetricCoverage,
}
impl ResidentRuntimeEvidence {
#[must_use]
pub const fn complete(
resident_device_bytes: u64,
host_copy_bytes: u64,
host_copy_avoided_bytes: u64,
ring_occupancy: RingOccupancy,
control_decode_ns: u64,
ring_decode_ns: u64,
) -> Self {
Self {
schema_version: RUNTIME_IO_EVIDENCE_SCHEMA_VERSION,
resident_device_bytes,
host_copy_bytes,
host_copy_avoided_bytes,
ring_occupancy,
control_decode_ns,
ring_decode_ns,
coverage: RuntimeEvidenceMetricCoverage::complete(),
}
}
#[must_use]
pub fn missing_metric_families(&self) -> Vec<RuntimeEvidenceMetricFamily> {
self.coverage.missing_families()
}
#[must_use]
pub fn is_complete(&self) -> bool {
self.schema_version == RUNTIME_IO_EVIDENCE_SCHEMA_VERSION
&& self.missing_metric_families().is_empty()
}
#[must_use]
pub fn host_copy_avoidance_bps(&self) -> u16 {
let total = u128::from(self.host_copy_bytes)
.saturating_add(u128::from(self.host_copy_avoided_bytes));
if total == 0 {
return 0;
}
let bps = u128::from(self.host_copy_avoided_bytes).saturating_mul(10_000) / total;
bps.min(10_000) as u16
}
}
#[cfg(test)]
mod evidence_tests {
use super::*;
#[test]
fn runtime_evidence_reports_missing_metric_families() {
let evidence = ResidentRuntimeEvidence {
schema_version: RUNTIME_IO_EVIDENCE_SCHEMA_VERSION,
resident_device_bytes: 0,
host_copy_bytes: 0,
host_copy_avoided_bytes: 0,
ring_occupancy: RingOccupancy::default(),
control_decode_ns: 0,
ring_decode_ns: 0,
coverage: RuntimeEvidenceMetricCoverage {
ring: true,
control: false,
copy: true,
residency: false,
},
};
let missing = evidence
.missing_metric_families()
.into_iter()
.map(RuntimeEvidenceMetricFamily::as_str)
.collect::<Vec<_>>();
assert_eq!(missing, vec!["control", "residency"]);
assert!(!evidence.is_complete());
}
#[test]
fn runtime_evidence_records_copy_avoidance_and_occupancy() {
let evidence = ResidentRuntimeEvidence::complete(
4096,
1024,
3072,
RingOccupancy {
empty: 1,
published: 2,
claimed: 3,
done: 4,
wait_io: 5,
yield_count: 6,
requeue: 7,
fault: 8,
unknown: 9,
},
11,
13,
);
assert!(evidence.is_complete());
assert_eq!(evidence.resident_device_bytes, 4096);
assert_eq!(evidence.ring_occupancy.total_slots(), 45);
assert_eq!(evidence.ring_occupancy.queue_depth(), 40);
assert_eq!(evidence.host_copy_avoidance_bps(), 7500);
}
}
pub const TELEMETRY_DECODE_CAPACITY_SCHEMA_VERSION: u32 = 1;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TelemetryDecodeCapacityEvidence {
pub schema_version: u32,
pub decoded_slot_count: usize,
pub slot_output_capacity: usize,
pub decoded_window_count: usize,
pub window_output_capacity: usize,
pub window_opcode_scratch_capacity: usize,
pub window_accumulator_scratch_capacity: usize,
pub uses_caller_owned_scratch: bool,
}
impl TelemetryDecodeCapacityEvidence {
#[must_use]
pub fn is_complete(self) -> bool {
self.schema_version == TELEMETRY_DECODE_CAPACITY_SCHEMA_VERSION
&& self.uses_caller_owned_scratch
&& self.slot_output_capacity >= self.decoded_slot_count
&& self.window_output_capacity >= self.decoded_window_count
&& self.window_accumulator_scratch_capacity >= self.decoded_window_count
}
}