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