aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2010-03-11 17:04:36 -0500
committerThomas Gleixner <tglx@linutronix.de>2010-04-06 15:50:02 -0400
commit3bbb9ec946428b96657126768f65487a48dd090c (patch)
treeb560e8c15102281a110cd5ccd93866084e31014b /kernel
parent3d0205bd1383aa3cac93c209b7c7d03b27930195 (diff)
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>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/timer.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/kernel/timer.c b/kernel/timer.c
index 7e12e7bc7ce6..49773f38c9bc 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -318,6 +318,24 @@ unsigned long round_jiffies_up_relative(unsigned long j)
318} 318}
319EXPORT_SYMBOL_GPL(round_jiffies_up_relative); 319EXPORT_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 */
333void set_timer_slack(struct timer_list *timer, int slack_hz)
334{
335 timer->slack = slack_hz;
336}
337EXPORT_SYMBOL_GPL(set_timer_slack);
338
321 339
322static inline void set_running_timer(struct tvec_base *base, 340static inline void set_running_timer(struct tvec_base *base,
323 struct timer_list *timer) 341 struct timer_list *timer)
@@ -549,6 +567,7 @@ static void __init_timer(struct timer_list *timer,
549{ 567{
550 timer->entry.next = NULL; 568 timer->entry.next = NULL;
551 timer->base = __raw_get_cpu_var(tvec_bases); 569 timer->base = __raw_get_cpu_var(tvec_bases);
570 timer->slack = -1;
552#ifdef CONFIG_TIMER_STATS 571#ifdef CONFIG_TIMER_STATS
553 timer->start_site = NULL; 572 timer->start_site = NULL;
554 timer->start_pid = -1; 573 timer->start_pid = -1;
@@ -714,6 +733,41 @@ int mod_timer_pending(struct timer_list *timer, unsigned long expires)
714} 733}
715EXPORT_SYMBOL(mod_timer_pending); 734EXPORT_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 */
746static inline
747unsigned 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 * mod_timer - modify a timer's timeout 772 * mod_timer - modify a timer's timeout
719 * @timer: the timer to be modified 773 * @timer: the timer to be modified
@@ -744,6 +798,8 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
744 if (timer_pending(timer) && timer->expires == expires) 798 if (timer_pending(timer) && timer->expires == expires)
745 return 1; 799 return 1;
746 800
801 expires = apply_slack(timer, expires);
802
747 return __mod_timer(timer, expires, false, TIMER_NOT_PINNED); 803 return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
748} 804}
749EXPORT_SYMBOL(mod_timer); 805EXPORT_SYMBOL(mod_timer);