cubecl_server/device_events/base.rs
1use cubecl_common::profile::Duration;
2
3use crate::driver::DriverError;
4
5/// The device event calls an [`EventFence`](super::EventFence) and an
6/// [`EventProfiler`](super::EventProfiler) are built from.
7///
8/// The C-family device APIs agree on an event model: a timestamp is recorded
9/// into a queue, the device stamps it as the queue reaches it, and the span
10/// between two of them is read back afterwards. One implementation per backend
11/// spells those calls; everything above them — a fence's lifetime, a profiling
12/// window, the anchor that places one on the host clock — is written once.
13///
14/// This is deliberately only what those two types need. Memory, launches and
15/// module loading have their own seams; widening this trait to cover them would
16/// make it the device API rather than the device's *event* API, and the name
17/// would stop being true.
18pub trait EventApi: Send + Sync + 'static {
19 /// A timestamp recorded on the device.
20 ///
21 /// A handle into the driver rather than thread-affine state: it is
22 /// recorded on the server's thread and read back on whichever thread waits
23 /// for it, so the backend asserts `Send + Sync` on its own newtype, where
24 /// the justification is specific enough to check.
25 type Event: Send + Sync;
26
27 /// The queue an event is recorded into.
28 ///
29 /// No `Send` bound: a stream is held by the profiler, which lives inside a
30 /// server the backend already asserts is `Send` as a whole. Only the event
31 /// crosses threads on its own.
32 type Stream: Copy;
33
34 /// The backend as a reader of a log line sees it.
35 const BACKEND: &'static str;
36
37 /// Create an event with timing enabled.
38 ///
39 /// Timing is the point: the flag a pure synchronization event would take
40 /// to disable it is exactly the timestamp a profiler reads back.
41 ///
42 /// # Errors
43 ///
44 /// [`DriverError`] when the driver refuses the event, which is when the
45 /// device is already in trouble or out of resources.
46 fn event_create() -> Result<Self::Event, DriverError>;
47
48 /// Release an event. Called from the event's own `Drop`.
49 ///
50 /// # Errors
51 ///
52 /// [`DriverError`], which the caller can only log: a destructor has
53 /// nowhere to report.
54 fn event_destroy(event: &mut Self::Event) -> Result<(), DriverError>;
55
56 /// Enqueue the timestamp on `stream`, returning once it is queued.
57 ///
58 /// # Errors
59 ///
60 /// [`DriverError`] when the stream will not take the event — a stream
61 /// recording a graph is the case callers screen for in advance.
62 fn event_record(event: &Self::Event, stream: Self::Stream) -> Result<(), DriverError>;
63
64 /// Block the calling thread until the device has reached `event`.
65 ///
66 /// # Errors
67 ///
68 /// [`DriverError`], which is the fault the wait revealed on the stream the
69 /// event was recorded into.
70 fn event_wait(event: &Self::Event) -> Result<(), DriverError>;
71
72 /// Device time from `start` to `end`. Both must have been reached.
73 ///
74 /// Implementations clamp a negative reading to zero rather than trusting
75 /// it: the device clock is monotonic, but a negative duration would panic
76 /// the conversion, and a profiler is not worth a panic.
77 ///
78 /// # Errors
79 ///
80 /// [`DriverError`], including the driver's own "not ready" when either
81 /// event has not been reached.
82 fn event_elapsed(start: &Self::Event, end: &Self::Event) -> Result<Duration, DriverError>;
83
84 /// Make `stream` wait for `event` on the device, without blocking the host.
85 ///
86 /// # Errors
87 ///
88 /// [`DriverError`] when the driver refuses the dependency.
89 fn stream_wait_event(stream: Self::Stream, event: &Self::Event) -> Result<(), DriverError>;
90
91 /// Block the host until every operation enqueued on `stream` has completed.
92 ///
93 /// # Errors
94 ///
95 /// [`DriverError`] when the stream's work failed.
96 fn stream_synchronize(stream: Self::Stream) -> Result<(), DriverError>;
97
98 /// Create a stream that does not synchronize with the legacy default one.
99 ///
100 /// # Errors
101 ///
102 /// [`DriverError`] when the driver will not create the stream.
103 fn stream_create_non_blocking() -> Result<Self::Stream, DriverError>;
104
105 /// Release a stream created by [`stream_create_non_blocking`](Self::stream_create_non_blocking).
106 ///
107 /// # Errors
108 ///
109 /// [`DriverError`], which the caller can only log: this runs from a `Drop`.
110 fn stream_destroy(stream: Self::Stream) -> Result<(), DriverError>;
111}