Commit 3bbb9ec946428b96657126768f65487a48dd090c

Authored by Arjan van de Ven
Committed by Thomas Gleixner
1 parent 3d0205bd13

timers: Introduce the concept of timer slack for legacy timers

While HR timers have had the concept of timer slack for quite some time
now, the legacy timers lacked this concept, and had to make do with
round_jiffies() and friends.

Timer slack is important for power management; grouping timers reduces the
number of wakeups which in turn reduces power consumption.

This patch introduces timer slack to the legacy timers using the following
pieces:
* A slack field in the timer struct
* An api (set_timer_slack) that callers can use to set explicit timer slack
* A default slack of 0.4% of the requested delay for callers that do not set
  any explicit slack
* Rounding code that is part of mod_timer() that tries to
  group timers around jiffies values every 'power of two'
  (so quick timers will group around every 2, but longer timers
  will group around every 4, 8, 16, 32 etc)

Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Cc: johnstul@us.ibm.com
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Showing 2 changed files with 65 additions and 1 deletions Side-by-side Diff

include/linux/timer.h
... ... @@ -10,13 +10,19 @@
10 10 struct tvec_base;
11 11  
12 12 struct timer_list {
  13 + /*
  14 + * All fields that change during normal runtime grouped to the
  15 + * same cacheline
  16 + */
13 17 struct list_head entry;
14 18 unsigned long expires;
  19 + struct tvec_base *base;
15 20  
16 21 void (*function)(unsigned long);
17 22 unsigned long data;
18 23  
19   - struct tvec_base *base;
  24 + int slack;
  25 +
20 26 #ifdef CONFIG_TIMER_STATS
21 27 void *start_site;
22 28 char start_comm[16];
... ... @@ -164,6 +170,8 @@
164 170 extern int mod_timer(struct timer_list *timer, unsigned long expires);
165 171 extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
166 172 extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires);
  173 +
  174 +extern void set_timer_slack(struct timer_list *time, int slack_hz);
167 175  
168 176 #define TIMER_NOT_PINNED 0
169 177 #define TIMER_PINNED 1
... ... @@ -318,7 +318,25 @@
318 318 }
319 319 EXPORT_SYMBOL_GPL(round_jiffies_up_relative);
320 320  
  321 +/**
  322 + * set_timer_slack - set the allowed slack for a timer
  323 + * @slack_hz: the amount of time (in jiffies) allowed for rounding
  324 + *
  325 + * Set the amount of time, in jiffies, that a certain timer has
  326 + * in terms of slack. By setting this value, the timer subsystem
  327 + * will schedule the actual timer somewhere between
  328 + * the time mod_timer() asks for, and that time plus the slack.
  329 + *
  330 + * By setting the slack to -1, a percentage of the delay is used
  331 + * instead.
  332 + */
  333 +void set_timer_slack(struct timer_list *timer, int slack_hz)
  334 +{
  335 + timer->slack = slack_hz;
  336 +}
  337 +EXPORT_SYMBOL_GPL(set_timer_slack);
321 338  
  339 +
322 340 static inline void set_running_timer(struct tvec_base *base,
323 341 struct timer_list *timer)
324 342 {
... ... @@ -549,6 +567,7 @@
549 567 {
550 568 timer->entry.next = NULL;
551 569 timer->base = __raw_get_cpu_var(tvec_bases);
  570 + timer->slack = -1;
552 571 #ifdef CONFIG_TIMER_STATS
553 572 timer->start_site = NULL;
554 573 timer->start_pid = -1;
... ... @@ -714,6 +733,41 @@
714 733 }
715 734 EXPORT_SYMBOL(mod_timer_pending);
716 735  
  736 +/*
  737 + * Decide where to put the timer while taking the slack into account
  738 + *
  739 + * Algorithm:
  740 + * 1) calculate the maximum (absolute) time
  741 + * 2) calculate the highest bit where the expires and new max are different
  742 + * 3) use this bit to make a mask
  743 + * 4) use the bitmask to round down the maximum time, so that all last
  744 + * bits are zeros
  745 + */
  746 +static inline
  747 +unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
  748 +{
  749 + unsigned long expires_limit, mask;
  750 + int bit;
  751 +
  752 + expires_limit = expires + timer->slack;
  753 +
  754 + if (timer->slack < 0) /* auto slack: use 0.4% */
  755 + expires_limit = expires + (expires - jiffies)/256;
  756 +
  757 + mask = expires ^ expires_limit;
  758 +
  759 + if (mask == 0)
  760 + return expires;
  761 +
  762 + bit = find_last_bit(&mask, BITS_PER_LONG);
  763 +
  764 + mask = (1 << bit) - 1;
  765 +
  766 + expires_limit = expires_limit & ~(mask);
  767 +
  768 + return expires_limit;
  769 +}
  770 +
717 771 /**
718 772 * mod_timer - modify a timer's timeout
719 773 * @timer: the timer to be modified
... ... @@ -743,6 +797,8 @@
743 797 */
744 798 if (timer_pending(timer) && timer->expires == expires)
745 799 return 1;
  800 +
  801 + expires = apply_slack(timer, expires);
746 802  
747 803 return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
748 804 }