ratelimit,sd-journal: don't read the clock once per journal file per entry
sd_journal_next() sweeps every open journal file to find the next entry, and next_beyond_location() rate-limits its tail timestamp refresh per file. Since ratelimit_below() reads the clock itself, iterating a journal spread over a hundred files meant a hundred clock_gettime() calls for every single entry, nearly all of them only to conclude that the one second interval had not elapsed yet. On a 730M journal in 100 files this was the single largest cost in journalctl, over a fifth of the run. Add ratelimit_below_at(), which takes the timestamp from the caller, and read the clock once per sweep in real_journal_next() instead. ratelimit_below() keeps its behaviour and becomes a wrapper. The timestamp is now sampled once for the whole sweep rather than once per file. The interval being rate-limited is a second and a sweep takes microseconds, so this makes no practical difference. On that journal, journalctl -o export goes from 4.02s to 2.93s, and the default journalctl -o short from 3.30s to 2.14s.
This commit is contained in:
committed by
Yu Watanabe
parent
7461360c15
commit
79e32e7c73
+11
-5
@@ -6,16 +6,12 @@
|
||||
/* Modelled after Linux' lib/ratelimit.c by Dave Young
|
||||
* <hidave.darkstar@gmail.com>, which is licensed GPLv2. */
|
||||
|
||||
bool ratelimit_below(RateLimit *rl) {
|
||||
usec_t ts;
|
||||
|
||||
bool ratelimit_below_at(RateLimit *rl, usec_t ts) {
|
||||
assert(rl);
|
||||
|
||||
if (!ratelimit_configured(rl))
|
||||
return true;
|
||||
|
||||
ts = now(CLOCK_BOOTTIME);
|
||||
|
||||
if (rl->begin <= 0 ||
|
||||
usec_sub_unsigned(ts, rl->begin) > rl->interval) {
|
||||
rl->begin = ts; /* Start a new time window */
|
||||
@@ -30,6 +26,16 @@ bool ratelimit_below(RateLimit *rl) {
|
||||
return rl->num <= rl->burst;
|
||||
}
|
||||
|
||||
bool ratelimit_below(RateLimit *rl) {
|
||||
assert(rl);
|
||||
|
||||
if (!ratelimit_configured(rl)) /* Keep this check here too: the argument below is evaluated
|
||||
* before the callee could short-circuit on it. */
|
||||
return true;
|
||||
|
||||
return ratelimit_below_at(rl, now(CLOCK_BOOTTIME));
|
||||
}
|
||||
|
||||
unsigned ratelimit_num_dropped(const RateLimit *rl) {
|
||||
assert(rl);
|
||||
|
||||
|
||||
@@ -21,6 +21,11 @@ static inline bool ratelimit_configured(const RateLimit *rl) {
|
||||
}
|
||||
|
||||
bool ratelimit_below(RateLimit *rl);
|
||||
/* Like ratelimit_below(), but takes the current CLOCK_BOOTTIME timestamp from the caller, for callers
|
||||
* that check many rate limits in a row and should not read the clock for each of them. The timestamps
|
||||
* passed for a given RateLimit must not go backwards: a ts before the one that opened the current
|
||||
* window makes usec_sub_unsigned() return 0, i.e. the window looks like it just started. */
|
||||
bool ratelimit_below_at(RateLimit *rl, usec_t ts);
|
||||
|
||||
unsigned ratelimit_num_dropped(const RateLimit *rl);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user