Skip to content

Commit 2114c5d

Browse files
committed
Implement JobQueue support for pipelining
This commit adds support to Cargo's internal `JobQueue` to execute pipelined rlib compilations actually in a pipelined fashion. This internally invovled some refactoring to ensure we juggled the right jobs into the right places, ensuring that as soon as an rmeta file is produce we can start subsequent compilations but still synchronize with the finished result of a `Build` unit. Internally this continues to still not actually pipeline anything in the sense that rustc doesn't support pipelining, but it's in theory all the groundwork necessary to read a signal from rustc that a metadata file is ready to go and then plumb that into Cargo's job scheduler.
1 parent 1caae51 commit 2114c5d

File tree

8 files changed

+285
-44
lines changed

8 files changed

+285
-44
lines changed

src/cargo/core/compiler/build_config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ pub enum CompileMode {
127127
Test,
128128
/// Building a target with `rustc` (lib or bin).
129129
Build,
130+
/// Building just the metadata of an rlib with `rustc`
131+
///
132+
/// This is somewhat of a special mode, and for more information see the
133+
/// documentation in `job_queue.rs`
130134
BuildRmeta,
131135
/// Building a target with `rustc` to emit `rmeta` metadata only. If
132136
/// `test` is true, then it is also compiled with `--test` to check it like

src/cargo/core/compiler/context/unit_dependencies.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ fn pipeline_compilations(state: &mut State<'_, '_, '_>) -> CargoResult<()> {
660660
debug_assert_eq!(build_rmeta_unit.mode, CompileMode::BuildRmeta);
661661
debug_assert_eq!(build_unit.mode, CompileMode::Build);
662662

663-
// There may be multiple paths to the root of the depenency graph as we
663+
// There may be multiple paths to the root of the dependency graph as we
664664
// walk upwards, but we don't want to add units more than once. Use a
665665
// visited set to guard against this.
666666
if !updated.insert((*build_unit, *build_rmeta_unit)) {

src/cargo/core/compiler/job_queue.rs

Lines changed: 225 additions & 24 deletions
Large diffs are not rendered by default.

src/cargo/core/compiler/mod.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ fn rustc<'a, 'cfg>(
244244
.unwrap_or_else(|| cx.bcx.config.cwd())
245245
.to_path_buf();
246246
let fingerprint_dir = cx.files().fingerprint_dir(unit);
247+
let is_build_rmeta = unit.mode == CompileMode::BuildRmeta;
247248

248249
return Ok(Work::new(move |state| {
249250
// Only at runtime have we discovered what the extra -L and -l
@@ -315,6 +316,25 @@ fn rustc<'a, 'cfg>(
315316
.chain_err(|| format!("Could not compile `{}`.", name))?;
316317
}
317318

319+
// FIXME(rust-lang/rust#58465): this is the whole point of "pipelined
320+
// compilation" in Cargo. We want to, here in this unit, call
321+
// `finish_rmeta` as soon as we can which indicates that the metadata
322+
// file is emitted by rustc and ready to go. This will start dependency
323+
// compilations as soon as possible.
324+
//
325+
// The compiler doesn't currently actually implement the ability to let
326+
// us know, however, when the metadata file is ready to go. It actually
327+
// today produces the file very late in compilation, far later than it
328+
// would otherwise be able to do!
329+
//
330+
// In any case this is all covered by the issue above. This is just a
331+
// marker for "yes we unconditionally do this today but tomorrow we
332+
// should actually read what rustc is doing and execute this at an
333+
// appropriate time, ideally long before rustc finishes completely".
334+
if is_build_rmeta {
335+
state.finish_rmeta();
336+
}
337+
318338
if do_rename && real_name != crate_name {
319339
let dst = &outputs[0].path;
320340
let src = dst.with_file_name(
@@ -790,11 +810,14 @@ fn build_base_args<'a, 'cfg>(
790810
}
791811
}
792812

793-
if unit.mode.is_check() {
794-
cmd.arg("--emit=dep-info,metadata");
795-
} else {
796-
cmd.arg("--emit=dep-info,metadata,link");
797-
}
813+
cmd.arg(match unit.mode {
814+
CompileMode::Build | CompileMode::Test | CompileMode::Bench => "--emit=dep-info,link",
815+
CompileMode::BuildRmeta => "--emit=dep-info,metadata,link",
816+
CompileMode::Check { .. } => "--emit=dep-info,metadata",
817+
CompileMode::Doc { .. } | CompileMode::Doctest | CompileMode::RunCustomBuild => {
818+
unreachable!()
819+
}
820+
});
798821

799822
let prefer_dynamic = (unit.target.for_host() && !unit.target.is_custom_build())
800823
|| (crate_types.contains(&"dylib") && bcx.ws.members().any(|p| p != unit.pkg));

src/cargo/core/manifest.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ impl LibKind {
124124
pub fn requires_upstream_objects(&self) -> bool {
125125
match *self {
126126
// "lib" == "rlib" and is a compilation that doesn't actually
127-
// require upstream object files to exist, only upstream etadata
127+
// require upstream object files to exist, only upstream metadata
128128
// files. As a result, it doesn't require upstream artifacts
129129
LibKind::Lib | LibKind::Rlib => false,
130130

src/cargo/util/dependency_queue.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,19 @@ impl<K: Hash + Eq + Clone, V> DependencyQueue<K, V> {
132132
Some((key, data))
133133
}
134134

135+
/// Forcibly dequeues a particular key from the dependency queue.
136+
///
137+
/// # Panics
138+
///
139+
/// Panics if `key`'s dependencies haven't finished yet or if `key` isn't in
140+
/// the dependency queue.
141+
pub fn dequeue_key(&mut self, key: &K) -> V {
142+
let (deps, data) = self.dep_map.remove(&key).unwrap();
143+
assert!(deps.is_empty());
144+
self.pending.insert(key.clone());
145+
return data;
146+
}
147+
135148
/// Returns `true` if there are remaining packages to be built.
136149
pub fn is_empty(&self) -> bool {
137150
self.dep_map.is_empty() && self.pending.is_empty()

tests/testsuite/build.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,11 +1451,11 @@ fn cargo_default_env_metadata_env_var() {
14511451

14521452
// No metadata on libbar since it's a dylib path dependency
14531453
p.cargo("build -v")
1454-
.with_stderr(
1454+
.with_stderr(&format!(
14551455
"\
14561456
[COMPILING] bar v0.0.1 ([CWD]/bar)
14571457
[RUNNING] `rustc --crate-name bar bar/src/lib.rs --color never --crate-type dylib \
1458-
--emit=[..]link \
1458+
--emit=dep-info,link \
14591459
-C prefer-dynamic -C debuginfo=2 \
14601460
-C metadata=[..] \
14611461
--out-dir [..] \
@@ -1467,21 +1467,23 @@ fn cargo_default_env_metadata_env_var() {
14671467
-C extra-filename=[..] \
14681468
--out-dir [..] \
14691469
-L dependency=[CWD]/target/debug/deps \
1470-
--extern bar=[CWD]/target/debug/deps/libbar[..]`
1470+
--extern bar=[CWD]/target/debug/deps/{prefix}bar{suffix}`
14711471
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
1472-
)
1472+
prefix = env::consts::DLL_PREFIX,
1473+
suffix = env::consts::DLL_SUFFIX,
1474+
))
14731475
.run();
14741476

14751477
p.cargo("clean").run();
14761478

14771479
// If you set the env-var, then we expect metadata on libbar
14781480
p.cargo("build -v")
14791481
.env("__CARGO_DEFAULT_LIB_METADATA", "stable")
1480-
.with_stderr(
1482+
.with_stderr(&format!(
14811483
"\
14821484
[COMPILING] bar v0.0.1 ([CWD]/bar)
14831485
[RUNNING] `rustc --crate-name bar bar/src/lib.rs --color never --crate-type dylib \
1484-
--emit=[..]link \
1486+
--emit=dep-info,link \
14851487
-C prefer-dynamic -C debuginfo=2 \
14861488
-C metadata=[..] \
14871489
--out-dir [..] \
@@ -1493,10 +1495,12 @@ fn cargo_default_env_metadata_env_var() {
14931495
-C extra-filename=[..] \
14941496
--out-dir [..] \
14951497
-L dependency=[CWD]/target/debug/deps \
1496-
--extern bar=[CWD]/target/debug/deps/libbar-[..]`
1498+
--extern bar=[CWD]/target/debug/deps/{prefix}bar-[..]{suffix}`
14971499
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
14981500
",
1499-
)
1501+
prefix = env::consts::DLL_PREFIX,
1502+
suffix = env::consts::DLL_SUFFIX,
1503+
))
15001504
.run();
15011505
}
15021506

@@ -1921,9 +1925,6 @@ fn verbose_release_build_deps() {
19211925
version = "0.0.0"
19221926
authors = []
19231927
1924-
[lib]
1925-
crate-type = ['cdylib']
1926-
19271928
[dependencies.foo]
19281929
path = "foo"
19291930
"#,
@@ -1958,7 +1959,7 @@ fn verbose_release_build_deps() {
19581959
--out-dir [..] \
19591960
-L dependency=[CWD]/target/release/deps`
19601961
[COMPILING] test v0.0.0 ([CWD])
1961-
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type cdylib \
1962+
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
19621963
--emit=[..]link \
19631964
-C opt-level=3 \
19641965
-C metadata=[..] \

tests/testsuite/dep_info.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ fn build_dep_info_rlib() {
6161
.build();
6262

6363
p.cargo("build --example=ex")
64-
.stream()
6564
.env("RUST_LOG", "cargo")
6665
.run();
6766
assert!(p.example_lib("ex", "rlib").with_extension("d").is_file());

0 commit comments

Comments
 (0)