1use alloc::format;
2use alloc::string::String;
3use alloc::sync::Arc;
4use core::{
5 any::{Any, TypeId},
6 fmt::Display,
7 hash::{Hash, Hasher},
8};
9use cubecl_common::{
10 format::{DebugRaw, format_str},
11 hash::{StableHash, StableHasher},
12};
13use cubecl_ir::{
14 AddressType,
15 settings::{Dim3, ExecutionMode},
16};
17use derive_more::{Eq, PartialEq};
18
19#[macro_export(local_inner_macros)]
20macro_rules! storage_id_type {
22 ($name:ident) => {
23 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
25 pub struct $name {
26 value: usize,
27 }
28
29 impl $name {
30 pub fn new() -> Self {
32 use core::sync::atomic::{AtomicUsize, Ordering};
33
34 static COUNTER: AtomicUsize = AtomicUsize::new(0);
35
36 let value = COUNTER.fetch_add(1, Ordering::Relaxed);
37 if value == usize::MAX {
38 core::panic!("Memory ID overflowed");
39 }
40 Self { value }
41 }
42 }
43
44 impl Default for $name {
45 fn default() -> Self {
46 Self::new()
47 }
48 }
49 };
50}
51
52#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
63pub struct GraphId {
64 value: u64,
65}
66
67impl GraphId {
68 pub fn new() -> Self {
70 use core::sync::atomic::{AtomicU64, Ordering};
71
72 static COUNTER: AtomicU64 = AtomicU64::new(0);
73
74 let value = COUNTER.fetch_add(1, Ordering::Relaxed);
75 if value == u64::MAX {
76 core::panic!("Graph ID overflowed");
77 }
78 Self { value }
79 }
80}
81
82impl Default for GraphId {
83 fn default() -> Self {
84 Self::new()
85 }
86}
87
88#[derive(Clone, PartialEq, Eq)]
90pub struct KernelId {
91 #[eq(skip)]
92 type_name: &'static str,
93 pub(crate) type_id: core::any::TypeId,
94 pub cube_dim: Dim3,
96 pub address_type: AddressType,
98 pub mode: ExecutionMode,
100 pub(crate) info: Option<Info>,
101}
102
103impl Hash for KernelId {
104 fn hash<H: Hasher>(&self, state: &mut H) {
105 self.type_id.hash(state);
106 self.address_type.hash(state);
107 self.cube_dim.hash(state);
108 self.mode.hash(state);
109 self.info.hash(state);
110 }
111}
112
113impl core::fmt::Debug for KernelId {
114 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
115 let mut debug_str = f.debug_struct("KernelId");
116 debug_str
117 .field("type", &DebugRaw(self.type_name))
118 .field("address_type", &self.address_type);
119 debug_str.field("cube_dim", &self.cube_dim);
120 debug_str.field("mode", &self.mode);
121 match &self.info {
122 Some(info) => debug_str.field("info", info),
123 None => debug_str.field("info", &self.info),
124 };
125 debug_str.finish()
126 }
127}
128
129impl Display for KernelId {
130 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
131 match &self.info {
132 Some(info) => f.write_str(
133 format_str(
134 format!("{info:?}").as_str(),
135 &[('(', ')'), ('[', ']'), ('{', '}')],
136 true,
137 )
138 .as_str(),
139 ),
140 None => f.write_str("No info"),
141 }
142 }
143}
144
145impl KernelId {
146 pub fn new<T: 'static>() -> Self {
148 Self {
149 type_id: core::any::TypeId::of::<T>(),
150 type_name: core::any::type_name::<T>(),
151 info: None,
152 cube_dim: Dim3::new_single(),
153 mode: ExecutionMode::Checked,
154 address_type: Default::default(),
155 }
156 }
157
158 pub fn stable_format(&self) -> String {
162 format!(
163 "{}-{}-{:?}-{:?}-{:?}",
164 self.type_name, self.address_type, self.cube_dim, self.mode, self.info
165 )
166 }
167
168 pub fn stable_hash(&self) -> StableHash {
172 let mut hasher = StableHasher::new();
173 self.type_name.hash(&mut hasher);
174 self.address_type.hash(&mut hasher);
175 self.cube_dim.hash(&mut hasher);
176 self.mode.hash(&mut hasher);
177 self.info.hash(&mut hasher);
178
179 hasher.finalize()
180 }
181
182 pub fn info<I: 'static + PartialEq + Eq + Hash + core::fmt::Debug + Send + Sync>(
187 mut self,
188 info: I,
189 ) -> Self {
190 self.info = Some(Info::new(info));
191 self
192 }
193
194 pub fn mode(mut self, mode: ExecutionMode) -> Self {
196 self.mode = mode;
197 self
198 }
199
200 pub fn cube_dim(mut self, cube_dim: Dim3) -> Self {
202 self.cube_dim = cube_dim;
203 self
204 }
205
206 pub fn address_type(mut self, addr_ty: AddressType) -> Self {
208 self.address_type = addr_ty;
209 self
210 }
211}
212
213impl core::fmt::Debug for Info {
214 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
215 self.value.fmt(f)
216 }
217}
218
219impl Info {
220 fn new<T: 'static + PartialEq + Eq + Hash + core::fmt::Debug + Send + Sync>(id: T) -> Self {
221 Self {
222 value: Arc::new(id),
223 }
224 }
225}
226
227trait DynKey: core::fmt::Debug + Send + Sync {
233 fn dyn_type_id(&self) -> TypeId;
234 fn dyn_eq(&self, other: &dyn DynKey) -> bool;
235 fn dyn_hash(&self, state: &mut dyn Hasher);
236 fn dyn_hash_one(&self) -> StableHash;
237 fn as_any(&self) -> &dyn Any;
238}
239
240impl PartialEq for Info {
241 fn eq(&self, other: &Self) -> bool {
242 self.value.dyn_eq(other.value.as_ref())
243 }
244}
245
246#[derive(Clone)]
248pub(crate) struct Info {
249 value: Arc<dyn DynKey>,
250}
251impl Eq for Info {}
252
253impl Hash for Info {
254 fn hash<H: Hasher>(&self, state: &mut H) {
255 self.value.dyn_type_id().hash(state);
256 self.value.dyn_hash(state)
257 }
258}
259
260impl<T: 'static + PartialEq + Eq + Hash + core::fmt::Debug + Send + Sync> DynKey for T {
261 fn dyn_eq(&self, other: &dyn DynKey) -> bool {
262 if let Some(other) = other.as_any().downcast_ref::<T>() {
263 self == other
264 } else {
265 false
266 }
267 }
268
269 fn dyn_type_id(&self) -> TypeId {
270 TypeId::of::<T>()
271 }
272
273 fn dyn_hash(&self, state: &mut dyn Hasher) {
274 let hash = self.dyn_hash_one();
275 state.write_u128(hash);
276 }
277
278 fn dyn_hash_one(&self) -> StableHash {
279 let mut hasher = StableHasher::new();
280 self.hash(&mut hasher);
281 hasher.finalize()
282 }
283
284 fn as_any(&self) -> &dyn Any {
285 self
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292 use std::collections::HashSet;
293
294 #[test_log::test]
295 pub fn kernel_id_hash() {
296 let value_1 = KernelId::new::<()>().info("1");
297 let value_2 = KernelId::new::<()>().info("2");
298
299 let mut set = HashSet::new();
300
301 set.insert(value_1.clone());
302
303 assert!(set.contains(&value_1));
304 assert!(!set.contains(&value_2));
305 }
306}