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 llvm::computeLTOCacheKey to determine post-ThinLTO CGU reuse #76859

Merged
merged 1 commit into from
Oct 11, 2020

Conversation

Aaron1011
Copy link
Member

During incremental ThinLTO compilation, we attempt to re-use the
optimized (post-ThinLTO) bitcode file for a module if it is 'safe' to do
so.

Up until now, 'safe' has meant that the set of modules that our current
modules imports from/exports to is unchanged from the previous
compilation session. See PR #67020 and PR #71131 for more details.

However, this turns out be insufficient to guarantee that it's safe
to reuse the post-LTO module (i.e. that optimizing the pre-LTO module
would produce the same result). When LLVM optimizes a module during
ThinLTO, it may look at other information from the 'module index', such
as whether a (non-imported!) global variable is used. If this
information changes between compilation runs, we may end up re-using an
optimized module that (for example) had dead-code elimination run on a
function that is now used by another module.

Fortunately, LLVM implements its own ThinLTO module cache, which is used
when ThinLTO is performed by a linker plugin (e.g. when clang is used to
compile a C proect). Using this cache directly would require extensive
refactoring of our code - but fortunately for us, LLVM provides a
function that does exactly what we need.

The function llvm::computeLTOCacheKey is used to compute a SHA-1 hash
from all data that might influence the result of ThinLTO on a module.
In addition to the module imports/exports that we manually track, it
also hashes information about global variables (e.g. their liveness)
which might be used during optimization. By using this function, we
shouldn't have to worry about new LLVM passes breaking our module re-use
behavior.

In LLVM, the output of this function forms part of the filename used to
store the post-ThinLTO module. To keep our current filename structure
intact, this PR just writes out the mapping 'CGU name -> Hash' to a
file. To determine if a post-LTO module should be reused, we compare
hashes from the previous session.

This should unblock PR #75199 - by sheer chance, it seems to have hit
this issue due to the particular CGU partitioning and optimization
decisions that end up getting made.

During incremental ThinLTO compilation, we attempt to re-use the
optimized (post-ThinLTO) bitcode file for a module if it is 'safe' to do
so.

Up until now, 'safe' has meant that the set of modules that our current
modules imports from/exports to is unchanged from the previous
compilation session. See PR rust-lang#67020 and PR rust-lang#71131 for more details.

However, this turns out be insufficient to guarantee that it's safe
to reuse the post-LTO module (i.e. that optimizing the pre-LTO module
would produce the same result). When LLVM optimizes a module during
ThinLTO, it may look at other information from the 'module index', such
as whether a (non-imported!) global variable is used. If this
information changes between compilation runs, we may end up re-using an
optimized module that (for example) had dead-code elimination run on a
function that is now used by another module.

Fortunately, LLVM implements its own ThinLTO module cache, which is used
when ThinLTO is performed by a linker plugin (e.g. when clang is used to
compile a C proect). Using this cache directly would require extensive
refactoring of our code - but fortunately for us, LLVM provides a
function that does exactly what we need.

The function `llvm::computeLTOCacheKey` is used to compute a SHA-1 hash
from all data that might influence the result of ThinLTO on a module.
In addition to the module imports/exports that we manually track, it
also hashes information about global variables (e.g. their liveness)
which might be used during optimization. By using this function, we
shouldn't have to worry about new LLVM passes breaking our module re-use
behavior.

In LLVM, the output of this function forms part of the filename used to
store the post-ThinLTO module. To keep our current filename structure
intact, this PR just writes out the mapping 'CGU name -> Hash' to a
file. To determine if a post-LTO module should be reused, we compare
hashes from the previous session.

This should unblock PR rust-lang#75199 - by sheer chance, it seems to have hit
this issue due to the particular CGU partitioning and optimization
decisions that end up getting made.
@rust-highfive
Copy link
Collaborator

r? @petrochenkov

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 18, 2020
@Aaron1011
Copy link
Member Author

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented Sep 18, 2020

⌛ Trying commit cfe07cd with merge f35705fb01020929514f970af7f0c5878c90cb37...

@bors
Copy link
Contributor

bors commented Sep 18, 2020

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

@rust-timer
Copy link
Collaborator

Queued f35705fb01020929514f970af7f0c5878c90cb37 with parent f3c923a, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking try commit (f35705fb01020929514f970af7f0c5878c90cb37): comparison url.

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. Please note that if the perf results are neutral, you should likely undo the rollup=never given below by specifying rollup- to bors.

Importantly, though, if the results of this run are non-neutral do not roll this PR up -- it will mask other regressions or improvements in the roll up.

@bors rollup=never

@petrochenkov
Copy link
Contributor

r? @pnkfelix

@Mark-Simulacrum
Copy link
Member

cc @rust-lang/wg-incr-comp -- could we find a reviewer for this PR? It's blocking re-enabling debug assertions in CI on some builders (#75199).

Copy link
Member

@davidtwco davidtwco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too familiar with ThinLTO, but this all seems reasonable to me.

r=me unless you want another review

@Aaron1011
Copy link
Member Author

@nikic Does this look reasonable to you?

@nikic
Copy link
Contributor

nikic commented Oct 11, 2020

Looks very reasonable, and is hopefully the end of the road for this class of problems...

@bors r=davidtwco,nikic

@bors
Copy link
Contributor

bors commented Oct 11, 2020

📌 Commit cfe07cd has been approved by davidtwco,nikic

@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 Oct 11, 2020
@bors
Copy link
Contributor

bors commented Oct 11, 2020

⌛ Testing commit cfe07cd with merge c71248b...

@bors
Copy link
Contributor

bors commented Oct 11, 2020

☀️ Test successful - checks-actions, checks-azure
Approved by: davidtwco,nikic
Pushing c71248b to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Oct 11, 2020
@bors bors merged commit c71248b into rust-lang:master Oct 11, 2020
@rustbot rustbot added this to the 1.49.0 milestone Oct 11, 2020
@Mark-Simulacrum
Copy link
Member

Presumably due to finer-grained tracking in some cases, this was a major improvement on some incremental tests. Of course, the correctness is much more important here :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. 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.

None yet

10 participants