Skip to main content

runmat_execution/placement/
candidate.rs

1use runmat_types::{RegionGuardId, RegionId};
2use serde::{Deserialize, Serialize};
3
4use super::ExecutionCostEstimate;
5
6#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
7#[serde(rename_all = "snake_case")]
8pub enum ExecutionCandidateKind {
9    SharedRuntime,
10    GenericNativeCpu,
11    SpecializedNativeCpu,
12    VectorizedNativeCpu,
13    CpuLibrary,
14    ProviderOperation,
15    ProviderLibrary,
16    ProviderGraph,
17    ProviderFusion,
18}
19
20impl ExecutionCandidateKind {
21    pub const fn is_provider(self) -> bool {
22        matches!(
23            self,
24            Self::ProviderOperation
25                | Self::ProviderLibrary
26                | Self::ProviderGraph
27                | Self::ProviderFusion
28        )
29    }
30}
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
33#[serde(rename_all = "snake_case", tag = "kind")]
34pub enum CandidateExecutionLocation {
35    Host,
36    Provider { device_id: u32 },
37}
38
39#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
40#[serde(rename_all = "snake_case")]
41pub enum CandidatePreparationState {
42    Ready,
43    Warm,
44    Cold,
45    Preparing,
46}
47
48#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
49#[serde(rename_all = "snake_case", tag = "kind")]
50pub enum CandidateOutputResidency {
51    Host,
52    Provider { device_id: u32 },
53    Mirrored { device_id: u32 },
54    Unknown,
55}
56
57#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
58#[serde(deny_unknown_fields)]
59pub struct ExecutionCandidateDescriptor {
60    pub identity: String,
61    pub region: Option<RegionId>,
62    pub kind: ExecutionCandidateKind,
63    pub execution_location: CandidateExecutionLocation,
64    pub preparation: CandidatePreparationState,
65    pub cost: ExecutionCostEstimate,
66    pub output_residency: CandidateOutputResidency,
67    pub guards: Vec<RegionGuardId>,
68}
69
70impl ExecutionCandidateDescriptor {
71    pub fn validate(&self) -> Result<(), &'static str> {
72        if self.identity.is_empty()
73            || self.identity.len() > 128
74            || self.identity.chars().any(char::is_control)
75        {
76            return Err("candidate identity must be 1..=128 bytes without control characters");
77        }
78        if self.cost.checked_total_ns().is_none() {
79            return Err("candidate cost components overflow u64");
80        }
81        if self.kind.is_provider()
82            != matches!(
83                self.execution_location,
84                CandidateExecutionLocation::Provider { .. }
85            )
86        {
87            return Err("candidate kind and execution location are inconsistent");
88        }
89        if self.guards.windows(2).any(|pair| pair[0] >= pair[1]) {
90            return Err("candidate guards must be sorted and unique");
91        }
92        if self
93            .region
94            .is_some_and(|region| self.guards.iter().any(|guard| guard.region != region))
95        {
96            return Err("candidate guards must belong to the candidate region");
97        }
98        Ok(())
99    }
100}