Skip to content

Commit 83d086d

Browse files
committed
Auto merge of #7062 - goffrie:master, r=alexcrichton
Fix exponentiality in depend_on_deps_of_deps. With `CARGO_BUILD_PIPELINING=true`, cargo was spending a long time (15 seconds) before starting any compilation. That is caused by a naive graph traversal in `depend_on_deps_of_deps`. Instead, let's make sure not to keep traversing the same deps. With this patch, things are fast again.
2 parents 4c1fa54 + 15e0802 commit 83d086d

File tree

2 files changed

+69
-9
lines changed

2 files changed

+69
-9
lines changed

src/cargo/core/compiler/job_queue.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,12 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
154154
let dependencies = cx.dep_targets(unit);
155155
let mut queue_deps = dependencies
156156
.iter()
157+
.cloned()
157158
.filter(|unit| {
158159
// Binaries aren't actually needed to *compile* tests, just to run
159160
// them, so we don't include this dependency edge in the job graph.
160161
!unit.target.is_test() || !unit.target.is_bin()
161162
})
162-
.cloned()
163163
.map(|dep| {
164164
// Handle the case here where our `unit -> dep` dependency may
165165
// only require the metadata, not the full compilation to
@@ -172,7 +172,7 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
172172
};
173173
(dep, artifact)
174174
})
175-
.collect::<Vec<_>>();
175+
.collect::<HashMap<_, _>>();
176176

177177
// This is somewhat tricky, but we may need to synthesize some
178178
// dependencies for this target if it requires full upstream
@@ -196,19 +196,18 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
196196
// `Metadata` propagate upwards `All` dependencies to anything that
197197
// transitively contains the `Metadata` edge.
198198
if unit.requires_upstream_objects() {
199-
for dep in dependencies.iter() {
199+
for dep in dependencies {
200200
depend_on_deps_of_deps(cx, &mut queue_deps, dep);
201201
}
202202

203203
fn depend_on_deps_of_deps<'a>(
204204
cx: &Context<'a, '_>,
205-
deps: &mut Vec<(Unit<'a>, Artifact)>,
206-
unit: &Unit<'a>,
205+
deps: &mut HashMap<Unit<'a>, Artifact>,
206+
unit: Unit<'a>,
207207
) {
208-
for dep in cx.dep_targets(unit) {
209-
if cx.only_requires_rmeta(unit, &dep) {
210-
deps.push((dep, Artifact::All));
211-
depend_on_deps_of_deps(cx, deps, &dep);
208+
for dep in cx.dep_targets(&unit) {
209+
if deps.insert(dep, Artifact::All).is_none() {
210+
depend_on_deps_of_deps(cx, deps, dep);
212211
}
213212
}
214213
}

tests/testsuite/build.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4583,6 +4583,67 @@ fn pipelining_works() {
45834583
.run();
45844584
}
45854585

4586+
#[cargo_test]
4587+
fn pipelining_big_graph() {
4588+
if !crate::support::is_nightly() {
4589+
return;
4590+
}
4591+
4592+
// Create a crate graph of the form {a,b}{0..19}, where {a,b}(n) depend on {a,b}(n+1)
4593+
// Then have `foo`, a binary crate, depend on the whole thing.
4594+
let mut project = project()
4595+
.file(
4596+
"Cargo.toml",
4597+
r#"
4598+
[package]
4599+
name = "foo"
4600+
version = "0.1.0"
4601+
[dependencies]
4602+
a1 = { path = "a1" }
4603+
b1 = { path = "b1" }
4604+
"#,
4605+
)
4606+
.file("src/main.rs", "fn main(){}");
4607+
4608+
for n in 0..30 {
4609+
for x in &["a", "b"] {
4610+
project = project
4611+
.file(
4612+
&format!("{x}{n}/Cargo.toml", x = x, n = n),
4613+
&format!(
4614+
r#"
4615+
[package]
4616+
name = "{x}{n}"
4617+
version = "0.1.0"
4618+
[dependencies]
4619+
a{np1} = {{ path = "../a{np1}" }}
4620+
b{np1} = {{ path = "../b{np1}" }}
4621+
"#,
4622+
x = x,
4623+
n = n,
4624+
np1 = n + 1
4625+
),
4626+
)
4627+
.file(&format!("{x}{n}/src/lib.rs", x = x, n = n), "");
4628+
}
4629+
}
4630+
4631+
let foo = project
4632+
.file("a30/Cargo.toml", &basic_lib_manifest("a30"))
4633+
.file(
4634+
"a30/src/lib.rs",
4635+
r#"compile_error!("don't actually build me");"#,
4636+
)
4637+
.file("b30/Cargo.toml", &basic_lib_manifest("b30"))
4638+
.file("b30/src/lib.rs", "")
4639+
.build();
4640+
foo.cargo("build -p foo")
4641+
.env("CARGO_BUILD_PIPELINING", "true")
4642+
.with_status(101)
4643+
.with_stderr_contains("[ERROR] Could not compile `a30`[..]")
4644+
.run();
4645+
}
4646+
45864647
#[cargo_test]
45874648
fn forward_rustc_output() {
45884649
let foo = project()

0 commit comments

Comments
 (0)