-
Notifications
You must be signed in to change notification settings - Fork 174
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
Optimize read buffer with capacity to reduce allocations #888
Conversation
Sound find 🙌 Open questions: (cc @Jarema, @n1ghtmare):
|
I checked I can update MR by removing configuration parameter and leaving a comment about selected value referencing this discussion. Authors of |
@YaZasnyal can you please resolve conflicts? I'm still benchmarking and checking suff around this one. |
3164f91
to
9545674
Compare
@Jarema rebased to the latest |
Comparing main to this branch (on Linux).
|
On Mac however:
|
So benchmarks are bit flaky on macOS, sometimes getting send errors, which panics and invalidates the run where-as they're consistently better on Linux. Did also fiddle a bit with SO_RCVBUF which leads to a high throughput bump.
|
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.
Been benchmarking this quite a bit, different variants including setting the recv_buffer_size which can be a follow-up.
lgtm, just one quick round of name bikeshedding 😄
async-nats/src/connector.rs
Outdated
@@ -57,6 +57,7 @@ pub(crate) struct ConnectorOptions { | |||
pub(crate) name: Option<String>, | |||
pub(crate) ignore_discovered_servers: bool, | |||
pub(crate) retain_servers_order: bool, | |||
pub(crate) receive_buffer_capacity: usize, |
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.
Lets call it read_buffer_capacity, to avoid conflicting with the recv_buffer of the socket.
pub(crate) receive_buffer_capacity: usize, | |
pub(crate) read_buffer_capacity: usize, |
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 main thing I dislike in the current solution is that buffer is going to shrink to 65k anyway. Maybe we should alse change usize to u16?
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.
u16 would map nicely, sgtm.
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.
done
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.
lgtm.
Problem: poor read performance for small messages
How read procedure works: read operation makes an attempt to get a message from the buffer. If there is insufficient data in the buffer, pull some from the socket.
It seems that the current implementation of the
AsyncRead.read_buf
fills available space in the buffer and resizes it only iflen==cap
. If the message is read from the buffer len becomes smaller and the buffer will attempt to reclaim free space but will have to allocate a new buffer and transfer leftover because the previous buffer is shared bysplit_to().freeze()
. New buffer will have the capacity of the original buffer.All of the above causes a lot of small reads from the socket and buffer reallocations. The situation gets a lot better if just a single big message is received that increases the capacity.
To avoid this problem we can initialize a buffer with some sane capacity so it can read multiple small messages at once. My tests show that it greatly increases performance (+60% on small buffers).