1*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 3*9c5db199SXin Li# found in the LICENSE file. 4*9c5db199SXin Li 5*9c5db199SXin Liimport logging, os, re 6*9c5db199SXin Li 7*9c5db199SXin Lifrom autotest_lib.client.bin import utils 8*9c5db199SXin Lifrom autotest_lib.client.common_lib import error 9*9c5db199SXin Li 10*9c5db199SXin Liclass KernelTrace(object): 11*9c5db199SXin Li """Allows access and control to Kernel tracing facilities. 12*9c5db199SXin Li 13*9c5db199SXin Li Example code snippet: 14*9c5db199SXin Li trace = KernelTrace(events=['mali_dvfs:mali_dvfs_set_clock']) 15*9c5db199SXin Li results = trace.read(regexp=r'frequency=(\d+)') 16*9c5db199SXin Li 17*9c5db199SXin Li Public methods: 18*9c5db199SXin Li on : Enables tracing 19*9c5db199SXin Li off : Disables tracing 20*9c5db199SXin Li is_tracing : Returns Boolean of tracing status. 21*9c5db199SXin Li event_on : Turns event on. Returns boolean of success 22*9c5db199SXin Li event_off : Turns event off. Returns boolean of success 23*9c5db199SXin Li flush : Flushes trace buffer 24*9c5db199SXin Li read : Reads trace buffer returns list of 25*9c5db199SXin Li - tuples if regexp provided 26*9c5db199SXin Li - else matching string 27*9c5db199SXin Li uptime_secs : Returns float of current uptime. 28*9c5db199SXin Li 29*9c5db199SXin Li Private functions: 30*9c5db199SXin Li _onoff : Disable/enable tracing 31*9c5db199SXin Li _onoff_event : Disable/enable events 32*9c5db199SXin Li 33*9c5db199SXin Li Private attributes: 34*9c5db199SXin Li _buffer : list to hold parsed results from trace buffer 35*9c5db199SXin Li _buffer_ptr : integer pointing to last byte read 36*9c5db199SXin Li 37*9c5db199SXin Li TODO(tbroch): List of potential enhancements 38*9c5db199SXin Li - currently only supports trace events. Add other tracers. 39*9c5db199SXin Li """ 40*9c5db199SXin Li _TRACE_ROOT = '/sys/kernel/debug/tracing' 41*9c5db199SXin Li _TRACE_ON_PATH = os.path.join(_TRACE_ROOT, 'tracing_on') 42*9c5db199SXin Li 43*9c5db199SXin Li def __init__(self, flush=True, events=None, on=True): 44*9c5db199SXin Li """Constructor for KernelTrace class""" 45*9c5db199SXin Li self._buffer = [] 46*9c5db199SXin Li self._buffer_ptr = 0 47*9c5db199SXin Li self._events = [] 48*9c5db199SXin Li self._on = on 49*9c5db199SXin Li 50*9c5db199SXin Li if flush: 51*9c5db199SXin Li self.flush() 52*9c5db199SXin Li for event in events: 53*9c5db199SXin Li if self.event_on(event): 54*9c5db199SXin Li self._events.append(event) 55*9c5db199SXin Li if on: 56*9c5db199SXin Li self.on() 57*9c5db199SXin Li 58*9c5db199SXin Li 59*9c5db199SXin Li def __del__(self, flush=True, events=None, on=True): 60*9c5db199SXin Li """Deconstructor for KernelTrace class""" 61*9c5db199SXin Li for event in self._events: 62*9c5db199SXin Li self.event_off(event) 63*9c5db199SXin Li if self._on: 64*9c5db199SXin Li self.off() 65*9c5db199SXin Li 66*9c5db199SXin Li 67*9c5db199SXin Li def _onoff(self, val): 68*9c5db199SXin Li """Turn tracing on or off. 69*9c5db199SXin Li 70*9c5db199SXin Li Arguments: 71*9c5db199SXin Li val: integer, 1 for on, 0 for off 72*9c5db199SXin Li 73*9c5db199SXin Li Raises: 74*9c5db199SXin Li error.TestFail: If unable to turn tracing on or off. 75*9c5db199SXin Li """ 76*9c5db199SXin Li utils.write_one_line(self._TRACE_ON_PATH, val) 77*9c5db199SXin Li result = int(utils.read_one_line(self._TRACE_ON_PATH).strip()) 78*9c5db199SXin Li if not result == val: 79*9c5db199SXin Li raise error.TestFail("Unable to %sable tracing" % 80*9c5db199SXin Li 'en' if val == 1 else 'dis') 81*9c5db199SXin Li 82*9c5db199SXin Li 83*9c5db199SXin Li def on(self): 84*9c5db199SXin Li """Enable tracing.""" 85*9c5db199SXin Li return self._onoff(1) 86*9c5db199SXin Li 87*9c5db199SXin Li 88*9c5db199SXin Li def off(self): 89*9c5db199SXin Li """Disable tracing.""" 90*9c5db199SXin Li self._onoff(0) 91*9c5db199SXin Li 92*9c5db199SXin Li 93*9c5db199SXin Li def is_tracing(self): 94*9c5db199SXin Li """Is tracing on? 95*9c5db199SXin Li 96*9c5db199SXin Li Returns: 97*9c5db199SXin Li True if tracing enabled and at least one event is enabled. 98*9c5db199SXin Li """ 99*9c5db199SXin Li result = int(utils.read_one_line(self._TRACE_ON_PATH).strip()) 100*9c5db199SXin Li if result == 1 and len(self._events) > 0: 101*9c5db199SXin Li return True 102*9c5db199SXin Li return False 103*9c5db199SXin Li 104*9c5db199SXin Li 105*9c5db199SXin Li def _event_onoff(self, event, val): 106*9c5db199SXin Li """Enable/Disable tracing event. 107*9c5db199SXin Li 108*9c5db199SXin Li TODO(tbroch) Consider allowing wild card enabling of trace events via 109*9c5db199SXin Li /sys/kernel/debug/tracing/set_event although it makes filling buffer 110*9c5db199SXin Li really easy 111*9c5db199SXin Li 112*9c5db199SXin Li Arguments: 113*9c5db199SXin Li event: list of events. 114*9c5db199SXin Li See kernel(Documentation/trace/events.txt) for formatting. 115*9c5db199SXin Li val: integer, 1 for on, 0 for off 116*9c5db199SXin Li 117*9c5db199SXin Li Returns: 118*9c5db199SXin Li True if success, false otherwise 119*9c5db199SXin Li """ 120*9c5db199SXin Li logging.debug("event_onoff: event:%s val:%d", event, val) 121*9c5db199SXin Li event_path = event.replace(':', '/') 122*9c5db199SXin Li fname = os.path.join(self._TRACE_ROOT, 'events', event_path, 'enable') 123*9c5db199SXin Li 124*9c5db199SXin Li if not os.path.exists(fname): 125*9c5db199SXin Li logging.warning("Unable to locate tracing event %s", fname) 126*9c5db199SXin Li return False 127*9c5db199SXin Li utils.write_one_line(fname, val) 128*9c5db199SXin Li 129*9c5db199SXin Li fname = os.path.join(self._TRACE_ROOT, "set_event") 130*9c5db199SXin Li found = False 131*9c5db199SXin Li with open(fname) as fd: 132*9c5db199SXin Li for ln in fd.readlines(): 133*9c5db199SXin Li logging.debug("set_event ln:%s", ln) 134*9c5db199SXin Li if re.findall(event, ln): 135*9c5db199SXin Li found = True 136*9c5db199SXin Li break 137*9c5db199SXin Li 138*9c5db199SXin Li if val == 1 and not found: 139*9c5db199SXin Li logging.warning("Event %s not enabled", event) 140*9c5db199SXin Li return False 141*9c5db199SXin Li 142*9c5db199SXin Li if val == 0 and found: 143*9c5db199SXin Li logging.warning("Event %s not disabled", event) 144*9c5db199SXin Li return False 145*9c5db199SXin Li 146*9c5db199SXin Li return True 147*9c5db199SXin Li 148*9c5db199SXin Li 149*9c5db199SXin Li def event_on(self, event): 150*9c5db199SXin Li return self._event_onoff(event, 1) 151*9c5db199SXin Li 152*9c5db199SXin Li 153*9c5db199SXin Li def event_off(self, event): 154*9c5db199SXin Li return self._event_onoff(event, 0) 155*9c5db199SXin Li 156*9c5db199SXin Li 157*9c5db199SXin Li def flush(self): 158*9c5db199SXin Li """Flush trace buffer. 159*9c5db199SXin Li 160*9c5db199SXin Li Raises: 161*9c5db199SXin Li error.TestFail: If unable to flush 162*9c5db199SXin Li """ 163*9c5db199SXin Li self.off() 164*9c5db199SXin Li fname = os.path.join(self._TRACE_ROOT, 'free_buffer') 165*9c5db199SXin Li utils.write_one_line(fname, 1) 166*9c5db199SXin Li self._buffer_ptr = 0 167*9c5db199SXin Li 168*9c5db199SXin Li fname = os.path.join(self._TRACE_ROOT, 'buffer_size_kb') 169*9c5db199SXin Li result = utils.read_one_line(fname).strip() 170*9c5db199SXin Li if result == '0': 171*9c5db199SXin Li return True 172*9c5db199SXin Li return False 173*9c5db199SXin Li 174*9c5db199SXin Li 175*9c5db199SXin Li def read(self, regexp=None): 176*9c5db199SXin Li fname = os.path.join(self._TRACE_ROOT, 'trace') 177*9c5db199SXin Li fd = open(fname) 178*9c5db199SXin Li fd.seek(self._buffer_ptr) 179*9c5db199SXin Li for ln in fd.readlines(): 180*9c5db199SXin Li if regexp is None: 181*9c5db199SXin Li self._buffer.append(ln) 182*9c5db199SXin Li continue 183*9c5db199SXin Li results = re.findall(regexp, ln) 184*9c5db199SXin Li if results: 185*9c5db199SXin Li logging.debug(ln) 186*9c5db199SXin Li self._buffer.append(results[0]) 187*9c5db199SXin Li self._buffer_ptr = fd.tell() 188*9c5db199SXin Li fd.close() 189*9c5db199SXin Li return self._buffer 190*9c5db199SXin Li 191*9c5db199SXin Li 192*9c5db199SXin Li @staticmethod 193*9c5db199SXin Li def uptime_secs(): 194*9c5db199SXin Li results = utils.read_one_line("/proc/uptime") 195*9c5db199SXin Li return float(results.split()[0]) 196