Skip to content
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

Simpler slice Iterator methods #72166

Merged
merged 2 commits into from
May 16, 2020

Conversation

nnethercote
Copy link
Contributor

These reduce the amount of LLVM IR generated, helping compile times.

r? @cuviper

The default implementations of several `Iterator` methods use `fold` or
`try_fold`, which works, but is overkill for slices and bloats the
amount of LLVM IR generated and consequently hurts compile times.

This commit adds the simple, obvious implementations for `for_each`,
`all`, `any`, `find`, `find_map`, and simplifies the existing
implementations for `position` and `rposition`. These changes reduce
compile times significantly on some benchmarks.
Currently it uses `for x in self`, which seems dubious within an
iterator method. Furthermore, `self.next()` is used in all the other
iterator methods.
@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 13, 2020
@nnethercote
Copy link
Contributor Author

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented May 13, 2020

⌛ Trying commit 3b10858 with merge 7f1659b19bed7255f86fa296721f74e5f107f9ef...

@bors
Copy link
Contributor

bors commented May 13, 2020

☀️ Try build successful - checks-actions, checks-azure
Build commit: 7f1659b19bed7255f86fa296721f74e5f107f9ef (7f1659b19bed7255f86fa296721f74e5f107f9ef)

@rust-timer
Copy link
Collaborator

Queued 7f1659b19bed7255f86fa296721f74e5f107f9ef with parent a2e0b48, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking try commit 7f1659b19bed7255f86fa296721f74e5f107f9ef, comparison URL.

@andjo403
Copy link
Contributor

nice perf results
but some questions that I started thinking of:

  • is this common enough to grant special handling only 5 of 114 benchmarks with more than 1% so maybe not?
  • when to stop with manual inlining the next() function is also called and probably inlined in all this functions and if that is inlined by hand shall the next level of functions be inlined also?
  • when/if mir inlining is merged will someone remember to remove this manual inlining if that gives no extra compile time?

@nnethercote
Copy link
Contributor Author

* is this common enough to grant special handling only 5 of 114 benchmarks with more than 1% so maybe not?

It's a huge win for clap-rs. It's a sizeable win for a few other benchmarks. And it's a tiny win for a lot of benchmarks. Plenty of compile time optimizations that land only affect a few benchmarks.

* when to stop with manual inlining the next() function is also called and probably inlined in all this functions and if that is inlined by hand shall the next level of functions be inlined also?

The exact inlining is up to LLVM. The methods in Iterator are also marked with #[inline] so this is not much of a change.

* when/if mir inlining is merged will someone remember to remove this manual inlining if that gives no extra compile time?

Maybe, maybe not. But if these functions are unnecessary, the cost of them remaining is small.

In general, many optimizations for compile time involve trade-offs, adding complexity for speed. This one is no exception, but I feel that the extra complexity in this case is small relative to the speed improvements.

Overall, I feel this optimization scores quite well on the speed-ups vs. complexity trade-off.

@andjo403
Copy link
Contributor

  • when to stop with manual inlining the next() function is also called and probably inlined in all this functions and if that is inlined by hand shall the next level of functions be inlined also?

The exact inlining is up to LLVM. The methods in Iterator are also marked with #[inline] so this is not much of a change.

what I was trying to ask was. as this change have inlined try_for in to this functions so this have already taken the decision away from LLVM so why stop there.
eg. there is already macros used maybe have a macro that do what next() is doing.

only wondering if this will open the floodgate for PRs that changes inline functions to macros.

also feel that there is a difference if it is a compiler change that makes a win for a few benchmarks or if it is a change in the std lib.

but I agree overall this PR is not making the code more complex and there is good compile time speedups nice work as always and thanks for the answers.

@nnethercote
Copy link
Contributor Author

I thought about doing a similar thing in other iterators, but can't see any suitable candidates. try_fold gets used reasonably often for Filter and Map, e.g. if you have x.iter().filter(...).any(). But we want to call try_fold on the iterator within Filter in that case, to maximize optimization opportunities, so we can't do a simple loop-based implementation for Filter::any. Unless I'm overlooking something.

@nnethercote
Copy link
Contributor Author

cc @bluss

@cuviper
Copy link
Member

cuviper commented May 16, 2020

Looks good!

@bors r+

@bors
Copy link
Contributor

bors commented May 16, 2020

📌 Commit 3b10858 has been approved by cuviper

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 16, 2020
bors added a commit to rust-lang-ci/rust that referenced this pull request May 16, 2020
Rollup of 7 pull requests

Successful merges:

 - rust-lang#71625 (Improve the documentation for ManuallyDrop to resolve conflicting usage of terminology)
 - rust-lang#71919 (Update transitive dependency to work towards removing syn <1.0 dep)
 - rust-lang#72166 (Simpler slice `Iterator` methods)
 - rust-lang#72216 (Remove `lang_items\(\).*\.unwrap\(\)`)
 - rust-lang#72230 (Updated documentation of Prefix::VerbatimDisk)
 - rust-lang#72234 (Implement Default for proc_macro::TokenStream)
 - rust-lang#72258 (Fix typo Arbintrary to Arbitrary)

Failed merges:

r? @ghost
@bors bors merged commit e8f0fb1 into rust-lang:master May 16, 2020
@nnethercote nnethercote deleted the simpler-slice-Iterator-methods branch May 17, 2020 20:15
@nnethercote
Copy link
Contributor Author

Final perf results are here. This landed as part of a rollup because I forgot to mark it with rollup=never, but those results look very similar to the results we saw above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants