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

change default ratelimiter high_resolution_clock to steady_clock #3328

Merged
merged 8 commits into from
Mar 12, 2025

Conversation

qqwangxiaow
Copy link
Contributor

@qqwangxiaow qqwangxiaow commented Mar 6, 2025

Issue #, if available:
#806
#2949

Description of changes:
Implementation under the GCC C++20 version, std::chrono::high_resolution_clock is typically an alias for system_clock, which can lead to issues with clock rollback. The rate limiter relies on the time difference to replenish the local token bucket, and this could result in negative replenishment, causing the rate limiter to not function as expected and continuously sleep.
Although this is implemented as a template and allows for custom clock types, using steady_clock is a more reasonable choice for default users, as it is a monotonically increasing clock.
In Microsoft's MSVC compiler, high_resolution_clock is implemented as an alias for steady_clock.

GCC implemention:
https://github.com/gcc-mirror/gcc/blob/63663e4e69527b308687c63bacb0cc038b386593/libstdc%2B%2B-v3/include/bits/chrono.h#L1285

using high_resolution_clock = system_clock

MSVC:
https://github.com/hsutter/STL/blob/c53ac59abae552e50654943f7f80f23376a8039a/stl/inc/__msvc_chrono.hpp#L814

    _EXPORT_STD using high_resolution_clock = steady_clock;

Check all that applies:

  • [x ] Did a review by yourself.
  • Added proper tests to cover this PR. (If tests are not applicable, explain.)
  • Checked if this PR is a breaking (APIs have been changed) change.
  • Checked if this PR will not introduce cross-platform inconsistent behavior.
  • Checked if this PR would require a ReadMe/Wiki update.

Check which platforms you have built SDK on to verify the correctness of this PR.

  • Linux
  • Windows
  • Android
  • MacOS
  • IOS
  • Other Platforms

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

sbiscigl
sbiscigl previously approved these changes Mar 7, 2025
@sbiscigl
Copy link
Contributor

sbiscigl commented Mar 7, 2025

Hey @qqwangxiaow we'reok with this change, but looks like it doesnt compile

/home/runner/work/aws-sdk-cpp/aws-sdk-cpp/aws-sdk-cpp/tests/aws-cpp-sdk-core-tests/utils/ratelimiter/RateLimiterTests.cpp: In member function ‘virtual void DefaultRateLimitTest_unnormalizedChangeRateLimitTest_Test::TestBody()’:
/home/runner/work/aws-sdk-cpp/aws-sdk-cpp/aws-sdk-cpp/tests/aws-cpp-sdk-core-tests/utils/ratelimiter/RateLimiterTests.cpp:206:135: error: no matching function for call to ‘Aws::Utils::RateLimits::DefaultRateLimiter<std::chrono::_V2::system_clock, std::chrono::duration<long int>, false>::DefaultRateLimiter(int, Aws::Utils::RateLimits::DefaultRateLimiter<>::InternalTimePointType (&)())’
  206 |     DefaultRateLimiter<std::chrono::high_resolution_clock, std::chrono::seconds, false> limiter(100, DefaultRateLimitTest::GetTestTime);
      |                                                                                                                                       ^
In file included from /home/runner/work/aws-sdk-cpp/aws-sdk-cpp/aws-sdk-cpp/tests/aws-cpp-sdk-core-tests/utils/ratelimiter/RateLimiterTests.cpp:8:
/home/runner/work/aws-sdk-cpp/aws-sdk-cpp/aws-sdk-cpp/src/aws-cpp-sdk-core/include/aws/core/utils/ratelimiter/DefaultRateLimiter.h:39:17: note: candidate: ‘Aws::Utils::RateLimits::DefaultRateLimiter<CLOCK, DUR, RENORMALIZE_RATE_CHANGES>::DefaultRateLimiter(int64_t, ElapsedTimeFunctionType) [with CLOCK = std::chrono::_V2::system_clock; DUR = std::chrono::duration<long int>; bool RENORMALIZE_RATE_CHANGES = false; int64_t = long int; ElapsedTimeFunctionType = std::function<std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >()>]’
   39 |                 DefaultRateLimiter(int64_t maxRate, ElapsedTimeFunctionType elapsedTimeFunction = CLOCK::now) :
      |                 ^~~~~~~~~~~~~~~~~~
/home/runner/work/aws-sdk-cpp/aws-sdk-cpp/aws-sdk-cpp/src/aws-cpp-sdk-core/include/aws/core/utils/ratelimiter/DefaultRateLimiter.h:39:77: note:   no known conversion for argument 2 from ‘Aws::Utils::RateLimits::DefaultRateLimiter<>::InternalTimePointType()’ {aka ‘std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >()’} to ‘Aws::Utils::RateLimits::DefaultRateLimiter<std::chrono::_V2::system_clock, std::chrono::duration<long int>, false>::ElapsedTimeFunctionType’ {aka ‘std::function<std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >()>’}
   39 |                 DefaultRateLimiter(int64_t maxRate, ElapsedTimeFunctionType elapsedTimeFunction = CLOCK::now) :
      |                                                     ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gmake[2]: *** [tests/aws-cpp-sdk-core-tests/CMakeFiles/aws-cpp-sdk-core-tests.dir/build.make:950: tests/aws-cpp-sdk-core-tests/CMakeFiles/aws-cpp-sdk-core-tests.dir/utils/ratelimiter/RateLimiterTests.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:4700: tests/aws-cpp-sdk-core-tests/CMakeFiles/aws-cpp-sdk-core-tests.dir/all] Error 2
gmake: *** [Makefile:136: all] Error 2

could you please update and verify the tests? also this scares me a little bit because this sounds like backwards incompatible changes, will dig into that a bit.

@sbiscigl sbiscigl dismissed their stale review March 7, 2025 20:45

tests need to be updated/more invesigation needs to be done to see if this is a backwards incompat change

@qqwangxiaow
Copy link
Contributor Author

@sbiscigl
Hi, I fixed the compilation issue, this was caused by a time type inconsistency in the test code.
This change generally shouldn't be a problem, the steady clock is inherently more suitable for calculating time intervals, and our test results confirm it maintains normal operation.

However, I recently discovered that the clock rollback might only cause rate limiting inaccuracies for a short period.
The infinite sleep in our service's rate limiting is likely related to the int64_t overflow. I have submitted a PR.
#3338

@sbera87 sbera87 self-requested a review March 12, 2025 13:12
@sbera87 sbera87 merged commit cd009d5 into aws:main Mar 12, 2025
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants