1 # Copyright (c) 2014 The Chromium OS 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 import os, re, subprocess 5 from autotest_lib.client.bin import test 6 from autotest_lib.client.common_lib import error 7 8 9 class platform_Perf(test.test): 10 """ 11 Gathers perf data and makes sure it is well-formed. 12 """ 13 version = 1 14 15 16 def run_once(self): 17 """ 18 Collect a perf data profile and check the detailed perf report. 19 """ 20 keyvals = {} 21 num_errors = 0 22 23 try: 24 # Create temporary file and get its name. Then close it. 25 perf_file_path = os.tempnam() 26 27 # Perf command for recording a profile. 28 perf_record_args = [ 'perf', 'record', '-a', '-o', perf_file_path, 29 '--', 'sleep', '2'] 30 # Perf command for getting a detailed report. 31 perf_report_args = [ 'perf', 'report', '-D', '-i', perf_file_path ] 32 33 try: 34 subprocess.check_output(perf_record_args, 35 stderr=subprocess.STDOUT) 36 except subprocess.CalledProcessError as cmd_error: 37 raise error.TestFail("Running command [%s] failed: %s" % 38 (' '.join(perf_record_args), 39 cmd_error.output)) 40 41 # Make sure the file still exists. 42 if not os.path.isfile(perf_file_path): 43 raise error.TestFail('Could not find perf output file: ' + 44 perf_file_path) 45 46 # Get detailed perf data view and extract the line containing the 47 # kernel MMAP summary. 48 result = None 49 p = subprocess.Popen(perf_report_args, stdout=subprocess.PIPE) 50 for line in p.stdout: 51 if 'PERF_RECORD_MMAP' in line and 'kallsyms' in line: 52 result = line 53 break; 54 55 # Read the rest of output to EOF. 56 for _ in p.stdout: 57 pass 58 p.wait(); 59 60 finally: 61 # Delete the perf data file. 62 try: 63 os.remove(perf_file_path) 64 except OSError as e: 65 if e.errno != errno.ENONENT: raise 66 67 if result is None: 68 raise error.TestFail('Could not find kernel mapping in perf ' 69 'report.') 70 # Get the kernel mapping values. 71 result = result.split(':')[2] 72 start, length, pgoff = re.sub(r'[][()@]', ' ', result).strip().split() 73 74 # Write keyvals. 75 keyvals = {} 76 keyvals['start'] = start 77 keyvals['length'] = length 78 keyvals['pgoff'] = pgoff 79 self.write_perf_keyval(keyvals) 80 81 # Make sure that the kernel mapping values follow an expected pattern, 82 # 83 # Expect one of two patterns: 84 # (1) start == pgoff, e.g.: 85 # start=0x80008200 86 # pgoff=0x80008200 87 # len =0xfffffff7ff7dff 88 # (2) start < pgoff < start + len, e.g.: 89 # start=0x3bc00000 90 # pgoff=0xffffffffbcc00198 91 # len =0xffffffff843fffff 92 start = int(start, 0) 93 length = int(length, 0) 94 pgoff = int(pgoff, 0) 95 if not (start == pgoff or start < pgoff < start + length): 96 raise error.TestFail('Improper kernel mapping values!') 97