diff options
author | Frederic Weisbecker <frederic@kernel.org> | 2020-07-17 16:05:45 +0200 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2020-07-17 21:55:22 +0200 |
commit | 001ec1b3925da0d51847c23fc0aa4129282db526 (patch) | |
tree | 0ca510af92153bc4788f719e657e3532eed825dd | |
parent | 4468897211628865ee2392acb5ad281f74176f63 (diff) |
timers: Optimize _next_timer_interrupt() level iteration
If a level has a timer that expires before reaching the next level, there
is no need to iterate further.
The next level is reached when the 3 lower bits of the current level are
cleared. If the next event happens before/during that, the next levels
won't provide an earlier expiration.
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juri Lelli <juri.lelli@redhat.com>
Link: https://lkml.kernel.org/r/20200717140551.29076-7-frederic@kernel.org
-rw-r--r-- | kernel/time/timer.c | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/kernel/time/timer.c b/kernel/time/timer.c index af1c08b0b168..9abc41715fd2 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1526,6 +1526,7 @@ static unsigned long __next_timer_interrupt(struct timer_base *base) clk = base->clk; for (lvl = 0; lvl < LVL_DEPTH; lvl++, offset += LVL_SIZE) { int pos = next_pending_bucket(base, offset, clk & LVL_MASK); + unsigned long lvl_clk = clk & LVL_CLK_MASK; if (pos >= 0) { unsigned long tmp = clk + (unsigned long) pos; @@ -1533,6 +1534,13 @@ static unsigned long __next_timer_interrupt(struct timer_base *base) tmp <<= LVL_SHIFT(lvl); if (time_before(tmp, next)) next = tmp; + + /* + * If the next expiration happens before we reach + * the next level, no need to check further. + */ + if (pos <= ((LVL_CLK_DIV - lvl_clk) & LVL_CLK_MASK)) + break; } /* * Clock for the next level. If the current level clock lower @@ -1570,7 +1578,7 @@ static unsigned long __next_timer_interrupt(struct timer_base *base) * So the simple check whether the lower bits of the current * level are 0 or not is sufficient for all cases. */ - adj = clk & LVL_CLK_MASK ? 1 : 0; + adj = lvl_clk ? 1 : 0; clk >>= LVL_CLK_SHIFT; clk += adj; } |