-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Replace LockCell with atomic types #56614
Conversation
src/librustc/session/mod.rs
Outdated
pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool { | ||
#[inline(never)] | ||
#[cold] | ||
pub fn consider_optimizing_cold<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does splitting this into two functions really translate to faster compile-times?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used in layout computation. Not sure how hot it is, but it probably won't hurt. Especially if we want to add more MIR optimizations (and debug them)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyway this PR is mostly about getting rid of LockCell
, I just found this on the way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. It does hurt code quality though as it makes things more complicated and thus harder to read and maintain. I personally prefer not to do things like this without evidence that it carries it's weight.
@bors try |
Replace LockCell with atomic types Split from #56509 r? @michaelwoerister
☀️ Test successful - status-travis |
Just a suggestion: Instead of
|
src/librustc/session/mod.rs
Outdated
let mut ret = true; | ||
if let Some(ref c) = self.optimization_fuel_crate { | ||
if c == crate_name { | ||
assert_eq!(self.query_threads(), 1); | ||
let fuel = self.optimization_fuel_limit.get(); | ||
let fuel = self.optimization_fuel_limit.load(SeqCst); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is pretty racy I think.
This should all be in a cas loop and the other section (for print_fuel) should be a fetch add, right?
Granted it was racy before even with locks, but still.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It asserts that the compiler is running in single-threaded mode, so it should be fine. It would be nicer though if the two fields in question would be behind a single lock.
@stjepang This looks great. Yes, that sounds like the way to go. We already have |
@rust-timer build bcc6e63 |
Success: Queued bcc6e63 with parent 3a75e80, comparison URL. |
262: Move AtomicCell into crossbeam-utils r=jeehoonkang a=stjepang At this point, I feel pretty confident about the current state of `AtomicCell` in the sense that we probably won't make any breaking changes to its public API in the future. It's also a reasonably small utility without dependencies that deserves living in `crossbeam-utils`. The Rust compiler would like to use it in place of its `LockCell`, and already has `crossbeam-utils` whitelisted. See [this PR](rust-lang/rust#56614 (comment)). Let's move `AtomicCell` into `crossbeam-utils` so that people can use it without depending on whole `crossbeam`. Co-authored-by: Stjepan Glavina <stjepang@gmail.com>
Finished benchmarking try commit bcc6e63 |
The changes here don't seem to make much of a difference performance-wise. I'd say, as a consequence, we should optimize for code quality:
|
262: Move AtomicCell into crossbeam-utils r=stjepang a=stjepang At this point, I feel pretty confident about the current state of `AtomicCell` in the sense that we probably won't make any breaking changes to its public API in the future. It's also a reasonably small utility without dependencies that deserves living in `crossbeam-utils`. The Rust compiler would like to use it in place of its `LockCell`, and already has `crossbeam-utils` whitelisted. See [this PR](rust-lang/rust#56614 (comment)). Let's move `AtomicCell` into `crossbeam-utils` so that people can use it without depending on whole `crossbeam`. Co-authored-by: Stjepan Glavina <stjepang@gmail.com>
I've just put |
@stjepang The use of volatile reads doesn't inspire confidence. Some |
FWIW, @RalfJung has reviewed those volatile reads and written comments above them.
The code is parametrized over
Another benefit is that reads are very fast (faster than Additionally, if you don't need |
@stjepang Do you mean the comments in https://github.com/crossbeam-rs/crossbeam/pull/234/files? Those are different accesses though, are they not? The volatile accesses I looked at all have a comment saying "this is UB but we do it anyway because performance".^^ |
@RalfJung Sorry, my bad! I confused this volatile read with the CAS that issues a SeqCst fence. If you'd like to review this situation, though, that'd be great! :) We're using a volatile read to read a value that might be concurrently written to. However, we can detect when a data race happens by reading the sequence number. If the value was overwritten while we were reading it, then we try reading again in a loop. The Chase-Lev deque uses a very similar technique. If we wanted to be pedantic, we'd use multiple |
The main benefit I see is being able to remove |
This PR already does that and uses |
I didn't notice the lack of |
I depends. If I don't really need them (like in the cases modified in this PR), I prefer them not to be exposed in the interface. |
I would say yes.
Not only that, let a = AtomicCell::new(vec![]);
// Thread #1
a.store(vec![1, 2, 3], Relaxed);
// Thread #2
println!("{:?}", a.take(Relaxed)); // unsynchronized read! |
This sounds a lot like sequence locks to me, which are a notorious problem for language-level memory models. AFAIK, they cannot be implemented in C and hence not in Rust, either. So the reason you don't do a relaxed load is because this is arbitrarily-sized data? Following our own definitions, this is UB because of a read-write race. Following LLVM's definitions, the read is fine but returns However, given taht volatile loads cannot be duplicated, the If we keep wanting the LLVM memory model, maybe we should just change the documentation and say we are using the LLVM model? The relevant difference is that read-write races are not UB, they just return indeterminate data (which is the same as uninitialized data and padding bits). You are not allowed to do anything with that data, and you should probably wrap it in a For the LLVM side, can we at least get an LLVM developer on the record saying that volatile accesses never return Cc @rkruppe |
So which ordering does it use, always release/acquire? |
Yes, this is a sequence lock. We based our implementation on the paper you've linked.
Exactly.
Yeah, we don't use the data if a race happens (it's mem::forgotten). The Chase-Lev deque (
I was a big proponent of guaranteeing |
Ah I see, the data is literally not looked at at all if a race happened, and the detection happens through another channel. The The good news is that I think you don't even need a volatile read! You don't care if racy reads yield I suspect Rust picked the C11 model because it is much better studied, and that is still true. I know of hardly any academic work on memory models that are as permissive with read-write races as LLVM is. However, there is some very recent work that I should read that takes this into account.
No.
I think I took a look at the
A read in the fast case proceeds as
I just spent quite a while wondering about what the correctness argument here is, and why the fence is needed, and why the initial Generally, the library has way fewer comments than is adequate for such subtle concurrent data structures. In |
📌 Commit 9b47acf has been approved by |
Replace LockCell with atomic types Split from #56509 r? @michaelwoerister
☀️ Test successful - status-appveyor, status-travis |
Optimize try_mark_green and eliminate the lock on dep node colors Blocked on rust-lang#56614 r? @michaelwoerister
Optimize try_mark_green and eliminate the lock on dep node colors Blocked on rust-lang#56614 r? @michaelwoerister
Optimize try_mark_green and eliminate the lock on dep node colors Blocked on rust-lang#56614 r? @michaelwoerister
Optimize try_mark_green and eliminate the lock on dep node colors Blocked on rust-lang#56614 r? @michaelwoerister
Optimize try_mark_green and eliminate the lock on dep node colors Blocked on #56614 r? @michaelwoerister
Split from #56509
r? @michaelwoerister