use serde::{Deserialize, Serialize};
use crate::analyses::AccessKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum BankConflictKind {
NoConflict,
BroadcastSafe,
Conflict { way_count: u32 },
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ConflictSeverity {
None,
Mild,
Severe,
Critical,
Unknown,
}
impl BankConflictKind {
#[must_use]
pub fn severity(&self) -> ConflictSeverity {
match self {
Self::NoConflict | Self::BroadcastSafe => ConflictSeverity::None,
Self::Conflict { way_count } => match *way_count {
0..=1 => ConflictSeverity::None,
2..=4 => ConflictSeverity::Mild,
5..=15 => ConflictSeverity::Severe,
_ => ConflictSeverity::Critical,
},
Self::Unknown => ConflictSeverity::Unknown,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BankAccessSite {
pub op_index: usize,
pub kind: AccessKind,
pub binding_slot: u32,
pub conflict: BankConflictKind,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BankConflictReport {
pub kernel_id: String,
pub bank_count: u32,
pub sites: Vec<BankAccessSite>,
}
impl BankConflictReport {
#[must_use]
pub fn problematic_count(&self) -> usize {
self.sites
.iter()
.filter(|s| !matches!(s.conflict.severity(), ConflictSeverity::None))
.count()
}
#[must_use]
pub fn critical_count(&self) -> usize {
self.sites
.iter()
.filter(|s| matches!(s.conflict.severity(), ConflictSeverity::Critical))
.count()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_conflict_severity_is_none() {
assert_eq!(
BankConflictKind::NoConflict.severity(),
ConflictSeverity::None
);
}
#[test]
fn broadcast_safe_severity_is_none() {
assert_eq!(
BankConflictKind::BroadcastSafe.severity(),
ConflictSeverity::None
);
}
#[test]
fn way_2_conflict_is_mild() {
assert_eq!(
BankConflictKind::Conflict { way_count: 2 }.severity(),
ConflictSeverity::Mild
);
}
#[test]
fn way_4_conflict_is_mild() {
assert_eq!(
BankConflictKind::Conflict { way_count: 4 }.severity(),
ConflictSeverity::Mild
);
}
#[test]
fn way_8_conflict_is_severe() {
assert_eq!(
BankConflictKind::Conflict { way_count: 8 }.severity(),
ConflictSeverity::Severe
);
}
#[test]
fn way_15_conflict_is_severe() {
assert_eq!(
BankConflictKind::Conflict { way_count: 15 }.severity(),
ConflictSeverity::Severe
);
}
#[test]
fn way_16_conflict_is_critical() {
assert_eq!(
BankConflictKind::Conflict { way_count: 16 }.severity(),
ConflictSeverity::Critical
);
}
#[test]
fn way_32_conflict_is_critical() {
assert_eq!(
BankConflictKind::Conflict { way_count: 32 }.severity(),
ConflictSeverity::Critical
);
}
#[test]
fn unknown_severity_is_unknown() {
assert_eq!(
BankConflictKind::Unknown.severity(),
ConflictSeverity::Unknown
);
}
#[test]
fn empty_report_has_zero_problematic() {
let r = BankConflictReport {
kernel_id: "empty".into(),
bank_count: 32,
sites: vec![],
};
assert_eq!(r.problematic_count(), 0);
assert_eq!(r.critical_count(), 0);
}
#[test]
fn problematic_count_aggregates_correctly() {
let r = BankConflictReport {
kernel_id: "k".into(),
bank_count: 32,
sites: vec![
BankAccessSite {
op_index: 0,
kind: AccessKind::Load,
binding_slot: 0,
conflict: BankConflictKind::NoConflict,
},
BankAccessSite {
op_index: 1,
kind: AccessKind::Load,
binding_slot: 0,
conflict: BankConflictKind::Conflict { way_count: 4 },
},
BankAccessSite {
op_index: 2,
kind: AccessKind::Store,
binding_slot: 1,
conflict: BankConflictKind::Conflict { way_count: 32 },
},
],
};
assert_eq!(r.problematic_count(), 2);
assert_eq!(r.critical_count(), 1);
}
}