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/

Reply via email to