1
0
mirror of https://github.com/ARM-software/devlib.git synced 2025-01-31 02:00:45 +00:00

devlib/collector: Update Collectors to implement collector interface

This commit is contained in:
Marc Bonnici 2019-12-05 13:37:55 +00:00
parent 15a77a841d
commit cf8ebf6668
6 changed files with 109 additions and 62 deletions

View File

@ -18,7 +18,8 @@ import re
from itertools import takewhile
from datetime import timedelta
from devlib.collector import CollectorBase
from devlib.collector import (CollectorBase, CollectorOutput,
CollectorOutputEntry)
class KernelLogEntry(object):
@ -151,6 +152,7 @@ class DmesgCollector(CollectorBase):
def __init__(self, target, level=LOG_LEVELS[-1], facility='kern'):
super(DmesgCollector, self).__init__(target)
self.output_path = None
if level not in self.LOG_LEVELS:
raise ValueError('level needs to be one of: {}'.format(
@ -195,6 +197,12 @@ class DmesgCollector(CollectorBase):
self.dmesg_out = self.target.execute(cmd)
def get_trace(self, outfile):
with open(outfile, 'wt') as f:
def set_output(self, output_path):
self.output_path = output_path
def get_data(self):
if self.output_path is None:
raise RuntimeError("Output path was not set.")
with open(self.output_path, 'wt') as f:
f.write(self.dmesg_out + '\n')
return CollectorOutput([CollectorOutputEntry(self.output_path, 'file')])

View File

@ -23,7 +23,8 @@ import sys
import contextlib
from pipes import quote
from devlib.collector import CollectorBase
from devlib.collector import (CollectorBase, CollectorOutput,
CollectorOutputEntry)
from devlib.host import PACKAGE_BIN_DIRECTORY
from devlib.exception import TargetStableError, HostError
from devlib.utils.misc import check_output, which, memoized
@ -86,6 +87,7 @@ class FtraceCollector(CollectorBase):
self.target_output_file = target.path.join(self.target.working_directory, OUTPUT_TRACE_FILE)
text_file_name = target.path.splitext(OUTPUT_TRACE_FILE)[0] + '.txt'
self.target_text_file = target.path.join(self.target.working_directory, text_file_name)
self.output_path = None
self.target_binary = None
self.host_binary = None
self.start_time = None
@ -300,9 +302,14 @@ class FtraceCollector(CollectorBase):
timeout=TIMEOUT, as_root=True)
self._reset_needed = True
def get_trace(self, outfile):
if os.path.isdir(outfile):
outfile = os.path.join(outfile, os.path.basename(self.target_output_file))
def set_output(self, output_path):
if os.path.isdir(output_path):
output_path = os.path.join(output_path, os.path.basename(self.target_output_file))
self.output_path = output_path
def get_data(self):
if self.output_path is None:
raise RuntimeError("Output path was not set.")
self.target.execute('{0} extract -o {1}; chmod 666 {1}'.format(self.target_binary,
self.target_output_file),
timeout=TIMEOUT, as_root=True)
@ -311,20 +318,24 @@ class FtraceCollector(CollectorBase):
# Therefore timout for the pull command must also be adjusted
# accordingly.
pull_timeout = 10 * (self.stop_time - self.start_time)
self.target.pull(self.target_output_file, outfile, timeout=pull_timeout)
if not os.path.isfile(outfile):
self.target.pull(self.target_output_file, self.output_path, timeout=pull_timeout)
output = CollectorOutput()
if not os.path.isfile(self.output_path):
self.logger.warning('Binary trace not pulled from device.')
else:
output.append(CollectorOutputEntry(self.output_path, 'file'))
if self.autoreport:
textfile = os.path.splitext(outfile)[0] + '.txt'
textfile = os.path.splitext(self.output_path)[0] + '.txt'
if self.report_on_target:
self.generate_report_on_target()
self.target.pull(self.target_text_file,
textfile, timeout=pull_timeout)
else:
self.report(outfile, textfile)
self.report(self.output_path, textfile)
output.append(CollectorOutputEntry(textfile, 'file'))
if self.autoview:
self.view(outfile)
self.view(self.output_path)
return output
def get_stats(self, outfile):
if not (self.functions and self.tracer is None):

View File

@ -16,7 +16,8 @@
import os
import shutil
from devlib.collector import CollectorBase
from devlib.collector import (CollectorBase, CollectorOutput,
CollectorOutputEntry)
from devlib.utils.android import LogcatMonitor
class LogcatCollector(CollectorBase):
@ -24,6 +25,7 @@ class LogcatCollector(CollectorBase):
def __init__(self, target, regexps=None):
super(LogcatCollector, self).__init__(target)
self.regexps = regexps
self.output_path = None
self._collecting = False
self._prev_log = None
self._monitor = None
@ -45,12 +47,14 @@ class LogcatCollector(CollectorBase):
"""
Start collecting logcat lines
"""
if self.output_path is None:
raise RuntimeError("Output path was not set.")
self._monitor = LogcatMonitor(self.target, self.regexps)
if self._prev_log:
# Append new data collection to previous collection
self._monitor.start(self._prev_log)
else:
self._monitor.start()
self._monitor.start(self.output_path)
self._collecting = True
@ -65,9 +69,10 @@ class LogcatCollector(CollectorBase):
self._collecting = False
self._prev_log = self._monitor.logfile
def get_trace(self, outfile):
"""
Output collected logcat lines to designated file
"""
# copy self._monitor.logfile to outfile
shutil.copy(self._monitor.logfile, outfile)
def set_output(self, output_path):
self.output_path = output_path
def get_data(self):
if self.output_path is None:
raise RuntimeError("No data collected.")
return CollectorOutput([CollectorOutputEntry(self.output_path, 'file')])

View File

@ -19,7 +19,8 @@ import time
from past.builtins import basestring, zip
from devlib.host import PACKAGE_BIN_DIRECTORY
from devlib.collector import CollectorBase
from devlib.collector import (CollectorBase, CollectorOutput,
CollectorOutputEntry)
from devlib.utils.misc import ensure_file_directory_exists as _f
@ -95,6 +96,7 @@ class PerfCollector(CollectorBase):
self.force_install = force_install
self.labels = labels
self.report_options = report_options
self.output_path = None
# Validate parameters
if isinstance(optionstring, list):
@ -148,14 +150,24 @@ class PerfCollector(CollectorBase):
self.target.killall('sleep', as_root=self.target.is_rooted)
# NB: we hope that no other "important" sleep is on-going
# pylint: disable=arguments-differ
def get_trace(self, outdir):
def set_output(self, output_path):
self.output_path = output_path
def get_data(self):
if self.output_path is None:
raise RuntimeError("Output path was not set.")
output = CollectorOutput()
for label in self.labels:
if self.command == 'record':
self._wait_for_data_file_write(label, outdir)
self._pull_target_file_to_host(label, 'rpt', outdir)
self._wait_for_data_file_write(label, self.output_path)
path = self._pull_target_file_to_host(label, 'rpt', self.output_path)
output.append(CollectorOutputEntry(path, 'file'))
else:
self._pull_target_file_to_host(label, 'out', outdir)
path = self._pull_target_file_to_host(label, 'out', self.output_path)
output.append(CollectorOutputEntry(path, 'file'))
return output
def _deploy_perf(self):
host_executable = os.path.join(PACKAGE_BIN_DIRECTORY,
@ -198,13 +210,14 @@ class PerfCollector(CollectorBase):
outfile=self._get_target_file(label, 'data'))
return command
def _pull_target_file_to_host(self, label, extension, outdir):
def _pull_target_file_to_host(self, label, extension, output_path):
target_file = self._get_target_file(label, extension)
host_relpath = os.path.basename(target_file)
host_file = _f(os.path.join(outdir, host_relpath))
host_file = _f(os.path.join(output_path, host_relpath))
self.target.pull(target_file, host_file)
return host_file
def _wait_for_data_file_write(self, label, outdir):
def _wait_for_data_file_write(self, label, output_path):
data_file_finished_writing = False
max_tries = 80
current_tries = 0

View File

@ -17,7 +17,8 @@ import shutil
from tempfile import NamedTemporaryFile
from pexpect.exceptions import TIMEOUT
from devlib.collector import CollectorBase
from devlib.collector import (CollectorBase, CollectorOutput,
CollectorOutputEntry)
from devlib.utils.serial_port import get_connection
@ -32,33 +33,35 @@ class SerialTraceCollector(CollectorBase):
self.serial_port = serial_port
self.baudrate = baudrate
self.timeout = timeout
self.output_path - None
self._serial_target = None
self._conn = None
self._tmpfile = None
self._outfile_fh = None
self._collecting = False
def reset(self):
if self._collecting:
raise RuntimeError("reset was called whilst collecting")
if self._tmpfile:
self._tmpfile.close()
self._tmpfile = None
if self._outfile_fh:
self._outfile_fh.close()
self._outfile_fh = None
def start(self):
if self._collecting:
raise RuntimeError("start was called whilst collecting")
if self.output_path is None:
raise RuntimeError("Output path was not set.")
self._tmpfile = NamedTemporaryFile()
self._outfile_fh = open(self.output_path, 'w')
start_marker = "-------- Starting serial logging --------\n"
self._tmpfile.write(start_marker.encode('utf-8'))
self._outfile_fh.write(start_marker.encode('utf-8'))
self._serial_target, self._conn = get_connection(port=self.serial_port,
baudrate=self.baudrate,
timeout=self.timeout,
logfile=self._tmpfile,
logfile=self._outfile_fh,
init_dtr=0)
self._collecting = True
@ -78,17 +81,19 @@ class SerialTraceCollector(CollectorBase):
del self._conn
stop_marker = "-------- Stopping serial logging --------\n"
self._tmpfile.write(stop_marker.encode('utf-8'))
self._outfile_fh.write(stop_marker.encode('utf-8'))
self._outfile_fh.flush()
self._outfile_fh.close()
self._outfile_fh = None
self._collecting = False
def get_trace(self, outfile):
def set_output(self, output_path):
self.output_path = output_path
def get_data(self):
if self._collecting:
raise RuntimeError("get_trace was called whilst collecting")
self._tmpfile.flush()
shutil.copy(self._tmpfile.name, outfile)
self._tmpfile.close()
self._tmpfile = None
raise RuntimeError("get_data was called whilst collecting")
if self.output_path is None:
raise RuntimeError("No data collected.")
return CollectorOutput([CollectorOutputEntry(self.output_path, 'file')])

View File

@ -19,8 +19,9 @@ import subprocess
from shutil import copyfile
from tempfile import NamedTemporaryFile
from devlib.collector import (CollectorBase, CollectorOutput,
CollectorOutputEntry)
from devlib.exception import TargetStableError, HostError
from devlib.collector import CollectorBase
import devlib.utils.android
from devlib.utils.misc import memoized
@ -74,9 +75,10 @@ class SystraceCollector(CollectorBase):
self.categories = categories or DEFAULT_CATEGORIES
self.buffer_size = buffer_size
self.output_path = None
self._systrace_process = None
self._tmpfile = None
self._outfile_fh = None
# Try to find a systrace binary
self.systrace_binary = None
@ -104,12 +106,12 @@ class SystraceCollector(CollectorBase):
self.reset()
def _build_cmd(self):
self._tmpfile = NamedTemporaryFile()
self._outfile_fh = open(self.output_path, 'w')
# pylint: disable=attribute-defined-outside-init
self.systrace_cmd = 'python2 -u {} -o {} -e {}'.format(
self.systrace_binary,
self._tmpfile.name,
self._outfile_fh.name,
self.target.adb_name
)
@ -122,13 +124,11 @@ class SystraceCollector(CollectorBase):
if self._systrace_process:
self.stop()
if self._tmpfile:
self._tmpfile.close()
self._tmpfile = None
def start(self):
if self._systrace_process:
raise RuntimeError("Tracing is already underway, call stop() first")
if self.output_path is None:
raise RuntimeError("Output path was not set.")
self.reset()
@ -151,11 +151,16 @@ class SystraceCollector(CollectorBase):
self._systrace_process.communicate('\n')
self._systrace_process = None
def get_trace(self, outfile):
if self._outfile_fh:
self._outfile_fh.close()
self._outfile_fh = None
def set_output(self, output_path):
self.output_path = output_path
def get_data(self):
if self._systrace_process:
raise RuntimeError("Tracing is underway, call stop() first")
if not self._tmpfile:
raise RuntimeError("No tracing data available")
copyfile(self._tmpfile.name, outfile)
if self.output_path is None:
raise RuntimeError("No data collected.")
return CollectorOutput([CollectorOutputEntry(self.output_path, 'file')])