1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-01-18 12:06:08 +00:00

framework/target: Add logcat buffer wrap detection

As WA currently supports either a single logcat dump after each job,
or fixed rate polling of logcat, it is possible that the fixed size
logcat buffer wraps around and overwrites data between each dump or
poll. This data may be used by output processors that should be
notified of the loss.

This change allows the detection of buffer wrapping by inserting a
known log entry into the buffer, although it cannot say how much data
was lost, and only applies to the "main" logcat buffer.

If buffer wrap is detected, a warning is logged by WA.
This commit is contained in:
Jonathan Paynter 2020-07-08 17:18:57 +01:00 committed by Marc Bonnici
parent 08fcc7d30f
commit 716e59daf5

View File

@ -21,9 +21,11 @@ import tempfile
import threading import threading
import time import time
from wa.framework.plugin import Parameter
from wa.framework.exception import WorkerThreadError from wa.framework.exception import WorkerThreadError
from wa.framework.plugin import Parameter
from wa.utils.android import LogcatParser
from wa.utils.misc import touch from wa.utils.misc import touch
import wa.framework.signal as signal
class LinuxAssistant(object): class LinuxAssistant(object):
@ -73,6 +75,13 @@ class AndroidAssistant(object):
self.logcat_poll_period = logcat_poll_period self.logcat_poll_period = logcat_poll_period
self.disable_selinux = disable_selinux self.disable_selinux = disable_selinux
self.logcat_poller = None self.logcat_poller = None
self.logger = logging.getLogger('logcat')
self._logcat_marker_msg = None
self._logcat_marker_tag = None
signal.connect(self._before_workload, signal.BEFORE_WORKLOAD_EXECUTION)
if self.logcat_poll_period:
signal.connect(self._after_workload, signal.AFTER_WORKLOAD_EXECUTION)
if self.target.is_rooted and self.disable_selinux: if self.target.is_rooted and self.disable_selinux:
self.do_disable_selinux() self.do_disable_selinux()
@ -80,6 +89,10 @@ class AndroidAssistant(object):
if self.logcat_poll_period: if self.logcat_poll_period:
self.logcat_poller = LogcatPoller(self.target, self.logcat_poll_period) self.logcat_poller = LogcatPoller(self.target, self.logcat_poll_period)
self.logcat_poller.start() self.logcat_poller.start()
else:
if not self._logcat_marker_msg:
self._logcat_marker_msg = 'WA logcat marker for wrap detection'
self._logcat_marker_tag = 'WAlog'
def stop(self): def stop(self):
if self.logcat_poller: if self.logcat_poller:
@ -90,6 +103,11 @@ class AndroidAssistant(object):
self.dump_logcat(logcat_file) self.dump_logcat(logcat_file)
context.add_artifact('logcat', logcat_file, kind='log') context.add_artifact('logcat', logcat_file, kind='log')
self.clear_logcat() self.clear_logcat()
if not self._check_logcat_nowrap(logcat_file):
self.logger.warning('The main logcat buffer wrapped and lost data;'
' results that rely on this buffer may be'
' inaccurate or incomplete.'
)
def dump_logcat(self, outfile): def dump_logcat(self, outfile):
if self.logcat_poller: if self.logcat_poller:
@ -100,6 +118,37 @@ class AndroidAssistant(object):
def clear_logcat(self): def clear_logcat(self):
if self.logcat_poller: if self.logcat_poller:
self.logcat_poller.clear_buffer() self.logcat_poller.clear_buffer()
else:
self.target.clear_logcat()
def _before_workload(self, _):
if self.logcat_poller:
self.logcat_poller.start_logcat_wrap_detect()
else:
self.insert_logcat_marker()
def _after_workload(self, _):
self.logcat_poller.stop_logcat_wrap_detect()
def _check_logcat_nowrap(self, outfile):
if self.logcat_poller:
return self.logcat_poller.check_logcat_nowrap(outfile)
else:
parser = LogcatParser()
for event in parser.parse(outfile):
if (event.tag == self._logcat_marker_tag and
event.message == self._logcat_marker_msg):
return True
return False
def insert_logcat_marker(self):
self.logger.debug('Inserting logcat marker')
self.target.execute(
'log -t "{}" "{}"'.format(
self._logcat_marker_tag, self._logcat_marker_msg
)
)
def do_disable_selinux(self): def do_disable_selinux(self):
# SELinux was added in Android 4.3 (API level 18). Trying to # SELinux was added in Android 4.3 (API level 18). Trying to
@ -119,15 +168,21 @@ class LogcatPoller(threading.Thread):
self.period = period self.period = period
self.timeout = timeout self.timeout = timeout
self.stop_signal = threading.Event() self.stop_signal = threading.Event()
self.lock = threading.Lock() self.lock = threading.RLock()
self.buffer_file = tempfile.mktemp() self.buffer_file = tempfile.mktemp()
self.last_poll = 0 self.last_poll = 0
self.daemon = True self.daemon = True
self.exc = None self.exc = None
self._logcat_marker_tag = 'WALog'
self._logcat_marker_msg = 'WA logcat marker for wrap detection:{}'
self._marker_count = 0
self._start_marker = None
self._end_marker = None
def run(self): def run(self):
self.logger.debug('Starting polling') self.logger.debug('Starting polling')
try: try:
self.insert_logcat_marker()
while True: while True:
if self.stop_signal.is_set(): if self.stop_signal.is_set():
break break
@ -135,6 +190,7 @@ class LogcatPoller(threading.Thread):
current_time = time.time() current_time = time.time()
if (current_time - self.last_poll) >= self.period: if (current_time - self.last_poll) >= self.period:
self.poll() self.poll()
self.insert_logcat_marker()
time.sleep(0.5) time.sleep(0.5)
except Exception: # pylint: disable=W0703 except Exception: # pylint: disable=W0703
self.exc = WorkerThreadError(self.name, sys.exc_info()) self.exc = WorkerThreadError(self.name, sys.exc_info())
@ -173,6 +229,46 @@ class LogcatPoller(threading.Thread):
self.target.dump_logcat(self.buffer_file, append=True, timeout=self.timeout) self.target.dump_logcat(self.buffer_file, append=True, timeout=self.timeout)
self.target.clear_logcat() self.target.clear_logcat()
def insert_logcat_marker(self):
self.logger.debug('Inserting logcat marker')
with self.lock:
self.target.execute(
'log -t "{}" "{}"'.format(
self._logcat_marker_tag,
self._logcat_marker_msg.format(self._marker_count)
)
)
self._marker_count += 1
def check_logcat_nowrap(self, outfile):
parser = LogcatParser()
counter = self._start_marker
for event in parser.parse(outfile):
message = self._logcat_marker_msg.split(':')[0]
if not (event.tag == self._logcat_marker_tag and
event.message.split(':')[0] == message):
continue
number = int(event.message.split(':')[1])
if number > counter:
return False
elif number == counter:
counter += 1
if counter == self._end_marker:
return True
return False
def start_logcat_wrap_detect(self):
with self.lock:
self._start_marker = self._marker_count
self.insert_logcat_marker()
def stop_logcat_wrap_detect(self):
with self.lock:
self._end_marker = self._marker_count
class ChromeOsAssistant(LinuxAssistant): class ChromeOsAssistant(LinuxAssistant):