-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pathological performance in resolve with lots of unused imports in style
crate
#43572
Comments
cc @rust-lang/compiler |
style
crate
We could address this quickly by just emitting the first 10 unused imports warnings and then warning that there are more unused imports not shown. |
I can never deal with more than 10 lints at a time anyway myself, so seems like a reasonable solution to me! |
Dumping out a ton of warnings is useful when you're hooked into an IDE and you can see them as e.g. green squiggles under the offending text as opposed to 10k lines on a terminal. |
I think the reason fn ensure_filemap_source_present(&self, file_map: Rc<FileMap>) -> bool {
let src = self.file_loader.read_file(Path::new(&file_map.name)).ok();
return file_map.add_external_src(src)
} I don't think we want to read source files multiple times like that. |
Thank you for looking into Servo compile times Alex, and great find here! Could you CC me or someone from the Servo team for Servo-related issues? Thanks. |
Can do! |
In general I've always wanted the lint system to avoid even running in Currently the lint system runs all lints in parallel on the tree. This is great since it means we only traverse it once, and the cost of the traversal is consolidated. We don't need to reduce that cost itself (which is nice because then we don't have to worry about Most lints do not maintain state. The lint framework has the capability to do so, and we use this a couple times in Clippy, but most lints are The "allowness" of a lint is tied to where in the tree the lint traversal is, not the span emitted by the lint. It's perfectly possible to All of this enables this proposal: If we had a specialized It doesn't even have to be a trait, really, it could just be a defaulted fake-static method (until rust-lang/rfcs#2027 happens) on LateLintPass. I suspect this will get significant speedups for crates like Style. I may be able to take a crack at this if y'all think this is a good approach. |
It occurs to me that a boolean check per lint each tree node might actually end up being more expensive? I'll have look at this code closer. Might be possible to make this fast by having a second array of trait objects which only contains the active lint passes. |
It seems like we do a large enough amount of work that the whole "vector of active lints" stuff won't really be necessary. However, I just realized that this bug is not during the lint pass but during the resolution phase (which defers linting to the actual lint pass). This won't be able to help, though we can fix it by doing the span_to_snippet in the actual lint and then making this optimization. So in that case I suspect this optimization is unnecessary. In general we've rarely had performance issues with lints in clippy (which has way more lints than rustc), and we've been pretty careful to measure impact there. Still, if folks think this optimization can help, let me know. |
A local build of Servo's
style
crate shows a huge amount of time (46 seconds!) in name resolution. It turns out that basically all of it is callingspan_to_snippet
, specifically this one. That's a lot of unused imports!Sure enough if we create a synthetic file locally with this script:
we find:
That's a lot of time spent processing unused imports!
The slowdown here isn't quite the same as the style crate, unfortunately. The style crate only has ~7k unused imports, which apparently takes it 48s in that profile. In any case the intent here is clear, lots of unused imports seem to slow down compilation, and the
style
crate looks to have a lot of unused imports!The text was updated successfully, but these errors were encountered: