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

perf(gateway): speed up ratelimiter #2143

Merged
merged 8 commits into from
Mar 25, 2023

Conversation

vilgotf
Copy link
Member

@vilgotf vilgotf commented Feb 14, 2023

This PR optimizes available and poll_available based on two observations:

  1. The instant queue is ordered, so finding the partition point is enough for counting elapsed and unelapsed ones.
  2. Instant::elapsed internally calls Instant::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.

@vilgotf vilgotf added c-gateway Affects the gateway crate t-perf Improves performace t-refactor Refactors APIs or code. labels Feb 14, 2023
Copy link
Member

@zeylahellyer zeylahellyer left a 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.

@vilgotf
Copy link
Member Author

vilgotf commented Feb 17, 2023

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.

@vilgotf vilgotf force-pushed the vilgotf/gateway/perf/ratelimiter branch from 9c6c367 to a614a13 Compare February 28, 2023 03:32
@vilgotf vilgotf changed the title perf(gateway): utilize that ratelimiter instants are ordered perf(gateway): speed up ratelimiter Feb 28, 2023
@vilgotf vilgotf force-pushed the vilgotf/gateway/perf/ratelimiter branch 3 times, most recently from 92d4694 to 5048925 Compare February 28, 2023 05:12
@vilgotf
Copy link
Member Author

vilgotf commented Feb 28, 2023

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

command ratelimiter/empty
                        time:   [191.37 ns 212.46 ns 229.33 ns]
command ratelimiter/half elapsed
                        time:   [3.6624 µs 3.6838 µs 3.7117 µs]
Found 9 outliers among 100 measurements (9.00%)
  1 (1.00%) high mild
  8 (8.00%) high severe
command ratelimiter/half full
                        time:   [3.6387 µs 3.6788 µs 3.7245 µs]
Found 11 outliers among 100 measurements (11.00%)
  4 (4.00%) high mild
  7 (7.00%) high severe

With this PR

command ratelimiter/empty
                        time:   [200.13 ns 219.23 ns 234.52 ns]
                        change: [-14.968% +3.0799% +25.051%] (p = 0.76 > 0.05)
                        No change in performance detected.
command ratelimiter/half elapsed
                        time:   [56.646 ns 57.611 ns 58.745 ns]
                        change: [-98.472% -98.448% -98.422%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  2 (2.00%) high mild
  7 (7.00%) high severe
command ratelimiter/half full
                        time:   [58.656 ns 59.632 ns 60.759 ns]
                        change: [-98.414% -98.388% -98.363%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  4 (4.00%) high mild
  8 (8.00%) high severe

@vilgotf vilgotf force-pushed the vilgotf/gateway/perf/ratelimiter branch from 9ee126d to f8f1fbd Compare March 1, 2023 07:29
@vilgotf
Copy link
Member Author

vilgotf commented Mar 1, 2023

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 {
Copy link
Member Author

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()).

@vilgotf vilgotf force-pushed the vilgotf/gateway/perf/ratelimiter branch 2 times, most recently from 4d42832 to 1ff2212 Compare March 1, 2023 08:01
@vilgotf vilgotf force-pushed the vilgotf/gateway/perf/ratelimiter branch 4 times, most recently from f495577 to 19e9853 Compare March 1, 2023 09:11
@vilgotf vilgotf removed the t-refactor Refactors APIs or code. label Mar 1, 2023
By storing the time at which instants complete they're comparable to
Instant::now, which is cheaper than `Instant::elapsed`
@vilgotf vilgotf force-pushed the vilgotf/gateway/perf/ratelimiter branch 3 times, most recently from 86c33b5 to 6786600 Compare March 3, 2023 21:44
@vilgotf vilgotf force-pushed the vilgotf/gateway/perf/ratelimiter branch from 6786600 to 8df7c9d Compare March 3, 2023 22:16
@vilgotf vilgotf force-pushed the vilgotf/gateway/perf/ratelimiter branch from 8df7c9d to e16958b Compare March 3, 2023 22:28
@zeylahellyer
Copy link
Member

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.

Copy link
Member

@zeylahellyer zeylahellyer left a 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.

@zeylahellyer zeylahellyer merged commit d8e1c54 into main Mar 25, 2023
@zeylahellyer zeylahellyer deleted the vilgotf/gateway/perf/ratelimiter branch March 25, 2023 14:35
zeylahellyer pushed a commit that referenced this pull request Apr 1, 2023
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.
vilgotf added a commit that referenced this pull request Jun 22, 2023
#2185)

Regression test that the sleep deadline is not reset on spurious ratelimiter polls.
The opimization was introduced in #2143.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c-gateway Affects the gateway crate t-perf Improves performace
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants