-
-
Notifications
You must be signed in to change notification settings - Fork 130
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
perf(gateway): speed up ratelimiter #2143
Conversation
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 curious what benchmark results would say here. I would also highly prefer the refactoring to be outside of the performance work, it's hard to keep track of what benefits performance and what's just refactoring, and we should probably keep the two separate for record purposes.
Thank you for reminding me to always benchmark! I'll get to it shortly. Note that it's sadly impossible to commit a benchmark due to the critical methods being private. |
9c6c367
to
a614a13
Compare
92d4694
to
5048925
Compare
I don't know how to add the benchmark to Twilight in a good way. It requires public access to private functions, which I guarded behind a commented out by default "unstable" feature flag. It somewhat breaks RA and CI, and I don't know how to fix that. Anyway, here's the benchmark results: Previously
With this PR
|
This reverts commit ca70a54.
9ee126d
to
f8f1fbd
Compare
To make CI pass and therefore show that this PR is ready, I pushed and immediately reverted the benchmark commit (so you can test run the benchmark yourself). |
@@ -58,8 +55,8 @@ impl CommandRatelimiter { | |||
|
|||
/// Duration until the next permit is available. | |||
pub fn next_available(&self) -> Duration { |
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 should arguably return the instant at which the next permit is available. Users can get the Duration until then via elapsed.saturating_duration_since(Instant::now())
.
4d42832
to
1ff2212
Compare
f495577
to
19e9853
Compare
By storing the time at which instants complete they're comparable to Instant::now, which is cheaper than `Instant::elapsed`
86c33b5
to
6786600
Compare
6786600
to
8df7c9d
Compare
8df7c9d
to
e16958b
Compare
Thanks for the benchmark, that's quite impressive. I'll see if I can take a look and understand what's going on this week. |
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.
Thank you for all the work you did on this. The benchmarks are quite impressive.
In pull request #2143, the ratelimiter's performance was increased due to removing the call to `Instant::now` when the instant queue is not full. This PR goes one step further and removes it for all spurious calls, where spurious equates to calling poll_available when the timer has not fired.
This PR optimizes
available
andpoll_available
based on two observations:Instant::elapsed
internally callsInstant::now
(which might result in a syscall) so calling it over the queue is inefficient, a single instant should instead be reused.To simplify the code, the time at which permits elapse is now stored instead of when in was acquired.