runmat_execution/placement/
cost.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
4#[serde(rename_all = "snake_case")]
5pub enum EstimateConfidence {
6 Prior,
7 Low,
8 Medium,
9 High,
10 Exact,
11}
12
13impl EstimateConfidence {
14 pub const fn uncertainty_basis_points(self) -> u32 {
15 match self {
16 Self::Prior => 2_500,
17 Self::Low => 1_500,
18 Self::Medium => 500,
19 Self::High => 100,
20 Self::Exact => 0,
21 }
22 }
23}
24
25#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
26#[serde(rename_all = "snake_case")]
27pub enum EstimateSource {
28 StaticPrior,
29 Calibration,
30 Observation,
31 Compiler,
32 Provider,
33 Synthetic,
34}
35
36#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
42#[serde(deny_unknown_fields)]
43pub struct ExecutionCostComponents {
44 pub compile_or_prepare_ns: u64,
45 pub upload_ns: u64,
46 pub allocation_ns: u64,
47 pub queue_ns: u64,
48 pub execution_ns: u64,
49 pub synchronization_ns: u64,
50 pub download_ns: u64,
51 pub downstream_ns: u64,
52}
53
54impl ExecutionCostComponents {
55 pub fn checked_total_ns(self) -> Option<u64> {
56 [
57 self.compile_or_prepare_ns,
58 self.upload_ns,
59 self.allocation_ns,
60 self.queue_ns,
61 self.execution_ns,
62 self.synchronization_ns,
63 self.download_ns,
64 self.downstream_ns,
65 ]
66 .into_iter()
67 .try_fold(0_u64, u64::checked_add)
68 }
69}
70
71#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
72#[serde(deny_unknown_fields)]
73pub struct ExecutionCostEstimate {
74 pub components: ExecutionCostComponents,
75 pub scratch_bytes: u64,
76 pub confidence: EstimateConfidence,
77 pub source: EstimateSource,
78}
79
80impl ExecutionCostEstimate {
81 pub fn checked_total_ns(self) -> Option<u64> {
82 self.components.checked_total_ns()
83 }
84
85 pub fn checked_risk_adjusted_ns(self) -> Option<u64> {
86 let total = self.checked_total_ns()?;
87 let uncertainty = total
88 .checked_mul(u64::from(self.confidence.uncertainty_basis_points()))?
89 .checked_add(9_999)?
90 / 10_000;
91 total.checked_add(uncertainty)
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn component_totals_and_uncertainty_are_checked() {
101 let estimate = ExecutionCostEstimate {
102 components: ExecutionCostComponents {
103 execution_ns: 100,
104 upload_ns: 20,
105 ..ExecutionCostComponents::default()
106 },
107 scratch_bytes: 0,
108 confidence: EstimateConfidence::Medium,
109 source: EstimateSource::Synthetic,
110 };
111 assert_eq!(estimate.checked_total_ns(), Some(120));
112 assert_eq!(estimate.checked_risk_adjusted_ns(), Some(126));
113
114 let overflow = ExecutionCostComponents {
115 execution_ns: u64::MAX,
116 upload_ns: 1,
117 ..ExecutionCostComponents::default()
118 };
119 assert_eq!(overflow.checked_total_ns(), None);
120 }
121}