-
Notifications
You must be signed in to change notification settings - Fork 156
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
[WIP] Initial WebSocket protocol implementation #73
base: main
Are you sure you want to change the base?
[WIP] Initial WebSocket protocol implementation #73
Conversation
Initial benchmarks on the read side without digging into optimization:
|
Got rid of Did a little work on lowering the garbage. Was getting a bunch of boxing of
|
Would be good to understand why #69 |
Creating a SequenceReader was showing up as a hot path. Just getting rid of creating an instance of it and moving to parsing via Span got me a 20% win by itself. If we're forced to take that overload and always create a SequenceReader it's going to be hard to hit BCL numbers. As is, right now, the BCL version is just so much more at the raw level that even after mangling my code such that all the sync paths don't allocate any more async state machines (except in ProtocolReader, which I haven't touched), that's only getting me an additional 5-10% over what you see in the latest bench. |
Here's the latest with a quiet machine: looks like maybe not even that 5-10%. Comes up allocation free, now, though (although if you actually profile, ProtocolReader.Read allocates a state machine still).
|
Yeah, I was thinking on how to eliminate that. I can do it for the sync path just by doing what I've done here and check IsCompletedSuccessfully and have a non-state machine path, but that won't help the async path (nor does it for my code currently). I have another idea but I'll throw it on that issue. |
//We need to at least be able to read the start of frame header | ||
if (input.Length < 2) | ||
{ | ||
message = default; | ||
return false; | ||
} | ||
|
||
reader.TryRead(out var finOpcodeByte); | ||
reader.TryRead(out var maskLengthByte); | ||
if (input.IsSingleSegment || input.FirstSpan.Length >= 14) |
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.
We need to encapsulate this logic in a helper (it's impossible with stackalloc though).
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'm not following you, what's a helper in this context and why do we need to?
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.
A method in the framework that can get you a span of bytes given a minimum length.
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.
Ah, I gotcha. Yeah, it's hard to picture a way of implementing that without having to either go to the pool or allocate a byte array, because you can't leak the stackalloc'd span.
c373ed0
to
5e64028
Compare
…es, and smoke tests.
…uenceReader from frame reader.
5e64028
to
925e8c7
Compare
925e8c7
to
b55d182
Compare
Got the shape of the write API in a decent place finally and got some smoke tests implemented. Been taking longer than I wanted. Should be getting some benchmark numbers in the next day or two. |
Next year or 2 😄 |
😬 I know...this year got a little crazy... Are you thinking of bringing this project back into the forefront? |
Span<byte> tempSpan = stackalloc byte[14]; | ||
|
||
var bytesToCopy = Math.Min(input.Length, tempSpan.Length); | ||
input.Slice(0, bytesToCopy).CopyTo(tempSpan); |
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.
Wouldn't this fail with ArgumentException
that bytesToCopy is outside the range if input has length of less than 14
bytes?
I think there should be a check somewhere right?
Addresses #62. This is not fully complete yet. The read side API looks like how I want it, but the write side is still very basic and not the shape I would like yet. Needs a bunch more tests and some final protocol details.