use std::sync::Arc;
use onnx_runtime_ir::{Graph, WeightRef};
use onnx_runtime_tracer::{Args, SpanGuard};
use crate::error::{OptimizerError, Result};
fn optimizer_span(pass_name: &str) -> Option<SpanGuard> {
onnx_runtime_tracer::global_context()
.filter(|trace| trace.is_enabled())
.map(|trace| trace.span(format!("optimize.{pass_name}"), "optimize"))
}
pub trait InitializerResolver: Send + Sync {
fn bytes<'a>(&'a self, weight: &'a WeightRef) -> Option<&'a [u8]>;
}
#[derive(Clone, Default)]
#[non_exhaustive]
pub struct PassContext {
initializer_resolver: Option<Arc<dyn InitializerResolver>>,
}
impl std::fmt::Debug for PassContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PassContext")
.field(
"initializer_resolver",
&self.initializer_resolver.as_ref().map(|_| "<resolver>"),
)
.finish()
}
}
impl PassContext {
pub fn new() -> Self {
Self::default()
}
pub fn with_initializer_resolver(mut self, resolver: Arc<dyn InitializerResolver>) -> Self {
self.initializer_resolver = Some(resolver);
self
}
pub fn initializer_bytes<'b>(&'b self, weight: &'b WeightRef) -> Option<&'b [u8]> {
match weight {
WeightRef::Inline(tensor) => Some(&tensor.data),
WeightRef::External { .. } => self.initializer_resolver.as_deref()?.bytes(weight),
}
}
}
pub trait OptimizationPass: Send + Sync {
fn name(&self) -> &str;
fn run(&self, graph: &mut Graph, ctx: &PassContext) -> Result<()>;
fn postconditions(&self, graph: &Graph) -> Result<()> {
graph
.validate()
.map_err(|errors| OptimizerError::PostconditionFailed {
pass: self.name().to_string(),
errors,
})
}
}
pub fn run_passes(
graph: &mut Graph,
passes: &[Box<dyn OptimizationPass>],
ctx: &PassContext,
) -> Result<()> {
for pass in passes {
let nodes_before = graph.num_nodes();
let values_before = graph.values.len();
let mut span = optimizer_span(pass.name());
if let Some(span) = span.as_mut() {
span.set_args(
Args::new()
.with("pass", pass.name().to_string())
.with("nodes_before", nodes_before as u64)
.with("values_before", values_before as u64),
);
}
pass.run(graph, ctx)?;
#[cfg(debug_assertions)]
pass.postconditions(graph)?;
if let Some(span) = span.as_mut() {
span.set_args(
Args::new()
.with("pass", pass.name().to_string())
.with("nodes_before", nodes_before as u64)
.with("nodes_after", graph.num_nodes() as u64)
.with(
"nodes_delta",
graph.num_nodes() as i64 - nodes_before as i64,
)
.with("values_before", values_before as u64)
.with("values_after", graph.values.len() as u64),
);
}
}
Ok(())
}