use crate::tune::{
AutotuneKey, AutotuneLogContext, AutotuneLogEvent, PersistentCacheKey, Placement, TuneCache,
TunePlan,
};
use alloc::string::String;
use alloc::vec::Vec;
use core::time::Duration;
use cubecl_environment::records::{Record, RecordEffect, Span};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TuneRecord<K> {
pub table: String,
pub entry: PersistentCacheKey<K>,
pub winner: usize,
pub trials: Vec<Trial>,
pub short_circuit: Option<String>,
pub wall: Duration,
pub dry_run: bool,
pub stored: bool,
#[serde(default)]
pub plan: Vec<PlannedCandidate>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PlannedCandidate {
pub name: String,
pub index: usize,
pub batch: Option<usize>,
pub groups: Vec<Placement>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Trial {
pub name: String,
pub wall: Duration,
}
impl<K> Record for TuneRecord<K> {
const KIND: &'static str = "autotune";
}
#[derive(Debug)]
pub(crate) struct TuneRecording<K> {
open: Option<OpenRecording<K>>,
}
#[derive(Debug)]
struct OpenRecording<K> {
span: Span,
table: String,
entry: PersistentCacheKey<K>,
dry_run: bool,
plan: Vec<PlannedCandidate>,
}
pub(crate) struct Answer {
pub winner: usize,
pub stored: bool,
}
impl<K: AutotuneKey> TuneRecording<K> {
pub(crate) fn new(cache: &TuneCache<K>, key: &K, checksum: &str) -> Self {
let open = Span::new().map(|span| OpenRecording {
span,
table: cache.table().into(),
entry: PersistentCacheKey {
key: key.clone(),
checksum: checksum.into(),
},
dry_run: crate::dry_run::dry_run(),
plan: Vec::new(),
});
Self { open }
}
pub(crate) fn is_open(&self) -> bool {
self.open.is_some()
}
pub(crate) fn plan(&mut self, plan: &TunePlan, names: &[&str]) {
if let Some(open) = &mut self.open {
open.plan = plan.account(names);
}
}
pub(crate) fn finish(self, answer: Answer, log_context: Option<&AutotuneLogContext>) {
let Some(open) = self.open else {
return;
};
let Some(wall) = open.span.elapsed() else {
return;
};
let mut trials = Vec::new();
let mut short_circuit = None;
for event in log_context.iter().flat_map(|context| &context.events) {
match event {
AutotuneLogEvent::TuningStep(name, wall) => trials.push(Trial {
name: name.clone(),
wall: *wall,
}),
AutotuneLogEvent::ShortCircuit(name) => short_circuit = Some(name.clone()),
}
}
let record = TuneRecord {
table: open.table,
entry: open.entry,
winner: answer.winner,
trials,
short_circuit,
wall,
dry_run: open.dry_run,
stored: answer.stored,
plan: open.plan,
};
let effect = if record.stored {
RecordEffect::Changed
} else {
RecordEffect::Observed
};
open.span.close(effect, &record);
}
}