| # 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 optparse |
| import threading |
| |
| import py_utils |
| |
| 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') |