-
Notifications
You must be signed in to change notification settings - Fork 120
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
feat(s2n-quic-core): add spsc channel #1614
Conversation
205c11a
to
8d521aa
Compare
8d521aa
to
8c79376
Compare
|
||
impl<'a, T> Slice<'a, Cell<T>> { | ||
#[inline] | ||
pub unsafe fn assume_init(self) -> Slice<'a, UnsafeCell<T>> { |
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.
What is the purpose of this function?
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.
Added a comment inline
if let Some(cell) = self.head.0.get(index) { | ||
cell | ||
} else { | ||
assume!(index >= self.head.0.len()); |
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.
How do you know to use assume!
here instead of a regular debug_assert!
?
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.
They're they exact same when debug assertions are enabled. However, when they're not, the assume
tells the compiler that it's impossible for this check to be false and then the compiler will optimize the code based on that assumption. Without extensive testing/proofs it's generally best to stick with a debug_assert. But in this case, I'm using loom
, kani
, and bolero
so the confidence is quite high that these assumptions always hold.
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.
I guess my question is more, is there something particular about this code that makes you believe the compiler would benefit from the assume!
and give us better performance, or is it more that we might as well use assume!
since all the testing and proofs give us high confidence that its safe.
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.
Yeah, it's mostly the latter. I want to try and give the compiler as much information as we can about the assumptions and prove that they will always hold. In this particular case, I didn't dive into the asm to know if it made a difference in the final outcome.
} | ||
|
||
#[inline] | ||
pub fn acquire_filled(&mut self) -> Result<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.
Can you add a comment on what the boolean in the result means? Same on acquire_capacity
|
||
#[inline] | ||
pub fn clear(&mut self) -> usize { | ||
// don't update the cursor so the caller can observe any updates through peek |
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.
Isn't the cursor being updated on line 115?
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.
Updated the comment
let len = pair.len(); | ||
|
||
for entry in pair.iter() { | ||
unsafe { |
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.
There are several unsafe
blocks in these files, could you maybe summarize in a comment somewhere any notes on why/how these operations are safe?
} | ||
|
||
#[test] | ||
// TODO enable this once https://github.com/model-checking/kani/pull/2172 is merged and released |
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.
Looks like it is merged, just waiting on release
#[inline] | ||
pub fn capacity(&self) -> usize { | ||
self.invariants(); | ||
self.capacity - 1 |
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.
Why - 1
?
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.
The cursor management is based on the one in VecDeque, which requires that we add one and round up to the next power of two. It basically boils down to the fact that if you allow the caller to write the full capacity, then you can't distinguish between an empty and a full queue because the cursors are equal. So if you limit capacity to total - 1
, you can assume that when cursors are equal, the queue is empty.
/// | ||
/// This can be used to optimize the code to avoid needless calculations. | ||
pub trait IsZst { | ||
const IS_ZST: 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.
Not going to block on this, but I would call this IS_ZERO_SIZED
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.
I was following the stdlib convention here, since the design of the queue cursors is based on VecDeque.
Description of changes:
This change adds a
spsc
(single-producer/single-consumer) channel to s2n-quic-core. This will be used to split the endpoint up into multiple tasks, which should improve packet processing latencies.Call-outs:
I needed the
unsafe_assert
macro froms2n-quic-crypto
moved intos2n-quic-core
for this. I also renamed it toassume!
, since you already have to call it in anunsafe
block, the name seemed redundant.Testing:
The feature includes a
bolero
test that generates random sequences of events to push/pop items from the queue. I ran the test underkani
but am waiting on model-checking/kani#2169 to be released. I also usedloom
to exhaustively explore atomic interleavings and assert that invariants hold in each case (I caught a few very subtle bugs with this - pretty cool!).I've also included a benchmark that compares
crossbeam-channel
:By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.