use std::time::{Duration, Instant};
use crate::Result;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GenerationPhase {
SamplerSnapshot,
RollbackSnapshot,
PrefixPreparation,
PrefillIngestion,
PrefillEvaluation,
DecodeEvaluation,
Sampling,
Callback,
CompletionSnapshot,
RollbackRestore,
SamplerRestore,
}
impl GenerationPhase {
pub const ALL: [Self; 11] = [
Self::SamplerSnapshot,
Self::RollbackSnapshot,
Self::PrefixPreparation,
Self::PrefillIngestion,
Self::PrefillEvaluation,
Self::DecodeEvaluation,
Self::Sampling,
Self::Callback,
Self::CompletionSnapshot,
Self::RollbackRestore,
Self::SamplerRestore,
];
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::SamplerSnapshot => "sampler-snapshot",
Self::RollbackSnapshot => "rollback-snapshot",
Self::PrefixPreparation => "prefix-preparation",
Self::PrefillIngestion => "prefill-ingestion",
Self::PrefillEvaluation => "prefill-evaluation",
Self::DecodeEvaluation => "decode-evaluation",
Self::Sampling => "sampling",
Self::Callback => "callback",
Self::CompletionSnapshot => "completion-snapshot",
Self::RollbackRestore => "rollback-restore",
Self::SamplerRestore => "sampler-restore",
}
}
const fn index(self) -> usize {
match self {
Self::SamplerSnapshot => 0,
Self::RollbackSnapshot => 1,
Self::PrefixPreparation => 2,
Self::PrefillIngestion => 3,
Self::PrefillEvaluation => 4,
Self::DecodeEvaluation => 5,
Self::Sampling => 6,
Self::Callback => 7,
Self::CompletionSnapshot => 8,
Self::RollbackRestore => 9,
Self::SamplerRestore => 10,
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct PhaseTiming {
pub elapsed: Duration,
pub attempted_calls: usize,
pub completed_calls: usize,
pub attempted_tokens: usize,
pub completed_tokens_lower_bound: usize,
pub partial_progress_unknown: bool,
}
#[derive(Clone, Debug, Default)]
pub struct GenerationTimings {
pub entered: bool,
pub total: Duration,
pub succeeded: bool,
pub prompt_tokens: usize,
pub reused_tokens: Option<usize>,
pub committed_generated_tokens: Option<usize>,
phases: [PhaseTiming; 11],
}
impl GenerationTimings {
pub(super) fn started(prompt_tokens: usize) -> Self {
Self {
entered: true,
prompt_tokens,
..Self::default()
}
}
#[must_use]
pub const fn phase(&self, phase: GenerationPhase) -> &PhaseTiming {
&self.phases[phase.index()]
}
}
pub(super) fn measure<T>(
timings: &mut Option<&mut GenerationTimings>,
phase: GenerationPhase,
tokens: usize,
operation: impl FnOnce() -> Result<T>,
) -> Result<T> {
let started = timings.as_ref().map(|_| Instant::now());
let result = operation();
if let (Some(timings), Some(started)) = (timings.as_deref_mut(), started) {
let timing = &mut timings.phases[phase.index()];
timing.elapsed += started.elapsed();
timing.attempted_calls += 1;
timing.attempted_tokens += tokens;
if result.is_ok() {
timing.completed_calls += 1;
timing.completed_tokens_lower_bound += tokens;
} else {
timing.partial_progress_unknown = true;
}
}
result
}