use xlog_ir::Stratum;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HardwareCapabilities {
pub sm_count: usize,
pub independent_rule_count: usize,
}
impl HardwareCapabilities {
pub fn new(sm_count: usize, independent_rule_count: usize) -> Self {
Self {
sm_count,
independent_rule_count,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StreamPhase {
Count,
Scan,
Resize,
Materialize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StreamPhaseNode {
pub stratum_id: u32,
pub rule_index: usize,
pub phase: StreamPhase,
pub stream_index: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StreamSchedule {
pub stratum_id: u32,
pub stream_count: usize,
pub phases: Vec<StreamPhaseNode>,
}
pub fn schedule_streams(stratum: &Stratum, hw: &HardwareCapabilities) -> StreamSchedule {
let rule_count = hw.independent_rule_count;
let stream_count = if rule_count == 0 {
0
} else {
let sm_lanes = (hw.sm_count / 4).max(1);
sm_lanes.min(rule_count)
};
let mut phases = Vec::with_capacity(rule_count.saturating_mul(4));
for phase in [
StreamPhase::Count,
StreamPhase::Scan,
StreamPhase::Resize,
StreamPhase::Materialize,
] {
for rule_index in 0..rule_count {
phases.push(StreamPhaseNode {
stratum_id: stratum.id,
rule_index,
phase,
stream_index: if stream_count == 0 {
0
} else {
rule_index % stream_count
},
});
}
}
StreamSchedule {
stratum_id: stratum.id,
stream_count,
phases,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn stratum() -> Stratum {
Stratum {
id: 7,
sccs: vec![0],
}
}
#[test]
fn schedules_four_rules_on_four_streams_by_phase() {
let schedule = schedule_streams(&stratum(), &HardwareCapabilities::new(16, 4));
assert_eq!(schedule.stream_count, 4);
assert_eq!(schedule.phases.len(), 16);
assert!(schedule.phases[0..4]
.iter()
.all(|node| node.phase == StreamPhase::Count));
assert!(schedule.phases[4..8]
.iter()
.all(|node| node.phase == StreamPhase::Scan));
assert!(schedule.phases[8..12]
.iter()
.all(|node| node.phase == StreamPhase::Resize));
assert!(schedule.phases[12..16]
.iter()
.all(|node| node.phase == StreamPhase::Materialize));
let stream_slots: Vec<_> = schedule.phases[0..4]
.iter()
.map(|node| node.stream_index)
.collect();
assert_eq!(stream_slots, vec![0, 1, 2, 3]);
}
#[test]
fn single_rule_uses_one_stream() {
let schedule = schedule_streams(&stratum(), &HardwareCapabilities::new(16, 1));
assert_eq!(schedule.stream_count, 1);
assert_eq!(schedule.phases.len(), 4);
assert!(schedule.phases.iter().all(|node| node.stream_index == 0));
}
}