1# Copyright 2017 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import py_utils 6import optparse 7import threading 8 9from devil.android import device_utils 10from systrace import trace_result 11from systrace import tracing_agents 12from py_trace_event import trace_time as trace_time_module 13 14TRACE_FILE_PATH = \ 15 '/sdcard/Android/data/org.chromium.latency.walt/files/trace.txt' 16 17CLOCK_DOMAIN_MARKER = '# clock_type=LINUX_CLOCK_MONOTONIC\n' 18 19 20def try_create_agent(options): 21 if options.is_walt_enabled: 22 return WaltAgent() 23 return None 24 25 26class WaltConfig(tracing_agents.TracingConfig): 27 def __init__(self, device_serial_number, is_walt_enabled): 28 tracing_agents.TracingConfig.__init__(self) 29 self.device_serial_number = device_serial_number 30 self.is_walt_enabled = is_walt_enabled 31 32 33def add_options(parser): 34 options = optparse.OptionGroup(parser, 'WALT trace options') 35 options.add_option('--walt', dest='is_walt_enabled', default=False, 36 action='store_true', help='Use the WALT tracing agent. ' 37 'WALT is a device for measuring latency of physical ' 38 'sensors on phones and computers. ' 39 'See https://github.com/google/walt') 40 return options 41 42 43def get_config(options): 44 return WaltConfig(options.device_serial_number, options.is_walt_enabled) 45 46 47class WaltAgent(tracing_agents.TracingAgent): 48 """ 49 This tracing agent requires the WALT app to be installed on the Android phone, 50 and requires the WALT device to be attached to the phone. WALT is a device 51 for measuring latency of physical sensors and outputs on phones and 52 computers. For more information, visit https://github.com/google/walt 53 """ 54 def __init__(self): 55 super(WaltAgent, self).__init__() 56 self._trace_contents = None 57 self._config = None 58 self._device_utils = None 59 self._clock_sync_marker = None 60 self._collection_thread = None 61 62 def __repr__(self): 63 return 'WaltAgent' 64 65 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT) 66 def StartAgentTracing(self, config, timeout=None): 67 del timeout # unused 68 self._config = config 69 self._device_utils = device_utils.DeviceUtils( 70 self._config.device_serial_number) 71 if self._device_utils.PathExists(TRACE_FILE_PATH): 72 # clear old trace events so they are not included in the current trace 73 self._device_utils.WriteFile(TRACE_FILE_PATH, '') 74 return True 75 76 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT) 77 def StopAgentTracing(self, timeout=None): 78 """Stops tracing and starts collecting results. 79 80 To synchronously retrieve the results after calling this function, 81 call GetResults(). 82 """ 83 del timeout # unused 84 self._collection_thread = threading.Thread( 85 target=self._collect_trace_data) 86 self._collection_thread.start() 87 return True 88 89 def _collect_trace_data(self): 90 self._trace_contents = self._device_utils.ReadFile(TRACE_FILE_PATH) 91 92 def SupportsExplicitClockSync(self): 93 return True 94 95 def RecordClockSyncMarker(self, sync_id, did_record_clock_sync_callback): 96 cmd = 'cat /proc/timer_list | grep now' 97 t1 = trace_time_module.Now() 98 command_result = self._device_utils.RunShellCommand(cmd, shell=True) 99 nsec = command_result[0].split()[2] 100 self._clock_sync_marker = format_clock_sync_marker(sync_id, nsec) 101 did_record_clock_sync_callback(t1, sync_id) 102 103 @py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT) 104 def GetResults(self, timeout=None): 105 del timeout # unused 106 self._collection_thread.join() 107 self._collection_thread = None 108 return trace_result.TraceResult('waltTrace', self._get_trace_result()) 109 110 def _get_trace_result(self): 111 result = '# tracer: \n' + CLOCK_DOMAIN_MARKER + self._trace_contents 112 if self._clock_sync_marker is not None: 113 result += self._clock_sync_marker 114 return result 115 116 117def format_clock_sync_marker(sync_id, nanosec_time): 118 return ('<0>-0 (-----) [001] ...1 ' + str(float(nanosec_time) / 1e9) 119 + ': tracing_mark_write: trace_event_clock_sync: name=' 120 + sync_id + '\n') 121