Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upNonlinear compile time blow-up with deeply nested types #38528
Comments
sfackler
added
I-compiletime
T-compiler
labels
Dec 22, 2016
This comment has been minimized.
This comment has been minimized.
This may be the effect of the projection cache. |
This comment has been minimized.
This comment has been minimized.
|
cc @alexcrichton This is obviously a show-stopper for futures. |
This comment has been minimized.
This comment has been minimized.
|
I can do some profiling. I've had some plans for improving collection/trans that I think may be related. One question to try and answer is what %age of this is just "we are making more code" vs "we are wasting time doing things in trait selection that could be cached". I have observed the latter from time to time and had some thoughts on how to fix it. |
This comment has been minimized.
This comment has been minimized.
|
I've also seen this before, with tokio-socks5 as well. Removing just a handful of the trait objects in that file makes the compile time of the crate shoot from 2.34s to 89.52s (!!) |
This comment has been minimized.
This comment has been minimized.
|
Here's a simple example of something that takes a very long time to compile: future::ok::<(),()>(()).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())).and_then(|()| Ok(())); |
nikomatsakis
referenced this issue
Mar 9, 2017
Closed
Methods take an insanely long time to compile #40280
This comment has been minimized.
This comment has been minimized.
|
Closed #40280 as a duplicate, moved some example code into the issue header. |
This comment has been minimized.
This comment has been minimized.
|
Just a stupid question ‒ the „translation item collection“, which is one of the two culprits here, is listed in the „MIR optimisations“. Does it really have to happen at all on non-optimised debug build? |
This comment has been minimized.
This comment has been minimized.
|
It's natural to read it that way, but the headers are actual after their group, so it's part of |
This comment has been minimized.
This comment has been minimized.
|
This seems to be hard enough to take some time fixing. So I thought of a workaround, if someone is also interested. It uses the trick with placing trait objects to split the chains of modifiers, but only on testing/debug builds where the compilation speed matters, while it keeps the complex but hopefully faster concrete types in release build: This one is for streams (that's what I needed), but can obviously work for futures or other things as well: #[cfg(debug_assertions)]
fn test_boxed<T, E, S>(s: S) -> Box<Stream<Item = T, Error = E>>
where S: Stream<Item = T, Error = E> + 'static
{
Box::new(s)
}
#[cfg(not(debug_assertions))]
fn test_boxed<S>(s: S) -> S {
s
}(I didn't find any better config option than the |
jonhoo
added a commit
to jonhoo/fantoccini
that referenced
this issue
Jun 20, 2017
Mark-Simulacrum
referenced this issue
Jun 23, 2017
Closed
Seemingly pathological behavior in typechecking, item collecting, and trans #33594
sfackler
referenced this issue
Jul 2, 2017
Closed
Long compile time due to excessively long translation passes #42941
This comment has been minimized.
This comment has been minimized.
Mark-Simulacrum
added
the
I-nominated
label
Jul 2, 2017
This comment has been minimized.
This comment has been minimized.
|
Repeating another bad case from #42941: extern crate futures;
use futures::{future, IntoFuture, Future};
fn main() {
let t: std::result::Result<(), ()> = Ok(());
let f = t
.into_future()
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()))
.and_then(|_| future::ok(()));
f.wait();
}The code above takes ~750s to compile on my laptop (you can make it shorter/longer by removing/adding
The extra ~250s is spent between |
jonhoo
referenced this issue
Jul 2, 2017
Closed
Borrow checking time regression from stable to nightly #43018
This comment has been minimized.
This comment has been minimized.
|
Another observation from #42941 about why this is becoming even more important is that the newly-released hyper |
This comment has been minimized.
This comment has been minimized.
|
triage: P-high We are raising to "high priority" to at least do some investigation and try to determine whether revised trait solving strategies will be of use here. |
rust-highfive
added
P-high
and removed
I-nominated
labels
Jul 6, 2017
nikomatsakis
self-assigned this
Jul 6, 2017
jonhoo
added a commit
to jonhoo/fantoccini
that referenced
this issue
Jul 8, 2017
Mark-Simulacrum
added
the
C-bug
label
Jul 26, 2017
This comment has been minimized.
This comment has been minimized.
|
status: waiting for niko |
This comment has been minimized.
This comment has been minimized.
|
Bump. This really hurts |
aturon
added this to the
impl period milestone
Sep 4, 2017
This comment has been minimized.
This comment has been minimized.
tanriol
commented
Jan 8, 2018
|
I've tried profiling rustc and getting a backtrace for the generic version by @hcpl above at some random moment of time. Likely relevant lines from the backtrace
The cause in this case seems to be that at every |
This comment has been minimized.
This comment has been minimized.
|
Thanks for the profiles everyone, btw, I've been spending a bit more time investigating too but don't yet have any insights to share. =) |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis can you share what problem have you stumbled over? Thanks to @tanriol's profile I think the root cause is quite clear; we just need to cache the call to eliminate the blowup. What I'm worrying is that |
This comment has been minimized.
This comment has been minimized.
ishitatsuyuki
referenced this issue
Feb 15, 2018
Closed
Compiler hangs during recursive monomorphisation #39684
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Finding as of today: The blowup roots from cc @tanriol @nikomatsakis Please check if this clears up some obstacles. Primarily I'm wondering why normalization is continuously performed (maybe due to snapshot?). |
This comment has been minimized.
This comment has been minimized.
|
Okay, I think I've successfully understood the overall picture of this blowup. First, it's true that we're calling Second, the blowup occurs in operations that are not currently cached. In Adding to that, To sum up, we didn't get any short circuits here due to the two factors preventing caching from happening. Next, I'm proposing some solutions below, focusing on fixing the "calling twice" problem:
I need your expertise on this, so we can reach a solution that resolves the issue. Please give me your opinion! |
This comment has been minimized.
This comment has been minimized.
|
Another update: the projection cache actually exists, but we're discarding them every time by wiping the InferCtxt (with snapshots). I have created a diagram to show how this recurs: So basically we need to implement this FIXME: rust/src/librustc/traits/project.rs Lines 1548 to 1550 in 554fe71 |
This comment has been minimized.
This comment has been minimized.
|
@arielb1 You seem to have created this FIXME. Can you give me some hints on implementing cross-infcx cache? |
ishitatsuyuki
referenced this issue
Feb 17, 2018
Merged
Fix exponential projection complexity on nested types #48296
This comment has been minimized.
This comment has been minimized.
|
I have launched a PoC in #48296 and I confirm that the exponential part should be resolved. I still observe some degree of polynomial time algorithms, which makes rustc chokes at about 50 |
This comment has been minimized.
This comment has been minimized.
|
@hcpl I suspect you copied the wrong code for the specialized version above, as I observe the same time-passes behavior and the code lacks Can you check again, and if possible, provide the correct specialized version code? |
This comment has been minimized.
This comment has been minimized.
|
Update: although I have fixed the normalization part, the typeck still seems to be exponential on time, and very memory consuming. I'm investigating the cause of this second issue. |
bors
added a commit
that referenced
this issue
Feb 18, 2018
This comment has been minimized.
This comment has been minimized.
|
I have implemented a fix for the typeck part too, and I believe there's no more exponential algorithms in rustc anymore. |
This comment has been minimized.
This comment has been minimized.
hcpl
commented
Feb 18, 2018
|
@ishitatsuyuki the code is correct, but both I've changed filenames to |

sfackler commentedDec 22, 2016
•
edited by nikomatsakis
Compiling the postgres-tokio crate at sfackler/rust-postgres@d27518b goes from 5 seconds to 45 seconds on nightly if the two
.boxed()calls in the middle of this call chain are removed: https://github.com/sfackler/rust-postgres/blob/d27518ba76d76ccaa59b3ccd63e981bd8bd0ef33/postgres-tokio/src/lib.rs#L342-L408.Looks like 15 seconds is spent in translation item collection, and 39 seconds is spent in translation:
Things are significantly worse on 1.13 - 2 minutes in translation!
Some discussion in IRC: https://botbot.me/mozilla/rust-internals/2016-12-22/?msg=78294648&page=1
cc @aturon
UPDATE: #40280 was closed as a duplicate of this. It had the following sample code:
--nmatsakis