cubecl_runtime/channel/
mpsc.rs1use std::{sync::Arc, thread};
2
3use cubecl_common::benchmark::TimestampsResult;
4
5use super::ComputeChannel;
6use crate::{
7 memory_management::MemoryUsage,
8 server::{Binding, ComputeServer, CubeCount, Handle},
9 storage::BindingResource,
10 ExecutionMode,
11};
12
13#[derive(Debug)]
16pub struct MpscComputeChannel<Server>
17where
18 Server: ComputeServer,
19{
20 state: Arc<MpscComputeChannelState<Server>>,
21}
22
23#[derive(Debug)]
24struct MpscComputeChannelState<Server>
25where
26 Server: ComputeServer,
27{
28 _handle: thread::JoinHandle<()>,
29 sender: async_channel::Sender<Message<Server>>,
30}
31
32type Callback<Response> = async_channel::Sender<Response>;
33
34enum Message<Server>
35where
36 Server: ComputeServer,
37{
38 Read(Vec<Binding>, Callback<Vec<Vec<u8>>>),
39 GetResource(Binding, Callback<BindingResource<Server>>),
40 Create(Vec<u8>, Callback<Handle>),
41 Empty(usize, Callback<Handle>),
42 ExecuteKernel((Server::Kernel, CubeCount, ExecutionMode), Vec<Binding>),
43 Flush,
44 SyncElapsed(Callback<TimestampsResult>),
45 Sync(Callback<()>),
46 GetMemoryUsage(Callback<MemoryUsage>),
47 EnableTimestamps,
48 DisableTimestamps,
49}
50
51impl<Server> MpscComputeChannel<Server>
52where
53 Server: ComputeServer + 'static,
54{
55 pub fn new(mut server: Server) -> Self {
57 let (sender, receiver) = async_channel::unbounded();
58
59 let _handle = thread::spawn(move || {
60 cubecl_common::future::block_on(async {
63 while let Ok(message) = receiver.recv().await {
64 match message {
65 Message::Read(bindings, callback) => {
66 let data = server.read(bindings).await;
67 callback.send(data).await.unwrap();
68 }
69 Message::GetResource(binding, callback) => {
70 let data = server.get_resource(binding);
71 callback.send(data).await.unwrap();
72 }
73 Message::Create(data, callback) => {
74 let handle = server.create(&data);
75 callback.send(handle).await.unwrap();
76 }
77 Message::Empty(size, callback) => {
78 let handle = server.empty(size);
79 callback.send(handle).await.unwrap();
80 }
81 Message::ExecuteKernel(kernel, bindings) => unsafe {
82 server.execute(kernel.0, kernel.1, bindings, kernel.2);
83 },
84 Message::SyncElapsed(callback) => {
85 let duration = server.sync_elapsed().await;
86 callback.send(duration).await.unwrap();
87 }
88 Message::Sync(callback) => {
89 server.sync().await;
90 callback.send(()).await.unwrap();
91 }
92 Message::Flush => {
93 server.flush();
94 }
95 Message::GetMemoryUsage(callback) => {
96 callback.send(server.memory_usage()).await.unwrap();
97 }
98 Message::EnableTimestamps => {
99 server.enable_timestamps();
100 }
101 Message::DisableTimestamps => {
102 server.disable_timestamps();
103 }
104 };
105 }
106 });
107 });
108
109 let state = Arc::new(MpscComputeChannelState { sender, _handle });
110
111 Self { state }
112 }
113}
114
115impl<Server: ComputeServer> Clone for MpscComputeChannel<Server> {
116 fn clone(&self) -> Self {
117 Self {
118 state: self.state.clone(),
119 }
120 }
121}
122
123impl<Server> ComputeChannel<Server> for MpscComputeChannel<Server>
124where
125 Server: ComputeServer + 'static,
126{
127 async fn read(&self, bindings: Vec<Binding>) -> Vec<Vec<u8>> {
128 let sender = self.state.sender.clone();
129 let (callback, response) = async_channel::unbounded();
130 sender
131 .send(Message::Read(bindings, callback))
132 .await
133 .unwrap();
134 handle_response(response.recv().await)
135 }
136
137 fn get_resource(&self, binding: Binding) -> BindingResource<Server> {
138 let (callback, response) = async_channel::unbounded();
139
140 self.state
141 .sender
142 .send_blocking(Message::GetResource(binding, callback))
143 .unwrap();
144
145 handle_response(response.recv_blocking())
146 }
147
148 fn create(&self, data: &[u8]) -> Handle {
149 let (callback, response) = async_channel::unbounded();
150
151 self.state
152 .sender
153 .send_blocking(Message::Create(data.to_vec(), callback))
154 .unwrap();
155
156 handle_response(response.recv_blocking())
157 }
158
159 fn empty(&self, size: usize) -> Handle {
160 let (callback, response) = async_channel::unbounded();
161 self.state
162 .sender
163 .send_blocking(Message::Empty(size, callback))
164 .unwrap();
165
166 handle_response(response.recv_blocking())
167 }
168
169 unsafe fn execute(
170 &self,
171 kernel: Server::Kernel,
172 count: CubeCount,
173 bindings: Vec<Binding>,
174 kind: ExecutionMode,
175 ) {
176 self.state
177 .sender
178 .send_blocking(Message::ExecuteKernel((kernel, count, kind), bindings))
179 .unwrap()
180 }
181
182 fn flush(&self) {
183 self.state.sender.send_blocking(Message::Flush).unwrap()
184 }
185
186 async fn sync(&self) {
187 let (callback, response) = async_channel::unbounded();
188 self.state
189 .sender
190 .send(Message::Sync(callback))
191 .await
192 .unwrap();
193 handle_response(response.recv().await)
194 }
195
196 async fn sync_elapsed(&self) -> TimestampsResult {
197 let (callback, response) = async_channel::unbounded();
198 self.state
199 .sender
200 .send(Message::SyncElapsed(callback))
201 .await
202 .unwrap();
203 handle_response(response.recv().await)
204 }
205
206 fn memory_usage(&self) -> crate::memory_management::MemoryUsage {
207 let (callback, response) = async_channel::unbounded();
208 self.state
209 .sender
210 .send_blocking(Message::GetMemoryUsage(callback))
211 .unwrap();
212 handle_response(response.recv_blocking())
213 }
214
215 fn enable_timestamps(&self) {
216 self.state
217 .sender
218 .send_blocking(Message::EnableTimestamps)
219 .unwrap();
220 }
221
222 fn disable_timestamps(&self) {
223 self.state
224 .sender
225 .send_blocking(Message::DisableTimestamps)
226 .unwrap();
227 }
228}
229
230fn handle_response<Response, Err: core::fmt::Debug>(response: Result<Response, Err>) -> Response {
231 match response {
232 Ok(val) => val,
233 Err(err) => panic!("Can't connect to the server correctly {err:?}"),
234 }
235}