mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
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>
This commit is contained in:
parent
12e09337fe
commit
7403f41f19
1 changed files with 35 additions and 18 deletions
|
@ -486,13 +486,14 @@ static inline int hrtimer_hres_active(void)
|
||||||
* next event
|
* next event
|
||||||
* Called with interrupts disabled and base->lock held
|
* Called with interrupts disabled and base->lock held
|
||||||
*/
|
*/
|
||||||
static void hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base)
|
static void
|
||||||
|
hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct hrtimer_clock_base *base = cpu_base->clock_base;
|
struct hrtimer_clock_base *base = cpu_base->clock_base;
|
||||||
ktime_t expires;
|
ktime_t expires, expires_next;
|
||||||
|
|
||||||
cpu_base->expires_next.tv64 = KTIME_MAX;
|
expires_next.tv64 = KTIME_MAX;
|
||||||
|
|
||||||
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++, base++) {
|
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++, base++) {
|
||||||
struct hrtimer *timer;
|
struct hrtimer *timer;
|
||||||
|
@ -508,10 +509,15 @@ static void hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base)
|
||||||
*/
|
*/
|
||||||
if (expires.tv64 < 0)
|
if (expires.tv64 < 0)
|
||||||
expires.tv64 = 0;
|
expires.tv64 = 0;
|
||||||
if (expires.tv64 < cpu_base->expires_next.tv64)
|
if (expires.tv64 < expires_next.tv64)
|
||||||
cpu_base->expires_next = expires;
|
expires_next = expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skip_equal && expires_next.tv64 == cpu_base->expires_next.tv64)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cpu_base->expires_next.tv64 = expires_next.tv64;
|
||||||
|
|
||||||
if (cpu_base->expires_next.tv64 != KTIME_MAX)
|
if (cpu_base->expires_next.tv64 != KTIME_MAX)
|
||||||
tick_program_event(cpu_base->expires_next, 1);
|
tick_program_event(cpu_base->expires_next, 1);
|
||||||
}
|
}
|
||||||
|
@ -594,7 +600,7 @@ static void retrigger_next_event(void *arg)
|
||||||
base->clock_base[CLOCK_REALTIME].offset =
|
base->clock_base[CLOCK_REALTIME].offset =
|
||||||
timespec_to_ktime(realtime_offset);
|
timespec_to_ktime(realtime_offset);
|
||||||
|
|
||||||
hrtimer_force_reprogram(base);
|
hrtimer_force_reprogram(base, 0);
|
||||||
spin_unlock(&base->lock);
|
spin_unlock(&base->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,7 +713,8 @@ static int hrtimer_switch_to_hres(void)
|
||||||
static inline int hrtimer_hres_active(void) { return 0; }
|
static inline int hrtimer_hres_active(void) { return 0; }
|
||||||
static inline int hrtimer_is_hres_enabled(void) { return 0; }
|
static inline int hrtimer_is_hres_enabled(void) { return 0; }
|
||||||
static inline int hrtimer_switch_to_hres(void) { return 0; }
|
static inline int hrtimer_switch_to_hres(void) { return 0; }
|
||||||
static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { }
|
static inline void
|
||||||
|
hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { }
|
||||||
static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
|
static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
|
||||||
struct hrtimer_clock_base *base,
|
struct hrtimer_clock_base *base,
|
||||||
int wakeup)
|
int wakeup)
|
||||||
|
@ -850,19 +857,29 @@ static void __remove_hrtimer(struct hrtimer *timer,
|
||||||
struct hrtimer_clock_base *base,
|
struct hrtimer_clock_base *base,
|
||||||
unsigned long newstate, int reprogram)
|
unsigned long newstate, int reprogram)
|
||||||
{
|
{
|
||||||
if (timer->state & HRTIMER_STATE_ENQUEUED) {
|
if (!(timer->state & HRTIMER_STATE_ENQUEUED))
|
||||||
/*
|
goto out;
|
||||||
* Remove the timer from the rbtree and replace the
|
|
||||||
* first entry pointer if necessary.
|
/*
|
||||||
*/
|
* Remove the timer from the rbtree and replace the first
|
||||||
if (base->first == &timer->node) {
|
* entry pointer if necessary.
|
||||||
base->first = rb_next(&timer->node);
|
*/
|
||||||
/* Reprogram the clock event device. if enabled */
|
if (base->first == &timer->node) {
|
||||||
if (reprogram && hrtimer_hres_active())
|
base->first = rb_next(&timer->node);
|
||||||
hrtimer_force_reprogram(base->cpu_base);
|
#ifdef CONFIG_HIGH_RES_TIMERS
|
||||||
|
/* Reprogram the clock event device. if enabled */
|
||||||
|
if (reprogram && hrtimer_hres_active()) {
|
||||||
|
ktime_t expires;
|
||||||
|
|
||||||
|
expires = ktime_sub(hrtimer_get_expires(timer),
|
||||||
|
base->offset);
|
||||||
|
if (base->cpu_base->expires_next.tv64 == expires.tv64)
|
||||||
|
hrtimer_force_reprogram(base->cpu_base, 1);
|
||||||
}
|
}
|
||||||
rb_erase(&timer->node, &base->active);
|
#endif
|
||||||
}
|
}
|
||||||
|
rb_erase(&timer->node, &base->active);
|
||||||
|
out:
|
||||||
timer->state = newstate;
|
timer->state = newstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue