Skip to content

Commit 3f55dd4

Browse files
committed
sort the pending queue according to cost/priority
If multiple pieces of work are waiting in the pending queue, we can sort it according to their priorities: higher priorities should be scheduled sooner. They are more often than not wider than pure chains, and this should create more parallelism opportunities earlier in the pipeline: a high priority piece of work represents more future pieces of work down the line. This is a scheduling tradeoff that behaves differently for each project, machine configuration, amount of available parallelism at a given point in time, etc, but seems to help more often than hinders, at low-core counts and with enough units of work to be done, so that there is jobserver token contention where choosing a "better" piece of work to work on next is possible.
1 parent 04a4081 commit 3f55dd4

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

src/cargo/core/compiler/job_queue.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
//! improved.
5151
5252
use std::cell::{Cell, RefCell};
53+
use std::cmp;
5354
use std::collections::{BTreeMap, HashMap, HashSet};
5455
use std::fmt::Write as _;
5556
use std::io;
@@ -583,11 +584,19 @@ impl<'cfg> DrainState<'cfg> {
583584
}
584585
}
585586

587+
// If multiple pieces of work are waiting in the pending queue, we can
588+
// sort it according to their priorities: higher priorities should be
589+
// scheduled sooner.
590+
self.pending_queue
591+
.sort_by_cached_key(|(unit, _)| self.queue.priority(unit));
592+
586593
// Now that we've learned of all possible work that we can execute
587594
// try to spawn it so long as we've got a jobserver token which says
588595
// we're able to perform some parallel work.
596+
// The `pending_queue` is sorted in ascending priority order, and we're
597+
// removing the highest priority items from its end.
589598
while self.has_extra_tokens() && !self.pending_queue.is_empty() {
590-
let (unit, job) = self.pending_queue.remove(0);
599+
let (unit, job) = self.pending_queue.pop().unwrap();
591600
*self.counts.get_mut(&unit.pkg.package_id()).unwrap() -= 1;
592601
if !cx.bcx.build_config.build_plan {
593602
// Print out some nice progress information.

src/cargo/util/dependency_queue.rs

+7
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,13 @@ impl<N: Hash + Eq + Clone, E: Eq + Hash + Clone, V> DependencyQueue<N, E, V> {
170170
self.dep_map.len()
171171
}
172172

173+
/// Returns the relative priority of a node. Higher priorities should be scheduled sooner.
174+
/// Currently computed as the transitive cost of the given node: its own, plus the cost of its
175+
/// reverse dependencies.
176+
pub(crate) fn priority(&self, node: &N) -> usize {
177+
self.priority[node]
178+
}
179+
173180
/// Indicate that something has finished.
174181
///
175182
/// Calling this function indicates that the `node` has produced `edge`. All

0 commit comments

Comments
 (0)