use crate::config::ddr5::SchedulerKind;
use std::fmt::Debug;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Candidate {
pub row_hit: bool,
pub ready_at: u64,
}
pub trait MemScheduler: Debug + Send + Sync {
fn pick(&self, candidates: &[Candidate], now: u64) -> Option<usize>;
}
#[derive(Debug, Default)]
pub struct Fcfs;
impl MemScheduler for Fcfs {
fn pick(&self, candidates: &[Candidate], _now: u64) -> Option<usize> {
if candidates.is_empty() { None } else { Some(0) }
}
}
#[derive(Debug, Default)]
pub struct FrFcfs;
impl MemScheduler for FrFcfs {
fn pick(&self, candidates: &[Candidate], now: u64) -> Option<usize> {
if let Some(seamless) = candidates.iter().position(|c| c.row_hit && c.ready_at <= now) {
return Some(seamless);
}
let mut best: Option<(usize, Candidate)> = None;
for (index, candidate) in candidates.iter().enumerate() {
let better = match best {
None => true,
Some((_, current)) => {
candidate.ready_at < current.ready_at
|| (candidate.ready_at == current.ready_at
&& candidate.row_hit
&& !current.row_hit)
}
};
if better {
best = Some((index, *candidate));
}
}
best.map(|(index, _)| index)
}
}
impl SchedulerKind {
#[must_use]
pub fn build(self) -> Box<dyn MemScheduler> {
match self {
Self::Fcfs => Box::new(Fcfs),
Self::FrFcfs => Box::new(FrFcfs),
}
}
}