1use alloc::{
2 boxed::Box,
3 string::{String, ToString},
4};
5use core::{
6 fmt::Display,
7 hash::Hash,
8 marker::PhantomData,
9 sync::atomic::{AtomicI8, Ordering},
10};
11
12use cubecl_common::format::format_str;
13use cubecl_ir::{
14 ElemType, Scope,
15 metadata::Info,
16 pliron::{format, value::Value},
17 settings::KernelSettings,
18};
19use serde::{Deserialize, Serialize};
20
21use crate::{
22 compiler::{CompilationError, Compiler, CubeTask},
23 config::{CubeClRuntimeConfig, RuntimeConfig, compilation::CompilationLogLevel},
24 id::KernelId,
25 server::CubeDim,
26};
27
28pub trait KernelMetadata: Send + Sync + 'static {
30 fn name(&self) -> &'static str {
32 core::any::type_name::<Self>()
33 }
34
35 fn id(&self) -> KernelId;
37
38 fn address_type(&self) -> ElemType;
40}
41
42#[allow(missing_docs)]
43pub struct KernelDefinition {
44 pub body: Scope,
45 pub info: Info,
46 pub settings: KernelSettings,
47}
48
49#[derive(Debug, PartialEq, Eq, Hash, Clone)]
50pub struct KernelArg {
52 pub id: usize,
54 pub value: Value,
56 pub has_extended_meta: bool,
58}
59
60#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
61#[allow(missing_docs)]
62pub struct ScalarKernelArg {
63 pub ty: ElemType,
64 pub count: usize,
65}
66
67#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Hash)]
68#[allow(missing_docs)]
69#[format]
70pub enum Visibility {
71 Uniform,
72 Read,
73 ReadWrite,
74}
75
76pub struct CompiledKernel<C: Compiler> {
78 pub entrypoint_name: String,
88
89 pub debug_name: Option<&'static str>,
107
108 pub source: String,
110 pub repr: Option<C::Representation>,
112 pub cube_dim: CubeDim,
114 pub debug_info: Option<DebugInformation>,
116}
117
118#[derive(new)]
120pub struct DebugInformation {
121 pub lang_tag: &'static str,
123 pub id: KernelId,
125}
126
127pub trait CubeKernel: KernelMetadata {
129 fn define(&self) -> KernelDefinition;
131}
132
133pub struct KernelTask<C: Compiler, K: CubeKernel> {
135 kernel_definition: K,
136 _compiler: PhantomData<C>,
137}
138
139pub struct CubeTaskKernel<C: Compiler> {
141 pub task: Box<dyn CubeTask<C>>,
143}
144
145impl<C: Compiler, K: CubeKernel> KernelTask<C, K> {
146 pub fn new(kernel_definition: K) -> Self {
148 Self {
149 kernel_definition,
150 _compiler: PhantomData,
151 }
152 }
153}
154
155impl<C: Compiler, K: CubeKernel> CubeTask<C> for KernelTask<C, K> {
156 fn define(&self) -> KernelDefinition {
157 self.kernel_definition.define()
158 }
159
160 fn compile(
161 &self,
162 gpu_ir: KernelDefinition,
163 compiler: &mut C,
164 compilation_options: &C::CompilationOptions,
165 ) -> Result<CompiledKernel<C>, CompilationError> {
166 let entrypoint_name = gpu_ir.settings.kernel_name.clone();
167 let cube_dim = gpu_ir.settings.cube_dim.into();
168 let lower_level_ir = compiler.compile(gpu_ir, compilation_options)?;
169
170 Ok(CompiledKernel {
171 entrypoint_name,
172 debug_name: Some(core::any::type_name::<K>()),
173 source: lower_level_ir.to_string(),
174 repr: Some(lower_level_ir),
175 cube_dim,
176 debug_info: None,
177 })
178 }
179}
180
181impl<C: Compiler, K: CubeKernel> KernelMetadata for KernelTask<C, K> {
182 fn id(&self) -> KernelId {
184 self.kernel_definition.id()
185 }
186
187 fn name(&self) -> &'static str {
189 self.kernel_definition.name()
190 }
191
192 fn address_type(&self) -> ElemType {
193 self.kernel_definition.address_type()
194 }
195}
196
197impl<C: Compiler> KernelMetadata for Box<dyn CubeTask<C>> {
198 fn id(&self) -> KernelId {
200 self.as_ref().id()
201 }
202
203 fn name(&self) -> &'static str {
205 self.as_ref().name()
206 }
207
208 fn address_type(&self) -> ElemType {
209 self.as_ref().address_type()
210 }
211}
212
213static COMPILATION_LEVEL: AtomicI8 = AtomicI8::new(-1);
214
215fn compilation_level() -> u8 {
216 let compilation_level = COMPILATION_LEVEL.load(Ordering::Relaxed);
217 if compilation_level == -1 {
218 let val = match CubeClRuntimeConfig::get().compilation.logger.level {
219 CompilationLogLevel::Full => 2,
220 CompilationLogLevel::Disabled => 0,
221 CompilationLogLevel::Basic => 1,
222 };
223
224 COMPILATION_LEVEL.store(val, Ordering::Relaxed);
225 val as u8
226 } else {
227 compilation_level as u8
228 }
229}
230
231impl<C: Compiler> Display for CompiledKernel<C> {
232 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
233 match compilation_level() {
234 2 => self.format_full(f),
235 _ => self.format_basic(f),
236 }
237 }
238}
239
240impl<C: Compiler> CompiledKernel<C> {
241 fn format_basic(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
242 f.write_str("[Compiling kernel]")?;
243 if let Some(name) = self.debug_name {
244 if name.len() <= 32 {
245 f.write_fmt(format_args!(" {name}"))?;
246 } else {
247 f.write_fmt(format_args!(" {}", name.split('<').next().unwrap_or("")))?;
248 }
249 }
250
251 Ok(())
252 }
253
254 fn format_full(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
255 f.write_str("[START_KERNEL_COMPILATION]")?;
256
257 if let Some(name) = self.debug_name {
258 if name.len() <= 32 {
259 f.write_fmt(format_args!("\nname: {name}"))?;
260 } else {
261 let name = format_str(name, &[('<', '>')], false);
262 f.write_fmt(format_args!("\nname: {name}"))?;
263 }
264 }
265
266 if let Some(info) = &self.debug_info {
267 f.write_fmt(format_args!("\nid: {:#?}", info.id))?;
268 }
269
270 f.write_fmt(format_args!(
271 "
272source:
273```{}
274{}
275```
276[END_KERNEL_COMPILATION]
277",
278 self.debug_info
279 .as_ref()
280 .map(|info| info.lang_tag)
281 .unwrap_or(""),
282 self.source
283 ))
284 }
285}