blob: 72d84b584d35afd5539f0ded65f1ae5469021987 [file] [log] [blame]
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import py_utils
import optparse
import threading
from devil.android import device_utils
from systrace import trace_result
from systrace import tracing_agents
from py_trace_event import trace_time as trace_time_module
TRACE_FILE_PATH = \
'/sdcard/Android/data/org.chromium.latency.walt/files/trace.txt'
CLOCK_DOMAIN_MARKER = '# clock_type=LINUX_CLOCK_MONOTONIC\n'
def try_create_agent(options):
if options.is_walt_enabled:
return WaltAgent()
return None
class WaltConfig(tracing_agents.TracingConfig):
def __init__(self, device_serial_number, is_walt_enabled):
tracing_agents.TracingConfig.__init__(self)
self.device_serial_number = device_serial_number
self.is_walt_enabled = is_walt_enabled
def add_options(parser):
options = optparse.OptionGroup(parser, 'WALT trace options')
options.add_option('--walt', dest='is_walt_enabled', default=False,
action='store_true', help='Use the WALT tracing agent. '
'WALT is a device for measuring latency of physical '
'sensors on phones and computers. '
'See https://github.com/google/walt')
return options
def get_config(options):
return WaltConfig(options.device_serial_number, options.is_walt_enabled)
class WaltAgent(tracing_agents.TracingAgent):
"""
This tracing agent requires the WALT app to be installed on the Android phone,
and requires the WALT device to be attached to the phone. WALT is a device
for measuring latency of physical sensors and outputs on phones and
computers. For more information, visit https://github.com/google/walt
"""
def __init__(self):
super(WaltAgent, self).__init__()
self._trace_contents = None
self._config = None
self._device_utils = None
self._clock_sync_marker = None
self._collection_thread = None
def __repr__(self):
return 'WaltAgent'
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
del timeout # unused
self._config = config
self._device_utils = device_utils.DeviceUtils(
self._config.device_serial_number)
if self._device_utils.PathExists(TRACE_FILE_PATH):
# clear old trace events so they are not included in the current trace
self._device_utils.WriteFile(TRACE_FILE_PATH, '')
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
"""Stops tracing and starts collecting results.
To synchronously retrieve the results after calling this function,
call GetResults().
"""
del timeout # unused
self._collection_thread = threading.Thread(
target=self._collect_trace_data)
self._collection_thread.start()
return True
def _collect_trace_data(self):
self._trace_contents = self._device_utils.ReadFile(TRACE_FILE_PATH)
def SupportsExplicitClockSync(self):
return True
def RecordClockSyncMarker(self, sync_id, did_record_clock_sync_callback):
cmd = 'cat /proc/timer_list | grep now'
t1 = trace_time_module.Now()
command_result = self._device_utils.RunShellCommand(cmd, shell=True)
nsec = command_result[0].split()[2]
self._clock_sync_marker = format_clock_sync_marker(sync_id, nsec)
did_record_clock_sync_callback(t1, sync_id)
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
del timeout # unused
self._collection_thread.join()
self._collection_thread = None
return trace_result.TraceResult('waltTrace', self._get_trace_result())
def _get_trace_result(self):
result = '# tracer: \n' + CLOCK_DOMAIN_MARKER + self._trace_contents
if self._clock_sync_marker is not None:
result += self._clock_sync_marker
return result
def format_clock_sync_marker(sync_id, nanosec_time):
return ('<0>-0 (-----) [001] ...1 ' + str(float(nanosec_time) / 1e9)
+ ': tracing_mark_write: trace_event_clock_sync: name='
+ sync_id + '\n')