use crate::client::Client;
use alloc::vec::Vec;
use cubecl_common::device::ServiceId;
use cubecl_environment::stream::StreamId;
use cubecl_environment::sync::{AtomicUsize, Mutex, Ordering};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StreamMode {
Execute,
Discard,
}
impl StreamMode {
fn index(self) -> usize {
match self {
Self::Execute => 0,
Self::Discard => 1,
}
}
fn opposite(self) -> Self {
match self {
Self::Execute => Self::Discard,
Self::Discard => Self::Execute,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ServiceStream {
pub service: ServiceId,
pub stream: StreamId,
}
#[derive(Debug)]
pub struct StreamModeOverride {
id: usize,
mode: StreamMode,
}
#[derive(Debug)]
struct StreamModeEntry {
id: usize,
stream: ServiceStream,
mode: StreamMode,
}
pub(crate) struct StreamModeRegistry {
entries: Mutex<Vec<StreamModeEntry>>,
live: [AtomicUsize; 2],
next_id: AtomicUsize,
}
pub(crate) static STREAM_MODES: StreamModeRegistry = StreamModeRegistry {
entries: Mutex::new(Vec::new()),
live: [AtomicUsize::new(0), AtomicUsize::new(0)],
next_id: AtomicUsize::new(0),
};
impl StreamModeRegistry {
pub(crate) fn set(
&'static self,
mode: StreamMode,
stream: ServiceStream,
) -> StreamModeOverride {
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
let mut entries = self.entries.lock();
entries.push(StreamModeEntry { id, stream, mode });
self.live[mode.index()].fetch_add(1, Ordering::Release);
StreamModeOverride { id, mode }
}
pub(crate) fn mode(&self, stream: ServiceStream, default: StreamMode) -> StreamMode {
if self.live[default.opposite().index()].load(Ordering::Acquire) == 0 {
return default;
}
self.entries
.lock()
.iter()
.rev()
.find(|entry| entry.stream == stream)
.map_or(default, |entry| entry.mode)
}
fn unset(&self, id: usize, mode: StreamMode) {
let mut entries = self.entries.lock();
entries.retain(|entry| entry.id != id);
self.live[mode.index()].fetch_sub(1, Ordering::Release);
}
}
impl StreamModeOverride {
pub fn new(mode: StreamMode, client: &Client) -> Self {
STREAM_MODES.set(mode, client.service_stream())
}
}
impl Drop for StreamModeOverride {
fn drop(&mut self) {
STREAM_MODES.unset(self.id, self.mode);
}
}