use onnx_runtime_ir::TensorLayout;
use crate::error::Result;
use crate::tensor::{TensorMut, TensorView};
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[non_exhaustive]
pub struct Cost {
pub compute_us: f64,
pub memory_us: f64,
pub transfer_us: f64,
pub launch_us: f64,
pub bytes_moved: u64,
}
impl Cost {
pub const ZERO: Cost = Cost {
compute_us: 0.0,
memory_us: 0.0,
transfer_us: 0.0,
launch_us: 0.0,
bytes_moved: 0,
};
pub fn new(compute_us: f64, memory_us: f64, transfer_us: f64) -> Self {
Self {
compute_us,
memory_us,
transfer_us,
..Self::ZERO
}
}
pub fn with_launch_us(mut self, launch_us: f64) -> Self {
self.launch_us = launch_us;
self
}
pub fn with_bytes_moved(mut self, bytes_moved: u64) -> Self {
self.bytes_moved = bytes_moved;
self
}
pub fn total_us(&self) -> f64 {
self.compute_us + self.memory_us + self.transfer_us + self.launch_us
}
}
pub enum KernelMatch {
Supported {
cost: Cost,
required_input_layouts: Option<Vec<TensorLayout>>,
output_layouts: Vec<TensorLayout>,
},
Unsupported,
}
impl KernelMatch {
pub fn is_supported(&self) -> bool {
matches!(self, KernelMatch::Supported { .. })
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ViewOutput {
pub input_index: usize,
pub shape: Vec<usize>,
pub strides: Vec<i64>,
pub byte_offset: usize,
}
pub trait Kernel: Send {
fn execute(&self, inputs: &[TensorView], outputs: &mut [TensorMut]) -> Result<()>;
fn estimated_flops(&self) -> Option<u64> {
None
}
fn view_outputs(&self, inputs: &[TensorView], num_outputs: usize) -> Option<Vec<ViewOutput>> {
let _ = (inputs, num_outputs);
None
}
fn supports_strided_input(&self, input_idx: usize) -> bool {
let _ = input_idx;
false
}
fn preferred_output_layout(&self) -> Option<TensorLayout> {
None
}
fn cuda_graph_compatible(&self) -> bool {
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cost_zero_and_total() {
assert_eq!(Cost::ZERO.total_us(), 0.0);
let c = Cost::new(10.0, 5.0, 2.0);
assert_eq!(c.total_us(), 17.0);
assert_eq!(c.bytes_moved, 0);
assert_eq!(c.launch_us, 0.0);
}
#[test]
fn cost_builders_are_additive() {
let c = Cost::new(10.0, 5.0, 2.0)
.with_launch_us(3.0)
.with_bytes_moved(4096);
assert_eq!(c.total_us(), 20.0);
assert_eq!(c.bytes_moved, 4096);
}
#[test]
fn kernel_match_reports_support() {
let supported = KernelMatch::Supported {
cost: Cost::new(1.0, 0.0, 0.0),
required_input_layouts: None,
output_layouts: vec![],
};
assert!(supported.is_supported());
assert!(!KernelMatch::Unsupported.is_supported());
}
}