1use serde::{Deserialize, Serialize};
3use ts_rs::TS;
4
5#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, TS)]
6#[serde(rename_all = "snake_case")]
7#[ts(export)]
8pub enum ComputePreference {
9 #[default]
11 Auto,
12 Cpu,
13 Gpu,
14}
15
16#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, TS)]
17#[serde(rename_all = "snake_case")]
18#[ts(export)]
19pub enum ComputeBackend {
20 #[default]
21 Cpu,
22 Cuda,
23}
24
25#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, TS)]
26#[serde(rename_all = "snake_case")]
27#[ts(export)]
28pub enum ComputeReason {
29 Recommended,
30 UserCpu,
31 UserGpu,
32 #[default]
33 NoDevice,
34 RuntimeUnavailable,
35 UnsupportedPlatform,
36 Integrated,
37 Legacy,
38 LowPerformance,
39 InsufficientMemory,
40 DeviceFailure,
41 SmallProblem,
42 IirReference,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)]
47#[ts(export)]
48pub struct GpuDeviceInfo {
49 pub id: u32,
50 pub name: String,
51 pub compute_major: u32,
52 pub compute_minor: u32,
53 pub multiprocessors: u32,
54 #[ts(type = "number")]
55 pub memory_bytes: u64,
56 pub integrated: bool,
57 pub supported: bool,
59 pub recommended: bool,
61 pub reason: ComputeReason,
62}
63
64#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, TS)]
65#[ts(export)]
66pub struct ComputeStatus {
67 pub preference: ComputePreference,
68 pub selected: ComputeBackend,
69 pub reason: ComputeReason,
70 pub gpu_available: bool,
71 pub device: Option<GpuDeviceInfo>,
72 pub devices: Vec<GpuDeviceInfo>,
73}
74
75#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, TS)]
76#[ts(export)]
77pub struct ComputeReport {
78 pub requested: ComputePreference,
79 pub backend: ComputeBackend,
81 pub device: Option<String>,
82 pub stage: Option<ComputeStage>,
84 pub accelerated_systems: u32,
85 pub cpu_systems: u32,
86 pub fallbacks: u32,
87 pub reason: Option<ComputeReason>,
88 #[serde(default, skip_serializing_if = "Option::is_none")]
93 #[ts(optional)]
94 pub detail: Option<String>,
95}
96
97impl ComputeReport {
98 pub const DETAIL_MAX_CHARS: usize = 200;
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)]
103#[serde(rename_all = "snake_case")]
104#[ts(export)]
105pub enum ComputeStage {
106 IdealFirSweep,
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn compute_defaults_are_automatic_with_cpu_provenance() {
115 assert_eq!(ComputePreference::default(), ComputePreference::Auto);
116 assert_eq!(ComputeReport::default().backend, ComputeBackend::Cpu);
117 assert!(!ComputeStatus::default().gpu_available);
118 }
119
120 #[test]
121 fn report_detail_is_optional_on_the_wire() {
122 let report = ComputeReport::default();
123 let value = serde_json::to_value(&report).unwrap();
124 assert!(value.get("detail").is_none());
125 assert_eq!(
126 serde_json::from_value::<ComputeReport>(value).unwrap(),
127 report
128 );
129 let failed = ComputeReport {
130 detail: Some("cuMemAlloc: CUDA_ERROR_OUT_OF_MEMORY".into()),
131 ..ComputeReport::default()
132 };
133 let value = serde_json::to_value(&failed).unwrap();
134 assert_eq!(value["detail"], "cuMemAlloc: CUDA_ERROR_OUT_OF_MEMORY");
135 assert_eq!(
136 serde_json::from_value::<ComputeReport>(value).unwrap(),
137 failed
138 );
139 }
140}