Re: [PATCH 07/10] sched: Migrate sched to use new tick dependency mask model

From: Peter Zijlstra
Date: Mon Aug 10 2015 - 11:12:12 EST


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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/