1mod access_graph;
6pub mod artifacts;
7#[path = "benchmark_statistics.rs"]
8pub mod benchmark;
9mod buffer_pool;
10pub mod bundle;
11mod dependency_frontier;
12pub mod fabric;
13pub mod image;
14pub mod inference;
15pub mod jobs;
16pub mod plan_cache;
17pub mod residency;
18mod runtime;
19#[cfg(target_os = "linux")]
20pub mod storage;
21mod target;
22pub mod tensor;
23pub use access_graph::{AccessGraph, AccessView};
24pub use buffer_pool::{BufferPool, PooledBuffer};
25pub use runtime::*;
26pub mod execution;
28#[path = "loom/model.rs"]
29pub mod model;
30pub use execution::{Access, Completion, Runtime};
31pub mod gpu {
34 pub use crate::runtime::*;
35}
36pub use target::{TARGET_KEY, Target};
37pub mod loom;
38#[cfg(feature = "npu")]
39pub mod npu;
40
41#[cfg(doctest)]
44#[doc = include_str!("../README.md")]
45pub struct Readme;
46
47#[derive(Debug, thiserror::Error)]
49#[non_exhaustive]
50pub enum Error {
51 #[error("resource busy: {0}")]
53 Busy(String),
54 #[error("unsupported capability: {0}")]
56 Unsupported(String),
57 #[error("device execution failed: {0}")]
59 DeviceLost(String),
60 #[error("{backend} {operation} failed ({code}): {message}")]
62 Backend {
63 backend: &'static str,
65 operation: &'static str,
67 code: i32,
69 message: Box<str>,
72 },
73 #[error("{source}")]
75 Execution {
76 #[source]
78 source: std::sync::Arc<Error>,
79 },
80 #[error("execution cancelled")]
82 Cancelled,
83 #[error("{0}")]
85 Message(String),
86 #[error("Loom compilation failed: {message}")]
88 Compile {
89 message: String,
91 diagnostics: Vec<loom::Diagnostic>,
93 report: Option<Box<serde_json::Value>>,
95 },
96 #[error("{0}")]
98 Io(#[from] std::io::Error),
99 #[error("{0}")]
101 Json(#[from] serde_json::Error),
102 #[error("{0}")]
104 Library(#[from] libloading::Error),
105 #[error("{0}")]
107 Download(#[source] Box<ureq::Error>),
108 #[error("{context}: {message}")]
111 Runtime {
112 context: String,
114 code: i32,
116 message: String,
118 },
119 #[error("{context}: {source}")]
121 Context {
122 context: String,
124 #[source]
125 source: Box<Error>,
127 },
128}
129impl Error {
130 pub fn compiler_diagnostics(&self) -> Option<&[loom::Diagnostic]> {
132 match self {
133 Self::Compile { diagnostics, .. } => Some(diagnostics),
134 Self::Context { source, .. } => source.compiler_diagnostics(),
135 Self::Execution { source } => source.compiler_diagnostics(),
136 _ => None,
137 }
138 }
139 pub fn compiler_report(&self) -> Option<&serde_json::Value> {
141 match self {
142 Self::Compile { report, .. } => report.as_deref(),
143 Self::Context { source, .. } => source.compiler_report(),
144 Self::Execution { source } => source.compiler_report(),
145 _ => None,
146 }
147 }
148 pub fn context(self, context: impl Into<String>) -> Self {
150 Self::Context {
151 context: context.into(),
152 source: Box::new(self),
153 }
154 }
155}
156pub type Result<T> = std::result::Result<T, Error>;
158
159pub mod runner;
160
161pub(crate) fn cached_init<T: Clone>(
163 cache: &std::sync::Mutex<Option<T>>,
164 initialize: impl FnOnce() -> Result<T>,
165) -> Result<T> {
166 let mut cached = cache
167 .lock()
168 .map_err(|_| Error::Message("initialization cache poisoned".into()))?;
169 if let Some(value) = cached.as_ref() {
170 return Ok(value.clone());
171 }
172 let value = initialize()?;
173 *cached = Some(value.clone());
174 Ok(value)
175}
176
177#[cfg(test)]
178mod initialization_tests {
179 #[test]
180 fn failures_retry_and_concurrent_success_initializes_once() {
181 use std::sync::{
182 Mutex,
183 atomic::{AtomicUsize, Ordering},
184 };
185 let cache = Mutex::new(None);
186 assert!(
187 super::cached_init(&cache, || Err::<usize, _>(super::Error::Message(
188 "transient".into()
189 )))
190 .is_err()
191 );
192 let calls = AtomicUsize::new(0);
193 std::thread::scope(|scope| {
194 for _ in 0..8 {
195 scope.spawn(|| {
196 assert_eq!(
197 super::cached_init(&cache, || {
198 calls.fetch_add(1, Ordering::Relaxed);
199 Ok(42)
200 })
201 .unwrap(),
202 42
203 );
204 });
205 }
206 });
207 assert_eq!(calls.load(Ordering::Relaxed), 1);
208 }
209}