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:
parent
15a77a841d
commit
cf8ebf6668
@ -18,7 +18,8 @@ import re
|
|||||||
from itertools import takewhile
|
from itertools import takewhile
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from devlib.collector import CollectorBase
|
from devlib.collector import (CollectorBase, CollectorOutput,
|
||||||
|
CollectorOutputEntry)
|
||||||
|
|
||||||
|
|
||||||
class KernelLogEntry(object):
|
class KernelLogEntry(object):
|
||||||
@ -151,6 +152,7 @@ class DmesgCollector(CollectorBase):
|
|||||||
|
|
||||||
def __init__(self, target, level=LOG_LEVELS[-1], facility='kern'):
|
def __init__(self, target, level=LOG_LEVELS[-1], facility='kern'):
|
||||||
super(DmesgCollector, self).__init__(target)
|
super(DmesgCollector, self).__init__(target)
|
||||||
|
self.output_path = None
|
||||||
|
|
||||||
if level not in self.LOG_LEVELS:
|
if level not in self.LOG_LEVELS:
|
||||||
raise ValueError('level needs to be one of: {}'.format(
|
raise ValueError('level needs to be one of: {}'.format(
|
||||||
@ -195,6 +197,12 @@ class DmesgCollector(CollectorBase):
|
|||||||
|
|
||||||
self.dmesg_out = self.target.execute(cmd)
|
self.dmesg_out = self.target.execute(cmd)
|
||||||
|
|
||||||
def get_trace(self, outfile):
|
def set_output(self, output_path):
|
||||||
with open(outfile, 'wt') as f:
|
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')
|
f.write(self.dmesg_out + '\n')
|
||||||
|
return CollectorOutput([CollectorOutputEntry(self.output_path, 'file')])
|
||||||
|
@ -23,7 +23,8 @@ import sys
|
|||||||
import contextlib
|
import contextlib
|
||||||
from pipes import quote
|
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.host import PACKAGE_BIN_DIRECTORY
|
||||||
from devlib.exception import TargetStableError, HostError
|
from devlib.exception import TargetStableError, HostError
|
||||||
from devlib.utils.misc import check_output, which, memoized
|
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)
|
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'
|
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.target_text_file = target.path.join(self.target.working_directory, text_file_name)
|
||||||
|
self.output_path = None
|
||||||
self.target_binary = None
|
self.target_binary = None
|
||||||
self.host_binary = None
|
self.host_binary = None
|
||||||
self.start_time = None
|
self.start_time = None
|
||||||
@ -300,9 +302,14 @@ class FtraceCollector(CollectorBase):
|
|||||||
timeout=TIMEOUT, as_root=True)
|
timeout=TIMEOUT, as_root=True)
|
||||||
self._reset_needed = True
|
self._reset_needed = True
|
||||||
|
|
||||||
def get_trace(self, outfile):
|
def set_output(self, output_path):
|
||||||
if os.path.isdir(outfile):
|
if os.path.isdir(output_path):
|
||||||
outfile = os.path.join(outfile, os.path.basename(self.target_output_file))
|
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.execute('{0} extract -o {1}; chmod 666 {1}'.format(self.target_binary,
|
||||||
self.target_output_file),
|
self.target_output_file),
|
||||||
timeout=TIMEOUT, as_root=True)
|
timeout=TIMEOUT, as_root=True)
|
||||||
@ -311,20 +318,24 @@ class FtraceCollector(CollectorBase):
|
|||||||
# Therefore timout for the pull command must also be adjusted
|
# Therefore timout for the pull command must also be adjusted
|
||||||
# accordingly.
|
# accordingly.
|
||||||
pull_timeout = 10 * (self.stop_time - self.start_time)
|
pull_timeout = 10 * (self.stop_time - self.start_time)
|
||||||
self.target.pull(self.target_output_file, outfile, timeout=pull_timeout)
|
self.target.pull(self.target_output_file, self.output_path, timeout=pull_timeout)
|
||||||
if not os.path.isfile(outfile):
|
output = CollectorOutput()
|
||||||
|
if not os.path.isfile(self.output_path):
|
||||||
self.logger.warning('Binary trace not pulled from device.')
|
self.logger.warning('Binary trace not pulled from device.')
|
||||||
else:
|
else:
|
||||||
|
output.append(CollectorOutputEntry(self.output_path, 'file'))
|
||||||
if self.autoreport:
|
if self.autoreport:
|
||||||
textfile = os.path.splitext(outfile)[0] + '.txt'
|
textfile = os.path.splitext(self.output_path)[0] + '.txt'
|
||||||
if self.report_on_target:
|
if self.report_on_target:
|
||||||
self.generate_report_on_target()
|
self.generate_report_on_target()
|
||||||
self.target.pull(self.target_text_file,
|
self.target.pull(self.target_text_file,
|
||||||
textfile, timeout=pull_timeout)
|
textfile, timeout=pull_timeout)
|
||||||
else:
|
else:
|
||||||
self.report(outfile, textfile)
|
self.report(self.output_path, textfile)
|
||||||
|
output.append(CollectorOutputEntry(textfile, 'file'))
|
||||||
if self.autoview:
|
if self.autoview:
|
||||||
self.view(outfile)
|
self.view(self.output_path)
|
||||||
|
return output
|
||||||
|
|
||||||
def get_stats(self, outfile):
|
def get_stats(self, outfile):
|
||||||
if not (self.functions and self.tracer is None):
|
if not (self.functions and self.tracer is None):
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from devlib.collector import CollectorBase
|
from devlib.collector import (CollectorBase, CollectorOutput,
|
||||||
|
CollectorOutputEntry)
|
||||||
from devlib.utils.android import LogcatMonitor
|
from devlib.utils.android import LogcatMonitor
|
||||||
|
|
||||||
class LogcatCollector(CollectorBase):
|
class LogcatCollector(CollectorBase):
|
||||||
@ -24,6 +25,7 @@ class LogcatCollector(CollectorBase):
|
|||||||
def __init__(self, target, regexps=None):
|
def __init__(self, target, regexps=None):
|
||||||
super(LogcatCollector, self).__init__(target)
|
super(LogcatCollector, self).__init__(target)
|
||||||
self.regexps = regexps
|
self.regexps = regexps
|
||||||
|
self.output_path = None
|
||||||
self._collecting = False
|
self._collecting = False
|
||||||
self._prev_log = None
|
self._prev_log = None
|
||||||
self._monitor = None
|
self._monitor = None
|
||||||
@ -45,12 +47,14 @@ class LogcatCollector(CollectorBase):
|
|||||||
"""
|
"""
|
||||||
Start collecting logcat lines
|
Start collecting logcat lines
|
||||||
"""
|
"""
|
||||||
|
if self.output_path is None:
|
||||||
|
raise RuntimeError("Output path was not set.")
|
||||||
self._monitor = LogcatMonitor(self.target, self.regexps)
|
self._monitor = LogcatMonitor(self.target, self.regexps)
|
||||||
if self._prev_log:
|
if self._prev_log:
|
||||||
# Append new data collection to previous collection
|
# Append new data collection to previous collection
|
||||||
self._monitor.start(self._prev_log)
|
self._monitor.start(self._prev_log)
|
||||||
else:
|
else:
|
||||||
self._monitor.start()
|
self._monitor.start(self.output_path)
|
||||||
|
|
||||||
self._collecting = True
|
self._collecting = True
|
||||||
|
|
||||||
@ -65,9 +69,10 @@ class LogcatCollector(CollectorBase):
|
|||||||
self._collecting = False
|
self._collecting = False
|
||||||
self._prev_log = self._monitor.logfile
|
self._prev_log = self._monitor.logfile
|
||||||
|
|
||||||
def get_trace(self, outfile):
|
def set_output(self, output_path):
|
||||||
"""
|
self.output_path = output_path
|
||||||
Output collected logcat lines to designated file
|
|
||||||
"""
|
def get_data(self):
|
||||||
# copy self._monitor.logfile to outfile
|
if self.output_path is None:
|
||||||
shutil.copy(self._monitor.logfile, outfile)
|
raise RuntimeError("No data collected.")
|
||||||
|
return CollectorOutput([CollectorOutputEntry(self.output_path, 'file')])
|
||||||
|
@ -19,7 +19,8 @@ import time
|
|||||||
from past.builtins import basestring, zip
|
from past.builtins import basestring, zip
|
||||||
|
|
||||||
from devlib.host import PACKAGE_BIN_DIRECTORY
|
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
|
from devlib.utils.misc import ensure_file_directory_exists as _f
|
||||||
|
|
||||||
|
|
||||||
@ -95,6 +96,7 @@ class PerfCollector(CollectorBase):
|
|||||||
self.force_install = force_install
|
self.force_install = force_install
|
||||||
self.labels = labels
|
self.labels = labels
|
||||||
self.report_options = report_options
|
self.report_options = report_options
|
||||||
|
self.output_path = None
|
||||||
|
|
||||||
# Validate parameters
|
# Validate parameters
|
||||||
if isinstance(optionstring, list):
|
if isinstance(optionstring, list):
|
||||||
@ -148,14 +150,24 @@ class PerfCollector(CollectorBase):
|
|||||||
self.target.killall('sleep', as_root=self.target.is_rooted)
|
self.target.killall('sleep', as_root=self.target.is_rooted)
|
||||||
# NB: we hope that no other "important" sleep is on-going
|
# NB: we hope that no other "important" sleep is on-going
|
||||||
|
|
||||||
# pylint: disable=arguments-differ
|
def set_output(self, output_path):
|
||||||
def get_trace(self, outdir):
|
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:
|
for label in self.labels:
|
||||||
if self.command == 'record':
|
if self.command == 'record':
|
||||||
self._wait_for_data_file_write(label, outdir)
|
self._wait_for_data_file_write(label, self.output_path)
|
||||||
self._pull_target_file_to_host(label, 'rpt', outdir)
|
path = self._pull_target_file_to_host(label, 'rpt', self.output_path)
|
||||||
|
output.append(CollectorOutputEntry(path, 'file'))
|
||||||
else:
|
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):
|
def _deploy_perf(self):
|
||||||
host_executable = os.path.join(PACKAGE_BIN_DIRECTORY,
|
host_executable = os.path.join(PACKAGE_BIN_DIRECTORY,
|
||||||
@ -198,13 +210,14 @@ class PerfCollector(CollectorBase):
|
|||||||
outfile=self._get_target_file(label, 'data'))
|
outfile=self._get_target_file(label, 'data'))
|
||||||
return command
|
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)
|
target_file = self._get_target_file(label, extension)
|
||||||
host_relpath = os.path.basename(target_file)
|
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)
|
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
|
data_file_finished_writing = False
|
||||||
max_tries = 80
|
max_tries = 80
|
||||||
current_tries = 0
|
current_tries = 0
|
||||||
|
@ -17,7 +17,8 @@ import shutil
|
|||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
from pexpect.exceptions import TIMEOUT
|
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
|
from devlib.utils.serial_port import get_connection
|
||||||
|
|
||||||
|
|
||||||
@ -32,33 +33,35 @@ class SerialTraceCollector(CollectorBase):
|
|||||||
self.serial_port = serial_port
|
self.serial_port = serial_port
|
||||||
self.baudrate = baudrate
|
self.baudrate = baudrate
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
self.output_path - None
|
||||||
|
|
||||||
self._serial_target = None
|
self._serial_target = None
|
||||||
self._conn = None
|
self._conn = None
|
||||||
self._tmpfile = None
|
self._outfile_fh = None
|
||||||
self._collecting = False
|
self._collecting = False
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
if self._collecting:
|
if self._collecting:
|
||||||
raise RuntimeError("reset was called whilst collecting")
|
raise RuntimeError("reset was called whilst collecting")
|
||||||
|
|
||||||
if self._tmpfile:
|
if self._outfile_fh:
|
||||||
self._tmpfile.close()
|
self._outfile_fh.close()
|
||||||
self._tmpfile = None
|
self._outfile_fh = None
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
if self._collecting:
|
if self._collecting:
|
||||||
raise RuntimeError("start was called whilst collecting")
|
raise RuntimeError("start was called whilst collecting")
|
||||||
|
if self.output_path is None:
|
||||||
|
raise RuntimeError("Output path was not set.")
|
||||||
|
|
||||||
|
self._outfile_fh = open(self.output_path, 'w')
|
||||||
self._tmpfile = NamedTemporaryFile()
|
|
||||||
start_marker = "-------- Starting serial logging --------\n"
|
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,
|
self._serial_target, self._conn = get_connection(port=self.serial_port,
|
||||||
baudrate=self.baudrate,
|
baudrate=self.baudrate,
|
||||||
timeout=self.timeout,
|
timeout=self.timeout,
|
||||||
logfile=self._tmpfile,
|
logfile=self._outfile_fh,
|
||||||
init_dtr=0)
|
init_dtr=0)
|
||||||
self._collecting = True
|
self._collecting = True
|
||||||
|
|
||||||
@ -78,17 +81,19 @@ class SerialTraceCollector(CollectorBase):
|
|||||||
del self._conn
|
del self._conn
|
||||||
|
|
||||||
stop_marker = "-------- Stopping serial logging --------\n"
|
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
|
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:
|
if self._collecting:
|
||||||
raise RuntimeError("get_trace was called whilst collecting")
|
raise RuntimeError("get_data was called whilst collecting")
|
||||||
|
if self.output_path is None:
|
||||||
self._tmpfile.flush()
|
raise RuntimeError("No data collected.")
|
||||||
|
return CollectorOutput([CollectorOutputEntry(self.output_path, 'file')])
|
||||||
shutil.copy(self._tmpfile.name, outfile)
|
|
||||||
|
|
||||||
self._tmpfile.close()
|
|
||||||
self._tmpfile = None
|
|
||||||
|
@ -19,8 +19,9 @@ import subprocess
|
|||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
|
|
||||||
|
from devlib.collector import (CollectorBase, CollectorOutput,
|
||||||
|
CollectorOutputEntry)
|
||||||
from devlib.exception import TargetStableError, HostError
|
from devlib.exception import TargetStableError, HostError
|
||||||
from devlib.collector import CollectorBase
|
|
||||||
import devlib.utils.android
|
import devlib.utils.android
|
||||||
from devlib.utils.misc import memoized
|
from devlib.utils.misc import memoized
|
||||||
|
|
||||||
@ -74,9 +75,10 @@ class SystraceCollector(CollectorBase):
|
|||||||
|
|
||||||
self.categories = categories or DEFAULT_CATEGORIES
|
self.categories = categories or DEFAULT_CATEGORIES
|
||||||
self.buffer_size = buffer_size
|
self.buffer_size = buffer_size
|
||||||
|
self.output_path = None
|
||||||
|
|
||||||
self._systrace_process = None
|
self._systrace_process = None
|
||||||
self._tmpfile = None
|
self._outfile_fh = None
|
||||||
|
|
||||||
# Try to find a systrace binary
|
# Try to find a systrace binary
|
||||||
self.systrace_binary = None
|
self.systrace_binary = None
|
||||||
@ -104,12 +106,12 @@ class SystraceCollector(CollectorBase):
|
|||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def _build_cmd(self):
|
def _build_cmd(self):
|
||||||
self._tmpfile = NamedTemporaryFile()
|
self._outfile_fh = open(self.output_path, 'w')
|
||||||
|
|
||||||
# pylint: disable=attribute-defined-outside-init
|
# pylint: disable=attribute-defined-outside-init
|
||||||
self.systrace_cmd = 'python2 -u {} -o {} -e {}'.format(
|
self.systrace_cmd = 'python2 -u {} -o {} -e {}'.format(
|
||||||
self.systrace_binary,
|
self.systrace_binary,
|
||||||
self._tmpfile.name,
|
self._outfile_fh.name,
|
||||||
self.target.adb_name
|
self.target.adb_name
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -122,13 +124,11 @@ class SystraceCollector(CollectorBase):
|
|||||||
if self._systrace_process:
|
if self._systrace_process:
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
if self._tmpfile:
|
|
||||||
self._tmpfile.close()
|
|
||||||
self._tmpfile = None
|
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
if self._systrace_process:
|
if self._systrace_process:
|
||||||
raise RuntimeError("Tracing is already underway, call stop() first")
|
raise RuntimeError("Tracing is already underway, call stop() first")
|
||||||
|
if self.output_path is None:
|
||||||
|
raise RuntimeError("Output path was not set.")
|
||||||
|
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
@ -151,11 +151,16 @@ class SystraceCollector(CollectorBase):
|
|||||||
self._systrace_process.communicate('\n')
|
self._systrace_process.communicate('\n')
|
||||||
self._systrace_process = None
|
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:
|
if self._systrace_process:
|
||||||
raise RuntimeError("Tracing is underway, call stop() first")
|
raise RuntimeError("Tracing is underway, call stop() first")
|
||||||
|
if self.output_path is None:
|
||||||
if not self._tmpfile:
|
raise RuntimeError("No data collected.")
|
||||||
raise RuntimeError("No tracing data available")
|
return CollectorOutput([CollectorOutputEntry(self.output_path, 'file')])
|
||||||
|
|
||||||
copyfile(self._tmpfile.name, outfile)
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user