From 2916a491b975ba8777834a931aed4f8380bd412a Mon Sep 17 00:00:00 2001 From: Alexey Rybalchenko Date: Sun, 17 May 2020 14:42:38 +0200 Subject: [PATCH] Format --- fairmq/tools/RateLimit.h | 177 ++++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 86 deletions(-) diff --git a/fairmq/tools/RateLimit.h b/fairmq/tools/RateLimit.h index 9eef4ba6..4becad42 100644 --- a/fairmq/tools/RateLimit.h +++ b/fairmq/tools/RateLimit.h @@ -38,97 +38,102 @@ namespace tools */ class RateLimiter { - using clock = std::chrono::steady_clock; + using clock = std::chrono::steady_clock; -public: - /** - * Constructs a rate limiter. - * - * \param rate Work rate in Hz (calls to maybe_sleep per second). Values less than/equal - * to 0 set the rate to 1 GHz (which is impossible to achieve, even with a - * loop that only calls RateLimiter::maybe_sleep). - */ - explicit RateLimiter(float rate) - : tw_req(std::chrono::seconds(1)) - , start_time(clock::now()) - { - if (rate <= 0) { - tw_req = std::chrono::nanoseconds(1); - } else { - tw_req = std::chrono::duration_cast(tw_req / rate); - } - skip_check_count = std::max(1, int(std::chrono::milliseconds(5) / tw_req)); - count = skip_check_count; - //std::cerr << "skip_check_count: " << skip_check_count << '\n'; - } - - /** - * Call this function at the end of the iteration rate limited loop. - * - * This function might use `std::this_thread::sleep_for` to limit the iteration rate. If no sleeps - * are necessary, the function will back off checking for the time to further allow increased - * iteration rates (until the requested rate or 1s between rechecks is reached). - */ - void maybe_sleep() - { - using namespace std::chrono; - if (--count == 0) { - auto now = clock::now(); - if (tw == clock::duration::zero()) { - tw = (now - start_time) / skip_check_count; - } else { - tw = (1 * tw + 3 * (now - start_time) / skip_check_count) / 4; - } - //std::ostringstream s; s << "tw = " << std::setw(10) << duration_cast(tw).count() << "ns, req = " << duration_cast(tw_req).count() << "ns, "; - if (tw > tw_req * 65 / 64) { - // the time between maybe_sleep calls is more than 1% too long - // fix it by reducing ts towards 0 and if ts = 0 doesn't suffice, increase - // skip_check_count - if (ts > clock::duration::zero()) { - ts = std::max(clock::duration::zero(), - ts - (tw - tw_req) * skip_check_count * 1 / 2); - //std::cerr << s.str() << "maybe_sleep: going too slow; sleep less: " << duration_cast(ts).count() << "µs\n"; + public: + /** + * Constructs a rate limiter. + * + * \param rate Work rate in Hz (calls to maybe_sleep per second). Values less than/equal + * to 0 set the rate to 1 GHz (which is impossible to achieve, even with a + * loop that only calls RateLimiter::maybe_sleep). + */ + explicit RateLimiter(float rate) + : tw_req(std::chrono::seconds(1)) + , start_time(clock::now()) + { + if (rate <= 0) { + tw_req = std::chrono::nanoseconds(1); } else { - skip_check_count = - std::min(int(seconds(1) / tw_req), // recheck at least every second - (skip_check_count * 5 + 3) / 4); - //std::cerr << s.str() << "maybe_sleep: going too slow; work more: " << skip_check_count << "\n"; + tw_req = std::chrono::duration_cast(tw_req / rate); } - } else if (tw < tw_req * 63 / 64) { - // the time between maybe_sleep calls is more than 1% too short - // fix it by reducing skip_check_count towards 1 and if skip_check_count = 1 - // doesn't suffice, increase ts - - // The minimum work count is defined such that a typical sleep time is greater - // than 1ms. - // The user requested 1/tw_req work iterations per second. Divided by 1000, that's - // the count per ms. - const int min_skip_count = std::max(1, int(milliseconds(5) / tw_req)); - if (skip_check_count > min_skip_count) { - assert(ts == clock::duration::zero()); - skip_check_count = std::max(min_skip_count, skip_check_count * 3 / 4); - //std::cerr << s.str() << "maybe_sleep: going too fast; work less: " << skip_check_count << "\n"; - } else { - ts += (tw_req - tw) * (skip_check_count * 7) / 8; - //std::cerr << s.str() << "maybe_sleep: going too fast; sleep more: " << duration_cast(ts).count() << "µs\n"; - } - } - - start_time = now; - count = skip_check_count; - if (ts > clock::duration::zero()) { - std::this_thread::sleep_for(ts); - } + skip_check_count = std::max(1, int(std::chrono::milliseconds(5) / tw_req)); + count = skip_check_count; + // std::cerr << "skip_check_count: " << skip_check_count << '\n'; } - } -private: - clock::duration tw{}, //! deduced duration between maybe_sleep calls - ts{}, //! sleep duration - tw_req; //! requested duration between maybe_sleep calls - clock::time_point start_time; - int count = 1; - int skip_check_count = 1; + /** + * Call this function at the end of the iteration rate limited loop. + * + * This function might use `std::this_thread::sleep_for` to limit the iteration rate. If no + * sleeps are necessary, the function will back off checking for the time to further allow + * increased iteration rates (until the requested rate or 1s between rechecks is reached). + */ + void maybe_sleep() + { + using namespace std::chrono; + if (--count == 0) { + auto now = clock::now(); + if (tw == clock::duration::zero()) { + tw = (now - start_time) / skip_check_count; + } else { + tw = (1 * tw + 3 * (now - start_time) / skip_check_count) / 4; + } + // std::ostringstream s; s << "tw = " << std::setw(10) << + // duration_cast(tw).count() << "ns, req = " << + // duration_cast(tw_req).count() << "ns, "; + if (tw > tw_req * 65 / 64) { + // the time between maybe_sleep calls is more than 1% too long + // fix it by reducing ts towards 0 and if ts = 0 doesn't suffice, increase + // skip_check_count + if (ts > clock::duration::zero()) { + ts = std::max(clock::duration::zero(), ts - (tw - tw_req) * skip_check_count * 1 / 2); + // std::cerr << s.str() << "maybe_sleep: going too slow; sleep less: " << + // duration_cast(ts).count() << "µs\n"; + } else { + skip_check_count = + std::min(int(seconds(1) / tw_req), // recheck at least every second + (skip_check_count * 5 + 3) / 4); + // std::cerr << s.str() << "maybe_sleep: going too slow; work more: " << + // skip_check_count << "\n"; + } + } else if (tw < tw_req * 63 / 64) { + // the time between maybe_sleep calls is more than 1% too short + // fix it by reducing skip_check_count towards 1 and if skip_check_count = 1 + // doesn't suffice, increase ts + + // The minimum work count is defined such that a typical sleep time is greater + // than 1ms. + // The user requested 1/tw_req work iterations per second. Divided by 1000, that's + // the count per ms. + const int min_skip_count = std::max(1, int(milliseconds(5) / tw_req)); + if (skip_check_count > min_skip_count) { + assert(ts == clock::duration::zero()); + skip_check_count = std::max(min_skip_count, skip_check_count * 3 / 4); + // std::cerr << s.str() << "maybe_sleep: going too fast; work less: " << + // skip_check_count << "\n"; + } else { + ts += (tw_req - tw) * (skip_check_count * 7) / 8; + // std::cerr << s.str() << "maybe_sleep: going too fast; sleep more: " << + // duration_cast(ts).count() << "µs\n"; + } + } + + start_time = now; + count = skip_check_count; + if (ts > clock::duration::zero()) { + std::this_thread::sleep_for(ts); + } + } + } + + private: + clock::duration tw{}, //! deduced duration between maybe_sleep calls + ts{}, //! sleep duration + tw_req; //! requested duration between maybe_sleep calls + clock::time_point start_time; + int count = 1; + int skip_check_count = 1; }; } /* namespace tools */