aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/hrtimer.c
diff options
context:
space:
mode:
authorAshwin Chaugule <ashwinc@quicinc.com>2009-09-01 23:03:33 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-09-15 11:09:44 -0400
commit7403f41f19574d6805197e9b97dfa7592003be10 (patch)
tree8d849ac38a64a60fbe06f9f2c8c6b26697fad74f /kernel/hrtimer.c
parent12e09337fe238981cb0c87543306e23775d1a143 (diff)
hrtimer: Eliminate needless reprogramming of clock events device
On NOHZ systems the following timers, - tick_nohz_restart_sched_tick (tick_sched_timer) - hrtimer_start (tick_sched_timer) are reprogramming the clock events device far more often than needed. No specific test case was required to observe this effect. This occurres because there was no check to see if the currently removed or restarted hrtimer was: 1) the one which previously armed the clock events device. 2) going to be replaced by another timer which has the same expiry time. Avoid the reprogramming in hrtimer_force_reprogram when the new expiry value which is evaluated from the clock bases is equal to cpu_base->expires_next. This results in faster application startup time by ~4%. [ tglx: simplified initial solution ] Signed-off-by: Ashwin Chaugule <ashwinc@quicinc.com> LKML-Reference: <4AA00165.90609@codeaurora.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/hrtimer.c')
-rw-r--r--kernel/hrtimer.c53
1 files changed, 35 insertions, 18 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index e2f91ecc01a8..1363c1aac158 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -486,13 +486,14 @@ static inline int hrtimer_hres_active(void)
486 * next event 486 * next event
487 * Called with interrupts disabled and base->lock held 487 * Called with interrupts disabled and base->lock held
488 */ 488 */
489static void hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base) 489static void
490hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
490{ 491{
491 int i; 492 int i;
492 struct hrtimer_clock_base *base = cpu_base->clock_base; 493 struct hrtimer_clock_base *base = cpu_base->clock_base;
493 ktime_t expires; 494 ktime_t expires, expires_next;
494 495
495 cpu_base->expires_next.tv64 = KTIME_MAX; 496 expires_next.tv64 = KTIME_MAX;
496 497
497 for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++, base++) { 498 for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++, base++) {
498 struct hrtimer *timer; 499 struct hrtimer *timer;
@@ -508,10 +509,15 @@ static void hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base)
508 */ 509 */
509 if (expires.tv64 < 0) 510 if (expires.tv64 < 0)
510 expires.tv64 = 0; 511 expires.tv64 = 0;
511 if (expires.tv64 < cpu_base->expires_next.tv64) 512 if (expires.tv64 < expires_next.tv64)
512 cpu_base->expires_next = expires; 513 expires_next = expires;
513 } 514 }
514 515
516 if (skip_equal && expires_next.tv64 == cpu_base->expires_next.tv64)
517 return;
518
519 cpu_base->expires_next.tv64 = expires_next.tv64;
520
515 if (cpu_base->expires_next.tv64 != KTIME_MAX) 521 if (cpu_base->expires_next.tv64 != KTIME_MAX)
516 tick_program_event(cpu_base->expires_next, 1); 522 tick_program_event(cpu_base->expires_next, 1);
517} 523}
@@ -594,7 +600,7 @@ static void retrigger_next_event(void *arg)
594 base->clock_base[CLOCK_REALTIME].offset = 600 base->clock_base[CLOCK_REALTIME].offset =
595 timespec_to_ktime(realtime_offset); 601 timespec_to_ktime(realtime_offset);
596 602
597 hrtimer_force_reprogram(base); 603 hrtimer_force_reprogram(base, 0);
598 spin_unlock(&base->lock); 604 spin_unlock(&base->lock);
599} 605}
600 606
@@ -707,7 +713,8 @@ static int hrtimer_switch_to_hres(void)
707static inline int hrtimer_hres_active(void) { return 0; } 713static inline int hrtimer_hres_active(void) { return 0; }
708static inline int hrtimer_is_hres_enabled(void) { return 0; } 714static inline int hrtimer_is_hres_enabled(void) { return 0; }
709static inline int hrtimer_switch_to_hres(void) { return 0; } 715static inline int hrtimer_switch_to_hres(void) { return 0; }
710static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { } 716static inline void
717hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { }
711static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, 718static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
712 struct hrtimer_clock_base *base, 719 struct hrtimer_clock_base *base,
713 int wakeup) 720 int wakeup)
@@ -850,19 +857,29 @@ static void __remove_hrtimer(struct hrtimer *timer,
850 struct hrtimer_clock_base *base, 857 struct hrtimer_clock_base *base,
851 unsigned long newstate, int reprogram) 858 unsigned long newstate, int reprogram)
852{ 859{
853 if (timer->state & HRTIMER_STATE_ENQUEUED) { 860 if (!(timer->state & HRTIMER_STATE_ENQUEUED))
854 /* 861 goto out;
855 * Remove the timer from the rbtree and replace the 862
856 * first entry pointer if necessary. 863 /*
857 */ 864 * Remove the timer from the rbtree and replace the first
858 if (base->first == &timer->node) { 865 * entry pointer if necessary.
859 base->first = rb_next(&timer->node); 866 */
860 /* Reprogram the clock event device. if enabled */ 867 if (base->first == &timer->node) {
861 if (reprogram && hrtimer_hres_active()) 868 base->first = rb_next(&timer->node);
862 hrtimer_force_reprogram(base->cpu_base); 869#ifdef CONFIG_HIGH_RES_TIMERS
870 /* Reprogram the clock event device. if enabled */
871 if (reprogram && hrtimer_hres_active()) {
872 ktime_t expires;
873
874 expires = ktime_sub(hrtimer_get_expires(timer),
875 base->offset);
876 if (base->cpu_base->expires_next.tv64 == expires.tv64)
877 hrtimer_force_reprogram(base->cpu_base, 1);
863 } 878 }
864 rb_erase(&timer->node, &base->active); 879#endif
865 } 880 }
881 rb_erase(&timer->node, &base->active);
882out:
866 timer->state = newstate; 883 timer->state = newstate;
867} 884}
868 885