On Mon, Aug 10, 2015 at 04:28:47PM +0200, Peter Zijlstra wrote: > On Mon, Aug 10, 2015 at 04:16:58PM +0200, Frederic Weisbecker wrote: > > > I considered many times relying on hrtick btw but everyone seem to say it > > has a lot > > of overhead, especially due to clock reprogramming on schedule() calls. > > Yeah, I have some vague ideas of how to take out much of that overhead > (tglx will launch frozen sharks at me I suspect), but we cannot get > around the overhead of actually having to program the hardware and that > is still a significant amount on many machines. > > Supposedly machines with TSC deadline are better, but I've not tried > to benchmark that.
Basically something along these lines.. which avoids a whole bunch of hrtimer stuff. But without fast hardware its all still pointless. diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 76dd4f0da5ca..c279950cb8c3 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -200,6 +200,7 @@ struct hrtimer_cpu_base { unsigned int nr_retries; unsigned int nr_hangs; unsigned int max_hang_time; + ktime_t expires_sched; #endif struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; } ____cacheline_aligned; diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 5c7ae4b641c4..be9c0a555eaa 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -68,6 +68,7 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) = { .lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock), .seq = SEQCNT_ZERO(hrtimer_bases.seq), + .expires_sched = { .tv64 = KTIME_MAX, }, .clock_base = { { @@ -460,7 +461,7 @@ static inline void hrtimer_update_next_timer(struct hrtimer_cpu_base *cpu_base, static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base) { struct hrtimer_clock_base *base = cpu_base->clock_base; - ktime_t expires, expires_next = { .tv64 = KTIME_MAX }; + ktime_t expires, expires_next = cpu_base->expires_sched; unsigned int active = cpu_base->active_bases; hrtimer_update_next_timer(cpu_base, NULL); @@ -1289,6 +1290,33 @@ static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now) #ifdef CONFIG_HIGH_RES_TIMERS +void sched_hrtick_set(u64 ns) +{ + struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); + ktime_t expires = ktime_add_ns(ktime_get(), ns); + + raw_spin_lock(&cpu_base->lock); + cpu_base->expires_sched = expires; + + if (expires.tv64 < cpu_base->expires_next.tv64) + hrtimer_force_reprogram(cpu_base, 0); + + raw_spin_unlock(&cpu_base->lock); +} + +void sched_hrtick_cancel(void) +{ + struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); + + raw_spin_lock(&cpu_base->lock); + /* + * If the current event was this sched event, eat the superfluous + * interrupt rather than touch the hardware again. + */ + cpu_base->expires_sched.tv64 = KTIME_MAX; + raw_spin_unlock(&cpu_base->lock); +} + /* * High resolution timer interrupt * Called with interrupts disabled @@ -1316,6 +1344,13 @@ void hrtimer_interrupt(struct clock_event_device *dev) */ cpu_base->expires_next.tv64 = KTIME_MAX; + if (cpu_base->expires_sched.tv64 < now.tv64) { + cpu_base->expires_sched.tv64 = KTIME_MAX; + raw_spin_unlock(&cpu_base->lock); + scheduler_hrtick(); + raw_spin_lock(&cpu_base->lock); + } + __hrtimer_run_queues(cpu_base, now); /* Reevaluate the clock bases for the next expiry */ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/