summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sched.h17
-rw-r--r--kernel/sched_clock.c39
-rw-r--r--kernel/time/tick-sched.c2
3 files changed, 56 insertions, 2 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c5d3f847ca8..33a8f42041f 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1573,13 +1573,28 @@ static inline void sched_clock_idle_sleep_event(void)
static inline void sched_clock_idle_wakeup_event(u64 delta_ns)
{
}
-#else
+
+#ifdef CONFIG_NO_HZ
+static inline void sched_clock_tick_stop(int cpu)
+{
+}
+
+static inline void sched_clock_tick_start(int cpu)
+{
+}
+#endif
+
+#else /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */
extern void sched_clock_init(void);
extern u64 sched_clock_cpu(int cpu);
extern void sched_clock_tick(void);
extern void sched_clock_idle_sleep_event(void);
extern void sched_clock_idle_wakeup_event(u64 delta_ns);
+#ifdef CONFIG_NO_HZ
+extern void sched_clock_tick_stop(int cpu);
+extern void sched_clock_tick_start(int cpu);
#endif
+#endif /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */
/*
* For kernel-internal use: high-speed (but slightly incorrect) per-cpu
diff --git a/kernel/sched_clock.c b/kernel/sched_clock.c
index 42b81fa38cb..97159e225a7 100644
--- a/kernel/sched_clock.c
+++ b/kernel/sched_clock.c
@@ -45,6 +45,9 @@ struct sched_clock_data {
u64 tick_raw;
u64 tick_gtod;
u64 clock;
+#ifdef CONFIG_NO_HZ
+ int check_max;
+#endif
};
static DEFINE_PER_CPU_SHARED_ALIGNED(struct sched_clock_data, sched_clock_data);
@@ -76,11 +79,45 @@ void sched_clock_init(void)
scd->tick_raw = 0;
scd->tick_gtod = ktime_now;
scd->clock = ktime_now;
+#ifdef CONFIG_NO_HZ
+ scd->check_max = 1;
+#endif
}
sched_clock_running = 1;
}
+#ifdef CONFIG_NO_HZ
+/*
+ * The dynamic ticks makes the delta jiffies inaccurate. This
+ * prevents us from checking the maximum time update.
+ * Disable the maximum check during stopped ticks.
+ */
+void sched_clock_tick_stop(int cpu)
+{
+ struct sched_clock_data *scd = cpu_sdc(cpu);
+
+ scd->check_max = 0;
+}
+
+void sched_clock_tick_start(int cpu)
+{
+ struct sched_clock_data *scd = cpu_sdc(cpu);
+
+ scd->check_max = 1;
+}
+
+static int check_max(struct sched_clock_data *scd)
+{
+ return scd->check_max;
+}
+#else
+static int check_max(struct sched_clock_data *scd)
+{
+ return 1;
+}
+#endif /* CONFIG_NO_HZ */
+
/*
* update the percpu scd from the raw @now value
*
@@ -112,7 +149,7 @@ static void __update_sched_clock(struct sched_clock_data *scd, u64 now)
*/
max_clock = scd->tick_gtod + (2 + delta_jiffies) * TICK_NSEC;
- if (unlikely(clock + delta > max_clock)) {
+ if (unlikely(clock + delta > max_clock) && check_max(scd)) {
if (clock < max_clock)
clock = max_clock;
else
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index b854a895591..d63008b09a4 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -276,6 +276,7 @@ void tick_nohz_stop_sched_tick(void)
ts->tick_stopped = 1;
ts->idle_jiffies = last_jiffies;
rcu_enter_nohz();
+ sched_clock_tick_stop(cpu);
}
/*
@@ -375,6 +376,7 @@ void tick_nohz_restart_sched_tick(void)
select_nohz_load_balancer(0);
now = ktime_get();
tick_do_update_jiffies64(now);
+ sched_clock_tick_start(cpu);
cpu_clear(cpu, nohz_cpu_mask);
/*