use eredu_core::{
CompletedSpeculativeSchedule, PreparedSpeculativeLane, SpeculativeConstraint,
SpeculativeDriverError, SpeculativeExecutor, SpeculativeGenerationBatchOutput,
SpeculativeGenerationOutput, SpeculativeGenerationVisitor, SpeculativePublisher,
SpeculativeRequestTable, SpeculativeSampling,
};
pub struct SpeculativeScheduler<'a, E, S, C, P>
where
E: SpeculativeExecutor,
S: SpeculativeSampling<Logits = E::Logits, Error = E::Error>,
C: SpeculativeConstraint,
P: SpeculativePublisher<C>,
{
executor: &'a mut E,
context: E::Context<'a>,
optimistic_execution_available: bool,
component_timings_collected: bool,
requests: SpeculativeRequestTable<'a, E, S, C, P>,
}
impl<'a, E, S, C, P> SpeculativeScheduler<'a, E, S, C, P>
where
E: SpeculativeExecutor + 'a,
S: SpeculativeSampling<Logits = E::Logits, Error = E::Error, Context<'a> = E::Context<'a>> + 'a,
C: SpeculativeConstraint,
P: SpeculativePublisher<C>,
{
#[allow(clippy::too_many_arguments)]
pub fn new(
executor: &'a mut E,
options: eredu_core::generation::SpeculativeSchedulerOptions,
topology: eredu_core::SpeculativeExecutionTopology,
optimistic_execution_available: bool,
component_timings_collected: bool,
context: E::Context<'a>,
) -> Result<Self, SpeculativeDriverError<E::Error>> {
executor.set_telemetry_enabled(component_timings_collected);
Ok(Self {
executor,
context,
optimistic_execution_available,
component_timings_collected,
requests: SpeculativeRequestTable::new(options, topology)
.map_err(SpeculativeDriverError::Generation)?,
})
}
pub fn submit(
&mut self,
mut lane: PreparedSpeculativeLane<'a, E, S, C, P>,
) -> Result<eredu_core::generation::SpeculativeRequestId, SpeculativeDriverError<E::Error>>
{
self.requests.submit(
self.executor,
lane.take_cache(),
lane.take_input(),
lane.take_config(),
lane.take_runtime(),
lane.take_randomness(),
self.component_timings_collected,
self.context,
)
}
pub fn step(&mut self) -> Result<bool, SpeculativeDriverError<E::Error>> {
self.requests.step(
self.executor,
self.optimistic_execution_available,
self.context,
)
}
pub fn run(&mut self) -> Result<(), SpeculativeDriverError<E::Error>> {
while self.step()? {}
Ok(())
}
pub fn status(
&self,
id: eredu_core::generation::SpeculativeRequestId,
) -> Option<eredu_core::generation::SpeculativeRequestStatus> {
self.requests.status(id)
}
pub fn cancel(
&mut self,
id: eredu_core::generation::SpeculativeRequestId,
) -> Result<(), SpeculativeDriverError<E::Error>> {
self.requests.cancel(id)
}
pub fn is_finished(&self) -> bool {
self.requests.is_finished()
}
pub fn finish(
self,
) -> Result<CompletedSpeculativeSchedule<S>, SpeculativeDriverError<E::Error>> {
self.requests.finish()
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct RunSpeculativeGeneration {
options: eredu_core::generation::SpeculativeSchedulerOptions,
}
impl RunSpeculativeGeneration {
pub const fn new(options: eredu_core::generation::SpeculativeSchedulerOptions) -> Self {
Self { options }
}
}
impl SpeculativeGenerationVisitor for RunSpeculativeGeneration {
fn run<'a, E, S, C, P>(
self,
executor: &'a mut E,
lanes: Vec<PreparedSpeculativeLane<'a, E, S, C, P>>,
topology: eredu_core::SpeculativeExecutionTopology,
optimistic_execution_available: bool,
component_timings_collected: bool,
context: E::Context<'a>,
) -> Result<SpeculativeGenerationBatchOutput, SpeculativeDriverError<E::Error>>
where
E: SpeculativeExecutor + 'a,
S: SpeculativeSampling<Logits = E::Logits, Error = E::Error, Context<'a> = E::Context<'a>>
+ 'a,
C: SpeculativeConstraint,
P: SpeculativePublisher<C>,
{
let mut scheduler = SpeculativeScheduler::new(
executor,
self.options,
topology,
optimistic_execution_available,
component_timings_collected,
context,
)?;
for lane in lanes {
scheduler.submit(lane)?;
}
scheduler.run()?;
let mut completed = scheduler.finish()?;
let requests = completed
.take_requests()
.into_iter()
.map(|request| -> Result<_, SpeculativeDriverError<E::Error>> {
let finish_reason = request.finish_reason().ok_or_else(|| {
SpeculativeDriverError::Generation(
eredu_core::generation::GenerationError::MissingSpeculativeFinishReason {
index: request.id().index(),
},
)
})?;
Ok(SpeculativeGenerationOutput::new(
request.token_ids().to_vec(),
finish_reason,
request.stats().clone(),
))
})
.collect::<Result<Vec<_>, _>>()?;
Ok(SpeculativeGenerationBatchOutput::new(
requests,
completed.take_scheduler(),
))
}
}