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

Compile rustc crates with the initial-exec TLS model #78201

Merged
merged 1 commit into from
Nov 9, 2020

Conversation

joshtriplett
Copy link
Member

This should produce more efficient code, with fewer calls to
__tls_get_addr. The tradeoff is that libraries using it won't work with
dlopen, but that shouldn't be a problem for rustc's internal libraries.

@rust-highfive
Copy link
Collaborator

r? @Mark-Simulacrum

(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 Oct 21, 2020
@joshtriplett
Copy link
Member Author

cc @eddyb

@joshtriplett
Copy link
Member Author

Trying this out to see if it provides a performance improvement.

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented Oct 21, 2020

⌛ Trying commit 328401119c35ff10758630aafe5eb7a04925c399 with merge a612e191b94bc6e23963dbadbab26b6486a51dc3...

Comment on lines 111 to 113
if crate_name.map_or(false, |n| n.starts_with("rustc_") || n.starts_with("rustc-")) {
cmd.arg("-Z").arg("tls-model=initial-exec");
}
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we should also check that the path includes compiler/rustc_ because there's some stuff on crates.io that also starts with rustc_ or rustc- and it might not be strictly a rustc_driver dependency.

Copy link
Member Author

Choose a reason for hiding this comment

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

We need a much better way to handle this, yes; this was just the simplest way to test the impact of this change.

Copy link
Member

Choose a reason for hiding this comment

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

Best bet is probably to modify builder.rs to set RUSTC_IS_COMPILING_THE_COMPILER for cargo and then read that here.

@eddyb
Copy link
Member

eddyb commented Oct 21, 2020

This may be silly, but, if we want to exactly track which crates are using TLS, so that we can list them out in the wrapper, we could:

  • have an allow-by-default lint against using #[thread_local] (including from thread_local!)
  • pass -Fthread-local from the bootstrap/bin/rustc.rs wrapper by default for all crates
    • specifically using "forbid" means #[allow(thread_local)] wouldn't work so it couldn't be accidentally used
  • for an explicit list of crates, we would omit -Fthread-local
    • the subset of that which ends up linked into librustc_driver-*.so, also get -Ztls-model=initial-exec

This could get confusing so we might want to make it an internal rustc::untracked_tls_crate lint that has a custom message telling you to what list to add the crate etc.

@joshtriplett
Copy link
Member Author

joshtriplett commented Oct 21, 2020

@eddyb If we're going to go that far, I would rather just see this mechanism fixed to make the TLS model depend on the top-level artifact(s), such as "if you're building a binary use local-exec, if you're building a cdylib use global-dynamic for pub and local-dynamic for private". This shouldn't depend on the individual library crate, it should depend on the top-level crate.

@eddyb
Copy link
Member

eddyb commented Oct 21, 2020

If we're going to go that far, I would rather just see this mechanism fixed to make the TLS model depend on the top-level artifact(s)

Oh yeah I forgot I wanted that too (should be possible, based on my experiments an rlib crate is undecided between static and dynamic TLS until it's linked into a bin crate, or a dylib crate, respectively) and went down the rabbit hole of thinking about tracking which crates define #[thread_local] statics.

@bors
Copy link
Contributor

bors commented Oct 21, 2020

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

@rust-timer
Copy link
Collaborator

Queued a612e191b94bc6e23963dbadbab26b6486a51dc3 with parent 1d27267, future comparison URL.

@jyn514 jyn514 added A-codegen Area: Code generation A-thread-locals Area: Thread local storage (TLS) I-compiletime Issue: Problems and improvements with respect to compile times. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Oct 21, 2020
@rust-timer
Copy link
Collaborator

Finished benchmarking try commit (a612e191b94bc6e23963dbadbab26b6486a51dc3): 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

@joshtriplett
Copy link
Member Author

Looks like this is definitely worth doing, and we just need to figure out the best way to capture the set of crates we can safely do it for.

Ideally, we'd apply this to every crate that isn't a proc macro or compiled into a dynamically linkable version of std. How can we most easily capture that set here?

@bjorn3
Copy link
Member

bjorn3 commented Oct 22, 2020

If you tell the linker about the storage model instead of LLVM it should rewrite all TLS accesses to use that storage model I think. You could do that using a build.rs for rustc_driver. That will apply it to exactly the dylib that it should be applied to.

@Mark-Simulacrum
Copy link
Member

Hm, so when you ask "Ideally, we'd apply this to every crate that isn't a proc macro or compiled into a dynamically linkable version of std. How can we most easily capture that set here?" -- do you mean to do that as an end-user visible change (rather than just to crates compiled by rustbuild? It seems to me that rustc shouldn't really be special here in some sense. That's probably not quite true because we have the somewhat odd case of compiling to dylibs that aren't intended to be dlopen'd (rather just linked directly), but I'm not sure that's important.

I think the best thing is probably to start out with just a change to how we compile rustc which should be somewhat easier to land and see impacts of though. To do so we probably want to set the -Z flag via rustflags if possible, something like this diff. This will set it for pretty much everything except std workspace and crates that don't get rustflags (e.g., proc macros and other build deps). Note that this includes e.g. cargo and clippy too, but I think that's the right thing?

diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 707c1ff3efa..0f6a74b01ce 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1114,6 +1114,10 @@ impl<'a> Builder<'a> {
             }
         }
 
+        if mode != Mode::Std {
+            rustflags.arg("-Ztls-model=initial-exec");
+        }
+
         if self.config.incremental {
             cargo.env("CARGO_INCREMENTAL", "1");
         } else {

@Mark-Simulacrum Mark-Simulacrum 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 Oct 26, 2020
@joshtriplett
Copy link
Member Author

@Mark-Simulacrum Yeah, that looks perfect. That's exactly the set of crates that should work with this.

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented Oct 26, 2020

⌛ Trying commit 15068d492e48e3aefc563baa5aa9bd6ee9223a80 with merge e33e3c8a267474be0fabf07c0eb7b6e3f7e00e37...

@bors
Copy link
Contributor

bors commented Oct 26, 2020

☀️ Try build successful - checks-actions
Build commit: e33e3c8a267474be0fabf07c0eb7b6e3f7e00e37 (e33e3c8a267474be0fabf07c0eb7b6e3f7e00e37)

@jyn514
Copy link
Member

jyn514 commented Nov 8, 2020

Looks spurious?

------------------------------------------
stderr:
------------------------------------------
error: need to add support for DW_TAG_base_type '()' encoded with DW_ATE = 0x7, bit_size = 0
clang: CommandLine Error: Option 'h' registered more than once!
LLVM ERROR: inconsistency in registered CommandLine options
clang: CommandLine Error: Option 'h' registered more than once!
LLVM ERROR: inconsistency in registered CommandLine options

------------------------------------------

@Mark-Simulacrum
Copy link
Member

@bors retry - agreed that this seems spurious

error: need to add support for DW_TAG_base_type '()' encoded with DW_ATE = 0x7, bit_size = 0
clang: CommandLine Error: Option 'h' registered more than once!
LLVM ERROR: inconsistency in registered CommandLine options
clang: CommandLine Error: Option 'h' registered more than once!
LLVM ERROR: inconsistency in registered CommandLine **options*

@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 Nov 8, 2020
@bors
Copy link
Contributor

bors commented Nov 8, 2020

⌛ Testing commit 0328e69 with merge e012fa10bed4afe82574679760549a76eb053951...

@bors
Copy link
Contributor

bors commented Nov 9, 2020

💔 Test failed - checks-actions

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Nov 9, 2020
@mati865
Copy link
Contributor

mati865 commented Nov 9, 2020

The same error again on apple.
Maybe it should be enabled only on Linux?

@Aaron1011
Copy link
Member

This is a known issue which is unrelated to this PR: https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra/topic/apple-x86_64.20gha.20checks

@joshtriplett
Copy link
Member Author

@bors retry

@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 Nov 9, 2020
@bors
Copy link
Contributor

bors commented Nov 9, 2020

⌛ Testing commit 0328e69 with merge 25f6938...

@bors
Copy link
Contributor

bors commented Nov 9, 2020

☀️ Test successful - checks-actions
Approved by: Mark-Simulacrum
Pushing 25f6938 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Nov 9, 2020
@bors bors merged commit 25f6938 into rust-lang:master Nov 9, 2020
@rustbot rustbot added this to the 1.49.0 milestone Nov 9, 2020
@joshtriplett joshtriplett deleted the rustc-tls-model branch November 9, 2020 16:56
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Feb 14, 2021
Pkgsrc changes:
 * Adjust patches, convert tabs to spaces so that tests pass.
 * Remove patches which are no longer needed (upstream changed)
 * Minor adjustments for SunOS, e.g. disable stack probes.
 * Adjust cargo checksum patching accordingly.
 * Remove commented-out use of PATCHELF on NetBSD, which doesn't work anyway...

Upstream changes:

Version 1.49.0 (2020-12-31)
============================

Language
-----------------------

- [Unions can now implement `Drop`, and you can now have a field in a union
  with `ManuallyDrop<T>`.][77547]
- [You can now cast uninhabited enums to integers.][76199]
- [You can now bind by reference and by move in patterns.][76119] This
  allows you to selectively borrow individual components of a type. E.g.
  ```rust
  #[derive(Debug)]
  struct Person {
      name: String,
      age: u8,
  }

  let person = Person {
      name: String::from("Alice"),
      age: 20,
  };

  // `name` is moved out of person, but `age` is referenced.
  let Person { name, ref age } = person;
  println!("{} {}", name, age);
  ```

Compiler
-----------------------

- [Added tier 1\* support for `aarch64-unknown-linux-gnu`.][78228]
- [Added tier 2 support for `aarch64-apple-darwin`.][75991]
- [Added tier 2 support for `aarch64-pc-windows-msvc`.][75914]
- [Added tier 3 support for `mipsel-unknown-none`.][78676]
- [Raised the minimum supported LLVM version to LLVM 9.][78848]
- [Output from threads spawned in tests is now captured.][78227]
- [Change os and vendor values to "none" and "unknown" for some targets][78951]

\* Refer to Rust's [platform support page][forge-platform-support] for more
information on Rust's tiered platform support.

Libraries
-----------------------

- [`RangeInclusive` now checks for exhaustion when calling `contains`
  and indexing.][78109]
- [`ToString::to_string` now no longer shrinks the internal buffer
  in the default implementation.][77997]
- [`ops::{Index, IndexMut}` are now implemented for fixed sized
  arrays of any length.][74989]

Stabilized APIs
---------------

- [`slice::select_nth_unstable`]
- [`slice::select_nth_unstable_by`]
- [`slice::select_nth_unstable_by_key`]

The following previously stable methods are now `const`.

- [`Poll::is_ready`]
- [`Poll::is_pending`]

Cargo
-----------------------
- [Building a crate with `cargo-package` should now be independently
  reproducible.][cargo/8864]
- [`cargo-tree` now marks proc-macro crates.][cargo/8765]
- [Added `CARGO_PRIMARY_PACKAGE` build-time environment
  variable.]  [cargo/8758] This variable will be set if the crate
  being built is one the user selected to build, either with `-p`
  or through defaults.
- [You can now use glob patterns when specifying packages &
  targets.][cargo/8752]


Compatibility Notes
-------------------
- [Demoted `i686-unknown-freebsd` from host tier 2 to target tier
  2 support.][78746]
- [Macros that end with a semi-colon are now treated as statements
  even if they expand to nothing.][78376]
- [Rustc will now check for the validity of some built-in attributes
  on enum variants.][77015] Previously such invalid or unused
  attributes could be ignored.
- Leading whitespace is stripped more uniformly in documentation
  comments, which may change behavior. You read [this post about
  the changes][rustdoc-ws-post] for more details.
- [Trait bounds are no longer inferred for associated types.][79904]

Internal Only
-------------
These changes provide no direct user facing benefits, but represent
significant improvements to the internals and overall performance
of rustc and related tools.

- [rustc's internal crates are now compiled using the `initial-exec` Thread
  Local Storage model.][78201]
- [Calculate visibilities once in resolve.][78077]
- [Added `system` to the `llvm-libunwind` bootstrap config option.][77703]
- [Added `--color` for configuring terminal color support to bootstrap.][79004]


[75991]: rust-lang/rust#75991
[78951]: rust-lang/rust#78951
[78848]: rust-lang/rust#78848
[78746]: rust-lang/rust#78746
[78376]: rust-lang/rust#78376
[78228]: rust-lang/rust#78228
[78227]: rust-lang/rust#78227
[78201]: rust-lang/rust#78201
[78109]: rust-lang/rust#78109
[78077]: rust-lang/rust#78077
[77997]: rust-lang/rust#77997
[77703]: rust-lang/rust#77703
[77547]: rust-lang/rust#77547
[77015]: rust-lang/rust#77015
[76199]: rust-lang/rust#76199
[76119]: rust-lang/rust#76119
[75914]: rust-lang/rust#75914
[74989]: rust-lang/rust#74989
[79004]: rust-lang/rust#79004
[78676]: rust-lang/rust#78676
[79904]: rust-lang/rust#79904
[cargo/8864]: rust-lang/cargo#8864
[cargo/8765]: rust-lang/cargo#8765
[cargo/8758]: rust-lang/cargo#8758
[cargo/8752]: rust-lang/cargo#8752
[`slice::select_nth_unstable`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable
[`slice::select_nth_unstable_by`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by
[`slice::select_nth_unstable_by_key`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by_key
[`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html
[`Poll::is_ready`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_ready
[`Poll::is_pending`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_pending
[rustdoc-ws-post]: https://blog.guillaume-gomez.fr/articles/2020-11-11+New+doc+comment+handling+in+rustdoc
@glaubitz
Copy link
Contributor

This change broke the Rust compiler on 32-bit PowerPC, see: #81334

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-codegen Area: Code generation A-thread-locals Area: Thread local storage (TLS) I-compiletime Issue: Problems and improvements with respect to compile times. merged-by-bors This PR was explicitly merged by bors. relnotes Marks issues that should be documented in the release notes of the next release. 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.