[RFC/RFT][PATCH v2 6/6] time: tick-sched: Avoid running the same code twice in a row

2018-03-06 Thread Rafael J. Wysocki
From: Rafael J. Wysocki 

To avoid running the same piece of code twice in a row, move the
tick stopping part of __tick_nohz_next_event() into a new function
called __tick_nohz_stop_tick() and invoke them both separately.

Make __tick_nohz_idle_enter() avoid calling __tick_nohz_next_event()
if it has been called already by tick_nohz_get_sleep_length() and
use the new next_idle_tick field in struct tick_sched to pass the
next event time value between tick_nohz_get_sleep_length() and
__tick_nohz_idle_enter().

Signed-off-by: Rafael J. Wysocki 
---

-> v2: No changes.

---
 kernel/time/tick-sched.c |  130 ++-
 kernel/time/tick-sched.h |1 
 2 files changed, 73 insertions(+), 58 deletions(-)

Index: linux-pm/kernel/time/tick-sched.c
===
--- linux-pm.orig/kernel/time/tick-sched.c
+++ linux-pm/kernel/time/tick-sched.c
@@ -655,13 +655,10 @@ static inline bool local_timer_softirq_p
return local_softirq_pending() & TIMER_SOFTIRQ;
 }
 
-static ktime_t __tick_nohz_next_event(struct tick_sched *ts, int cpu,
- bool stop_tick)
+static ktime_t __tick_nohz_next_event(struct tick_sched *ts, int cpu)
 {
-   struct clock_event_device *dev = 
__this_cpu_read(tick_cpu_device.evtdev);
u64 basemono, next_tick, next_tmr, next_rcu, delta, expires;
unsigned long seq, basejiff;
-   ktime_t tick;
 
/* Read jiffies and the time when jiffies were updated last */
do {
@@ -714,34 +711,23 @@ static ktime_t __tick_nohz_next_event(st
 * We've not stopped the tick yet, and there's a timer in the
 * next period, so no point in stopping it either, bail.
 */
-   if (!ts->tick_stopped) {
-   tick = 0;
-   goto out;
-   }
+   if (!ts->tick_stopped)
+   return 0;
}
 
/*
-* If this CPU is the one which updates jiffies, then give up
-* the assignment and let it be taken by the CPU which runs
-* the tick timer next, which might be this CPU as well. If we
-* don't drop this here the jiffies might be stale and
-* do_timer() never invoked. Keep track of the fact that it
-* was the one which had the do_timer() duty last. If this CPU
-* is the one which had the do_timer() duty last, we limit the
-* sleep time to the timekeeping max_deferment value.
+* If this CPU is the one which had the do_timer() duty last, we limit
+* the sleep time to the timekeeping max_deferment value.
 * Otherwise we can sleep as long as we want.
 */
delta = timekeeping_max_deferment();
-   if (cpu == tick_do_timer_cpu) {
-   if (stop_tick) {
-   tick_do_timer_cpu = TICK_DO_TIMER_NONE;
-   ts->do_timer_last = 1;
+   if (cpu != tick_do_timer_cpu) {
+   if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) {
+   delta = KTIME_MAX;
+   ts->do_timer_last = 0;
+   } else if (!ts->do_timer_last) {
+   delta = KTIME_MAX;
}
-   } else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) {
-   delta = KTIME_MAX;
-   ts->do_timer_last = 0;
-   } else if (!ts->do_timer_last) {
-   delta = KTIME_MAX;
}
 
 #ifdef CONFIG_NO_HZ_FULL
@@ -756,24 +742,37 @@ static ktime_t __tick_nohz_next_event(st
else
expires = KTIME_MAX;
 
-   expires = min_t(u64, expires, next_tick);
-   tick = expires;
+   ts->next_idle_tick = min_t(u64, expires, next_tick);
+   return ts->next_idle_tick;
+}
 
-   if (!stop_tick) {
-   /* Undo the effect of get_next_timer_interrupt(). */
-   timer_clear_idle();
-   goto out;
+static void __tick_nohz_stop_tick(struct tick_sched *ts, int cpu, u64 expires)
+{
+   struct clock_event_device *dev = 
__this_cpu_read(tick_cpu_device.evtdev);
+   ktime_t tick = expires;
+
+   /*
+* If this CPU is the one which updates jiffies, then give up
+* the assignment and let it be taken by the CPU which runs
+* the tick timer next, which might be this CPU as well. If we
+* don't drop this here the jiffies might be stale and
+* do_timer() never invoked. Keep track of the fact that it
+* was the one which had the do_timer() duty last.
+*/
+   if (cpu == tick_do_timer_cpu) {
+   tick_do_timer_cpu = TICK_DO_TIMER_NONE;
+   ts->do_timer_last = 1;
}
 
/* Skip reprogram of event if its not changed */
if (ts->tick_stopped && (expires == ts->next_tick)) {
/* Sanity check: make sure clockevent is 

[RFC/RFT][PATCH v2 6/6] time: tick-sched: Avoid running the same code twice in a row

2018-03-06 Thread Rafael J. Wysocki
From: Rafael J. Wysocki 

To avoid running the same piece of code twice in a row, move the
tick stopping part of __tick_nohz_next_event() into a new function
called __tick_nohz_stop_tick() and invoke them both separately.

Make __tick_nohz_idle_enter() avoid calling __tick_nohz_next_event()
if it has been called already by tick_nohz_get_sleep_length() and
use the new next_idle_tick field in struct tick_sched to pass the
next event time value between tick_nohz_get_sleep_length() and
__tick_nohz_idle_enter().

Signed-off-by: Rafael J. Wysocki 
---

-> v2: No changes.

---
 kernel/time/tick-sched.c |  130 ++-
 kernel/time/tick-sched.h |1 
 2 files changed, 73 insertions(+), 58 deletions(-)

Index: linux-pm/kernel/time/tick-sched.c
===
--- linux-pm.orig/kernel/time/tick-sched.c
+++ linux-pm/kernel/time/tick-sched.c
@@ -655,13 +655,10 @@ static inline bool local_timer_softirq_p
return local_softirq_pending() & TIMER_SOFTIRQ;
 }
 
-static ktime_t __tick_nohz_next_event(struct tick_sched *ts, int cpu,
- bool stop_tick)
+static ktime_t __tick_nohz_next_event(struct tick_sched *ts, int cpu)
 {
-   struct clock_event_device *dev = 
__this_cpu_read(tick_cpu_device.evtdev);
u64 basemono, next_tick, next_tmr, next_rcu, delta, expires;
unsigned long seq, basejiff;
-   ktime_t tick;
 
/* Read jiffies and the time when jiffies were updated last */
do {
@@ -714,34 +711,23 @@ static ktime_t __tick_nohz_next_event(st
 * We've not stopped the tick yet, and there's a timer in the
 * next period, so no point in stopping it either, bail.
 */
-   if (!ts->tick_stopped) {
-   tick = 0;
-   goto out;
-   }
+   if (!ts->tick_stopped)
+   return 0;
}
 
/*
-* If this CPU is the one which updates jiffies, then give up
-* the assignment and let it be taken by the CPU which runs
-* the tick timer next, which might be this CPU as well. If we
-* don't drop this here the jiffies might be stale and
-* do_timer() never invoked. Keep track of the fact that it
-* was the one which had the do_timer() duty last. If this CPU
-* is the one which had the do_timer() duty last, we limit the
-* sleep time to the timekeeping max_deferment value.
+* If this CPU is the one which had the do_timer() duty last, we limit
+* the sleep time to the timekeeping max_deferment value.
 * Otherwise we can sleep as long as we want.
 */
delta = timekeeping_max_deferment();
-   if (cpu == tick_do_timer_cpu) {
-   if (stop_tick) {
-   tick_do_timer_cpu = TICK_DO_TIMER_NONE;
-   ts->do_timer_last = 1;
+   if (cpu != tick_do_timer_cpu) {
+   if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) {
+   delta = KTIME_MAX;
+   ts->do_timer_last = 0;
+   } else if (!ts->do_timer_last) {
+   delta = KTIME_MAX;
}
-   } else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) {
-   delta = KTIME_MAX;
-   ts->do_timer_last = 0;
-   } else if (!ts->do_timer_last) {
-   delta = KTIME_MAX;
}
 
 #ifdef CONFIG_NO_HZ_FULL
@@ -756,24 +742,37 @@ static ktime_t __tick_nohz_next_event(st
else
expires = KTIME_MAX;
 
-   expires = min_t(u64, expires, next_tick);
-   tick = expires;
+   ts->next_idle_tick = min_t(u64, expires, next_tick);
+   return ts->next_idle_tick;
+}
 
-   if (!stop_tick) {
-   /* Undo the effect of get_next_timer_interrupt(). */
-   timer_clear_idle();
-   goto out;
+static void __tick_nohz_stop_tick(struct tick_sched *ts, int cpu, u64 expires)
+{
+   struct clock_event_device *dev = 
__this_cpu_read(tick_cpu_device.evtdev);
+   ktime_t tick = expires;
+
+   /*
+* If this CPU is the one which updates jiffies, then give up
+* the assignment and let it be taken by the CPU which runs
+* the tick timer next, which might be this CPU as well. If we
+* don't drop this here the jiffies might be stale and
+* do_timer() never invoked. Keep track of the fact that it
+* was the one which had the do_timer() duty last.
+*/
+   if (cpu == tick_do_timer_cpu) {
+   tick_do_timer_cpu = TICK_DO_TIMER_NONE;
+   ts->do_timer_last = 1;
}
 
/* Skip reprogram of event if its not changed */
if (ts->tick_stopped && (expires == ts->next_tick)) {
/* Sanity check: make sure clockevent is actually programmed */
if (tick ==