1
0
mirror of https://github.com/ARM-software/devlib.git synced 2024-10-05 18:30:50 +01:00

ftrace: Add write-to-disk mode

Allow using trace-cmd record that continuously dump the trace to disk,
allowing to overcome the buffer size limitations when recording for
extended periods of time.
This commit is contained in:
Douglas Raillard 2024-05-30 14:59:03 +01:00
parent 50e7a40c32
commit 8d55c17cd1

View File

@ -21,6 +21,7 @@ import subprocess
import sys import sys
import contextlib import contextlib
from shlex import quote from shlex import quote
import signal
from devlib.collector import (CollectorBase, CollectorOutput, from devlib.collector import (CollectorBase, CollectorOutput,
CollectorOutputEntry) CollectorOutputEntry)
@ -71,6 +72,7 @@ class FtraceCollector(CollectorBase):
report_on_target=False, report_on_target=False,
trace_clock='local', trace_clock='local',
saved_cmdlines_nr=4096, saved_cmdlines_nr=4096,
mode='write-to-memory',
): ):
super(FtraceCollector, self).__init__(target) super(FtraceCollector, self).__init__(target)
self.events = events if events is not None else DEFAULT_EVENTS self.events = events if events is not None else DEFAULT_EVENTS
@ -98,6 +100,8 @@ class FtraceCollector(CollectorBase):
self.trace_clock = trace_clock self.trace_clock = trace_clock
self.saved_cmdlines_nr = saved_cmdlines_nr self.saved_cmdlines_nr = saved_cmdlines_nr
self._reset_needed = True self._reset_needed = True
self.mode = mode
self._bg_cmd = None
# pylint: disable=bad-whitespace # pylint: disable=bad-whitespace
# Setup tracing paths # Setup tracing paths
@ -276,18 +280,33 @@ class FtraceCollector(CollectorBase):
with contextlib.suppress(TargetStableError): with contextlib.suppress(TargetStableError):
self.target.write_value('/proc/sys/kernel/kptr_restrict', 0) self.target.write_value('/proc/sys/kernel/kptr_restrict', 0)
self.target.execute( params = '-B devlib {buffer_size} {cmdlines_size} {clock} {events} {tracer} {functions}'.format(
'{} start -B devlib {buffer_size} {cmdlines_size} {clock} {events} {tracer} {functions}'.format( events=self.event_string,
self.target_binary, tracer=tracer_string,
events=self.event_string, functions=tracecmd_functions,
tracer=tracer_string, buffer_size='-b {}'.format(self.buffer_size) if self.buffer_size is not None else '',
functions=tracecmd_functions, clock='-C {}'.format(self.trace_clock) if self.trace_clock else '',
buffer_size='-b {}'.format(self.buffer_size) if self.buffer_size is not None else '', cmdlines_size='--cmdlines-size {}'.format(self.saved_cmdlines_nr) if self.saved_cmdlines_nr is not None else '',
clock='-C {}'.format(self.trace_clock) if self.trace_clock else '',
cmdlines_size='--cmdlines-size {}'.format(self.saved_cmdlines_nr) if self.saved_cmdlines_nr is not None else '',
),
as_root=True,
) )
mode = self.mode
if mode == 'write-to-disk':
bg_cmd = self.target.background(
# cd into the working_directory first to workaround this issue:
# https://lore.kernel.org/linux-trace-devel/20240119162743.1a107fa9@gandalf.local.home/
f'cd {self.target.working_directory} && devlib-signal-target {self.target_binary} record -o {quote(self.target_output_file)} {params}',
as_root=True,
)
assert self._bg_cmd is None
self._bg_cmd = bg_cmd.__enter__()
elif mode == 'write-to-memory':
self.target.execute(
f'{self.target_binary} start {params}',
as_root=True,
)
else:
raise ValueError(f'Unknown mode {mode}')
if self.automark: if self.automark:
self.mark_start() self.mark_start()
if 'cpufreq' in self.target.modules: if 'cpufreq' in self.target.modules:
@ -322,8 +341,21 @@ class FtraceCollector(CollectorBase):
self.stop_time = time.time() self.stop_time = time.time()
if self.automark: if self.automark:
self.mark_stop() self.mark_stop()
self.target.execute('{} stop -B devlib'.format(self.target_binary),
timeout=TIMEOUT, as_root=True) mode = self.mode
if mode == 'write-to-disk':
bg_cmd = self._bg_cmd
self._bg_cmd = None
assert bg_cmd is not None
bg_cmd.send_signal(signal.SIGINT)
bg_cmd.communicate()
bg_cmd.__exit__(None, None, None)
elif mode == 'write-to-memory':
self.target.execute('{} stop -B devlib'.format(self.target_binary),
timeout=TIMEOUT, as_root=True)
else:
raise ValueError(f'Unknown mode {mode}')
self._reset_needed = True self._reset_needed = True
def set_output(self, output_path): def set_output(self, output_path):
@ -334,9 +366,18 @@ class FtraceCollector(CollectorBase):
def get_data(self): def get_data(self):
if self.output_path is None: if self.output_path is None:
raise RuntimeError("Output path was not set.") raise RuntimeError("Output path was not set.")
self.target.execute('{0} extract -B devlib -o {1}; chmod 666 {1}'.format(self.target_binary,
self.target_output_file), busybox = quote(self.target.busybox)
timeout=TIMEOUT, as_root=True)
mode = self.mode
if mode == 'write-to-disk':
# Interrupting trace-cmd record will make it create the file
pass
elif mode == 'write-to-memory':
cmd = f'{self.target_binary} extract -B devlib -o {self.target_output_file} && {busybox} chmod 666 {self.target_output_file}'
self.target.execute(cmd, timeout=TIMEOUT, as_root=True)
else:
raise ValueError(f'Unknown mode {mode}')
# The size of trace.dat will depend on how long trace-cmd was running. # The size of trace.dat will depend on how long trace-cmd was running.
# Therefore timout for the pull command must also be adjusted # Therefore timout for the pull command must also be adjusted