use crate::id::KernelId;
use cubecl_environment::records::{Record, RecordEffect, RecordLevel, Span};
use super::{KernelCacheKey, build_id_hash};
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct CompilationRecord {
pub kernel: alloc::string::String,
pub key: KernelCacheKey,
pub ir: Option<alloc::string::String>,
pub outcome: CompilationOutcome,
#[serde(alias = "duration")]
pub work: core::time::Duration,
pub source: Option<alloc::string::String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum CompilationOutcome {
Compiled,
Loaded,
Rekeyed,
}
impl Record for CompilationRecord {
const KIND: &'static str = "compilation";
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct CompilationBatchRecord {
pub kernels: u32,
pub threads: u32,
pub wall: core::time::Duration,
}
impl Record for CompilationBatchRecord {
const KIND: &'static str = "compilation_batch";
}
#[derive(Debug)]
pub(crate) struct BatchOutcome {
pub(crate) kernels: usize,
pub(crate) threads: usize,
pub(crate) stored: bool,
}
#[derive(Debug)]
pub(crate) struct CompilationBatchRecording {
span: Option<Span>,
}
impl CompilationBatchRecording {
pub(crate) fn new() -> Self {
Self { span: Span::new() }
}
pub(crate) fn close(self, batch: BatchOutcome) {
let Some(span) = self.span else {
return;
};
let Some(wall) = span.elapsed() else {
return;
};
let record = CompilationBatchRecord {
kernels: batch.kernels.try_into().unwrap_or(u32::MAX),
threads: batch.threads.try_into().unwrap_or(u32::MAX),
wall,
};
span.close(effect(batch.stored), &record);
}
}
#[derive(Debug)]
pub struct CompilationRecording {
open: Option<OpenRecording>,
}
#[derive(Debug)]
struct OpenRecording {
span: Span,
work: core::time::Duration,
kernel: &'static str,
key: KernelCacheKey,
ir: Option<alloc::string::String>,
source: Option<alloc::string::String>,
}
impl CompilationRecording {
pub fn new(kernel_id: &KernelId) -> Self {
let open = Span::new().map(|span| OpenRecording {
span,
work: core::time::Duration::ZERO,
kernel: kernel_id.type_name(),
key: KernelCacheKey::new(kernel_id, build_id_hash()),
ir: None,
source: None,
});
Self { open }
}
pub fn defined(&mut self, definition: &crate::kernel::KernelDefinition) {
if let Some(open) = self.open.as_mut().filter(|_| keeps_code()) {
open.ir = Some(alloc::format!("{}", definition.body));
}
}
pub fn source(&mut self, source: &str) {
if let Some(open) = self.open.as_mut().filter(|_| keeps_code()) {
open.source = Some(source.into());
}
}
pub fn worked(&mut self, duration: core::time::Duration) {
if let Some(open) = self.open.as_mut() {
open.work += duration;
}
}
pub fn close(self, outcome: CompilationOutcome, stored: bool) {
let Some(open) = self.open else {
return;
};
if open.span.elapsed().is_none() {
return;
}
let record = CompilationRecord {
kernel: open.kernel.into(),
key: open.key,
ir: open.ir,
outcome,
work: open.work,
source: open.source,
};
open.span.close(effect(stored), &record);
}
}
fn keeps_code() -> bool {
cubecl_environment::records::level() == RecordLevel::Full
}
fn effect(stored: bool) -> RecordEffect {
if stored {
RecordEffect::Changed
} else {
RecordEffect::Observed
}
}