Skip to content

Commit

Permalink
Auto merge of #7731 - Mark-Simulacrum:chatty-jobserver, r=alexcrichton
Browse files Browse the repository at this point in the history
Scalable jobserver for rustc

This refactors the job queue code for support of [per-rustc process jobservers](rust-lang/rust#67398). Furthermore, it also cleans up the code and refactors the main loop to be more amenable to understanding (splitting into methods and such).

Assignment of tokens to either rustc "threads" or processes is dedicated to the main loop, which proceeds in a strict "least recently requested" fashion among both thread and process token requests. Specifically, we will first allocate tokens to all pending process token requests (i.e., high-level units of work), and then (in per-rustc jobserver mode) follow up by assigning any remaining tokens to rustcs, again in the order that requests came into cargo (first request served first).

It's not quite clear that that model is good (no modeling or so has been done). On the other hand this strategy should mean that long-running crates will get more thread tokens once we bottom out in terms of rustc parallelism than short-running crates, which means that crates like syn which start early on but finish pretty late should hopefully get more parallelism nicely (without any more complex heuristics).

One plausible change that may be worth exploring is making the assignment prefer earlier rustc's, globally, rather than first attempting to spawn new crates and only then increasing parallelism for old crates. syn for example frequently gets compiled in the early storm of dozens of crates so is somewhat unlikely to have parallelism, until fairly late in its compilation.

We also currently conflate under this model the rayon threads and codegen threads. Eventually inside rustc those will probably(?) also be just one thing, and the rustc side of this implementation provides no information as to what the token request is for so we can't do better here yet.
  • Loading branch information
bors committed Jan 22, 2020
2 parents 9d11cd1 + 7e3e1b1 commit 8ee3d92
Show file tree
Hide file tree
Showing 5 changed files with 507 additions and 170 deletions.
25 changes: 25 additions & 0 deletions src/cargo/core/compiler/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ pub struct Context<'a, 'cfg> {
/// metadata files in addition to the rlib itself. This is only filled in
/// when `pipelining` above is enabled.
rmeta_required: HashSet<Unit<'a>>,

/// When we're in jobserver-per-rustc process mode, this keeps those
/// jobserver clients for each Unit (which eventually becomes a rustc
/// process).
pub rustc_clients: HashMap<Unit<'a>, Client>,
}

impl<'a, 'cfg> Context<'a, 'cfg> {
Expand Down Expand Up @@ -112,6 +117,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
unit_dependencies,
files: None,
rmeta_required: HashSet::new(),
rustc_clients: HashMap::new(),
pipelining,
})
}
Expand Down Expand Up @@ -491,4 +497,23 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
pub fn rmeta_required(&self, unit: &Unit<'a>) -> bool {
self.rmeta_required.contains(unit) || self.bcx.config.cli_unstable().timings.is_some()
}

pub fn new_jobserver(&mut self) -> CargoResult<Client> {
let tokens = self.bcx.build_config.jobs as usize;
let client = Client::new(tokens).chain_err(|| "failed to create jobserver")?;

// Drain the client fully
for i in 0..tokens {
while let Err(e) = client.acquire_raw() {
anyhow::bail!(
"failed to fully drain {}/{} token from jobserver at startup: {:?}",
i,
tokens,
e,
);
}
}

Ok(client)
}
}
Loading

0 comments on commit 8ee3d92

Please sign in to comment.