Disable stopping of the idle tick when having live cputime
event. When the tick is disabled, the idle counts are out
of date until next tick/update and perf cputime PMU provides
misleading counts.

Signed-off-by: Jiri Olsa <jo...@kernel.org>
---
 include/linux/perf_event.h |  1 +
 kernel/events/cputime.c    | 13 +++++++++++++
 kernel/time/tick-sched.c   |  4 ++++
 3 files changed, 18 insertions(+)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index aa9eaab370be..ba61d2f9602a 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1407,4 +1407,5 @@ int perf_event_exit_cpu(unsigned int cpu);
 #define perf_event_exit_cpu    NULL
 #endif
 
+bool has_cputime_event(int cpu);
 #endif /* _LINUX_PERF_EVENT_H */
diff --git a/kernel/events/cputime.c b/kernel/events/cputime.c
index efad24543f13..32d3cde0047e 100644
--- a/kernel/events/cputime.c
+++ b/kernel/events/cputime.c
@@ -1,6 +1,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/sched.h>
 #include <linux/perf_event.h>
+#include <linux/tick.h>
 
 enum perf_cputime_id {
        PERF_CPUTIME_USER,
@@ -16,6 +17,13 @@ enum perf_cputime_id {
        PERF_CPUTIME_MAX,
 };
 
+static DEFINE_PER_CPU(int, has_cputime);
+
+bool has_cputime_event(int cpu)
+{
+       return per_cpu(has_cputime, cpu) != 0;
+}
+
 static enum cpu_usage_stat map[PERF_CPUTIME_MAX] = {
        [PERF_CPUTIME_USER]             = CPUTIME_USER,
        [PERF_CPUTIME_NICE]             = CPUTIME_NICE,
@@ -143,12 +151,17 @@ static int cputime_event_add(struct perf_event *event, 
int flags)
        if (flags & PERF_EF_START)
                cputime_event_start(event, flags);
 
+       if (event->hw.config == PERF_CPUTIME_IDLE)
+               tick_nohz_idle_restart_tick();
+
+       this_cpu_inc(has_cputime);
        return 0;
 }
 
 static void cputime_event_del(struct perf_event *event, int flags)
 {
        cputime_event_stop(event, PERF_EF_UPDATE);
+       this_cpu_dec(has_cputime);
 }
 
 static void perf_cputime_read(struct perf_event *event)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index da9455a6b42b..1c105bc2a92e 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -28,6 +28,7 @@
 #include <linux/posix-timers.h>
 #include <linux/context_tracking.h>
 #include <linux/mm.h>
+#include <linux/perf_event.h>
 
 #include <asm/irq_regs.h>
 
@@ -912,6 +913,9 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched 
*ts)
                        return false;
        }
 
+       if (has_cputime_event(cpu))
+               return false;
+
        return true;
 }
 
-- 
2.13.6

Reply via email to