Skip to content

Commit

Permalink
Auto merge of #7390 - Eh2406:better-graph, r=alexcrichton
Browse files Browse the repository at this point in the history
change the priority in witch we build crates

On my windows 4 core, this made clean builds (of 3596cb8) go from 257-223s to 210-205s. So that looks like an improvement.
  • Loading branch information
bors committed Sep 19, 2019
2 parents b385d51 + 384056e commit b6c6f68
Showing 1 changed file with 24 additions and 21 deletions.
45 changes: 24 additions & 21 deletions src/cargo/util/dependency_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub struct DependencyQueue<N: Hash + Eq, E: Hash + Eq, V> {
/// easily indexable with just an `N`
reverse_dep_map: HashMap<N, HashMap<E, HashSet<N>>>,

/// Topological depth of each key
depth: HashMap<N, usize>,
/// The total number of packages that are transitively waiting on this package
priority: HashMap<N, usize>,
}

impl<N: Hash + Eq, E: Hash + Eq, V> Default for DependencyQueue<N, E, V> {
Expand All @@ -47,7 +47,7 @@ impl<N: Hash + Eq, E: Hash + Eq, V> DependencyQueue<N, E, V> {
DependencyQueue {
dep_map: HashMap::new(),
reverse_dep_map: HashMap::new(),
depth: HashMap::new(),
priority: HashMap::new(),
}
}
}
Expand Down Expand Up @@ -82,36 +82,39 @@ impl<N: Hash + Eq + Clone, E: Eq + Hash + Clone, V> DependencyQueue<N, E, V> {
/// All nodes have been added, calculate some internal metadata and prepare
/// for `dequeue`.
pub fn queue_finished(&mut self) {
let mut out = HashMap::new();
for key in self.dep_map.keys() {
depth(key, &self.reverse_dep_map, &mut self.depth);
depth(key, &self.reverse_dep_map, &mut out);
}
self.priority = out.into_iter().map(|(n, set)| (n, set.len())).collect();

fn depth<N: Hash + Eq + Clone, E: Hash + Eq + Clone>(
fn depth<'a, N: Hash + Eq + Clone, E: Hash + Eq + Clone>(
key: &N,
map: &HashMap<N, HashMap<E, HashSet<N>>>,
results: &mut HashMap<N, usize>,
) -> usize {
const IN_PROGRESS: usize = !0;

if let Some(&depth) = results.get(key) {
assert_ne!(depth, IN_PROGRESS, "cycle in DependencyQueue");
results: &'a mut HashMap<N, HashSet<N>>,
) -> &'a HashSet<N> {
if results.contains_key(key) {
let depth = &results[key];
assert!(!depth.is_empty(), "cycle in DependencyQueue");
return depth;
}
results.insert(key.clone(), HashSet::new());

results.insert(key.clone(), IN_PROGRESS);
let mut set = HashSet::new();
set.insert(key.clone());

let depth = 1 + map
for dep in map
.get(key)
.into_iter()
.flat_map(|it| it.values())
.flat_map(|set| set)
.map(|dep| depth(dep, map, results))
.max()
.unwrap_or(0);

*results.get_mut(key).unwrap() = depth;
{
set.extend(depth(dep, map, results).iter().cloned())
}

depth
let slot = results.get_mut(key).unwrap();
*slot = set;
return &*slot;
}
}

Expand All @@ -122,7 +125,7 @@ impl<N: Hash + Eq + Clone, E: Eq + Hash + Clone, V> DependencyQueue<N, E, V> {
pub fn dequeue(&mut self) -> Option<(N, V)> {
// Look at all our crates and find everything that's ready to build (no
// deps). After we've got that candidate set select the one which has
// the maximum depth in the dependency graph. This way we should
// the maximum priority in the dependency graph. This way we should
// hopefully keep CPUs hottest the longest by ensuring that long
// dependency chains are scheduled early on in the build process and the
// leafs higher in the tree can fill in the cracks later.
Expand All @@ -135,7 +138,7 @@ impl<N: Hash + Eq + Clone, E: Eq + Hash + Clone, V> DependencyQueue<N, E, V> {
.iter()
.filter(|(_, (deps, _))| deps.is_empty())
.map(|(key, _)| key.clone())
.max_by_key(|k| self.depth[k]);
.max_by_key(|k| self.priority[k]);
let key = match next {
Some(key) => key,
None => return None,
Expand Down

0 comments on commit b6c6f68

Please sign in to comment.