1#![warn(missing_docs)]
33
34#[cfg(all(target_os = "macos", feature = "metal"))]
35mod device;
36#[cfg(all(target_os = "macos", feature = "metal"))]
37mod kernel;
38#[cfg(all(target_os = "macos", feature = "metal"))]
39mod memory;
40#[cfg(all(target_os = "macos", feature = "metal"))]
41mod runtime;
42
43#[cfg(all(target_os = "macos", feature = "metal"))]
44pub use device::MetalDevice;
45#[cfg(all(target_os = "macos", feature = "metal"))]
46pub use kernel::MetalKernel;
47#[cfg(all(target_os = "macos", feature = "metal"))]
48pub use memory::MetalBuffer;
49#[cfg(all(target_os = "macos", feature = "metal"))]
50pub use runtime::MetalRuntime;
51
52#[cfg(not(all(target_os = "macos", feature = "metal")))]
54mod stub {
55 use async_trait::async_trait;
56 use ringkernel_core::error::{Result, RingKernelError};
57 use ringkernel_core::runtime::{
58 Backend, KernelHandle, KernelId, LaunchOptions, RingKernelRuntime, RuntimeMetrics,
59 };
60
61 pub struct MetalRuntime;
63
64 impl MetalRuntime {
65 pub async fn new() -> Result<Self> {
67 Err(RingKernelError::BackendUnavailable(
68 "Metal not available (requires macOS with metal feature)".to_string(),
69 ))
70 }
71 }
72
73 #[async_trait]
74 impl RingKernelRuntime for MetalRuntime {
75 fn backend(&self) -> Backend {
76 Backend::Metal
77 }
78
79 fn is_backend_available(&self, _backend: Backend) -> bool {
80 false
81 }
82
83 async fn launch(&self, _kernel_id: &str, _options: LaunchOptions) -> Result<KernelHandle> {
84 Err(RingKernelError::BackendUnavailable("Metal".to_string()))
85 }
86
87 fn get_kernel(&self, _kernel_id: &KernelId) -> Option<KernelHandle> {
88 None
89 }
90
91 fn list_kernels(&self) -> Vec<KernelId> {
92 vec![]
93 }
94
95 fn metrics(&self) -> RuntimeMetrics {
96 RuntimeMetrics::default()
97 }
98
99 async fn shutdown(&self) -> Result<()> {
100 Ok(())
101 }
102 }
103}
104
105#[cfg(not(all(target_os = "macos", feature = "metal")))]
106pub use stub::MetalRuntime;
107
108pub fn is_metal_available() -> bool {
110 #[cfg(all(target_os = "macos", feature = "metal"))]
111 {
112 metal::Device::system_default().is_some()
113 }
114 #[cfg(not(all(target_os = "macos", feature = "metal")))]
115 {
116 false
117 }
118}
119
120pub const RING_KERNEL_MSL_TEMPLATE: &str = r#"
122//
123// RingKernel Metal Shading Language Template
124// Generated by ringkernel-metal
125//
126
127#include <metal_stdlib>
128using namespace metal;
129
130// Control block structure (128 bytes)
131struct ControlBlock {
132 atomic_uint is_active;
133 atomic_uint should_terminate;
134 atomic_uint has_terminated;
135 uint _pad1;
136
137 atomic_ulong messages_processed;
138 atomic_ulong messages_in_flight;
139
140 atomic_ulong input_head;
141 atomic_ulong input_tail;
142 atomic_ulong output_head;
143 atomic_ulong output_tail;
144
145 uint input_capacity;
146 uint output_capacity;
147 uint input_mask;
148 uint output_mask;
149
150 // HLC state
151 atomic_ulong hlc_physical;
152 atomic_ulong hlc_logical;
153
154 atomic_uint last_error;
155 atomic_uint error_count;
156
157 uchar _reserved[16];
158};
159
160// Message header structure (256 bytes)
161struct MessageHeader {
162 ulong magic;
163 uint version;
164 uint flags;
165 ulong message_id;
166 ulong correlation_id;
167 ulong source_kernel;
168 ulong dest_kernel;
169 ulong message_type;
170 uchar priority;
171 uchar _reserved1[7];
172 ulong payload_size;
173 uint checksum;
174 uint _reserved2;
175 // HLC timestamp (24 bytes)
176 ulong ts_physical;
177 ulong ts_logical;
178 ulong ts_node_id;
179 // Deadline
180 ulong deadline_physical;
181 ulong deadline_logical;
182 ulong deadline_node_id;
183 uchar _reserved3[104];
184};
185
186// Kernel entry point
187kernel void ring_kernel_main(
188 device ControlBlock* control [[buffer(0)]],
189 device uchar* input_queue [[buffer(1)]],
190 device uchar* output_queue [[buffer(2)]],
191 device uchar* shared_state [[buffer(3)]],
192 uint thread_id [[thread_position_in_threadgroup]],
193 uint threadgroup_id [[threadgroup_position_in_grid]],
194 uint threads_per_group [[threads_per_threadgroup]]
195) {
196 // Check if kernel should process
197 uint is_active = atomic_load_explicit(&control->is_active, memory_order_acquire);
198 if (is_active == 0) {
199 return;
200 }
201
202 // Check termination
203 uint should_term = atomic_load_explicit(&control->should_terminate, memory_order_acquire);
204 if (should_term != 0) {
205 if (thread_id == 0 && threadgroup_id == 0) {
206 atomic_store_explicit(&control->has_terminated, 1, memory_order_release);
207 }
208 return;
209 }
210
211 // User kernel code will be inserted here
212 // USER_KERNEL_CODE
213
214 // Update message counter
215 if (thread_id == 0 && threadgroup_id == 0) {
216 atomic_fetch_add_explicit(&control->messages_processed, 1, memory_order_relaxed);
217 }
218}
219"#;