u280_hardware_promoter/
policy.rs1use crate::model::{
4 BASELINE_CLOCK_HZ, MAXIMUM_CAPTURE_CYCLES_PER_RESULT, MINIMUM_MEASURED_SAMPLES,
5 MINIMUM_SIGNATURES_PER_SECOND, PERFORMANCE_BATCH,
6};
7use crate::{FailureCode, PromotionError, PromotionResult};
8use serde::Serialize;
9use u280_evidence_oracle::VerifiedPerformanceObservations;
10
11const MAXIMUM_MEASURED_SAMPLES: usize = 1_000_000;
12
13#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
16pub struct PerformanceAssessment {
17 sample_count: usize,
18 p95_rank: usize,
19 p95_capture_interval_cycles: u64,
20 capture_results_denominator: u32,
21 p95_whole_kernel_nanoseconds: u64,
22 whole_kernel_results_denominator: u32,
23 actual_routed_hz: u64,
24}
25
26impl PerformanceAssessment {
27 #[must_use]
29 pub const fn sample_count(self) -> usize {
30 self.sample_count
31 }
32
33 #[must_use]
35 pub const fn p95_rank(self) -> usize {
36 self.p95_rank
37 }
38
39 #[must_use]
41 pub const fn p95_capture_interval_cycles(self) -> u64 {
42 self.p95_capture_interval_cycles
43 }
44
45 #[must_use]
47 pub const fn capture_results_denominator(self) -> u32 {
48 self.capture_results_denominator
49 }
50
51 #[must_use]
53 pub const fn p95_whole_kernel_nanoseconds(self) -> u64 {
54 self.p95_whole_kernel_nanoseconds
55 }
56
57 #[must_use]
59 pub const fn whole_kernel_results_denominator(self) -> u32 {
60 self.whole_kernel_results_denominator
61 }
62
63 #[must_use]
65 pub const fn actual_routed_hz(self) -> u64 {
66 self.actual_routed_hz
67 }
68}
69
70#[allow(dead_code)] pub(crate) fn evaluate_performance(
91 observations: &VerifiedPerformanceObservations,
92 actual_routed_hz: u64,
93) -> PromotionResult<PerformanceAssessment> {
94 let required_samples = usize::try_from(MINIMUM_MEASURED_SAMPLES).expect("u32 fits usize");
95 if observations.required_batch() != PERFORMANCE_BATCH
96 || observations.minimum_measured_samples() != required_samples
97 || observations.normalized_clock_hz() != BASELINE_CLOCK_HZ
98 || observations.minimum_signatures_per_second() != MINIMUM_SIGNATURES_PER_SECOND
99 || observations.maximum_capture_cycles_per_result() != MAXIMUM_CAPTURE_CYCLES_PER_RESULT
100 || !observations.required_batch_requested()
101 {
102 return Err(PromotionError::new(
103 FailureCode::PerformancePopulation,
104 "typed oracle observations do not contain the fixed promoter performance policy",
105 ));
106 }
107
108 let measured = observations
109 .samples()
110 .iter()
111 .filter(|sample| sample.phase() == "measured" && sample.batch() == PERFORMANCE_BATCH)
112 .collect::<Vec<_>>();
113 if measured.len() != observations.observed_measured_samples() {
114 return Err(PromotionError::new(
115 FailureCode::PerformancePopulation,
116 "typed oracle measured-sample count disagrees with its retained raw population",
117 ));
118 }
119
120 let clock = observations.clock();
121 if !clock.supports_hardware_rate_claim()
122 || clock.routed_clock_evidence().is_none()
123 || clock.declared_routed_hz() != Some(actual_routed_hz)
124 {
125 return Err(PromotionError::new(
126 FailureCode::IdentityJoin,
127 "accepted route clock does not match the oracle's bound routed-clock declaration",
128 ));
129 }
130
131 let capture = measured
132 .iter()
133 .map(|sample| sample.capture_core_interval_cycles())
134 .collect::<Vec<_>>();
135 let whole = measured
136 .iter()
137 .map(|sample| sample.whole_kernel_nanoseconds())
138 .collect::<Vec<_>>();
139 let assessment = assess_exact_population(actual_routed_hz, capture, whole)?;
140 if observations.p95_rank() != Some(assessment.p95_rank())
141 || observations.p95_capture_interval_cycles()
142 != Some(assessment.p95_capture_interval_cycles())
143 || observations.capture_results_denominator() != assessment.capture_results_denominator()
144 || observations.p95_whole_kernel_nanoseconds()
145 != Some(assessment.p95_whole_kernel_nanoseconds())
146 || observations.whole_kernel_results_denominator()
147 != assessment.whole_kernel_results_denominator()
148 {
149 return Err(PromotionError::new(
150 FailureCode::PerformancePopulation,
151 "typed oracle p95 summary disagrees with independent promoter recomputation",
152 ));
153 }
154
155 Ok(assessment)
156}
157
158fn assess_exact_population(
159 actual_routed_hz: u64,
160 capture: Vec<u64>,
161 whole: Vec<u64>,
162) -> PromotionResult<PerformanceAssessment> {
163 let required_samples = usize::try_from(MINIMUM_MEASURED_SAMPLES).expect("u32 fits usize");
164 if capture.len() != whole.len()
165 || capture.len() < required_samples
166 || capture.len() > MAXIMUM_MEASURED_SAMPLES
167 || actual_routed_hz == 0
168 || capture.iter().any(|value| *value == 0)
169 || whole.iter().any(|value| *value == 0)
170 {
171 return Err(PromotionError::new(
172 FailureCode::PerformancePopulation,
173 "performance population must contain 30..=1000000 paired positive raw samples and a nonzero routed clock",
174 ));
175 }
176 if actual_routed_hz < BASELINE_CLOCK_HZ {
177 return Err(PromotionError::new(
178 FailureCode::PerformanceThreshold,
179 format!(
180 "actual routed clock {actual_routed_hz} Hz is below the required {BASELINE_CLOCK_HZ} Hz baseline"
181 ),
182 ));
183 }
184
185 let sample_count = capture.len();
186 let (capture_rank, capture_p95) = nearest_rank_p95(capture)?;
187 let (whole_rank, whole_p95) = nearest_rank_p95(whole)?;
188 if capture_rank != whole_rank {
189 return Err(PromotionError::new(
190 FailureCode::PerformancePopulation,
191 "capture and whole-kernel populations produced different p95 ranks",
192 ));
193 }
194
195 let capture_denominator = u128::from(PERFORMANCE_BATCH - 1);
196 let whole_denominator = u128::from(PERFORMANCE_BATCH);
197 let capture_p95_u128 = u128::from(capture_p95);
198 let whole_p95_u128 = u128::from(whole_p95);
199 let minimum_rate = u128::from(MINIMUM_SIGNATURES_PER_SECOND);
200
201 let capture_cap_passes =
202 capture_p95_u128 <= u128::from(MAXIMUM_CAPTURE_CYCLES_PER_RESULT) * capture_denominator;
203 let normalized_rate_passes =
204 u128::from(BASELINE_CLOCK_HZ) * capture_denominator >= minimum_rate * capture_p95_u128;
205 let routed_rate_passes =
206 u128::from(actual_routed_hz) * capture_denominator >= minimum_rate * capture_p95_u128;
207 let whole_kernel_rate_passes =
208 1_000_000_000_u128 * whole_denominator >= minimum_rate * whole_p95_u128;
209 if !(capture_cap_passes
210 && normalized_rate_passes
211 && routed_rate_passes
212 && whole_kernel_rate_passes)
213 {
214 return Err(PromotionError::new(
215 FailureCode::PerformanceThreshold,
216 format!(
217 "exact p95 threshold failed (C95={capture_p95}/16383 cycles/result, T95={whole_p95}/16384 ns/result, actual_hz={actual_routed_hz})"
218 ),
219 ));
220 }
221
222 Ok(PerformanceAssessment {
223 sample_count,
224 p95_rank: capture_rank,
225 p95_capture_interval_cycles: capture_p95,
226 capture_results_denominator: PERFORMANCE_BATCH - 1,
227 p95_whole_kernel_nanoseconds: whole_p95,
228 whole_kernel_results_denominator: PERFORMANCE_BATCH,
229 actual_routed_hz,
230 })
231}
232
233fn nearest_rank_p95(mut values: Vec<u64>) -> PromotionResult<(usize, u64)> {
234 if values.is_empty() || values.len() > MAXIMUM_MEASURED_SAMPLES {
235 return Err(PromotionError::new(
236 FailureCode::PerformancePopulation,
237 "p95 population is empty or exceeds its memory bound",
238 ));
239 }
240 values.sort_unstable();
241 let scaled = values.len().checked_mul(95).ok_or_else(|| {
242 PromotionError::new(
243 FailureCode::PerformancePopulation,
244 "p95 rank arithmetic overflowed",
245 )
246 })?;
247 let rank = scaled.div_ceil(100);
249 Ok((rank, values[rank - 1]))
250}
251
252#[cfg(test)]
253mod tests {
254 use super::{assess_exact_population, nearest_rank_p95};
255 use crate::FailureCode;
256
257 #[test]
258 fn nearest_rank_p95_uses_ceil_rank_not_interpolation() {
259 let values = (1_u64..=30).collect::<Vec<_>>();
260 assert_eq!(nearest_rank_p95(values).unwrap(), (29, 29));
261 }
262
263 #[test]
264 fn exact_threshold_boundary_passes_without_rounding() {
265 let accepted = assess_exact_population(
266 250_000_000,
267 vec![500 * 16_383; 30],
268 vec![2_000 * 16_384; 30],
269 )
270 .unwrap();
271 assert_eq!(accepted.p95_capture_interval_cycles(), 500 * 16_383);
272 assert_eq!(accepted.p95_whole_kernel_nanoseconds(), 2_000 * 16_384);
273 }
274
275 #[test]
276 fn routed_clock_below_250mhz_fails_even_when_rate_inequalities_pass() {
277 let below_baseline = assess_exact_population(249_999_999, vec![1; 30], vec![1; 30]);
278 assert_eq!(
279 below_baseline.unwrap_err().code(),
280 FailureCode::PerformanceThreshold
281 );
282 }
283
284 #[test]
285 fn one_unit_beyond_either_exact_boundary_fails() {
286 let slow_capture =
287 assess_exact_population(250_000_000, vec![500 * 16_383 + 1; 30], vec![1; 30]);
288 assert_eq!(
289 slow_capture.unwrap_err().code(),
290 FailureCode::PerformanceThreshold
291 );
292
293 let slow_wall =
294 assess_exact_population(250_000_000, vec![1; 30], vec![2_000 * 16_384 + 1; 30]);
295 assert_eq!(
296 slow_wall.unwrap_err().code(),
297 FailureCode::PerformanceThreshold
298 );
299 }
300}