teeny_cuda/compiler/
graph.rs1use std::collections::HashMap;
18
19use teeny_compiler::compiler::backend::llvm::compiler::LlvmCompiler;
20use teeny_core::{
21 compiler::{Compiler, Target},
22 device::program::Kernel,
23 graph::{Graph, compiler::GraphCompiler},
24 model::{ExecutableOp, Lowering, LoweringMode, Model},
25 utils::dag::Dag,
26};
27
28use crate::{
29 errors::Result,
30 model::{CompiledNode, CudaModel},
31};
32
33struct ForwardKernelAdapter<'a>(&'a dyn ExecutableOp);
36
37#[cfg(feature = "training")]
39struct BackwardKernelAdapter<'a>(&'a dyn ExecutableOp);
40
41impl<'a> Kernel for ForwardKernelAdapter<'a> {
42 type Args<'b> = ();
44
45 fn name(&self) -> &str {
46 self.0.name()
47 }
48
49 fn source(&self) -> &str {
50 self.0.forward_kernel_source()
51 }
52
53 fn kernel_source(&self) -> &str {
54 self.0.forward_kernel_source()
55 }
56
57 fn entry_point_source(&self) -> &str {
58 ""
59 }
60}
61
62#[cfg(feature = "training")]
63impl<'a> Kernel for BackwardKernelAdapter<'a> {
64 type Args<'b> = ();
65
66 fn name(&self) -> &str {
67 self.0.name()
68 }
69
70 fn source(&self) -> &str {
71 self.0.backward_kernel_source()
72 }
73
74 fn kernel_source(&self) -> &str {
75 self.0.backward_kernel_source()
76 }
77
78 fn entry_point_source(&self) -> &str {
79 ""
80 }
81}
82
83#[derive(Debug, Clone)]
85pub struct CudaGraphCompiler {
86 compiler: LlvmCompiler,
87}
88
89impl CudaGraphCompiler {
90 pub fn new(compiler: LlvmCompiler) -> Self {
92 Self { compiler }
93 }
94
95 pub fn compile_model<'a, L: Lowering<'a>, T: Target>(
98 &self,
99 graph: &Graph,
100 lowering: &L,
101 target: &T,
102 mode: LoweringMode,
103 force: bool,
104 ) -> Result<CudaModel<'a>> {
105 self.compile_inner(graph, lowering, target, mode, force)
106 }
107
108 fn compile_inner<'a, L: Lowering<'a>, T: Target>(
109 &self,
110 graph: &Graph,
111 lowering: &L,
112 target: &T,
113 mode: LoweringMode,
114 force: bool,
115 ) -> Result<CudaModel<'a>> {
116 let (op_dag, graph_to_dag) = lowering.lower_with_mapping(graph, mode)?;
117
118 let compiler = match target.target_cpu() {
119 Some(cpu) => self.compiler.clone().with_target_cpu(cpu),
120 None => self.compiler.clone(),
121 };
122
123 let mut compiled_dag: Dag<CompiledNode> = Dag::new();
124
125 for i in 0..op_dag.len() {
126 let op = op_dag.node(i).value.as_ref();
127 let ptx_path = if op.is_input() {
128 String::new()
129 } else if op.forward_kernel_source().is_empty() {
130 return Err(anyhow::anyhow!(
131 "no forward kernel source for op {}",
132 op.name()
133 ));
134 } else {
135 let adapter = ForwardKernelAdapter(op);
136 compiler.compile(&adapter, target, force)?
137 };
138
139 #[cfg(feature = "training")]
140 let backward_ptx_path = if op.is_input() || op.backward_kernel_source().is_empty() {
141 None
142 } else {
143 let adapter = BackwardKernelAdapter(op);
144 Some(compiler.compile(&adapter, target, force)?)
145 };
146
147 compiled_dag.add_node(CompiledNode {
148 ptx_path,
149 entry_point: op.forward_kernel_entry_point().to_string(),
150 output_shape: op.output_shape().clone(),
151 output_dtype: op.output_dtype(),
152 runtime_op: op.runtime_op(),
153 #[cfg(feature = "training")]
154 backward_ptx_path,
155 #[cfg(feature = "training")]
156 backward_entry_point: op.backward_kernel_entry_point().to_string(),
157 });
158 }
159
160 for i in 0..op_dag.len() {
165 for &parent in &op_dag.node(i).parents {
166 compiled_dag.add_edge(parent, i);
167 }
168 }
169
170 let mut dag_names: HashMap<usize, String> = graph
173 .names
174 .iter()
175 .filter_map(|(&graph_idx, name)| {
176 let dag_idx = *graph_to_dag.get(graph_idx)?;
177 Some((dag_idx, name.clone()))
178 })
179 .collect();
180
181 for (dag_idx, name) in lowering.extra_dag_names(graph, &graph_to_dag) {
185 dag_names.entry(dag_idx).or_insert(name);
186 }
187
188 CudaModel::with_names(compiled_dag, dag_names)
189 }
190}
191
192impl GraphCompiler for CudaGraphCompiler {
193 fn compile<'a, L: Lowering<'a>, T: Target>(
194 &self,
195 graph: &Graph,
196 lowering: &L,
197 target: &T,
198 mode: LoweringMode,
199 force: bool,
200 ) -> Result<impl Model<'a>> {
201 self.compile_inner(graph, lowering, target, mode, force)
202 }
203}