1#!/usr/bin/python 2# 3# Copyright (c) 2015 The Chromium Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7import os 8 9from autotest_lib.client.bin import test, utils 10from autotest_lib.client.common_lib import error 11 12 13class platform_TraceClockMonotonic(test.test): 14 """ 15 This verifies that the kernel supports monotonic clock timestamps for 16 ftrace events. This is the same clock that Chrome will use for 17 timestamping its trace events. 18 """ 19 version = 1 20 21 executable = 'ftrace-clock-monotonic' 22 23 TRACE_PATH = '/sys/kernel/debug/tracing/' 24 TRACE_CLOCK = TRACE_PATH + 'trace_clock' 25 TRACE_FILE = TRACE_PATH + 'trace' 26 TRACE_ENABLE = TRACE_PATH + 'tracing_on' 27 28 def _setup_trace(self): 29 """ 30 Verify that the system supports the monotonic trace clock and set up 31 the trace system to use it, and clean up any old stuff in the trace 32 and enable it. 33 """ 34 with open(self.TRACE_CLOCK, 'r+') as clock: 35 content = clock.read() 36 if not 'mono' in content: 37 raise error.TestFail('Kernel does not support monotonic clock') 38 39 # Set up to use the monotonic clock 40 clock.write('mono') 41 42 # clear out the trace 43 with open(self.TRACE_FILE, 'w') as trace: 44 trace.write('') 45 46 # enable tracing 47 with open(self.TRACE_ENABLE, 'w') as enable: 48 enable.write('1') 49 50 def setup(self): 51 """Cleans and makes ftrace-clock-monotonic.c. 52 53 Prepares environment for tests by removing directory we will extract 54 to (if it exists), extracting tarball of tests, and making them. 55 """ 56 os.chdir(self.srcdir) 57 utils.make('clean') 58 utils.make() 59 60 def process_trace(self): 61 """Opens the trace file and processes it. 62 63 Looks for the 3 markers that are written out by the binary. The binary 64 gets a clock timestamp and then writes it out into the trace three times. 65 This looks at each entry and the content of the entry, and verifies that 66 they are all in chronological order. 67 Example trace file without the header: 68 <...>-16484 [003] ...1 509651.512676: tracing_mark_write: start: 509651.512651785 69 <...>-16484 [003] ...1 509651.512680: tracing_mark_write: middle: 509651.512678312 70 <...>-16484 [003] ...1 509651.512682: tracing_mark_write: end: 509651.512680934 71 """ 72 with open(self.TRACE_FILE, 'r') as trace: 73 prev_timestamp = 0 74 for line in trace: 75 if 'tracing_mark_write' not in line: 76 continue 77 78 columns = line.split() 79 entry_timestamp = float(columns[3].replace(':','')) 80 sample_timestamp = float(columns[6]) 81 if sample_timestamp > entry_timestamp: 82 raise error.TestFail('sample timestamp after trace marker entry') 83 84 if sample_timestamp < prev_timestamp: 85 raise error.TestFail('sample timestamp before previous timestamp') 86 prev_timestamp = entry_timestamp 87 88 if prev_timestamp == 0: 89 raise error.TestFail('no valid timestamps seen in trace file') 90 91 def run_once(self): 92 self._setup_trace() 93 binpath = os.path.join(self.srcdir, self.executable) 94 utils.system_output(binpath, retain_output = True) 95 self.process_trace() 96