diff --git a/devlib/bin/scripts/shutils.in b/devlib/bin/scripts/shutils.in index 0023a5e..9200b70 100755 --- a/devlib/bin/scripts/shutils.in +++ b/devlib/bin/scripts/shutils.in @@ -43,6 +43,18 @@ cpufreq_trace_all_frequencies() { done } +################################################################################ +# FTrace Utility Functions +################################################################################ + +ftrace_get_function_stats() { + for CPU in $(ls /sys/kernel/debug/tracing/trace_stat | sed 's/function//'); do + REPLACE_STRING="s/ Function/\n Function (CPU$CPU)/" + cat /sys/kernel/debug/tracing/trace_stat/function$CPU \ + | sed "$REPLACE_STRING" + done +} + ################################################################################ # Main Function Dispatcher ################################################################################ @@ -63,6 +75,9 @@ cpufreq_get_all_governors) cpufreq_trace_all_frequencies) cpufreq_trace_all_frequencies $* ;; +ftrace_get_function_stats) + ftrace_get_function_stats + ;; *) echo "Command [$CMD] not supported" exit -1 diff --git a/devlib/trace/ftrace.py b/devlib/trace/ftrace.py index c521b00..a177efc 100644 --- a/devlib/trace/ftrace.py +++ b/devlib/trace/ftrace.py @@ -15,7 +15,9 @@ from __future__ import division import os +import json import time +import re import subprocess from devlib.trace import TraceCollector @@ -27,6 +29,7 @@ from devlib.utils.misc import check_output, which TRACE_MARKER_START = 'TRACE_MARKER_START' TRACE_MARKER_STOP = 'TRACE_MARKER_STOP' OUTPUT_TRACE_FILE = 'trace.dat' +OUTPUT_PROFILE_FILE = 'trace_stat.dat' DEFAULT_EVENTS = [ 'cpu_frequency', 'cpu_idle', @@ -40,6 +43,9 @@ DEFAULT_EVENTS = [ ] TIMEOUT = 180 +# Regexps for parsing of function profiling data +CPU_RE = re.compile(r' Function \(CPU([0-9]+)\)') +STATS_RE = re.compile(r'([^ ]*) +([0-9]+) +([0-9.]+) us +([0-9.]+) us +([0-9.]+) us') class FtraceCollector(TraceCollector): @@ -165,6 +171,44 @@ class FtraceCollector(TraceCollector): if self.autoview: self.view(outfile) + def get_stats(self, outfile): + if not self.functions: + return + + if os.path.isdir(outfile): + outfile = os.path.join(outfile, OUTPUT_PROFILE_FILE) + output = self.target._execute_util('ftrace_get_function_stats', + as_root=True) + + function_stats = {} + for line in output.splitlines(): + # Match a new CPU dataset + match = CPU_RE.search(line) + if match: + cpu_id = int(match.group(1)) + function_stats[cpu_id] = {} + self.logger.debug("Processing stats for CPU%d...", cpu_id) + continue + # Match a new function dataset + match = STATS_RE.search(line) + if match: + fname = match.group(1) + function_stats[cpu_id][fname] = { + 'hits' : int(match.group(2)), + 'time' : float(match.group(3)), + 'avg' : float(match.group(4)), + 's_2' : float(match.group(5)), + } + self.logger.debug(" %s: %s", + fname, function_stats[cpu_id][fname]) + + self.logger.debug("FTrace stats output [%s]...", outfile) + with open(outfile, 'w') as fh: + json.dump(function_stats, fh, indent=4) + self.logger.info("FTrace function stats save in [%s]", outfile) + + return function_stats + def report(self, binfile, destfile): # To get the output of trace.dat, trace-cmd must be installed # This is done host-side because the generated file is very large