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

Do not reuse post LTO products when exports change #71131

Conversation

pnkfelix
Copy link
Member

Do not reuse post lto products when exports change

Generalizes code from PR #67020, which handled case when imports change.

Fix #69798

…file in

incremental compilation.

This is symmetric to PR rust-lang#67020, which handled the case where the LLVM module's
*imports* changed. This commit builds upon the infrastructure added there; the
export map is just the inverse of the import map, so we can build the export map
at the same time that we load the serialized import map.

Fix rust-lang#69798
Namely, a regression test for issue rust-lang#69798 (export added), and the inverse of
that test (export removd).
@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 Apr 14, 2020
@pnkfelix
Copy link
Member Author

@bors rollup=never

This may affect performance, especially of incremental compilations.

@pnkfelix pnkfelix added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Apr 14, 2020
@pnkfelix
Copy link
Member Author

nominating for beta backport; this bug is old, but it was exposed by a recent change (PR #67332), which has not made it to stable yet.

@petrochenkov
Copy link
Contributor

r? @alexcrichton or @michaelwoerister (if you are still around)

@pnkfelix
Copy link
Member Author

pnkfelix commented Apr 14, 2020

I think both @michaelwoerister and @alexcrichton have scaled back their involvement with the project.

I'll try r? @nagisa or @eddyb for now...

@rust-highfive rust-highfive assigned nagisa and unassigned alexcrichton Apr 14, 2020
@pnkfelix
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 Apr 14, 2020

⌛ Trying commit 12207f6 with merge c8085c9fa29609558b4745fc37c7a14c335e0ec3...

@eddyb
Copy link
Member

eddyb commented Apr 14, 2020

The symmetry here makes sense, r=me.

Copy link
Member

@nagisa nagisa left a comment

Choose a reason for hiding this comment

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

r=me on implementation sans the struct/variable names.

src/librustc_codegen_llvm/back/lto.rs Outdated Show resolved Hide resolved
@bors
Copy link
Contributor

bors commented Apr 15, 2020

☀️ Try build successful - checks-azure
Build commit: c8085c9fa29609558b4745fc37c7a14c335e0ec3 (c8085c9fa29609558b4745fc37c7a14c335e0ec3)

@rust-timer
Copy link
Collaborator

Queued c8085c9fa29609558b4745fc37c7a14c335e0ec3 with parent edc0258, future comparison URL.

Renamed the struct to make it a little clearer that it doesn't just hold one
imports map. (I couldn't bring myself to write it as `ThinLTOImportsExports`
though, mainly since the exports map is literally derived from the imports map
data.) Added some doc to the struct too.

Revised comments to add link to the newer issue that discusses why the exports
are relevant.

Renamed a few of the methods so that the two character difference is more
apparent (because 1. the method name is shorter and, perhaps more importantly,
the changed characters now lie at the beginning of the method name.)
@pnkfelix
Copy link
Member Author

Queued c8085c9 with parent edc0258, future comparison URL.

Wow, these results seem so bad that I'm having a hard time believing them to be true...

image

@spastorino spastorino added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 15, 2020
@eddyb
Copy link
Member

eddyb commented Apr 16, 2020

Is that because println! introduces a static? Or is that no longer the case, I can't remember.

@eddyb
Copy link
Member

eddyb commented Apr 16, 2020

Post rust-lang/rustc-perf#645 retry:
@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@pnkfelix
Copy link
Member Author

I'm going to land this as is for now, and look into the performance regression as a follow-up work item.

@pnkfelix
Copy link
Member Author

@bors r=nagisa rollup=never

@bors
Copy link
Contributor

bors commented Apr 16, 2020

📌 Commit d05ae3a 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-review Status: Awaiting review from the assignee but also interested parties. labels Apr 16, 2020
@pnkfelix pnkfelix added the beta-accepted Accepted for backporting to the compiler in the beta channel. label Apr 16, 2020
@pnkfelix
Copy link
Member Author

@bors p=2

(this gets slightly elevated priority because we want to backport it in time for next week's release, and I really dislike backporting things that have not landed in nightly. It remains rollup=never due to potential for performance impact.)

@bors
Copy link
Contributor

bors commented Apr 16, 2020

⌛ Testing commit d05ae3a with merge 73ee43c429079a6fb8f4c00eb04c5934bd1c8abb...

@Dylan-DPC-zz
Copy link

@bors retry

(yielding this for a rollup, will run this pr after that, when i'm asleep so that there is no need to monitor the queue :P )

@eddyb
Copy link
Member

eddyb commented Apr 16, 2020

@rust-timer build 4909ccc0a8d5affc76bd6e900e76f9a46d0e3e9e

@rust-timer
Copy link
Collaborator

Queued 4909ccc0a8d5affc76bd6e900e76f9a46d0e3e9e with parent 4e4d49d, future comparison URL.

@bors
Copy link
Contributor

bors commented Apr 17, 2020

⌛ Testing commit d05ae3a with merge 318726b...

@rust-timer
Copy link
Collaborator

Finished benchmarking try commit 4909ccc0a8d5affc76bd6e900e76f9a46d0e3e9e, comparison URL.

@bors
Copy link
Contributor

bors commented Apr 17, 2020

☀️ Test successful - checks-azure
Approved by: nagisa
Pushing 318726b to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Apr 17, 2020
@bors bors merged commit 318726b into rust-lang:master Apr 17, 2020
@Mark-Simulacrum Mark-Simulacrum removed the beta-nominated Nominated for backporting to the compiler in the beta channel. label Apr 17, 2020
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 18, 2020
…ulacrum

[beta] backports

This includes:
* Do not reuse post LTO products when exports change rust-lang#71131
* macro_rules: `NtLifetime` cannot start with an identifier rust-lang#70768
* Update RELEASES.md for 1.43.0 rust-lang#70354

r? @ghost
Aaron1011 added a commit to Aaron1011/rust that referenced this pull request Sep 18, 2020
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.
bors added a commit to rust-lang-ci/rust that referenced this pull request Oct 11, 2020
…twco,nikic

Use llvm::computeLTOCacheKey to determine post-ThinLTO CGU reuse

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
beta-accepted Accepted for backporting to the compiler in the beta channel. 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. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

cdylib link error after TLS unused -> used transition