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

Implement wide sequence lock #359

Merged
merged 2 commits into from
Oct 16, 2019
Merged

Conversation

jeehoonkang
Copy link
Contributor

@jeehoonkang jeehoonkang commented Apr 23, 2019

In #345, @mtak- discusses the problem of using AtomicUsize as a wrapping counter: wrapping takes only ~10 seconds, which will render the Crossbeam implementation of sequence lock wrong. Using AtomicU64 was proposed as a solution, but it is compiled to an expensive compare-exchange instruction in 32-bit x86 architectures.

Here is another solution: using two AtomicUsize as a counter (seq_lock_wide.rs). Observation is that we don't need the full atomicity of AtomicU64 for the counter of sequence lock. We just can use two AtomicUsize variables and synchronize accesses to them properly.

r? @stjepang
closes #345

@jeehoonkang
Copy link
Contributor Author

https://travis-ci.org/crossbeam-rs/crossbeam/jobs/523343511#L464

Tempting to bump the minimum Rust version.. @stjepang @Vtec234 what do you think?

@ghost
Copy link

ghost commented Apr 23, 2019

Oh, I like this change! Will take another look and do a proper review today :)

Regarding bumping the minimum Rust version... don't worry about it, that's fine.

@jeehoonkang jeehoonkang force-pushed the seq-lock-wide branch 2 times, most recently from 46eb3f7 to be50d6b Compare April 23, 2019 13:29
Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

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

This looks great, thank you!

I wonder - is the Rust version bumped only because of const fn? If so, you could also work around that by replacing SeqLock::new() with an initializer constant SEQ_LOCK_INIT defined like so:

pub const SEQ_LOCK_INIT: SeqLock = SeqLock { ... };

@mtak-
Copy link

mtak- commented Apr 23, 2019

iOS has a very weird scheduler where this issue is more likely to crop up under certain scenarios (see Update: A Warning for iOS). Thanks for the fix!

@ghost
Copy link

ghost commented Apr 23, 2019

Just so we don't forget, in all the other places where we have atomic timestamps, we should use AtomicU64 (I believe we can't use wide sequences like in this PR, unfortunately):

  • epoch representation
  • head/tail index in deque, channel, and queues

But that can come later in another PR. It will also require Rust 1.34 minimum.

Copy link
Member

@Vtec234 Vtec234 left a comment

Choose a reason for hiding this comment

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

I've only had a quick skim of the wide lock implementation but looks reasonable.

@@ -1,5 +1,16 @@
//! Atomic types.

cfg_if! {
// TODO(jeehoonkang): want to express `target_pointer_width >= "64"`, but it's not expressible
Copy link
Member

Choose a reason for hiding this comment

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

In principle Rust also supports a 16-bit target for which two AtomicUsizes would make a 32-bit counter. I think this can safely be ignored as it's very primitive hardware, but mentioning it here for completeness. There are no 128-bit targets currently as far as I can tell from a quick search.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

/// This method should be called before optimistic reads.
#[inline]
pub fn optimistic_read(&self) -> Option<(usize, usize)> {
let state_hi = self.state_hi.load(Ordering::Acquire);
Copy link
Member

Choose a reason for hiding this comment

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

Any reason why this is Acquire while other loads of state_hi are Relaxed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I left some explanation on this and other orderings.

@jeehoonkang
Copy link
Contributor Author

jeehoonkang commented Apr 24, 2019

@stjepang @Vtec234 Thank you for your comments. I addressed all of them.

I think @stjepang's comment on AtomicU64 can be dealt with another PR (or a new issue): #359 (comment)

@jeehoonkang
Copy link
Contributor Author

@stjepang any opinions on this PR?

@jeehoonkang
Copy link
Contributor Author

ping? @stjepang

@jeehoonkang
Copy link
Contributor Author

I'm trying to merge it, as it went through the test of time...

bors r+

bors bot added a commit that referenced this pull request Oct 16, 2019
359: Implement wide sequence lock r=jeehoonkang a=jeehoonkang

In #345, @mtak- discusses the problem of using `AtomicUsize` as a wrapping counter: wrapping takes only ~10 seconds, which will render the Crossbeam implementation of sequence lock wrong.  Using `AtomicU64` was proposed as a solution, but it is compiled to an expensive compare-exchange instruction in 32-bit x86 architectures.

Here is another solution: using two `AtomicUsize` as a counter (`seq_lock_wide.rs`).  Observation is that we don't need the full atomicity of `AtomicU64` for the counter of sequence lock.  We just can use two `AtomicUsize` variables and synchronize accesses to them properly.

r? @stjepang 
closes #345

Co-authored-by: Jeehoon Kang <[email protected]>
@bors
Copy link
Contributor

bors bot commented Oct 16, 2019

Build succeeded

@bors bors bot merged commit e870d0c into crossbeam-rs:master Oct 16, 2019
@jeehoonkang jeehoonkang deleted the seq-lock-wide branch January 15, 2021 04:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Ridiculous corner case on AtomicCell reads
3 participants