change interferrence graph impl
This commit is contained in:
parent
51a2e69f74
commit
88512b37ac
|
|
@ -1,6 +1,6 @@
|
|||
use std::{
|
||||
cmp::Reverse,
|
||||
collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, VecDeque},
|
||||
collections::{BTreeSet, BinaryHeap, HashMap, VecDeque},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
|
|
@ -64,41 +64,60 @@ impl ResourceLifetime {
|
|||
/// An edge means the two resources are live at the same command index.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ResourceInterference {
|
||||
adj: BTreeMap<ResourceId, BTreeSet<ResourceId>>,
|
||||
edges: Vec<BTreeSet<ResourceId>>,
|
||||
}
|
||||
|
||||
impl ResourceInterference {
|
||||
/// Build a symmetric interference graph from inclusive resource lifetimes.
|
||||
pub fn from_lifetimes(lifetimes: &HashMap<ResourceId, ResourceLifetime>) -> Self {
|
||||
let mut graph = Self::default();
|
||||
|
||||
let resources: Vec<_> = lifetimes
|
||||
let mut max_id = ResourceId(0);
|
||||
let mut resources: Vec<_> = lifetimes
|
||||
.iter()
|
||||
.inspect(|(id, _)| {
|
||||
if **id > max_id {
|
||||
max_id = **id;
|
||||
}
|
||||
})
|
||||
.map(|(&id, lifetime)| (id, *lifetime))
|
||||
.collect();
|
||||
|
||||
for (index, &(id, lifetime)) in resources.iter().enumerate() {
|
||||
graph.adj.entry(id).or_default();
|
||||
for &(other_id, other) in &resources[index + 1..] {
|
||||
if lifetime.overlaps(&other) {
|
||||
graph.adj.entry(id).or_default().insert(other_id);
|
||||
graph.adj.entry(other_id).or_default().insert(id);
|
||||
let mut edges = vec![BTreeSet::new(); max_id.index() + 1];
|
||||
|
||||
resources.sort_unstable_by_key(|&(_, lifetime)| lifetime.first_command);
|
||||
let mut resources = VecDeque::from(resources);
|
||||
|
||||
let mut index = 0;
|
||||
while index < resources.len() {
|
||||
let (id, lifetime) = resources[index];
|
||||
|
||||
let mut j = 0;
|
||||
while j < index {
|
||||
if resources[j].1.last_command < lifetime.first_command {
|
||||
resources.swap_remove_front(j);
|
||||
index -= 1;
|
||||
} else {
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
index += 1;
|
||||
|
||||
// resources is no longer sorted in the interval ..index, but because of the invariant `last_command >= first_command`, it is still partitioned by `a.last_command <= b.first_command`.
|
||||
let active = resources
|
||||
.partition_point(|&(_, other)| other.first_command <= lifetime.last_command);
|
||||
|
||||
for &(other_id, _) in resources.range(..active) {
|
||||
edges[id.index()].insert(other_id);
|
||||
edges[other_id.index()].insert(id);
|
||||
}
|
||||
graph
|
||||
}
|
||||
|
||||
Self { edges }
|
||||
}
|
||||
|
||||
/// Returns whether both resources are live at any common command index.
|
||||
pub fn interferes(&self, a: ResourceId, b: ResourceId) -> bool {
|
||||
self.adj
|
||||
.get(&a)
|
||||
.is_some_and(|neighbors| neighbors.contains(&b))
|
||||
}
|
||||
|
||||
/// Returns the resources that overlap `id`'s inclusive lifetime interval.
|
||||
pub fn neighbors(&self, id: ResourceId) -> Option<&BTreeSet<ResourceId>> {
|
||||
self.adj.get(&id)
|
||||
self.edges[a.index()].contains(&b)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue