From 6cdae6bbe10117b11b90f35285951e978fb17767 Mon Sep 17 00:00:00 2001 From: Brendan Jackman Date: Tue, 1 Nov 2016 18:21:49 +0000 Subject: [PATCH] ftrace: Poke all CPUs for cpu_idle events before collecting trace On some systems CPUs sometimes remain idle for several seconds. If a trace capture begins during one of these long idle periods, that CPU's idle state is unknown (in practice it is probably in its deepest available state from cpuidle's perspective but that can't be known for sure). The solution to the equivalent problem for cpufreq is to read the current frequencies from sysfs and inject artificial cpu_frequency events using trace_marker (see cpu_freq_trace_all_frequencies in bin/scripts/shutils.in). However we can't read the current idle state from sysfs. Instead, wake up each CPU by executing the "true" command on it via taskset. --- devlib/bin/scripts/shutils.in | 15 +++++++++++++++ devlib/module/cpuidle.py | 6 ++++++ devlib/trace/ftrace.py | 3 +++ 3 files changed, 24 insertions(+) diff --git a/devlib/bin/scripts/shutils.in b/devlib/bin/scripts/shutils.in index 799461f..b95ad2e 100755 --- a/devlib/bin/scripts/shutils.in +++ b/devlib/bin/scripts/shutils.in @@ -46,6 +46,18 @@ cpufreq_trace_all_frequencies() { done } +################################################################################ +# CPUIdle Utility Functions +################################################################################ + +cpuidle_wake_all_cpus() { + CPU_PATHS=/sys/devices/system/cpu/cpu[0-9]* + MASK=0x1; for F in $CPU_PATHS; do + $BUSYBOX taskset $MASK true + MASK=$($BUSYBOX printf '0x%x' $((MASK * 2))) + done +} + ################################################################################ # FTrace Utility Functions ################################################################################ @@ -185,6 +197,9 @@ cpufreq_get_all_governors) cpufreq_trace_all_frequencies) cpufreq_trace_all_frequencies $* ;; +cpuidle_wake_all_cpus) + cpuidle_wake_all_cpus $* + ;; cgroups_get_attributes) cgroups_get_attributes $* ;; diff --git a/devlib/module/cpuidle.py b/devlib/module/cpuidle.py index 1ac06ff..3f1938d 100644 --- a/devlib/module/cpuidle.py +++ b/devlib/module/cpuidle.py @@ -152,3 +152,9 @@ class Cpuidle(Module): for state in self.get_states(cpu): state.disable() + def perturb_cpus(self): + """ + Momentarily wake each CPU. Ensures cpu_idle events in trace file. + """ + output = self.target._execute_util('cpuidle_wake_all_cpus') + print(output) diff --git a/devlib/trace/ftrace.py b/devlib/trace/ftrace.py index a40a5f4..7affed5 100644 --- a/devlib/trace/ftrace.py +++ b/devlib/trace/ftrace.py @@ -170,6 +170,9 @@ class FtraceCollector(TraceCollector): if 'cpufreq' in self.target.modules: self.logger.debug('Trace CPUFreq frequencies') self.target.cpufreq.trace_frequencies() + if 'cpuidle' in self.target.modules: + self.logger.debug('Trace CPUIdle states') + self.target.cpuidle.perturb_cpus() # Enable kernel function profiling if self.functions: self.target.execute('echo nop > {}'.format(self.current_tracer_file),