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

Use a more efficient iteration order for forward dataflow #62062

Merged
merged 1 commit into from
Jul 1, 2019

Conversation

ecstatic-morse
Copy link
Contributor

Currently, dataflow begins by visiting each block in order of ID (BasicBlock(0), BasicBlock(1), etc.). This PR changes that initial iteration to reverse post-order (see this blog post for more info). This ensures that the effects of all predecessors will be applied before a basic block is visited if the CFG has no back-edges, and should result in less total iterations even when back-edges exist. This should not change the results of dataflow analysis.

The current ordering for basic blocks may be pretty close to RPO already--BasicBlock(0) is already the start block--in which case the cost of doing the traversal up front will outweigh the efficiency gains.
A perf run is needed to check this.

r? @pnkfelix (I think).

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 22, 2019
@nagisa

This comment has been minimized.

@bors

This comment has been minimized.

@ecstatic-morse
Copy link
Contributor Author

@nagisa. Do you think the assertion about unreachable basic blocks is correct? I added it because there could be two successive basic blocks which are unreachable from the start block, in which case the entry set for the second one would be wrong.

@bors

This comment has been minimized.

@rust-highfive

This comment has been minimized.

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 22, 2019
@nagisa

This comment has been minimized.

@bors

This comment has been minimized.

@rust-highfive

This comment has been minimized.

@nagisa

This comment has been minimized.

@bors

This comment has been minimized.

@bors

This comment has been minimized.

@rust-highfive

This comment has been minimized.

@nagisa
Copy link
Member

nagisa commented Jun 22, 2019

@bors try

@bors
Copy link
Contributor

bors commented Jun 22, 2019

⌛ Trying commit b03ebd53e5b427b95fa36b0ec295b72125d7e371 with merge 0905d6a630cb4afc3f894f9e91c1a7a20c32416b...

@bors
Copy link
Contributor

bors commented Jun 23, 2019

☀️ Try build successful - checks-travis
Build commit: 0905d6a630cb4afc3f894f9e91c1a7a20c32416b

@Centril
Copy link
Contributor

Centril commented Jun 23, 2019

@rust-timer build 0905d6a630cb4afc3f894f9e91c1a7a20c32416b

@rust-timer
Copy link
Collaborator

Success: Queued 0905d6a630cb4afc3f894f9e91c1a7a20c32416b with parent d6884ae, comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking try commit 0905d6a630cb4afc3f894f9e91c1a7a20c32416b, comparison URL.

@pnkfelix
Copy link
Member

This seems ... fine? It doesn't seems to hurt anything; it also doesn't improve things terribly much, probably because the block numbering was close to RPO already, as hypothesized.

ts probably not a good idea to implicitly rely on the block numbering always remaining close to RPO, right? And therefore we should land this?

What do you think, @ecstatic-morse ? (@nagisa and @arielb1 may also have thoughts on this, since I know they've each also spent time thinking about or working on dataflow analyses.)

@ecstatic-morse
Copy link
Contributor Author

ecstatic-morse commented Jun 27, 2019

I think this should probably land (totally not biased or anything :). It's a sensible default, the overhead of a single extra RPO traversal per dataflow analysis is pretty small, and it removes the implicit dependency on a certain basic block ordering, which may change as more MIR transformations are added. With the addition of more expensive dataflow passes (i.e. reaching definitions), the naive ordering could eventually have an observable performance impact.

The alternative is to wait until a MIR transformation is actually added which renumbers basic blocks, but this PR will probably be long forgotten by then 😄.

@ecstatic-morse
Copy link
Contributor Author

ecstatic-morse commented Jun 27, 2019

Also, this does reduce the number of dataflow iterations, just not enough to matter. I observed a reduction of 9% across all dataflow analyses which took more than 5 iterations when running the tests in src/test/run-pass/array-slice-vec/.

Currently, dataflow begins by visiting each block in order of ID
(`BasicBlock(0)`, `BasicBlock(1)`, etc.). This PR changes that initial
iteration to reverse post-order. This ensures that the effects of all
predecessors will be applied before a basic block is visited if the CFG
has no back-edges, and should result in less total iterations even when
back-edges exist. This should not change the results of dataflow
analysis.

The current ordering for basic blocks is pretty close to RPO
already--`BasicBlock(0)` is already the start block, so the gains from
this are pretty small, especially since we need to do an extra traversal
up front.

Note that some basic blocks are unreachable from the `START_BLOCK`
during dataflow. We add these blocks to the work queue as well to
preserve the original behavior.
ecstatic-morse added a commit to ecstatic-morse/rust that referenced this pull request Jun 27, 2019
This applies the same basic principle as rust-lang#62062 to the reverse dataflow
analysis used to compute liveness information. It is functionally
equivalent, except that post-order is used instead of reverse post-order.

Some `mir::Body`s contain basic blocks which are not reachable from the
`START_BLOCK`. We need to add them to the work queue as well to preserve
the original semantics.
@arielb1
Copy link
Contributor

arielb1 commented Jun 28, 2019

@pnkfelix

I think it's OK to land this to avoid the dependence on basic block ordering.

@nagisa
Copy link
Member

nagisa commented Jun 29, 2019

@bors r+

@bors
Copy link
Contributor

bors commented Jun 29, 2019

📌 Commit 07c5e2b has been approved by nagisa

@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-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 29, 2019
Centril added a commit to Centril/rust that referenced this pull request Jun 30, 2019
…gisa

Use a more efficient iteration order for forward dataflow

Currently, dataflow begins by visiting each block in order of ID (`BasicBlock(0)`, `BasicBlock(1)`, etc.). This PR changes that initial iteration to reverse post-order (see [this blog post](https://eli.thegreenplace.net/2015/directed-graph-traversal-orderings-and-applications-to-data-flow-analysis/#data-flow-analysis) for more info). This ensures that the effects of all predecessors will be applied before a basic block is visited if the CFG has no back-edges, and should result in less total iterations even when back-edges exist. This should not change the results of dataflow analysis.

The current ordering for basic blocks may be pretty close to RPO already--`BasicBlock(0)` is already the start block--in which case the cost of doing the traversal up front will outweigh the efficiency gains.
A perf run is needed to check this.

r? @pnkfelix (I think).
Centril added a commit to Centril/rust that referenced this pull request Jun 30, 2019
…der, r=nagisa

Use a more efficient iteration order for backward dataflow

This applies the same basic principle as rust-lang#62062 to the reverse dataflow analysis used to compute liveness information. It is functionally equivalent, except that post-order is used instead of reverse post-order.

In the long-term, `BitDenotation` should probably be extended to support both forward and backward dataflow, but there's some more work needed to get to that point.
bors added a commit that referenced this pull request Jul 1, 2019
Rollup of 8 pull requests

Successful merges:

 - #62062 (Use a more efficient iteration order for forward dataflow)
 - #62063 (Use a more efficient iteration order for backward dataflow)
 - #62224 (rustdoc: remove unused derives and variants)
 - #62228 (Extend the #[must_use] lint to boxed types)
 - #62235 (Extend the `#[must_use]` lint to arrays)
 - #62239 (Fix a typo)
 - #62241 (Always parse 'async unsafe fn' + properly ban in 2015)
 - #62248 (before_exec actually will only get deprecated with 1.37)

Failed merges:

r? @ghost
@bors bors merged commit 07c5e2b into rust-lang:master Jul 1, 2019
@ecstatic-morse ecstatic-morse deleted the dataflow-order branch October 6, 2020 01:42
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.

8 participants