Skip to main content

openinfer_simulator/runtime/executor/
mod.rs

1//! Graph execution engine.
2//!
3//! The executor runs a validated graph against a model, managing runtime state
4//! and tensor storage. Use `Simulator` to validate and create an executor.
5mod fetch;
6mod iter;
7
8use std::sync::Arc;
9
10use anyhow::Result;
11
12use crate::graph::Graph;
13use crate::runtime::model_loader::ModelLoader;
14use crate::runtime::state::RuntimeState;
15use crate::runtime::trace::{TraceEvent, TraceEventKind};
16use crate::simulator::Device;
17use crate::tensor::{Tensor, TensorElement, TensorValue};
18
19pub use fetch::Fetchable;
20pub use iter::ExecutorIter;
21pub(crate) use iter::run_block;
22
23/// Executes a graph against a model and mutable runtime state.
24pub struct Executor {
25    state: RuntimeState,
26}
27
28impl Executor {
29    /// Create a new executor for a graph/model/device configuration.
30    pub fn new(
31        model: Arc<ModelLoader>,
32        graph: Graph,
33        device: Device,
34        trace_enabled: bool,
35        timer_enabled: bool,
36    ) -> Result<Self> {
37        Ok(Self {
38            state: RuntimeState::new(model, graph, device, trace_enabled, timer_enabled)?,
39        })
40    }
41
42    /// Insert a dynamic (runtime-provided) tensor value.
43    ///
44    /// # Example
45    /// ```no_run
46    /// # use openinfer::{ModelLoader, Simulator, Device, Tensor, graph};
47    /// # fn main() -> anyhow::Result<()> {
48    /// let model = ModelLoader::open("model.oinf")?;
49    /// let g = graph! { dynamic { x: f32[1]; } block entry { return; } };
50    /// let mut exec = Simulator::new(&model, &g, Device::Cpu)?.make_executor()?;
51    /// exec.insert_dynamic("x", Tensor::from_vec(vec![1.0f32])?)?;
52    /// # Ok(()) }
53    /// ```
54    pub fn insert_dynamic<T: Into<TensorValue>>(&mut self, name: &str, data: T) -> Result<()> {
55        self.state.insert_dynamic(name, data.into())
56    }
57
58    /// Fetch a named value using a `Fetchable` adapter.
59    ///
60    /// # Example
61    /// ```no_run
62    /// # use openinfer::{ModelLoader, Simulator, Device, graph};
63    /// # fn main() -> anyhow::Result<()> {
64    /// let model = ModelLoader::open("model.oinf")?;
65    /// let g = graph! { constant { alpha: f32; } block entry { return; } };
66    /// let mut exec = Simulator::new(&model, &g, Device::Cpu)?.make_executor()?;
67    /// let alpha: f32 = exec.fetch("alpha")?;
68    /// # Ok(()) }
69    /// ```
70    pub fn fetch<T: Fetchable>(&mut self, name: &str) -> Result<T> {
71        T::fetch(&mut self.state, name)
72    }
73
74    /// Fetch a tensor and convert it to a concrete element type.
75    pub fn fetch_typed<T: TensorElement>(&mut self, name: &str) -> Result<Tensor<T>> {
76        self.state.fetch_typed(name)
77    }
78
79    /// Fetch a tensor as a raw `TensorValue`.
80    pub fn fetch_raw(&mut self, name: &str) -> Result<TensorValue> {
81        self.state.get_tensor(name)
82    }
83
84    /// Execute the graph to completion, returning the last trace event.
85    ///
86    /// # Example
87    /// ```no_run
88    /// # use openinfer::{ModelLoader, Simulator, Device, graph};
89    /// # fn main() -> anyhow::Result<()> {
90    /// let model = ModelLoader::open("model.oinf")?;
91    /// let g = graph! { block entry { return; } };
92    /// let mut exec = Simulator::new(&model, &g, Device::Cpu)?.make_executor()?;
93    /// exec.step()?;
94    /// # Ok(()) }
95    /// ```
96    pub fn step(&mut self) -> Result<Option<TraceEvent>> {
97        let trace_enabled = self.state.trace_enabled();
98        let mut iter = self.iterate();
99        let mut last_event = None;
100        while let Some(step) = iter.next() {
101            let step = step?;
102            if trace_enabled {
103                log_trace_event(&step.event);
104            }
105            last_event = Some(step.event);
106        }
107        Ok(last_event)
108    }
109
110    /// Return the accumulated trace events.
111    pub fn trace(&self) -> Vec<TraceEvent> {
112        self.state.trace()
113    }
114
115    /// Iterate execution step-by-step, yielding `TraceStep` values.
116    ///
117    /// # Example
118    /// ```no_run
119    /// # use openinfer::{ModelLoader, Simulator, Device, graph};
120    /// # fn main() -> anyhow::Result<()> {
121    /// let model = ModelLoader::open("model.oinf")?;
122    /// let g = graph! { block entry { return; } };
123    /// let mut exec = Simulator::new(&model, &g, Device::Cpu)?.make_executor()?;
124    /// for step in exec.iterate() {
125    ///     let _ = step?;
126    /// }
127    /// # Ok(()) }
128    /// ```
129    pub fn iterate(&mut self) -> ExecutorIter<'_> {
130        ExecutorIter::new(self)
131    }
132}
133
134fn log_trace_event(event: &TraceEvent) {
135    crate::log!(
136        "{} {} [{}] -- {} -- ({})",
137        event.node_index,
138        event.node_uuid,
139        event.block_name,
140        event.node_desc,
141        event.micros
142    );
143}