diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-07-21 14:25:05 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-08-04 14:28:25 -0400 |
commit | 97fd9ed48ce2b807edc363bef3e817aeeb5cd5e6 (patch) | |
tree | ffb221aba4444bd3a1f84affd2aba7aa0784484e /kernel/timer.c | |
parent | fbd90375d7531927d312766b548376d909811b4d (diff) |
timers: Cache __next_timer_interrupt result
Each time a cpu goes to sleep on a NOHZ=y system the timer
wheel is searched for the next timer interrupt. It can take
quite a few cycles to find the next pending timer.
This patch adds a field to tvec_base that caches the result of
__next_timer_interrupt.
The hit ratio is around 80% on my thinkpad under normal use, on
a server I've seen hit ratios from 5% to 95% dependent on the
workload.
-v2: jiffies wrap fixes
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Venki Pallipadi <venkatesh.pallipadi@intel.com>
LKML-Reference: <20090721202505.7d56a079@skybase>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/timer.c')
-rw-r--r-- | kernel/timer.c | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/kernel/timer.c b/kernel/timer.c index 0b36b9e5cc8b..5c1e49ec2f1b 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -72,6 +72,7 @@ struct tvec_base { | |||
72 | spinlock_t lock; | 72 | spinlock_t lock; |
73 | struct timer_list *running_timer; | 73 | struct timer_list *running_timer; |
74 | unsigned long timer_jiffies; | 74 | unsigned long timer_jiffies; |
75 | unsigned long next_timer; | ||
75 | struct tvec_root tv1; | 76 | struct tvec_root tv1; |
76 | struct tvec tv2; | 77 | struct tvec tv2; |
77 | struct tvec tv3; | 78 | struct tvec tv3; |
@@ -622,6 +623,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires, | |||
622 | 623 | ||
623 | if (timer_pending(timer)) { | 624 | if (timer_pending(timer)) { |
624 | detach_timer(timer, 0); | 625 | detach_timer(timer, 0); |
626 | if (timer->expires == base->next_timer && | ||
627 | !tbase_get_deferrable(timer->base)) | ||
628 | base->next_timer = base->timer_jiffies; | ||
625 | ret = 1; | 629 | ret = 1; |
626 | } else { | 630 | } else { |
627 | if (pending_only) | 631 | if (pending_only) |
@@ -663,6 +667,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires, | |||
663 | } | 667 | } |
664 | 668 | ||
665 | timer->expires = expires; | 669 | timer->expires = expires; |
670 | if (time_before(timer->expires, base->next_timer) && | ||
671 | !tbase_get_deferrable(timer->base)) | ||
672 | base->next_timer = timer->expires; | ||
666 | internal_add_timer(base, timer); | 673 | internal_add_timer(base, timer); |
667 | 674 | ||
668 | out_unlock: | 675 | out_unlock: |
@@ -781,6 +788,9 @@ void add_timer_on(struct timer_list *timer, int cpu) | |||
781 | spin_lock_irqsave(&base->lock, flags); | 788 | spin_lock_irqsave(&base->lock, flags); |
782 | timer_set_base(timer, base); | 789 | timer_set_base(timer, base); |
783 | debug_timer_activate(timer); | 790 | debug_timer_activate(timer); |
791 | if (time_before(timer->expires, base->next_timer) && | ||
792 | !tbase_get_deferrable(timer->base)) | ||
793 | base->next_timer = timer->expires; | ||
784 | internal_add_timer(base, timer); | 794 | internal_add_timer(base, timer); |
785 | /* | 795 | /* |
786 | * Check whether the other CPU is idle and needs to be | 796 | * Check whether the other CPU is idle and needs to be |
@@ -817,6 +827,9 @@ int del_timer(struct timer_list *timer) | |||
817 | base = lock_timer_base(timer, &flags); | 827 | base = lock_timer_base(timer, &flags); |
818 | if (timer_pending(timer)) { | 828 | if (timer_pending(timer)) { |
819 | detach_timer(timer, 1); | 829 | detach_timer(timer, 1); |
830 | if (timer->expires == base->next_timer && | ||
831 | !tbase_get_deferrable(timer->base)) | ||
832 | base->next_timer = base->timer_jiffies; | ||
820 | ret = 1; | 833 | ret = 1; |
821 | } | 834 | } |
822 | spin_unlock_irqrestore(&base->lock, flags); | 835 | spin_unlock_irqrestore(&base->lock, flags); |
@@ -850,6 +863,9 @@ int try_to_del_timer_sync(struct timer_list *timer) | |||
850 | ret = 0; | 863 | ret = 0; |
851 | if (timer_pending(timer)) { | 864 | if (timer_pending(timer)) { |
852 | detach_timer(timer, 1); | 865 | detach_timer(timer, 1); |
866 | if (timer->expires == base->next_timer && | ||
867 | !tbase_get_deferrable(timer->base)) | ||
868 | base->next_timer = base->timer_jiffies; | ||
853 | ret = 1; | 869 | ret = 1; |
854 | } | 870 | } |
855 | out: | 871 | out: |
@@ -1134,7 +1150,9 @@ unsigned long get_next_timer_interrupt(unsigned long now) | |||
1134 | unsigned long expires; | 1150 | unsigned long expires; |
1135 | 1151 | ||
1136 | spin_lock(&base->lock); | 1152 | spin_lock(&base->lock); |
1137 | expires = __next_timer_interrupt(base); | 1153 | if (time_before_eq(base->next_timer, base->timer_jiffies)) |
1154 | base->next_timer = __next_timer_interrupt(base); | ||
1155 | expires = base->next_timer; | ||
1138 | spin_unlock(&base->lock); | 1156 | spin_unlock(&base->lock); |
1139 | 1157 | ||
1140 | if (time_before_eq(expires, now)) | 1158 | if (time_before_eq(expires, now)) |
@@ -1523,6 +1541,7 @@ static int __cpuinit init_timers_cpu(int cpu) | |||
1523 | INIT_LIST_HEAD(base->tv1.vec + j); | 1541 | INIT_LIST_HEAD(base->tv1.vec + j); |
1524 | 1542 | ||
1525 | base->timer_jiffies = jiffies; | 1543 | base->timer_jiffies = jiffies; |
1544 | base->next_timer = base->timer_jiffies; | ||
1526 | return 0; | 1545 | return 0; |
1527 | } | 1546 | } |
1528 | 1547 | ||
@@ -1535,6 +1554,9 @@ static void migrate_timer_list(struct tvec_base *new_base, struct list_head *hea | |||
1535 | timer = list_first_entry(head, struct timer_list, entry); | 1554 | timer = list_first_entry(head, struct timer_list, entry); |
1536 | detach_timer(timer, 0); | 1555 | detach_timer(timer, 0); |
1537 | timer_set_base(timer, new_base); | 1556 | timer_set_base(timer, new_base); |
1557 | if (time_before(timer->expires, new_base->next_timer) && | ||
1558 | !tbase_get_deferrable(timer->base)) | ||
1559 | new_base->next_timer = timer->expires; | ||
1538 | internal_add_timer(new_base, timer); | 1560 | internal_add_timer(new_base, timer); |
1539 | } | 1561 | } |
1540 | } | 1562 | } |