use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use crate::state::{
Align, Bounds, ChanEntry, ChanID, ChanPoint, Config, Container, CopyInstInfo, DeviceKind,
DimKind, FSpace, FieldID, FillInstInfo, ISpaceID, Inst, MemID, MemKind, MemPoint, NodeID,
ProcID, ProcKind, ProcPoint, ProfUID, State, TimePoint, Timestamp,
};
use crate::conditional_assert;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct ProcGroup(pub Option<NodeID>, pub ProcKind, pub Option<DeviceKind>);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct MemGroup(pub Option<NodeID>, pub MemKind);
pub trait StatePostprocess {
fn has_multiple_nodes(&self) -> bool;
fn group_procs(&self) -> BTreeMap<ProcGroup, Vec<ProcID>>;
fn group_mems(&self) -> BTreeMap<MemGroup, Vec<MemID>>;
fn group_chans(&self) -> BTreeMap<Option<NodeID>, Vec<ChanID>>;
fn group_depparts(&self) -> BTreeMap<Option<NodeID>, Vec<ChanID>>;
fn proc_group_timepoints(
&self,
device: Option<DeviceKind>,
procs: &[ProcID],
) -> Vec<&Vec<ProcPoint>>;
fn mem_group_timepoints(&self, mems: &[MemID]) -> Vec<&Vec<MemPoint>>;
fn chan_group_timepoints(&self, chans: &[ChanID]) -> Vec<&Vec<ChanPoint>>;
fn group_node_proc_kind_timepoints(
&self,
) -> (
BTreeMap<ProcGroup, Vec<(ProcID, &Vec<ProcPoint>)>>,
BTreeMap<ProcGroup, u64>,
);
fn group_node_mem_kind_timepoints(&self) -> BTreeMap<MemGroup, Vec<(MemID, &Vec<MemPoint>)>>;
fn group_node_chan_kind_timepoints(
&self,
) -> BTreeMap<Option<NodeID>, Vec<(ChanID, &Vec<ChanPoint>)>>;
fn convert_points_to_utilization<Entry, Secondary>(
&self,
points: &[TimePoint<Entry, Secondary>],
utilization: &mut Vec<TimePoint<Entry, Secondary>>,
) where
Entry: Copy,
Secondary: Copy;
fn calculate_proc_utilization_data(
&self,
points: Vec<ProcPoint>,
owners: BTreeSet<ProcID>,
max_count: u64,
) -> Vec<(Timestamp, f64)>;
fn calculate_mem_utilization_data(
&self,
points: Vec<&MemPoint>,
owners: BTreeSet<MemID>,
) -> Vec<(Timestamp, f64)>;
fn calculate_chan_utilization_data(
&self,
points: Vec<ChanPoint>,
owners: BTreeSet<ChanID>,
) -> Vec<(Timestamp, f64)>;
}
impl StatePostprocess for State {
fn has_multiple_nodes(&self) -> bool {
let mut node = None;
for proc in self.procs.values() {
if !proc.is_visible() {
continue;
}
match node {
Some(n) => {
if n != proc.proc_id.node_id() {
return true;
}
}
None => {
node = Some(proc.proc_id.node_id());
}
}
}
false
}
fn group_procs(&self) -> BTreeMap<ProcGroup, Vec<ProcID>> {
let mut groups = BTreeMap::new();
for proc in self.procs.values() {
if !proc.is_visible() {
continue;
}
let nodes = [None, Some(proc.proc_id.node_id())];
let devices: &'static [_] = if proc.has_device_timepoints() {
&[Some(DeviceKind::Device), Some(DeviceKind::Host)]
} else {
&[None]
};
for node in nodes {
for device in devices {
let group = ProcGroup(node, proc.kind.unwrap(), *device);
groups
.entry(group)
.or_insert_with(Vec::new)
.push(proc.proc_id);
}
}
}
groups
}
fn group_mems(&self) -> BTreeMap<MemGroup, Vec<MemID>> {
let mut groups = BTreeMap::new();
for mem in self.mems.values() {
if !mem.is_visible() {
continue;
}
if !mem.util_time_points(None).is_empty() {
let nodes = [None, Some(mem.mem_id.node_id())];
for node in nodes {
let group = MemGroup(node, mem.kind);
groups
.entry(group)
.or_insert_with(Vec::new)
.push(mem.mem_id);
}
}
}
groups
}
fn group_chans(&self) -> BTreeMap<Option<NodeID>, Vec<ChanID>> {
let mut groups = BTreeMap::new();
for (chan_id, chan) in &self.chans {
match *chan_id {
ChanID::Copy { .. }
| ChanID::Fill { .. }
| ChanID::Gather { .. }
| ChanID::Scatter { .. } => {} _ => {
continue;
}
}
if !chan.is_visible() {
continue;
}
if !chan.util_time_points(None).is_empty() {
let mut nodes = vec![None];
match *chan_id {
ChanID::Copy { src, dst } => {
nodes.push(Some(src.node_id()));
nodes.push(Some(dst.node_id()));
}
ChanID::Fill { dst } | ChanID::Gather { dst } => {
nodes.push(Some(dst.node_id()))
}
ChanID::Scatter { src } => nodes.push(Some(src.node_id())),
ChanID::DepPart { .. } => unreachable!(),
}
nodes.dedup();
for node in nodes {
groups.entry(node).or_insert_with(Vec::new).push(*chan_id)
}
}
}
groups
}
fn group_depparts(&self) -> BTreeMap<Option<NodeID>, Vec<ChanID>> {
let mut groups = BTreeMap::new();
for (chan_id, chan) in &self.chans {
match *chan_id {
ChanID::DepPart { .. } => {} _ => {
continue;
}
}
if !chan.is_visible() {
continue;
}
if !chan.util_time_points(None).is_empty() {
let mut nodes = vec![None];
match *chan_id {
ChanID::DepPart { node_id } => nodes.push(Some(node_id)),
_ => unreachable!(),
}
nodes.dedup();
for node in nodes {
groups.entry(node).or_insert_with(Vec::new).push(*chan_id);
}
}
}
groups
}
fn proc_group_timepoints(
&self,
device: Option<DeviceKind>,
procs: &[ProcID],
) -> Vec<&Vec<ProcPoint>> {
let mut timepoints = Vec::new();
for proc_id in procs {
let proc = self.procs.get(proc_id).unwrap();
if proc.is_visible() {
timepoints.push(proc.util_time_points(device));
}
}
timepoints
}
fn mem_group_timepoints(&self, mems: &[MemID]) -> Vec<&Vec<MemPoint>> {
let mut timepoints = Vec::new();
for mem_id in mems {
let mem = self.mems.get(mem_id).unwrap();
if mem.is_visible() {
timepoints.push(mem.util_time_points(None));
}
}
timepoints
}
fn chan_group_timepoints(&self, chans: &[ChanID]) -> Vec<&Vec<ChanPoint>> {
let mut timepoints = Vec::new();
for chan_id in chans {
let chan = self.chans.get(chan_id).unwrap();
if chan.is_visible() {
timepoints.push(chan.util_time_points(None));
}
}
timepoints
}
fn group_node_proc_kind_timepoints(
&self,
) -> (
BTreeMap<ProcGroup, Vec<(ProcID, &Vec<ProcPoint>)>>,
BTreeMap<ProcGroup, u64>,
) {
let mut timepoint = BTreeMap::new();
let mut proc_count = BTreeMap::new();
for proc in self.procs.values() {
if !proc.is_visible() {
continue;
}
let nodes = [None, Some(proc.proc_id.node_id())];
let devices: &'static [_] = match proc.kind.unwrap() {
ProcKind::GPU => &[Some(DeviceKind::Device), Some(DeviceKind::Host)],
_ => &[None],
};
for node in nodes {
for device in devices {
let group = ProcGroup(node, proc.kind.unwrap(), *device);
proc_count.entry(group).and_modify(|i| *i += 1).or_insert(1);
if !proc.is_empty() {
timepoint
.entry(group)
.or_insert_with(Vec::new)
.push((proc.proc_id, proc.util_time_points(*device)));
}
}
}
}
(timepoint, proc_count)
}
fn group_node_mem_kind_timepoints(&self) -> BTreeMap<MemGroup, Vec<(MemID, &Vec<MemPoint>)>> {
let mut result = BTreeMap::new();
for mem in self.mems.values() {
if !mem.is_visible() {
continue;
}
if !mem.time_points(None).is_empty() {
let nodes = [None, Some(mem.mem_id.node_id())];
for node in nodes {
let group = MemGroup(node, mem.kind);
result
.entry(group)
.or_insert_with(Vec::new)
.push((mem.mem_id, mem.util_time_points(None)))
}
}
}
result
}
fn group_node_chan_kind_timepoints(
&self,
) -> BTreeMap<Option<NodeID>, Vec<(ChanID, &Vec<ChanPoint>)>> {
let mut result = BTreeMap::new();
for (chan_id, chan) in &self.chans {
if !chan.is_visible() {
continue;
}
if !chan.time_points(None).is_empty() {
let mut nodes = vec![None];
match *chan_id {
ChanID::Copy { src, dst } => {
nodes.push(Some(src.node_id()));
nodes.push(Some(dst.node_id()));
}
ChanID::Fill { dst } | ChanID::Gather { dst } => {
nodes.push(Some(dst.node_id()))
}
ChanID::Scatter { src } => nodes.push(Some(src.node_id())),
ChanID::DepPart { node_id } => nodes.push(Some(node_id)),
}
nodes.dedup();
for node in nodes {
if node.is_none_or(|n| State::is_on_visible_nodes(&self.visible_nodes, n)) {
result
.entry(node)
.or_insert_with(Vec::new)
.push((*chan_id, chan.util_time_points(None)))
}
}
}
}
result
}
fn convert_points_to_utilization<Entry, Secondary>(
&self,
points: &[TimePoint<Entry, Secondary>],
utilization: &mut Vec<TimePoint<Entry, Secondary>>,
) where
Entry: Copy,
Secondary: Copy,
{
let mut count = 0;
for point in points {
if point.first {
count += 1;
if count == 1 {
utilization.push(*point);
}
} else {
count -= 1;
if count == 0 {
utilization.push(*point);
}
}
}
}
fn calculate_proc_utilization_data(
&self,
points: Vec<ProcPoint>,
owners: BTreeSet<ProcID>,
max_count: u64,
) -> Vec<(Timestamp, f64)> {
assert!(!owners.is_empty());
let mut utilization = Vec::new();
let mut last_time = None;
let max_count = max_count as f64;
let mut count = 0;
for point in points {
if point.first {
count += 1;
} else {
count -= 1;
}
let ratio = count as f64 / max_count;
if last_time == Some(point.time) {
*utilization.last_mut().unwrap() = (point.time, ratio);
} else {
utilization.push((point.time, ratio));
}
last_time = Some(point.time);
}
utilization
}
fn calculate_mem_utilization_data(
&self,
points: Vec<&MemPoint>,
owners: BTreeSet<MemID>,
) -> Vec<(Timestamp, f64)> {
assert!(!owners.is_empty());
let mut result = Vec::new();
let mut max_count = 0;
for mem_id in owners {
let mem = self.mems.get(&mem_id).unwrap();
assert!(mem.capacity > 0);
max_count += mem.capacity;
}
let max_count = max_count as f64;
let mut last_time = None;
let mut count = 0;
for point in &points {
let inst = self.find_inst(point.entry).unwrap();
if point.first {
count += inst.size.unwrap();
} else {
count -= inst.size.unwrap();
}
let ratio = count as f64 / max_count;
if last_time == Some(point.time) {
*result.last_mut().unwrap() = (point.time, ratio);
} else {
result.push((point.time, ratio));
}
last_time = Some(point.time);
}
result
}
fn calculate_chan_utilization_data(
&self,
points: Vec<ChanPoint>,
owners: BTreeSet<ChanID>,
) -> Vec<(Timestamp, f64)> {
assert!(!owners.is_empty());
let max_count = owners.len();
let mut utilization = Vec::new();
let mut last_time = None;
let mut count = 0;
for point in &points {
if point.first {
count += 1;
} else {
count -= 1;
}
let count = count as f64;
let max_count = max_count as f64;
if last_time == Some(point.time) {
if count > 0.0 {
*utilization.last_mut().unwrap() = (point.time, 1.0);
} else {
*utilization.last_mut().unwrap() = (point.time, count / max_count);
}
} else if count > 0.0 {
utilization.push((point.time, 1.0));
} else {
utilization.push((point.time, count / max_count));
}
last_time = Some(point.time);
}
utilization
}
}
pub struct SizePretty(pub u64);
impl fmt::Display for SizePretty {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0 >= (1024 * 1024 * 1024) {
write!(f, "{:.3} GiB", self.0 as f64 / (1024.0 * 1024.0 * 1024.0))
} else if self.0 >= (1024 * 1024) {
write!(f, "{:.3} MiB", self.0 as f64 / (1024.0 * 1024.0))
} else if self.0 >= 1024 {
write!(f, "{:.3} KiB", self.0 as f64 / 1024.0)
} else {
write!(f, "{} B", self.0)
}
}
}
#[derive(Debug)]
pub struct ISpacePretty<'a>(pub ISpaceID, pub &'a State);
impl fmt::Display for ISpacePretty<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ISpacePretty(ispace_id, state) = self;
let ispace = state.index_spaces.get(ispace_id);
if ispace.is_none() {
write!(f, "ispace:{}", ispace_id.0)?;
return Ok(());
}
let ispace = ispace.unwrap();
if ispace.bounds == Bounds::Empty {
write!(f, "empty index space")?;
return Ok(());
}
if let Some(name) = &ispace.name {
write!(f, "{}", name)?;
} else {
let parent = ispace.parent.and_then(|p_id| {
state.index_partitions.get(&p_id).and_then(|p| {
p.parent
.map(|gp_id| state.index_spaces.get(&gp_id).unwrap())
})
});
if let Some(name) = parent.and_then(|p| p.name.as_ref()) {
write!(f, "{}", name)?;
} else if let Some(parent_id) = parent.map(|p| p.ispace_id) {
write!(f, "ispace:{}", parent_id.0)?;
} else {
write!(f, "ispace:{}", ispace_id.0)?;
}
}
if let Some(size) = &ispace.size {
if size.is_sparse {
write!(
f,
"[sparse:({} of {} points)]",
size.sparse_size, size.dense_size
)?;
return Ok(());
}
}
match &ispace.bounds {
Bounds::Point { point, dim } => {
for x in &point[..*dim as usize] {
write!(f, "[{}]", x)?;
}
}
Bounds::Rect { lo, hi, dim } => {
for (l, h) in lo.iter().zip(hi.iter()).take(*dim as usize) {
write!(f, "[{}:{}]", l, h)?;
}
}
Bounds::Empty => unreachable!(),
Bounds::Unknown => {}
}
Ok(())
}
}
#[derive(Debug)]
pub struct FSpaceShort<'a>(pub &'a FSpace);
impl fmt::Display for FSpaceShort<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let FSpaceShort(fspace) = self;
if let Some(name) = &fspace.name {
write!(f, "{} <{}>", name, fspace.fspace_id.0)
} else {
write!(f, "<{}>", fspace.fspace_id.0)
}
}
}
#[derive(Debug)]
pub struct FieldPretty<'a>(pub &'a FSpace, pub FieldID, pub &'a Align);
impl fmt::Display for FieldPretty<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let FieldPretty(fspace, field_id, align) = self;
if let Some(field) = fspace.fields.get(field_id) {
write!(f, "{} <{}>", field.name, field_id.0)?;
} else {
write!(f, "<{}>", field_id.0)?;
}
if align.has_align {
write!(f, " (align={})", align.align_desc)?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct FieldsPretty<'a>(pub &'a FSpace, pub &'a Inst);
impl fmt::Display for FieldsPretty<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let FieldsPretty(fspace, inst) = self;
let field_ids = inst.fields.get(&fspace.fspace_id).unwrap();
let align_desc = inst.align_desc.get(&fspace.fspace_id).unwrap();
let mut i = field_ids.iter().zip(align_desc.iter()).peekable();
while let Some((field_id, align)) = i.next() {
write!(f, "{}", FieldPretty(fspace, *field_id, align))?;
if i.peek().is_some() {
write!(f, ", ")?;
}
}
Ok(())
}
}
#[derive(Debug)]
pub struct FSpacePretty<'a>(pub &'a FSpace, pub &'a Inst);
impl fmt::Display for FSpacePretty<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let FSpacePretty(fspace, inst) = self;
if let Some(name) = &fspace.name {
write!(f, "{}", name)?;
} else {
write!(f, "fspace:{}", fspace.fspace_id.0)?;
}
let align_desc = inst.align_desc.get(&fspace.fspace_id).unwrap();
let fields = inst.fields.get(&fspace.fspace_id).unwrap();
let mut fields = fields.iter().enumerate().peekable();
if fields.peek().is_some() {
write!(f, "$Fields: [")?;
while let Some((i, field)) = fields.next() {
let align = &align_desc[i];
if let Some(fld) = fspace.fields.get(field) {
write!(f, "fid:{}:{}", field.0, fld.name)?;
} else {
write!(f, "fid:{}", field.0)?;
}
if align.has_align {
write!(f, ":align={}", align.align_desc)?;
}
if fields.peek().is_some() {
write!(f, ",")?;
if i % 5 == 0 {
write!(f, "$")?;
}
}
}
write!(f, "]")?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct DimOrderPretty<'a>(pub &'a Inst, pub bool);
impl fmt::Display for DimOrderPretty<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let DimOrderPretty(inst, brackets) = self;
let mut aos = false;
let mut soa = false;
let mut cmpx_order = false;
let mut column_major = 0;
let mut row_major = 0;
let dim_first = inst.dim_order.iter().next();
let dim_last = inst.dim_order.iter().last();
for (dim, dim_order) in &inst.dim_order {
if dim.0 == 0 {
if *dim_order == DimKind::DimF {
aos = true;
}
} else if dim == dim_last.unwrap().0 {
if *dim_order == DimKind::DimF {
soa = true;
}
} else if *dim_order == DimKind::DimF {
cmpx_order = true;
}
if *dim_last.unwrap().1 == DimKind::DimF && *dim_order != DimKind::DimF {
if *dim_order == DimKind::try_from(dim.0).unwrap() {
column_major += 1;
}
if *dim_order == DimKind::try_from(dim_last.unwrap().0.0 - dim.0 - 1).unwrap() {
row_major += 1;
}
}
if *dim_first.unwrap().1 == DimKind::DimF && *dim_order != DimKind::DimF {
if *dim_order == DimKind::try_from(dim.0 - 1).unwrap() {
column_major += 1;
}
if *dim_order == DimKind::try_from(dim_last.unwrap().0.0 - dim.0).unwrap() {
row_major += 1;
}
}
}
let open = |f: &mut fmt::Formatter<'_>, previous: &mut bool| -> fmt::Result {
if *brackets {
write!(f, "[")?;
} else if *previous {
write!(f, ", ")?;
}
Ok(())
};
let close = |f: &mut fmt::Formatter<'_>, previous: &mut bool| -> fmt::Result {
if *brackets {
write!(f, "]")?;
}
*previous = true;
Ok(())
};
let mut previous = false;
if dim_last.is_some_and(|(d, _)| d.0 != 1) {
if column_major == dim_last.unwrap().0.0 && !cmpx_order {
open(f, &mut previous)?;
write!(f, "Column Major")?;
close(f, &mut previous)?;
} else if row_major == dim_last.unwrap().0.0 && !cmpx_order {
open(f, &mut previous)?;
write!(f, "Row Major")?;
close(f, &mut previous)?;
}
}
if cmpx_order {
open(f, &mut previous)?;
for (dim, dim_order) in &inst.dim_order {
write!(f, "{:?}", dim_order)?;
if *brackets && (dim.0 + 1) % 4 == 0 && dim != dim_last.unwrap().0 {
write!(f, "$")?;
}
}
close(f, &mut previous)?;
} else if aos {
open(f, &mut previous)?;
write!(f, "Array-of-structs (AOS)")?;
close(f, &mut previous)?;
} else if soa {
open(f, &mut previous)?;
write!(f, "Struct-of-arrays (SOA)")?;
close(f, &mut previous)?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct InstShort<'a>(pub &'a Inst);
impl fmt::Display for InstShort<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let InstShort(inst) = self;
write!(f, "0x{:x}", inst.inst_id.unwrap().0)
}
}
#[derive(Debug)]
pub struct InstPretty<'a>(pub &'a Inst, pub &'a State);
impl fmt::Display for InstPretty<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let InstPretty(inst, state) = self;
let mut ispace_ids = inst.ispace_ids.iter().enumerate().peekable();
while let Some((i, ispace_id)) = ispace_ids.next() {
let fspace_id = inst.fspace_ids[i];
let fspace = state.field_spaces.get(&fspace_id).unwrap();
write!(
f,
"Region: {} x {}",
ISpacePretty(*ispace_id, state),
FSpacePretty(fspace, inst),
)?;
if ispace_ids.peek().is_some() {
write!(f, "$")?;
}
}
if !inst.dim_order.is_empty() {
write!(f, "$Layout Order: {} ", DimOrderPretty(inst, true))?;
}
write!(
f,
"$Inst: 0x{:x} $Size: {}",
inst.inst_id.unwrap().0,
SizePretty(inst.size.unwrap())
)?;
Ok(())
}
}
#[derive(Debug)]
pub struct ChanEntryShort<'a>(pub &'a ChanEntry);
impl fmt::Display for ChanEntryShort<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ChanEntryShort(entry) = self;
match entry {
ChanEntry::Copy(copy) => write!(f, "{}", copy.copy_kind.unwrap()),
ChanEntry::Fill(_) => write!(f, "Fill"),
ChanEntry::DepPart(deppart) => write!(f, "{}", deppart.part_op),
}
}
}
#[derive(Debug)]
pub struct ChanEntryFieldsPretty<'a>(pub Option<&'a Inst>, pub &'a Vec<FieldID>, pub &'a State);
impl fmt::Display for ChanEntryFieldsPretty<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ChanEntryFieldsPretty(inst, field_ids, state) = self;
let fspace = inst.and_then(|inst| {
if inst.fspace_ids.len() == 1 {
let fspace_id = inst.fspace_ids[0];
Some(state.field_spaces.get(&fspace_id).unwrap())
} else {
None
}
});
let mut i = field_ids.iter().peekable();
while let Some(fid) = i.next() {
if let Some(field) = fspace.and_then(|fs| fs.fields.get(fid)) {
write!(f, "{} <{}>", field.name, fid.0)?;
} else {
write!(f, "<{}>", fid.0)?;
}
if i.peek().is_some() {
write!(f, ", ")?;
}
}
Ok(())
}
}
#[derive(Debug)]
pub struct CopyInstInfoDisplay<'a>(
pub Option<&'a Inst>, pub Option<&'a Inst>, pub Option<ProfUID>, pub Option<ProfUID>, pub FieldID, pub FieldID, pub u32, );
impl fmt::Display for CopyInstInfoDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut src_inst_id = 0;
let mut dst_inst_id = 0;
if let Some(src_inst) = self.0 {
src_inst_id = src_inst.inst_id.unwrap().0;
}
if let Some(dst_inst) = self.1 {
dst_inst_id = dst_inst.inst_id.unwrap().0;
}
match (self.2, self.3) {
(None, None) => unreachable!(),
(None, _) => {
write!(
f,
"Scatter: dst_indirect_inst=0x{:x}, fid={}",
dst_inst_id, self.5.0
)
}
(_, None) => {
write!(
f,
"Gather: src_indirect_inst=0x{:x}, fid={}",
src_inst_id, self.4.0
)
}
(_, _) => {
write!(
f,
"src_inst=0x{:x}, src_fid={}, dst_inst=0x{:x}, dst_fid={}, num_hops={}",
src_inst_id, self.4.0, dst_inst_id, self.5.0, self.6
)
}
}
}
}
#[derive(Debug)]
pub struct CopyInstInfoVec<'a>(pub &'a Vec<CopyInstInfo>, pub &'a State);
impl fmt::Display for CopyInstInfoVec<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, elt) in self.0.iter().enumerate() {
let src_inst = if let Some(src_inst_uid) = elt.src_inst_uid {
self.1.find_inst(src_inst_uid)
} else {
None
};
let dst_inst = if let Some(dst_inst_uid) = elt.dst_inst_uid {
self.1.find_inst(dst_inst_uid)
} else {
None
};
write!(
f,
"$req[{}]: {}",
i,
CopyInstInfoDisplay(
src_inst,
dst_inst,
elt.src_inst_uid,
elt.dst_inst_uid,
elt.src_fid,
elt.dst_fid,
elt.num_hops
)
)?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct CopyInstInfoDumpInstVec<'a>(pub &'a Vec<CopyInstInfo>, pub &'a State);
impl fmt::Display for CopyInstInfoDumpInstVec<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut insts_set = BTreeSet::new();
for elt in self.0.iter() {
if let Some(src_inst_uid) = elt.src_inst_uid {
if let Some(src_inst) = self.1.find_inst(src_inst_uid) {
insts_set.insert(src_inst);
} else {
conditional_assert!(
false,
Config::all_logs(),
"Copy can not find src_inst:0x{:x}",
src_inst_uid.0
);
}
}
if let Some(dst_inst_uid) = elt.dst_inst_uid {
if let Some(dst_inst) = self.1.find_inst(dst_inst_uid) {
insts_set.insert(dst_inst);
} else {
conditional_assert!(
false,
Config::all_logs(),
"Copy can not find dst_inst:0x{:x}",
dst_inst_uid.0
);
}
}
}
write!(f, "[")?;
for (i, inst) in insts_set.iter().enumerate() {
write!(
f,
"[\"0x{:x}\",{}]",
inst.inst_id.unwrap().0,
inst.base.prof_uid.0
)?;
if i < insts_set.len() - 1 {
write!(f, ",")?;
}
}
write!(f, "]")?;
Ok(())
}
}
#[derive(Debug)]
pub struct FillInstInfoDisplay<'a>(pub Option<&'a Inst>, pub FieldID);
impl fmt::Display for FillInstInfoDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut inst_id = 0;
if let Some(inst) = self.0 {
inst_id = inst.inst_id.unwrap().0;
}
write!(f, "dst_inst=0x{:x}, fid={}", inst_id, self.1.0)
}
}
#[derive(Debug)]
pub struct FillInstInfoVec<'a>(pub &'a Vec<FillInstInfo>, pub &'a State);
impl fmt::Display for FillInstInfoVec<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, elt) in self.0.iter().enumerate() {
let inst = self.1.find_inst(elt.dst_inst_uid);
write!(f, "$req[{}]: {}", i, FillInstInfoDisplay(inst, elt.fid))?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct FillInstInfoDumpInstVec<'a>(pub &'a Vec<FillInstInfo>, pub &'a State);
impl fmt::Display for FillInstInfoDumpInstVec<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut insts_set = BTreeSet::new();
for elt in self.0.iter() {
if let Some(dst_inst) = self.1.find_inst(elt.dst_inst_uid) {
insts_set.insert(dst_inst);
} else {
conditional_assert!(
false,
Config::all_logs(),
"Fill can not find dst_inst:0x{:x}",
elt.dst_inst_uid.0
);
}
}
write!(f, "[")?;
for (i, inst) in insts_set.iter().enumerate() {
write!(
f,
"[\"0x{:x}\",{}]",
inst.inst_id.unwrap().0,
inst.base.prof_uid.0
)?;
if i < insts_set.len() - 1 {
write!(f, ",")?;
}
}
write!(f, "]")?;
Ok(())
}
}