aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/timer.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2015-05-26 18:50:28 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-06-19 09:18:27 -0400
commit1dabbcec2c0a36fe43509d06499b9e512e70a028 (patch)
treeafa43477a43f82b5681b4ac328463a39f4aad99d /kernel/time/timer.c
parent1bd04bf6f68d65f5422b2b85c495d65d49587a54 (diff)
timer: Use hlist for the timer wheel hash buckets
This reduces the size of struct tvec_base by 50% and results in slightly smaller code as well. Before: struct tvec_base: size: 8256, cachelines: 129 text data bss dec hex filename 17698 13297 8256 39251 9953 ../build/kernel/time/timer.o After: struct tvec_base: 4160, cachelines: 65 text data bss dec hex filename 17491 9201 4160 30852 7884 ../build/kernel/time/timer.o Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul McKenney <paulmck@linux.vnet.ibm.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Eric Dumazet <edumazet@google.com> Cc: John Stultz <john.stultz@linaro.org> Cc: Joonwoo Park <joonwoop@codeaurora.org> Cc: Wenbo Wang <wenbo.wang@memblaze.com> Link: http://lkml.kernel.org/r/20150526224511.854731214@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time/timer.c')
-rw-r--r--kernel/time/timer.c64
1 files changed, 27 insertions, 37 deletions
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index e212df24ad3f..3a5e0c840884 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -70,11 +70,11 @@ EXPORT_SYMBOL(jiffies_64);
70#define MAX_TVAL ((unsigned long)((1ULL << (TVR_BITS + 4*TVN_BITS)) - 1)) 70#define MAX_TVAL ((unsigned long)((1ULL << (TVR_BITS + 4*TVN_BITS)) - 1))
71 71
72struct tvec { 72struct tvec {
73 struct list_head vec[TVN_SIZE]; 73 struct hlist_head vec[TVN_SIZE];
74}; 74};
75 75
76struct tvec_root { 76struct tvec_root {
77 struct list_head vec[TVR_SIZE]; 77 struct hlist_head vec[TVR_SIZE];
78}; 78};
79 79
80struct tvec_base { 80struct tvec_base {
@@ -356,7 +356,7 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer)
356{ 356{
357 unsigned long expires = timer->expires; 357 unsigned long expires = timer->expires;
358 unsigned long idx = expires - base->timer_jiffies; 358 unsigned long idx = expires - base->timer_jiffies;
359 struct list_head *vec; 359 struct hlist_head *vec;
360 360
361 if (idx < TVR_SIZE) { 361 if (idx < TVR_SIZE) {
362 int i = expires & TVR_MASK; 362 int i = expires & TVR_MASK;
@@ -390,7 +390,7 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer)
390 vec = base->tv5.vec + i; 390 vec = base->tv5.vec + i;
391 } 391 }
392 392
393 list_add(&timer->entry, vec); 393 hlist_add_head(&timer->entry, vec);
394} 394}
395 395
396static void internal_add_timer(struct tvec_base *base, struct timer_list *timer) 396static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
@@ -504,8 +504,8 @@ static int timer_fixup_activate(void *addr, enum debug_obj_state state)
504 * statically initialized. We just make sure that it 504 * statically initialized. We just make sure that it
505 * is tracked in the object tracker. 505 * is tracked in the object tracker.
506 */ 506 */
507 if (timer->entry.next == NULL && 507 if (timer->entry.pprev == NULL &&
508 timer->entry.prev == TIMER_ENTRY_STATIC) { 508 timer->entry.next == TIMER_ENTRY_STATIC) {
509 debug_object_init(timer, &timer_debug_descr); 509 debug_object_init(timer, &timer_debug_descr);
510 debug_object_activate(timer, &timer_debug_descr); 510 debug_object_activate(timer, &timer_debug_descr);
511 return 0; 511 return 0;
@@ -551,7 +551,7 @@ static int timer_fixup_assert_init(void *addr, enum debug_obj_state state)
551 551
552 switch (state) { 552 switch (state) {
553 case ODEBUG_STATE_NOTAVAILABLE: 553 case ODEBUG_STATE_NOTAVAILABLE:
554 if (timer->entry.prev == TIMER_ENTRY_STATIC) { 554 if (timer->entry.next == TIMER_ENTRY_STATIC) {
555 /* 555 /*
556 * This is not really a fixup. The timer was 556 * This is not really a fixup. The timer was
557 * statically initialized. We just make sure that it 557 * statically initialized. We just make sure that it
@@ -655,7 +655,7 @@ static void do_init_timer(struct timer_list *timer, unsigned int flags,
655{ 655{
656 struct tvec_base *base = raw_cpu_read(tvec_bases); 656 struct tvec_base *base = raw_cpu_read(tvec_bases);
657 657
658 timer->entry.next = NULL; 658 timer->entry.pprev = NULL;
659 timer->base = (void *)((unsigned long)base | flags); 659 timer->base = (void *)((unsigned long)base | flags);
660 timer->slack = -1; 660 timer->slack = -1;
661#ifdef CONFIG_TIMER_STATS 661#ifdef CONFIG_TIMER_STATS
@@ -687,14 +687,14 @@ EXPORT_SYMBOL(init_timer_key);
687 687
688static inline void detach_timer(struct timer_list *timer, bool clear_pending) 688static inline void detach_timer(struct timer_list *timer, bool clear_pending)
689{ 689{
690 struct list_head *entry = &timer->entry; 690 struct hlist_node *entry = &timer->entry;
691 691
692 debug_deactivate(timer); 692 debug_deactivate(timer);
693 693
694 __list_del(entry->prev, entry->next); 694 __hlist_del(entry);
695 if (clear_pending) 695 if (clear_pending)
696 entry->next = NULL; 696 entry->pprev = NULL;
697 entry->prev = LIST_POISON2; 697 entry->next = LIST_POISON2;
698} 698}
699 699
700static inline void 700static inline void
@@ -1095,16 +1095,17 @@ EXPORT_SYMBOL(del_timer_sync);
1095static int cascade(struct tvec_base *base, struct tvec *tv, int index) 1095static int cascade(struct tvec_base *base, struct tvec *tv, int index)
1096{ 1096{
1097 /* cascade all the timers from tv up one level */ 1097 /* cascade all the timers from tv up one level */
1098 struct timer_list *timer, *tmp; 1098 struct timer_list *timer;
1099 struct list_head tv_list; 1099 struct hlist_node *tmp;
1100 struct hlist_head tv_list;
1100 1101
1101 list_replace_init(tv->vec + index, &tv_list); 1102 hlist_move_list(tv->vec + index, &tv_list);
1102 1103
1103 /* 1104 /*
1104 * We are removing _all_ timers from the list, so we 1105 * We are removing _all_ timers from the list, so we
1105 * don't have to detach them individually. 1106 * don't have to detach them individually.
1106 */ 1107 */
1107 list_for_each_entry_safe(timer, tmp, &tv_list, entry) { 1108 hlist_for_each_entry_safe(timer, tmp, &tv_list, entry) {
1108 BUG_ON(tbase_get_base(timer->base) != base); 1109 BUG_ON(tbase_get_base(timer->base) != base);
1109 /* No accounting, while moving them */ 1110 /* No accounting, while moving them */
1110 __internal_add_timer(base, timer); 1111 __internal_add_timer(base, timer);
@@ -1172,8 +1173,8 @@ static inline void __run_timers(struct tvec_base *base)
1172 spin_lock_irq(&base->lock); 1173 spin_lock_irq(&base->lock);
1173 1174
1174 while (time_after_eq(jiffies, base->timer_jiffies)) { 1175 while (time_after_eq(jiffies, base->timer_jiffies)) {
1175 struct list_head work_list; 1176 struct hlist_head work_list;
1176 struct list_head *head = &work_list; 1177 struct hlist_head *head = &work_list;
1177 int index; 1178 int index;
1178 1179
1179 if (!base->all_timers) { 1180 if (!base->all_timers) {
@@ -1192,13 +1193,13 @@ static inline void __run_timers(struct tvec_base *base)
1192 !cascade(base, &base->tv4, INDEX(2))) 1193 !cascade(base, &base->tv4, INDEX(2)))
1193 cascade(base, &base->tv5, INDEX(3)); 1194 cascade(base, &base->tv5, INDEX(3));
1194 ++base->timer_jiffies; 1195 ++base->timer_jiffies;
1195 list_replace_init(base->tv1.vec + index, head); 1196 hlist_move_list(base->tv1.vec + index, head);
1196 while (!list_empty(head)) { 1197 while (!hlist_empty(head)) {
1197 void (*fn)(unsigned long); 1198 void (*fn)(unsigned long);
1198 unsigned long data; 1199 unsigned long data;
1199 bool irqsafe; 1200 bool irqsafe;
1200 1201
1201 timer = list_first_entry(head, struct timer_list,entry); 1202 timer = hlist_entry(head->first, struct timer_list, entry);
1202 fn = timer->function; 1203 fn = timer->function;
1203 data = timer->data; 1204 data = timer->data;
1204 irqsafe = tbase_get_irqsafe(timer->base); 1205 irqsafe = tbase_get_irqsafe(timer->base);
@@ -1240,7 +1241,7 @@ static unsigned long __next_timer_interrupt(struct tvec_base *base)
1240 /* Look for timer events in tv1. */ 1241 /* Look for timer events in tv1. */
1241 index = slot = timer_jiffies & TVR_MASK; 1242 index = slot = timer_jiffies & TVR_MASK;
1242 do { 1243 do {
1243 list_for_each_entry(nte, base->tv1.vec + slot, entry) { 1244 hlist_for_each_entry(nte, base->tv1.vec + slot, entry) {
1244 if (tbase_get_deferrable(nte->base)) 1245 if (tbase_get_deferrable(nte->base))
1245 continue; 1246 continue;
1246 1247
@@ -1271,7 +1272,7 @@ cascade:
1271 1272
1272 index = slot = timer_jiffies & TVN_MASK; 1273 index = slot = timer_jiffies & TVN_MASK;
1273 do { 1274 do {
1274 list_for_each_entry(nte, varp->vec + slot, entry) { 1275 hlist_for_each_entry(nte, varp->vec + slot, entry) {
1275 if (tbase_get_deferrable(nte->base)) 1276 if (tbase_get_deferrable(nte->base))
1276 continue; 1277 continue;
1277 1278
@@ -1530,12 +1531,12 @@ signed long __sched schedule_timeout_uninterruptible(signed long timeout)
1530EXPORT_SYMBOL(schedule_timeout_uninterruptible); 1531EXPORT_SYMBOL(schedule_timeout_uninterruptible);
1531 1532
1532#ifdef CONFIG_HOTPLUG_CPU 1533#ifdef CONFIG_HOTPLUG_CPU
1533static void migrate_timer_list(struct tvec_base *new_base, struct list_head *head) 1534static void migrate_timer_list(struct tvec_base *new_base, struct hlist_head *head)
1534{ 1535{
1535 struct timer_list *timer; 1536 struct timer_list *timer;
1536 1537
1537 while (!list_empty(head)) { 1538 while (!hlist_empty(head)) {
1538 timer = list_first_entry(head, struct timer_list, entry); 1539 timer = hlist_entry(head->first, struct timer_list, entry);
1539 /* We ignore the accounting on the dying cpu */ 1540 /* We ignore the accounting on the dying cpu */
1540 detach_timer(timer, false); 1541 detach_timer(timer, false);
1541 timer_set_base(timer, new_base); 1542 timer_set_base(timer, new_base);
@@ -1603,23 +1604,12 @@ static inline void timer_register_cpu_notifier(void) { }
1603 1604
1604static void __init init_timer_cpu(struct tvec_base *base, int cpu) 1605static void __init init_timer_cpu(struct tvec_base *base, int cpu)
1605{ 1606{
1606 int j;
1607
1608 BUG_ON(base != tbase_get_base(base)); 1607 BUG_ON(base != tbase_get_base(base));
1609 1608
1610 base->cpu = cpu; 1609 base->cpu = cpu;
1611 per_cpu(tvec_bases, cpu) = base; 1610 per_cpu(tvec_bases, cpu) = base;
1612 spin_lock_init(&base->lock); 1611 spin_lock_init(&base->lock);
1613 1612
1614 for (j = 0; j < TVN_SIZE; j++) {
1615 INIT_LIST_HEAD(base->tv5.vec + j);
1616 INIT_LIST_HEAD(base->tv4.vec + j);
1617 INIT_LIST_HEAD(base->tv3.vec + j);
1618 INIT_LIST_HEAD(base->tv2.vec + j);
1619 }
1620 for (j = 0; j < TVR_SIZE; j++)
1621 INIT_LIST_HEAD(base->tv1.vec + j);
1622
1623 base->timer_jiffies = jiffies; 1613 base->timer_jiffies = jiffies;
1624 base->next_timer = base->timer_jiffies; 1614 base->next_timer = base->timer_jiffies;
1625} 1615}