162306a36Sopenharmony_ci#!/usr/bin/env python3 262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-only 362306a36Sopenharmony_ci# 462306a36Sopenharmony_ci# Tool for analyzing boot timing 562306a36Sopenharmony_ci# Copyright (c) 2013, Intel Corporation. 662306a36Sopenharmony_ci# 762306a36Sopenharmony_ci# This program is free software; you can redistribute it and/or modify it 862306a36Sopenharmony_ci# under the terms and conditions of the GNU General Public License, 962306a36Sopenharmony_ci# version 2, as published by the Free Software Foundation. 1062306a36Sopenharmony_ci# 1162306a36Sopenharmony_ci# This program is distributed in the hope it will be useful, but WITHOUT 1262306a36Sopenharmony_ci# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1362306a36Sopenharmony_ci# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1462306a36Sopenharmony_ci# more details. 1562306a36Sopenharmony_ci# 1662306a36Sopenharmony_ci# Authors: 1762306a36Sopenharmony_ci# Todd Brandt <todd.e.brandt@linux.intel.com> 1862306a36Sopenharmony_ci# 1962306a36Sopenharmony_ci# Description: 2062306a36Sopenharmony_ci# This tool is designed to assist kernel and OS developers in optimizing 2162306a36Sopenharmony_ci# their linux stack's boot time. It creates an html representation of 2262306a36Sopenharmony_ci# the kernel boot timeline up to the start of the init process. 2362306a36Sopenharmony_ci# 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci# ----------------- LIBRARIES -------------------- 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciimport sys 2862306a36Sopenharmony_ciimport time 2962306a36Sopenharmony_ciimport os 3062306a36Sopenharmony_ciimport string 3162306a36Sopenharmony_ciimport re 3262306a36Sopenharmony_ciimport platform 3362306a36Sopenharmony_ciimport shutil 3462306a36Sopenharmony_cifrom datetime import datetime, timedelta 3562306a36Sopenharmony_cifrom subprocess import call, Popen, PIPE 3662306a36Sopenharmony_ciimport sleepgraph as aslib 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cidef pprint(msg): 3962306a36Sopenharmony_ci print(msg) 4062306a36Sopenharmony_ci sys.stdout.flush() 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci# ----------------- CLASSES -------------------- 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci# Class: SystemValues 4562306a36Sopenharmony_ci# Description: 4662306a36Sopenharmony_ci# A global, single-instance container used to 4762306a36Sopenharmony_ci# store system values and test parameters 4862306a36Sopenharmony_ciclass SystemValues(aslib.SystemValues): 4962306a36Sopenharmony_ci title = 'BootGraph' 5062306a36Sopenharmony_ci version = '2.2' 5162306a36Sopenharmony_ci hostname = 'localhost' 5262306a36Sopenharmony_ci testtime = '' 5362306a36Sopenharmony_ci kernel = '' 5462306a36Sopenharmony_ci dmesgfile = '' 5562306a36Sopenharmony_ci ftracefile = '' 5662306a36Sopenharmony_ci htmlfile = 'bootgraph.html' 5762306a36Sopenharmony_ci testdir = '' 5862306a36Sopenharmony_ci kparams = '' 5962306a36Sopenharmony_ci result = '' 6062306a36Sopenharmony_ci useftrace = False 6162306a36Sopenharmony_ci usecallgraph = False 6262306a36Sopenharmony_ci suspendmode = 'boot' 6362306a36Sopenharmony_ci max_graph_depth = 2 6462306a36Sopenharmony_ci graph_filter = 'do_one_initcall' 6562306a36Sopenharmony_ci reboot = False 6662306a36Sopenharmony_ci manual = False 6762306a36Sopenharmony_ci iscronjob = False 6862306a36Sopenharmony_ci timeformat = '%.6f' 6962306a36Sopenharmony_ci bootloader = 'grub' 7062306a36Sopenharmony_ci blexec = [] 7162306a36Sopenharmony_ci def __init__(self): 7262306a36Sopenharmony_ci self.kernel, self.hostname = 'unknown', platform.node() 7362306a36Sopenharmony_ci self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S') 7462306a36Sopenharmony_ci if os.path.exists('/proc/version'): 7562306a36Sopenharmony_ci fp = open('/proc/version', 'r') 7662306a36Sopenharmony_ci self.kernel = self.kernelVersion(fp.read().strip()) 7762306a36Sopenharmony_ci fp.close() 7862306a36Sopenharmony_ci self.testdir = datetime.now().strftime('boot-%y%m%d-%H%M%S') 7962306a36Sopenharmony_ci def kernelVersion(self, msg): 8062306a36Sopenharmony_ci m = re.match('^[Ll]inux *[Vv]ersion *(?P<v>\S*) .*', msg) 8162306a36Sopenharmony_ci if m: 8262306a36Sopenharmony_ci return m.group('v') 8362306a36Sopenharmony_ci return 'unknown' 8462306a36Sopenharmony_ci def checkFtraceKernelVersion(self): 8562306a36Sopenharmony_ci m = re.match('^(?P<x>[0-9]*)\.(?P<y>[0-9]*)\.(?P<z>[0-9]*).*', self.kernel) 8662306a36Sopenharmony_ci if m: 8762306a36Sopenharmony_ci val = tuple(map(int, m.groups())) 8862306a36Sopenharmony_ci if val >= (4, 10, 0): 8962306a36Sopenharmony_ci return True 9062306a36Sopenharmony_ci return False 9162306a36Sopenharmony_ci def kernelParams(self): 9262306a36Sopenharmony_ci cmdline = 'initcall_debug log_buf_len=32M' 9362306a36Sopenharmony_ci if self.useftrace: 9462306a36Sopenharmony_ci if self.cpucount > 0: 9562306a36Sopenharmony_ci bs = min(self.memtotal // 2, 2*1024*1024) // self.cpucount 9662306a36Sopenharmony_ci else: 9762306a36Sopenharmony_ci bs = 131072 9862306a36Sopenharmony_ci cmdline += ' trace_buf_size=%dK trace_clock=global '\ 9962306a36Sopenharmony_ci 'trace_options=nooverwrite,funcgraph-abstime,funcgraph-cpu,'\ 10062306a36Sopenharmony_ci 'funcgraph-duration,funcgraph-proc,funcgraph-tail,'\ 10162306a36Sopenharmony_ci 'nofuncgraph-overhead,context-info,graph-time '\ 10262306a36Sopenharmony_ci 'ftrace=function_graph '\ 10362306a36Sopenharmony_ci 'ftrace_graph_max_depth=%d '\ 10462306a36Sopenharmony_ci 'ftrace_graph_filter=%s' % \ 10562306a36Sopenharmony_ci (bs, self.max_graph_depth, self.graph_filter) 10662306a36Sopenharmony_ci return cmdline 10762306a36Sopenharmony_ci def setGraphFilter(self, val): 10862306a36Sopenharmony_ci master = self.getBootFtraceFilterFunctions() 10962306a36Sopenharmony_ci fs = '' 11062306a36Sopenharmony_ci for i in val.split(','): 11162306a36Sopenharmony_ci func = i.strip() 11262306a36Sopenharmony_ci if func == '': 11362306a36Sopenharmony_ci doError('badly formatted filter function string') 11462306a36Sopenharmony_ci if '[' in func or ']' in func: 11562306a36Sopenharmony_ci doError('loadable module functions not allowed - "%s"' % func) 11662306a36Sopenharmony_ci if ' ' in func: 11762306a36Sopenharmony_ci doError('spaces found in filter functions - "%s"' % func) 11862306a36Sopenharmony_ci if func not in master: 11962306a36Sopenharmony_ci doError('function "%s" not available for ftrace' % func) 12062306a36Sopenharmony_ci if not fs: 12162306a36Sopenharmony_ci fs = func 12262306a36Sopenharmony_ci else: 12362306a36Sopenharmony_ci fs += ','+func 12462306a36Sopenharmony_ci if not fs: 12562306a36Sopenharmony_ci doError('badly formatted filter function string') 12662306a36Sopenharmony_ci self.graph_filter = fs 12762306a36Sopenharmony_ci def getBootFtraceFilterFunctions(self): 12862306a36Sopenharmony_ci self.rootCheck(True) 12962306a36Sopenharmony_ci fp = open(self.tpath+'available_filter_functions') 13062306a36Sopenharmony_ci fulllist = fp.read().split('\n') 13162306a36Sopenharmony_ci fp.close() 13262306a36Sopenharmony_ci list = [] 13362306a36Sopenharmony_ci for i in fulllist: 13462306a36Sopenharmony_ci if not i or ' ' in i or '[' in i or ']' in i: 13562306a36Sopenharmony_ci continue 13662306a36Sopenharmony_ci list.append(i) 13762306a36Sopenharmony_ci return list 13862306a36Sopenharmony_ci def myCronJob(self, line): 13962306a36Sopenharmony_ci if '@reboot' not in line: 14062306a36Sopenharmony_ci return False 14162306a36Sopenharmony_ci if 'bootgraph' in line or 'analyze_boot.py' in line or '-cronjob' in line: 14262306a36Sopenharmony_ci return True 14362306a36Sopenharmony_ci return False 14462306a36Sopenharmony_ci def cronjobCmdString(self): 14562306a36Sopenharmony_ci cmdline = '%s -cronjob' % os.path.abspath(sys.argv[0]) 14662306a36Sopenharmony_ci args = iter(sys.argv[1:]) 14762306a36Sopenharmony_ci for arg in args: 14862306a36Sopenharmony_ci if arg in ['-h', '-v', '-cronjob', '-reboot', '-verbose']: 14962306a36Sopenharmony_ci continue 15062306a36Sopenharmony_ci elif arg in ['-o', '-dmesg', '-ftrace', '-func']: 15162306a36Sopenharmony_ci next(args) 15262306a36Sopenharmony_ci continue 15362306a36Sopenharmony_ci elif arg == '-result': 15462306a36Sopenharmony_ci cmdline += ' %s "%s"' % (arg, os.path.abspath(next(args))) 15562306a36Sopenharmony_ci continue 15662306a36Sopenharmony_ci elif arg == '-cgskip': 15762306a36Sopenharmony_ci file = self.configFile(next(args)) 15862306a36Sopenharmony_ci cmdline += ' %s "%s"' % (arg, os.path.abspath(file)) 15962306a36Sopenharmony_ci continue 16062306a36Sopenharmony_ci cmdline += ' '+arg 16162306a36Sopenharmony_ci if self.graph_filter != 'do_one_initcall': 16262306a36Sopenharmony_ci cmdline += ' -func "%s"' % self.graph_filter 16362306a36Sopenharmony_ci cmdline += ' -o "%s"' % os.path.abspath(self.testdir) 16462306a36Sopenharmony_ci return cmdline 16562306a36Sopenharmony_ci def manualRebootRequired(self): 16662306a36Sopenharmony_ci cmdline = self.kernelParams() 16762306a36Sopenharmony_ci pprint('To generate a new timeline manually, follow these steps:\n\n'\ 16862306a36Sopenharmony_ci '1. Add the CMDLINE string to your kernel command line.\n'\ 16962306a36Sopenharmony_ci '2. Reboot the system.\n'\ 17062306a36Sopenharmony_ci '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n\n'\ 17162306a36Sopenharmony_ci 'CMDLINE="%s"' % cmdline) 17262306a36Sopenharmony_ci sys.exit() 17362306a36Sopenharmony_ci def blGrub(self): 17462306a36Sopenharmony_ci blcmd = '' 17562306a36Sopenharmony_ci for cmd in ['update-grub', 'grub-mkconfig', 'grub2-mkconfig']: 17662306a36Sopenharmony_ci if blcmd: 17762306a36Sopenharmony_ci break 17862306a36Sopenharmony_ci blcmd = self.getExec(cmd) 17962306a36Sopenharmony_ci if not blcmd: 18062306a36Sopenharmony_ci doError('[GRUB] missing update command') 18162306a36Sopenharmony_ci if not os.path.exists('/etc/default/grub'): 18262306a36Sopenharmony_ci doError('[GRUB] missing /etc/default/grub') 18362306a36Sopenharmony_ci if 'grub2' in blcmd: 18462306a36Sopenharmony_ci cfg = '/boot/grub2/grub.cfg' 18562306a36Sopenharmony_ci else: 18662306a36Sopenharmony_ci cfg = '/boot/grub/grub.cfg' 18762306a36Sopenharmony_ci if not os.path.exists(cfg): 18862306a36Sopenharmony_ci doError('[GRUB] missing %s' % cfg) 18962306a36Sopenharmony_ci if 'update-grub' in blcmd: 19062306a36Sopenharmony_ci self.blexec = [blcmd] 19162306a36Sopenharmony_ci else: 19262306a36Sopenharmony_ci self.blexec = [blcmd, '-o', cfg] 19362306a36Sopenharmony_ci def getBootLoader(self): 19462306a36Sopenharmony_ci if self.bootloader == 'grub': 19562306a36Sopenharmony_ci self.blGrub() 19662306a36Sopenharmony_ci else: 19762306a36Sopenharmony_ci doError('unknown boot loader: %s' % self.bootloader) 19862306a36Sopenharmony_ci def writeDatafileHeader(self, filename): 19962306a36Sopenharmony_ci self.kparams = open('/proc/cmdline', 'r').read().strip() 20062306a36Sopenharmony_ci fp = open(filename, 'w') 20162306a36Sopenharmony_ci fp.write(self.teststamp+'\n') 20262306a36Sopenharmony_ci fp.write(self.sysstamp+'\n') 20362306a36Sopenharmony_ci fp.write('# command | %s\n' % self.cmdline) 20462306a36Sopenharmony_ci fp.write('# kparams | %s\n' % self.kparams) 20562306a36Sopenharmony_ci fp.close() 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cisysvals = SystemValues() 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci# Class: Data 21062306a36Sopenharmony_ci# Description: 21162306a36Sopenharmony_ci# The primary container for test data. 21262306a36Sopenharmony_ciclass Data(aslib.Data): 21362306a36Sopenharmony_ci dmesg = {} # root data structure 21462306a36Sopenharmony_ci start = 0.0 # test start 21562306a36Sopenharmony_ci end = 0.0 # test end 21662306a36Sopenharmony_ci dmesgtext = [] # dmesg text file in memory 21762306a36Sopenharmony_ci testnumber = 0 21862306a36Sopenharmony_ci idstr = '' 21962306a36Sopenharmony_ci html_device_id = 0 22062306a36Sopenharmony_ci valid = False 22162306a36Sopenharmony_ci tUserMode = 0.0 22262306a36Sopenharmony_ci boottime = '' 22362306a36Sopenharmony_ci phases = ['kernel', 'user'] 22462306a36Sopenharmony_ci do_one_initcall = False 22562306a36Sopenharmony_ci def __init__(self, num): 22662306a36Sopenharmony_ci self.testnumber = num 22762306a36Sopenharmony_ci self.idstr = 'a' 22862306a36Sopenharmony_ci self.dmesgtext = [] 22962306a36Sopenharmony_ci self.dmesg = { 23062306a36Sopenharmony_ci 'kernel': {'list': dict(), 'start': -1.0, 'end': -1.0, 'row': 0, 23162306a36Sopenharmony_ci 'order': 0, 'color': 'linear-gradient(to bottom, #fff, #bcf)'}, 23262306a36Sopenharmony_ci 'user': {'list': dict(), 'start': -1.0, 'end': -1.0, 'row': 0, 23362306a36Sopenharmony_ci 'order': 1, 'color': '#fff'} 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci def deviceTopology(self): 23662306a36Sopenharmony_ci return '' 23762306a36Sopenharmony_ci def newAction(self, phase, name, pid, start, end, ret, ulen): 23862306a36Sopenharmony_ci # new device callback for a specific phase 23962306a36Sopenharmony_ci self.html_device_id += 1 24062306a36Sopenharmony_ci devid = '%s%d' % (self.idstr, self.html_device_id) 24162306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 24262306a36Sopenharmony_ci length = -1.0 24362306a36Sopenharmony_ci if(start >= 0 and end >= 0): 24462306a36Sopenharmony_ci length = end - start 24562306a36Sopenharmony_ci i = 2 24662306a36Sopenharmony_ci origname = name 24762306a36Sopenharmony_ci while(name in list): 24862306a36Sopenharmony_ci name = '%s[%d]' % (origname, i) 24962306a36Sopenharmony_ci i += 1 25062306a36Sopenharmony_ci list[name] = {'name': name, 'start': start, 'end': end, 25162306a36Sopenharmony_ci 'pid': pid, 'length': length, 'row': 0, 'id': devid, 25262306a36Sopenharmony_ci 'ret': ret, 'ulen': ulen } 25362306a36Sopenharmony_ci return name 25462306a36Sopenharmony_ci def deviceMatch(self, pid, cg): 25562306a36Sopenharmony_ci if cg.end - cg.start == 0: 25662306a36Sopenharmony_ci return '' 25762306a36Sopenharmony_ci for p in data.phases: 25862306a36Sopenharmony_ci list = self.dmesg[p]['list'] 25962306a36Sopenharmony_ci for devname in list: 26062306a36Sopenharmony_ci dev = list[devname] 26162306a36Sopenharmony_ci if pid != dev['pid']: 26262306a36Sopenharmony_ci continue 26362306a36Sopenharmony_ci if cg.name == 'do_one_initcall': 26462306a36Sopenharmony_ci if(cg.start <= dev['start'] and cg.end >= dev['end'] and dev['length'] > 0): 26562306a36Sopenharmony_ci dev['ftrace'] = cg 26662306a36Sopenharmony_ci self.do_one_initcall = True 26762306a36Sopenharmony_ci return devname 26862306a36Sopenharmony_ci else: 26962306a36Sopenharmony_ci if(cg.start > dev['start'] and cg.end < dev['end']): 27062306a36Sopenharmony_ci if 'ftraces' not in dev: 27162306a36Sopenharmony_ci dev['ftraces'] = [] 27262306a36Sopenharmony_ci dev['ftraces'].append(cg) 27362306a36Sopenharmony_ci return devname 27462306a36Sopenharmony_ci return '' 27562306a36Sopenharmony_ci def printDetails(self): 27662306a36Sopenharmony_ci sysvals.vprint('Timeline Details:') 27762306a36Sopenharmony_ci sysvals.vprint(' Host: %s' % sysvals.hostname) 27862306a36Sopenharmony_ci sysvals.vprint(' Kernel: %s' % sysvals.kernel) 27962306a36Sopenharmony_ci sysvals.vprint(' Test time: %s' % sysvals.testtime) 28062306a36Sopenharmony_ci sysvals.vprint(' Boot time: %s' % self.boottime) 28162306a36Sopenharmony_ci for phase in self.phases: 28262306a36Sopenharmony_ci dc = len(self.dmesg[phase]['list']) 28362306a36Sopenharmony_ci sysvals.vprint('%9s mode: %.3f - %.3f (%d initcalls)' % (phase, 28462306a36Sopenharmony_ci self.dmesg[phase]['start']*1000, 28562306a36Sopenharmony_ci self.dmesg[phase]['end']*1000, dc)) 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci# ----------------- FUNCTIONS -------------------- 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci# Function: parseKernelLog 29062306a36Sopenharmony_ci# Description: 29162306a36Sopenharmony_ci# parse a kernel log for boot data 29262306a36Sopenharmony_cidef parseKernelLog(): 29362306a36Sopenharmony_ci sysvals.vprint('Analyzing the dmesg data (%s)...' % \ 29462306a36Sopenharmony_ci os.path.basename(sysvals.dmesgfile)) 29562306a36Sopenharmony_ci phase = 'kernel' 29662306a36Sopenharmony_ci data = Data(0) 29762306a36Sopenharmony_ci data.dmesg['kernel']['start'] = data.start = ktime = 0.0 29862306a36Sopenharmony_ci sysvals.stamp = { 29962306a36Sopenharmony_ci 'time': datetime.now().strftime('%B %d %Y, %I:%M:%S %p'), 30062306a36Sopenharmony_ci 'host': sysvals.hostname, 30162306a36Sopenharmony_ci 'mode': 'boot', 'kernel': ''} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci tp = aslib.TestProps() 30462306a36Sopenharmony_ci devtemp = dict() 30562306a36Sopenharmony_ci if(sysvals.dmesgfile): 30662306a36Sopenharmony_ci lf = open(sysvals.dmesgfile, 'rb') 30762306a36Sopenharmony_ci else: 30862306a36Sopenharmony_ci lf = Popen('dmesg', stdout=PIPE).stdout 30962306a36Sopenharmony_ci for line in lf: 31062306a36Sopenharmony_ci line = aslib.ascii(line).replace('\r\n', '') 31162306a36Sopenharmony_ci # grab the stamp and sysinfo 31262306a36Sopenharmony_ci if re.match(tp.stampfmt, line): 31362306a36Sopenharmony_ci tp.stamp = line 31462306a36Sopenharmony_ci continue 31562306a36Sopenharmony_ci elif re.match(tp.sysinfofmt, line): 31662306a36Sopenharmony_ci tp.sysinfo = line 31762306a36Sopenharmony_ci continue 31862306a36Sopenharmony_ci elif re.match(tp.cmdlinefmt, line): 31962306a36Sopenharmony_ci tp.cmdline = line 32062306a36Sopenharmony_ci continue 32162306a36Sopenharmony_ci elif re.match(tp.kparamsfmt, line): 32262306a36Sopenharmony_ci tp.kparams = line 32362306a36Sopenharmony_ci continue 32462306a36Sopenharmony_ci idx = line.find('[') 32562306a36Sopenharmony_ci if idx > 1: 32662306a36Sopenharmony_ci line = line[idx:] 32762306a36Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 32862306a36Sopenharmony_ci if(not m): 32962306a36Sopenharmony_ci continue 33062306a36Sopenharmony_ci ktime = float(m.group('ktime')) 33162306a36Sopenharmony_ci if(ktime > 120): 33262306a36Sopenharmony_ci break 33362306a36Sopenharmony_ci msg = m.group('msg') 33462306a36Sopenharmony_ci data.dmesgtext.append(line) 33562306a36Sopenharmony_ci if(ktime == 0.0 and re.match('^Linux version .*', msg)): 33662306a36Sopenharmony_ci if(not sysvals.stamp['kernel']): 33762306a36Sopenharmony_ci sysvals.stamp['kernel'] = sysvals.kernelVersion(msg) 33862306a36Sopenharmony_ci continue 33962306a36Sopenharmony_ci m = re.match('.* setting system clock to (?P<d>[0-9\-]*)[ A-Z](?P<t>[0-9:]*) UTC.*', msg) 34062306a36Sopenharmony_ci if(m): 34162306a36Sopenharmony_ci bt = datetime.strptime(m.group('d')+' '+m.group('t'), '%Y-%m-%d %H:%M:%S') 34262306a36Sopenharmony_ci bt = bt - timedelta(seconds=int(ktime)) 34362306a36Sopenharmony_ci data.boottime = bt.strftime('%Y-%m-%d_%H:%M:%S') 34462306a36Sopenharmony_ci sysvals.stamp['time'] = bt.strftime('%B %d %Y, %I:%M:%S %p') 34562306a36Sopenharmony_ci continue 34662306a36Sopenharmony_ci m = re.match('^calling *(?P<f>.*)\+.* @ (?P<p>[0-9]*)', msg) 34762306a36Sopenharmony_ci if(m): 34862306a36Sopenharmony_ci func = m.group('f') 34962306a36Sopenharmony_ci pid = int(m.group('p')) 35062306a36Sopenharmony_ci devtemp[func] = (ktime, pid) 35162306a36Sopenharmony_ci continue 35262306a36Sopenharmony_ci m = re.match('^initcall *(?P<f>.*)\+.* returned (?P<r>.*) after (?P<t>.*) usecs', msg) 35362306a36Sopenharmony_ci if(m): 35462306a36Sopenharmony_ci data.valid = True 35562306a36Sopenharmony_ci data.end = ktime 35662306a36Sopenharmony_ci f, r, t = m.group('f', 'r', 't') 35762306a36Sopenharmony_ci if(f in devtemp): 35862306a36Sopenharmony_ci start, pid = devtemp[f] 35962306a36Sopenharmony_ci data.newAction(phase, f, pid, start, ktime, int(r), int(t)) 36062306a36Sopenharmony_ci del devtemp[f] 36162306a36Sopenharmony_ci continue 36262306a36Sopenharmony_ci if(re.match('^Freeing unused kernel .*', msg)): 36362306a36Sopenharmony_ci data.tUserMode = ktime 36462306a36Sopenharmony_ci data.dmesg['kernel']['end'] = ktime 36562306a36Sopenharmony_ci data.dmesg['user']['start'] = ktime 36662306a36Sopenharmony_ci phase = 'user' 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if tp.stamp: 36962306a36Sopenharmony_ci sysvals.stamp = 0 37062306a36Sopenharmony_ci tp.parseStamp(data, sysvals) 37162306a36Sopenharmony_ci data.dmesg['user']['end'] = data.end 37262306a36Sopenharmony_ci lf.close() 37362306a36Sopenharmony_ci return data 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci# Function: parseTraceLog 37662306a36Sopenharmony_ci# Description: 37762306a36Sopenharmony_ci# Check if trace is available and copy to a temp file 37862306a36Sopenharmony_cidef parseTraceLog(data): 37962306a36Sopenharmony_ci sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 38062306a36Sopenharmony_ci os.path.basename(sysvals.ftracefile)) 38162306a36Sopenharmony_ci # if available, calculate cgfilter allowable ranges 38262306a36Sopenharmony_ci cgfilter = [] 38362306a36Sopenharmony_ci if len(sysvals.cgfilter) > 0: 38462306a36Sopenharmony_ci for p in data.phases: 38562306a36Sopenharmony_ci list = data.dmesg[p]['list'] 38662306a36Sopenharmony_ci for i in sysvals.cgfilter: 38762306a36Sopenharmony_ci if i in list: 38862306a36Sopenharmony_ci cgfilter.append([list[i]['start']-0.0001, 38962306a36Sopenharmony_ci list[i]['end']+0.0001]) 39062306a36Sopenharmony_ci # parse the trace log 39162306a36Sopenharmony_ci ftemp = dict() 39262306a36Sopenharmony_ci tp = aslib.TestProps() 39362306a36Sopenharmony_ci tp.setTracerType('function_graph') 39462306a36Sopenharmony_ci tf = open(sysvals.ftracefile, 'r') 39562306a36Sopenharmony_ci for line in tf: 39662306a36Sopenharmony_ci if line[0] == '#': 39762306a36Sopenharmony_ci continue 39862306a36Sopenharmony_ci m = re.match(tp.ftrace_line_fmt, line.strip()) 39962306a36Sopenharmony_ci if(not m): 40062306a36Sopenharmony_ci continue 40162306a36Sopenharmony_ci m_time, m_proc, m_pid, m_msg, m_dur = \ 40262306a36Sopenharmony_ci m.group('time', 'proc', 'pid', 'msg', 'dur') 40362306a36Sopenharmony_ci t = float(m_time) 40462306a36Sopenharmony_ci if len(cgfilter) > 0: 40562306a36Sopenharmony_ci allow = False 40662306a36Sopenharmony_ci for r in cgfilter: 40762306a36Sopenharmony_ci if t >= r[0] and t < r[1]: 40862306a36Sopenharmony_ci allow = True 40962306a36Sopenharmony_ci break 41062306a36Sopenharmony_ci if not allow: 41162306a36Sopenharmony_ci continue 41262306a36Sopenharmony_ci if t > data.end: 41362306a36Sopenharmony_ci break 41462306a36Sopenharmony_ci if(m_time and m_pid and m_msg): 41562306a36Sopenharmony_ci t = aslib.FTraceLine(m_time, m_msg, m_dur) 41662306a36Sopenharmony_ci pid = int(m_pid) 41762306a36Sopenharmony_ci else: 41862306a36Sopenharmony_ci continue 41962306a36Sopenharmony_ci if t.fevent or t.fkprobe: 42062306a36Sopenharmony_ci continue 42162306a36Sopenharmony_ci key = (m_proc, pid) 42262306a36Sopenharmony_ci if(key not in ftemp): 42362306a36Sopenharmony_ci ftemp[key] = [] 42462306a36Sopenharmony_ci ftemp[key].append(aslib.FTraceCallGraph(pid, sysvals)) 42562306a36Sopenharmony_ci cg = ftemp[key][-1] 42662306a36Sopenharmony_ci res = cg.addLine(t) 42762306a36Sopenharmony_ci if(res != 0): 42862306a36Sopenharmony_ci ftemp[key].append(aslib.FTraceCallGraph(pid, sysvals)) 42962306a36Sopenharmony_ci if(res == -1): 43062306a36Sopenharmony_ci ftemp[key][-1].addLine(t) 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci tf.close() 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci # add the callgraph data to the device hierarchy 43562306a36Sopenharmony_ci for key in ftemp: 43662306a36Sopenharmony_ci proc, pid = key 43762306a36Sopenharmony_ci for cg in ftemp[key]: 43862306a36Sopenharmony_ci if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 43962306a36Sopenharmony_ci continue 44062306a36Sopenharmony_ci if(not cg.postProcess()): 44162306a36Sopenharmony_ci pprint('Sanity check failed for %s-%d' % (proc, pid)) 44262306a36Sopenharmony_ci continue 44362306a36Sopenharmony_ci # match cg data to devices 44462306a36Sopenharmony_ci devname = data.deviceMatch(pid, cg) 44562306a36Sopenharmony_ci if not devname: 44662306a36Sopenharmony_ci kind = 'Orphan' 44762306a36Sopenharmony_ci if cg.partial: 44862306a36Sopenharmony_ci kind = 'Partial' 44962306a36Sopenharmony_ci sysvals.vprint('%s callgraph found for %s %s-%d [%f - %f]' %\ 45062306a36Sopenharmony_ci (kind, cg.name, proc, pid, cg.start, cg.end)) 45162306a36Sopenharmony_ci elif len(cg.list) > 1000000: 45262306a36Sopenharmony_ci pprint('WARNING: the callgraph found for %s is massive! (%d lines)' %\ 45362306a36Sopenharmony_ci (devname, len(cg.list))) 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci# Function: retrieveLogs 45662306a36Sopenharmony_ci# Description: 45762306a36Sopenharmony_ci# Create copies of dmesg and/or ftrace for later processing 45862306a36Sopenharmony_cidef retrieveLogs(): 45962306a36Sopenharmony_ci # check ftrace is configured first 46062306a36Sopenharmony_ci if sysvals.useftrace: 46162306a36Sopenharmony_ci tracer = sysvals.fgetVal('current_tracer').strip() 46262306a36Sopenharmony_ci if tracer != 'function_graph': 46362306a36Sopenharmony_ci doError('ftrace not configured for a boot callgraph') 46462306a36Sopenharmony_ci # create the folder and get dmesg 46562306a36Sopenharmony_ci sysvals.systemInfo(aslib.dmidecode(sysvals.mempath)) 46662306a36Sopenharmony_ci sysvals.initTestOutput('boot') 46762306a36Sopenharmony_ci sysvals.writeDatafileHeader(sysvals.dmesgfile) 46862306a36Sopenharmony_ci call('dmesg >> '+sysvals.dmesgfile, shell=True) 46962306a36Sopenharmony_ci if not sysvals.useftrace: 47062306a36Sopenharmony_ci return 47162306a36Sopenharmony_ci # get ftrace 47262306a36Sopenharmony_ci sysvals.writeDatafileHeader(sysvals.ftracefile) 47362306a36Sopenharmony_ci call('cat '+sysvals.tpath+'trace >> '+sysvals.ftracefile, shell=True) 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci# Function: colorForName 47662306a36Sopenharmony_ci# Description: 47762306a36Sopenharmony_ci# Generate a repeatable color from a list for a given name 47862306a36Sopenharmony_cidef colorForName(name): 47962306a36Sopenharmony_ci list = [ 48062306a36Sopenharmony_ci ('c1', '#ec9999'), 48162306a36Sopenharmony_ci ('c2', '#ffc1a6'), 48262306a36Sopenharmony_ci ('c3', '#fff0a6'), 48362306a36Sopenharmony_ci ('c4', '#adf199'), 48462306a36Sopenharmony_ci ('c5', '#9fadea'), 48562306a36Sopenharmony_ci ('c6', '#a699c1'), 48662306a36Sopenharmony_ci ('c7', '#ad99b4'), 48762306a36Sopenharmony_ci ('c8', '#eaffea'), 48862306a36Sopenharmony_ci ('c9', '#dcecfb'), 48962306a36Sopenharmony_ci ('c10', '#ffffea') 49062306a36Sopenharmony_ci ] 49162306a36Sopenharmony_ci i = 0 49262306a36Sopenharmony_ci total = 0 49362306a36Sopenharmony_ci count = len(list) 49462306a36Sopenharmony_ci while i < len(name): 49562306a36Sopenharmony_ci total += ord(name[i]) 49662306a36Sopenharmony_ci i += 1 49762306a36Sopenharmony_ci return list[total % count] 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cidef cgOverview(cg, minlen): 50062306a36Sopenharmony_ci stats = dict() 50162306a36Sopenharmony_ci large = [] 50262306a36Sopenharmony_ci for l in cg.list: 50362306a36Sopenharmony_ci if l.fcall and l.depth == 1: 50462306a36Sopenharmony_ci if l.length >= minlen: 50562306a36Sopenharmony_ci large.append(l) 50662306a36Sopenharmony_ci if l.name not in stats: 50762306a36Sopenharmony_ci stats[l.name] = [0, 0.0] 50862306a36Sopenharmony_ci stats[l.name][0] += (l.length * 1000.0) 50962306a36Sopenharmony_ci stats[l.name][1] += 1 51062306a36Sopenharmony_ci return (large, stats) 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci# Function: createBootGraph 51362306a36Sopenharmony_ci# Description: 51462306a36Sopenharmony_ci# Create the output html file from the resident test data 51562306a36Sopenharmony_ci# Arguments: 51662306a36Sopenharmony_ci# testruns: array of Data objects from parseKernelLog or parseTraceLog 51762306a36Sopenharmony_ci# Output: 51862306a36Sopenharmony_ci# True if the html file was created, false if it failed 51962306a36Sopenharmony_cidef createBootGraph(data): 52062306a36Sopenharmony_ci # html function templates 52162306a36Sopenharmony_ci html_srccall = '<div id={6} title="{5}" class="srccall" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;">{0}</div>\n' 52262306a36Sopenharmony_ci html_timetotal = '<table class="time1">\n<tr>'\ 52362306a36Sopenharmony_ci '<td class="blue">Init process starts @ <b>{0} ms</b></td>'\ 52462306a36Sopenharmony_ci '<td class="blue">Last initcall ends @ <b>{1} ms</b></td>'\ 52562306a36Sopenharmony_ci '</tr>\n</table>\n' 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci # device timeline 52862306a36Sopenharmony_ci devtl = aslib.Timeline(100, 20) 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci # write the test title and general info header 53162306a36Sopenharmony_ci devtl.createHeader(sysvals, sysvals.stamp) 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci # Generate the header for this timeline 53462306a36Sopenharmony_ci t0 = data.start 53562306a36Sopenharmony_ci tMax = data.end 53662306a36Sopenharmony_ci tTotal = tMax - t0 53762306a36Sopenharmony_ci if(tTotal == 0): 53862306a36Sopenharmony_ci pprint('ERROR: No timeline data') 53962306a36Sopenharmony_ci return False 54062306a36Sopenharmony_ci user_mode = '%.0f'%(data.tUserMode*1000) 54162306a36Sopenharmony_ci last_init = '%.0f'%(tTotal*1000) 54262306a36Sopenharmony_ci devtl.html += html_timetotal.format(user_mode, last_init) 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci # determine the maximum number of rows we need to draw 54562306a36Sopenharmony_ci devlist = [] 54662306a36Sopenharmony_ci for p in data.phases: 54762306a36Sopenharmony_ci list = data.dmesg[p]['list'] 54862306a36Sopenharmony_ci for devname in list: 54962306a36Sopenharmony_ci d = aslib.DevItem(0, p, list[devname]) 55062306a36Sopenharmony_ci devlist.append(d) 55162306a36Sopenharmony_ci devtl.getPhaseRows(devlist, 0, 'start') 55262306a36Sopenharmony_ci devtl.calcTotalRows() 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci # draw the timeline background 55562306a36Sopenharmony_ci devtl.createZoomBox() 55662306a36Sopenharmony_ci devtl.html += devtl.html_tblock.format('boot', '0', '100', devtl.scaleH) 55762306a36Sopenharmony_ci for p in data.phases: 55862306a36Sopenharmony_ci phase = data.dmesg[p] 55962306a36Sopenharmony_ci length = phase['end']-phase['start'] 56062306a36Sopenharmony_ci left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) 56162306a36Sopenharmony_ci width = '%.3f' % ((length*100.0)/tTotal) 56262306a36Sopenharmony_ci devtl.html += devtl.html_phase.format(left, width, \ 56362306a36Sopenharmony_ci '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ 56462306a36Sopenharmony_ci phase['color'], '') 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci # draw the device timeline 56762306a36Sopenharmony_ci num = 0 56862306a36Sopenharmony_ci devstats = dict() 56962306a36Sopenharmony_ci for phase in data.phases: 57062306a36Sopenharmony_ci list = data.dmesg[phase]['list'] 57162306a36Sopenharmony_ci for devname in sorted(list): 57262306a36Sopenharmony_ci cls, color = colorForName(devname) 57362306a36Sopenharmony_ci dev = list[devname] 57462306a36Sopenharmony_ci info = '@|%.3f|%.3f|%.3f|%d' % (dev['start']*1000.0, dev['end']*1000.0, 57562306a36Sopenharmony_ci dev['ulen']/1000.0, dev['ret']) 57662306a36Sopenharmony_ci devstats[dev['id']] = {'info':info} 57762306a36Sopenharmony_ci dev['color'] = color 57862306a36Sopenharmony_ci height = devtl.phaseRowHeight(0, phase, dev['row']) 57962306a36Sopenharmony_ci top = '%.6f' % ((dev['row']*height) + devtl.scaleH) 58062306a36Sopenharmony_ci left = '%.6f' % (((dev['start']-t0)*100)/tTotal) 58162306a36Sopenharmony_ci width = '%.6f' % (((dev['end']-dev['start'])*100)/tTotal) 58262306a36Sopenharmony_ci length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) 58362306a36Sopenharmony_ci devtl.html += devtl.html_device.format(dev['id'], 58462306a36Sopenharmony_ci devname+length+phase+'_mode', left, top, '%.3f'%height, 58562306a36Sopenharmony_ci width, devname, ' '+cls, '') 58662306a36Sopenharmony_ci rowtop = devtl.phaseRowTop(0, phase, dev['row']) 58762306a36Sopenharmony_ci height = '%.6f' % (devtl.rowH / 2) 58862306a36Sopenharmony_ci top = '%.6f' % (rowtop + devtl.scaleH + (devtl.rowH / 2)) 58962306a36Sopenharmony_ci if data.do_one_initcall: 59062306a36Sopenharmony_ci if('ftrace' not in dev): 59162306a36Sopenharmony_ci continue 59262306a36Sopenharmony_ci cg = dev['ftrace'] 59362306a36Sopenharmony_ci large, stats = cgOverview(cg, 0.001) 59462306a36Sopenharmony_ci devstats[dev['id']]['fstat'] = stats 59562306a36Sopenharmony_ci for l in large: 59662306a36Sopenharmony_ci left = '%f' % (((l.time-t0)*100)/tTotal) 59762306a36Sopenharmony_ci width = '%f' % (l.length*100/tTotal) 59862306a36Sopenharmony_ci title = '%s (%0.3fms)' % (l.name, l.length * 1000.0) 59962306a36Sopenharmony_ci devtl.html += html_srccall.format(l.name, left, 60062306a36Sopenharmony_ci top, height, width, title, 'x%d'%num) 60162306a36Sopenharmony_ci num += 1 60262306a36Sopenharmony_ci continue 60362306a36Sopenharmony_ci if('ftraces' not in dev): 60462306a36Sopenharmony_ci continue 60562306a36Sopenharmony_ci for cg in dev['ftraces']: 60662306a36Sopenharmony_ci left = '%f' % (((cg.start-t0)*100)/tTotal) 60762306a36Sopenharmony_ci width = '%f' % ((cg.end-cg.start)*100/tTotal) 60862306a36Sopenharmony_ci cglen = (cg.end - cg.start) * 1000.0 60962306a36Sopenharmony_ci title = '%s (%0.3fms)' % (cg.name, cglen) 61062306a36Sopenharmony_ci cg.id = 'x%d' % num 61162306a36Sopenharmony_ci devtl.html += html_srccall.format(cg.name, left, 61262306a36Sopenharmony_ci top, height, width, title, dev['id']+cg.id) 61362306a36Sopenharmony_ci num += 1 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci # draw the time scale, try to make the number of labels readable 61662306a36Sopenharmony_ci devtl.createTimeScale(t0, tMax, tTotal, 'boot') 61762306a36Sopenharmony_ci devtl.html += '</div>\n' 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci # timeline is finished 62062306a36Sopenharmony_ci devtl.html += '</div>\n</div>\n' 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci # draw a legend which describes the phases by color 62362306a36Sopenharmony_ci devtl.html += '<div class="legend">\n' 62462306a36Sopenharmony_ci pdelta = 20.0 62562306a36Sopenharmony_ci pmargin = 36.0 62662306a36Sopenharmony_ci for phase in data.phases: 62762306a36Sopenharmony_ci order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin) 62862306a36Sopenharmony_ci devtl.html += devtl.html_legend.format(order, \ 62962306a36Sopenharmony_ci data.dmesg[phase]['color'], phase+'_mode', phase[0]) 63062306a36Sopenharmony_ci devtl.html += '</div>\n' 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci hf = open(sysvals.htmlfile, 'w') 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci # add the css 63562306a36Sopenharmony_ci extra = '\ 63662306a36Sopenharmony_ci .c1 {background:rgba(209,0,0,0.4);}\n\ 63762306a36Sopenharmony_ci .c2 {background:rgba(255,102,34,0.4);}\n\ 63862306a36Sopenharmony_ci .c3 {background:rgba(255,218,33,0.4);}\n\ 63962306a36Sopenharmony_ci .c4 {background:rgba(51,221,0,0.4);}\n\ 64062306a36Sopenharmony_ci .c5 {background:rgba(17,51,204,0.4);}\n\ 64162306a36Sopenharmony_ci .c6 {background:rgba(34,0,102,0.4);}\n\ 64262306a36Sopenharmony_ci .c7 {background:rgba(51,0,68,0.4);}\n\ 64362306a36Sopenharmony_ci .c8 {background:rgba(204,255,204,0.4);}\n\ 64462306a36Sopenharmony_ci .c9 {background:rgba(169,208,245,0.4);}\n\ 64562306a36Sopenharmony_ci .c10 {background:rgba(255,255,204,0.4);}\n\ 64662306a36Sopenharmony_ci .vt {transform:rotate(-60deg);transform-origin:0 0;}\n\ 64762306a36Sopenharmony_ci table.fstat {table-layout:fixed;padding:150px 15px 0 0;font-size:10px;column-width:30px;}\n\ 64862306a36Sopenharmony_ci .fstat th {width:55px;}\n\ 64962306a36Sopenharmony_ci .fstat td {text-align:left;width:35px;}\n\ 65062306a36Sopenharmony_ci .srccall {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\ 65162306a36Sopenharmony_ci .srccall:hover {color:white;font-weight:bold;border:1px solid white;}\n' 65262306a36Sopenharmony_ci aslib.addCSS(hf, sysvals, 1, False, extra) 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci # write the device timeline 65562306a36Sopenharmony_ci hf.write(devtl.html) 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci # add boot specific html 65862306a36Sopenharmony_ci statinfo = 'var devstats = {\n' 65962306a36Sopenharmony_ci for n in sorted(devstats): 66062306a36Sopenharmony_ci statinfo += '\t"%s": [\n\t\t"%s",\n' % (n, devstats[n]['info']) 66162306a36Sopenharmony_ci if 'fstat' in devstats[n]: 66262306a36Sopenharmony_ci funcs = devstats[n]['fstat'] 66362306a36Sopenharmony_ci for f in sorted(funcs, key=lambda k:(funcs[k], k), reverse=True): 66462306a36Sopenharmony_ci if funcs[f][0] < 0.01 and len(funcs) > 10: 66562306a36Sopenharmony_ci break 66662306a36Sopenharmony_ci statinfo += '\t\t"%f|%s|%d",\n' % (funcs[f][0], f, funcs[f][1]) 66762306a36Sopenharmony_ci statinfo += '\t],\n' 66862306a36Sopenharmony_ci statinfo += '};\n' 66962306a36Sopenharmony_ci html = \ 67062306a36Sopenharmony_ci '<div id="devicedetailtitle"></div>\n'\ 67162306a36Sopenharmony_ci '<div id="devicedetail" style="display:none;">\n'\ 67262306a36Sopenharmony_ci '<div id="devicedetail0">\n' 67362306a36Sopenharmony_ci for p in data.phases: 67462306a36Sopenharmony_ci phase = data.dmesg[p] 67562306a36Sopenharmony_ci html += devtl.html_phaselet.format(p+'_mode', '0', '100', phase['color']) 67662306a36Sopenharmony_ci html += '</div>\n</div>\n'\ 67762306a36Sopenharmony_ci '<script type="text/javascript">\n'+statinfo+\ 67862306a36Sopenharmony_ci '</script>\n' 67962306a36Sopenharmony_ci hf.write(html) 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci # add the callgraph html 68262306a36Sopenharmony_ci if(sysvals.usecallgraph): 68362306a36Sopenharmony_ci aslib.addCallgraphs(sysvals, hf, data) 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci # add the test log as a hidden div 68662306a36Sopenharmony_ci if sysvals.testlog and sysvals.logmsg: 68762306a36Sopenharmony_ci hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') 68862306a36Sopenharmony_ci # add the dmesg log as a hidden div 68962306a36Sopenharmony_ci if sysvals.dmesglog: 69062306a36Sopenharmony_ci hf.write('<div id="dmesglog" style="display:none;">\n') 69162306a36Sopenharmony_ci for line in data.dmesgtext: 69262306a36Sopenharmony_ci line = line.replace('<', '<').replace('>', '>') 69362306a36Sopenharmony_ci hf.write(line) 69462306a36Sopenharmony_ci hf.write('</div>\n') 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci # write the footer and close 69762306a36Sopenharmony_ci aslib.addScriptCode(hf, [data]) 69862306a36Sopenharmony_ci hf.write('</body>\n</html>\n') 69962306a36Sopenharmony_ci hf.close() 70062306a36Sopenharmony_ci return True 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci# Function: updateCron 70362306a36Sopenharmony_ci# Description: 70462306a36Sopenharmony_ci# (restore=False) Set the tool to run automatically on reboot 70562306a36Sopenharmony_ci# (restore=True) Restore the original crontab 70662306a36Sopenharmony_cidef updateCron(restore=False): 70762306a36Sopenharmony_ci if not restore: 70862306a36Sopenharmony_ci sysvals.rootUser(True) 70962306a36Sopenharmony_ci crondir = '/var/spool/cron/crontabs/' 71062306a36Sopenharmony_ci if not os.path.exists(crondir): 71162306a36Sopenharmony_ci crondir = '/var/spool/cron/' 71262306a36Sopenharmony_ci if not os.path.exists(crondir): 71362306a36Sopenharmony_ci doError('%s not found' % crondir) 71462306a36Sopenharmony_ci cronfile = crondir+'root' 71562306a36Sopenharmony_ci backfile = crondir+'root-analyze_boot-backup' 71662306a36Sopenharmony_ci cmd = sysvals.getExec('crontab') 71762306a36Sopenharmony_ci if not cmd: 71862306a36Sopenharmony_ci doError('crontab not found') 71962306a36Sopenharmony_ci # on restore: move the backup cron back into place 72062306a36Sopenharmony_ci if restore: 72162306a36Sopenharmony_ci if os.path.exists(backfile): 72262306a36Sopenharmony_ci shutil.move(backfile, cronfile) 72362306a36Sopenharmony_ci call([cmd, cronfile]) 72462306a36Sopenharmony_ci return 72562306a36Sopenharmony_ci # backup current cron and install new one with reboot 72662306a36Sopenharmony_ci if os.path.exists(cronfile): 72762306a36Sopenharmony_ci shutil.move(cronfile, backfile) 72862306a36Sopenharmony_ci else: 72962306a36Sopenharmony_ci fp = open(backfile, 'w') 73062306a36Sopenharmony_ci fp.close() 73162306a36Sopenharmony_ci res = -1 73262306a36Sopenharmony_ci try: 73362306a36Sopenharmony_ci fp = open(backfile, 'r') 73462306a36Sopenharmony_ci op = open(cronfile, 'w') 73562306a36Sopenharmony_ci for line in fp: 73662306a36Sopenharmony_ci if not sysvals.myCronJob(line): 73762306a36Sopenharmony_ci op.write(line) 73862306a36Sopenharmony_ci continue 73962306a36Sopenharmony_ci fp.close() 74062306a36Sopenharmony_ci op.write('@reboot python %s\n' % sysvals.cronjobCmdString()) 74162306a36Sopenharmony_ci op.close() 74262306a36Sopenharmony_ci res = call([cmd, cronfile]) 74362306a36Sopenharmony_ci except Exception as e: 74462306a36Sopenharmony_ci pprint('Exception: %s' % str(e)) 74562306a36Sopenharmony_ci shutil.move(backfile, cronfile) 74662306a36Sopenharmony_ci res = -1 74762306a36Sopenharmony_ci if res != 0: 74862306a36Sopenharmony_ci doError('crontab failed') 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci# Function: updateGrub 75162306a36Sopenharmony_ci# Description: 75262306a36Sopenharmony_ci# update grub.cfg for all kernels with our parameters 75362306a36Sopenharmony_cidef updateGrub(restore=False): 75462306a36Sopenharmony_ci # call update-grub on restore 75562306a36Sopenharmony_ci if restore: 75662306a36Sopenharmony_ci try: 75762306a36Sopenharmony_ci call(sysvals.blexec, stderr=PIPE, stdout=PIPE, 75862306a36Sopenharmony_ci env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'}) 75962306a36Sopenharmony_ci except Exception as e: 76062306a36Sopenharmony_ci pprint('Exception: %s\n' % str(e)) 76162306a36Sopenharmony_ci return 76262306a36Sopenharmony_ci # extract the option and create a grub config without it 76362306a36Sopenharmony_ci sysvals.rootUser(True) 76462306a36Sopenharmony_ci tgtopt = 'GRUB_CMDLINE_LINUX_DEFAULT' 76562306a36Sopenharmony_ci cmdline = '' 76662306a36Sopenharmony_ci grubfile = '/etc/default/grub' 76762306a36Sopenharmony_ci tempfile = '/etc/default/grub.analyze_boot' 76862306a36Sopenharmony_ci shutil.move(grubfile, tempfile) 76962306a36Sopenharmony_ci res = -1 77062306a36Sopenharmony_ci try: 77162306a36Sopenharmony_ci fp = open(tempfile, 'r') 77262306a36Sopenharmony_ci op = open(grubfile, 'w') 77362306a36Sopenharmony_ci cont = False 77462306a36Sopenharmony_ci for line in fp: 77562306a36Sopenharmony_ci line = line.strip() 77662306a36Sopenharmony_ci if len(line) == 0 or line[0] == '#': 77762306a36Sopenharmony_ci continue 77862306a36Sopenharmony_ci opt = line.split('=')[0].strip() 77962306a36Sopenharmony_ci if opt == tgtopt: 78062306a36Sopenharmony_ci cmdline = line.split('=', 1)[1].strip('\\') 78162306a36Sopenharmony_ci if line[-1] == '\\': 78262306a36Sopenharmony_ci cont = True 78362306a36Sopenharmony_ci elif cont: 78462306a36Sopenharmony_ci cmdline += line.strip('\\') 78562306a36Sopenharmony_ci if line[-1] != '\\': 78662306a36Sopenharmony_ci cont = False 78762306a36Sopenharmony_ci else: 78862306a36Sopenharmony_ci op.write('%s\n' % line) 78962306a36Sopenharmony_ci fp.close() 79062306a36Sopenharmony_ci # if the target option value is in quotes, strip them 79162306a36Sopenharmony_ci sp = '"' 79262306a36Sopenharmony_ci val = cmdline.strip() 79362306a36Sopenharmony_ci if val and (val[0] == '\'' or val[0] == '"'): 79462306a36Sopenharmony_ci sp = val[0] 79562306a36Sopenharmony_ci val = val.strip(sp) 79662306a36Sopenharmony_ci cmdline = val 79762306a36Sopenharmony_ci # append our cmd line options 79862306a36Sopenharmony_ci if len(cmdline) > 0: 79962306a36Sopenharmony_ci cmdline += ' ' 80062306a36Sopenharmony_ci cmdline += sysvals.kernelParams() 80162306a36Sopenharmony_ci # write out the updated target option 80262306a36Sopenharmony_ci op.write('\n%s=%s%s%s\n' % (tgtopt, sp, cmdline, sp)) 80362306a36Sopenharmony_ci op.close() 80462306a36Sopenharmony_ci res = call(sysvals.blexec) 80562306a36Sopenharmony_ci os.remove(grubfile) 80662306a36Sopenharmony_ci except Exception as e: 80762306a36Sopenharmony_ci pprint('Exception: %s' % str(e)) 80862306a36Sopenharmony_ci res = -1 80962306a36Sopenharmony_ci # cleanup 81062306a36Sopenharmony_ci shutil.move(tempfile, grubfile) 81162306a36Sopenharmony_ci if res != 0: 81262306a36Sopenharmony_ci doError('update grub failed') 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci# Function: updateKernelParams 81562306a36Sopenharmony_ci# Description: 81662306a36Sopenharmony_ci# update boot conf for all kernels with our parameters 81762306a36Sopenharmony_cidef updateKernelParams(restore=False): 81862306a36Sopenharmony_ci # find the boot loader 81962306a36Sopenharmony_ci sysvals.getBootLoader() 82062306a36Sopenharmony_ci if sysvals.bootloader == 'grub': 82162306a36Sopenharmony_ci updateGrub(restore) 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci# Function: doError Description: 82462306a36Sopenharmony_ci# generic error function for catastrphic failures 82562306a36Sopenharmony_ci# Arguments: 82662306a36Sopenharmony_ci# msg: the error message to print 82762306a36Sopenharmony_ci# help: True if printHelp should be called after, False otherwise 82862306a36Sopenharmony_cidef doError(msg, help=False): 82962306a36Sopenharmony_ci if help == True: 83062306a36Sopenharmony_ci printHelp() 83162306a36Sopenharmony_ci pprint('ERROR: %s\n' % msg) 83262306a36Sopenharmony_ci sysvals.outputResult({'error':msg}) 83362306a36Sopenharmony_ci sys.exit() 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci# Function: printHelp 83662306a36Sopenharmony_ci# Description: 83762306a36Sopenharmony_ci# print out the help text 83862306a36Sopenharmony_cidef printHelp(): 83962306a36Sopenharmony_ci pprint('\n%s v%s\n'\ 84062306a36Sopenharmony_ci 'Usage: bootgraph <options> <command>\n'\ 84162306a36Sopenharmony_ci '\n'\ 84262306a36Sopenharmony_ci 'Description:\n'\ 84362306a36Sopenharmony_ci ' This tool reads in a dmesg log of linux kernel boot and\n'\ 84462306a36Sopenharmony_ci ' creates an html representation of the boot timeline up to\n'\ 84562306a36Sopenharmony_ci ' the start of the init process.\n'\ 84662306a36Sopenharmony_ci '\n'\ 84762306a36Sopenharmony_ci ' If no specific command is given the tool reads the current dmesg\n'\ 84862306a36Sopenharmony_ci ' and/or ftrace log and creates a timeline\n'\ 84962306a36Sopenharmony_ci '\n'\ 85062306a36Sopenharmony_ci ' Generates output files in subdirectory: boot-yymmdd-HHMMSS\n'\ 85162306a36Sopenharmony_ci ' HTML output: <hostname>_boot.html\n'\ 85262306a36Sopenharmony_ci ' raw dmesg output: <hostname>_boot_dmesg.txt\n'\ 85362306a36Sopenharmony_ci ' raw ftrace output: <hostname>_boot_ftrace.txt\n'\ 85462306a36Sopenharmony_ci '\n'\ 85562306a36Sopenharmony_ci 'Options:\n'\ 85662306a36Sopenharmony_ci ' -h Print this help text\n'\ 85762306a36Sopenharmony_ci ' -v Print the current tool version\n'\ 85862306a36Sopenharmony_ci ' -verbose Print extra information during execution and analysis\n'\ 85962306a36Sopenharmony_ci ' -addlogs Add the dmesg log to the html output\n'\ 86062306a36Sopenharmony_ci ' -result fn Export a results table to a text file for parsing.\n'\ 86162306a36Sopenharmony_ci ' -o name Overrides the output subdirectory name when running a new test\n'\ 86262306a36Sopenharmony_ci ' default: boot-{date}-{time}\n'\ 86362306a36Sopenharmony_ci ' [advanced]\n'\ 86462306a36Sopenharmony_ci ' -fstat Use ftrace to add function detail and statistics (default: disabled)\n'\ 86562306a36Sopenharmony_ci ' -f/-callgraph Add callgraph detail, can be very large (default: disabled)\n'\ 86662306a36Sopenharmony_ci ' -maxdepth N limit the callgraph data to N call levels (default: 2)\n'\ 86762306a36Sopenharmony_ci ' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 86862306a36Sopenharmony_ci ' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])\n'\ 86962306a36Sopenharmony_ci ' -expandcg pre-expand the callgraph data in the html output (default: disabled)\n'\ 87062306a36Sopenharmony_ci ' -func list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)\n'\ 87162306a36Sopenharmony_ci ' -cgfilter S Filter the callgraph output in the timeline\n'\ 87262306a36Sopenharmony_ci ' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\ 87362306a36Sopenharmony_ci ' -bl name Use the following boot loader for kernel params (default: grub)\n'\ 87462306a36Sopenharmony_ci ' -reboot Reboot the machine automatically and generate a new timeline\n'\ 87562306a36Sopenharmony_ci ' -manual Show the steps to generate a new timeline manually (used with -reboot)\n'\ 87662306a36Sopenharmony_ci '\n'\ 87762306a36Sopenharmony_ci 'Other commands:\n'\ 87862306a36Sopenharmony_ci ' -flistall Print all functions capable of being captured in ftrace\n'\ 87962306a36Sopenharmony_ci ' -sysinfo Print out system info extracted from BIOS\n'\ 88062306a36Sopenharmony_ci ' -which exec Print an executable path, should function even without PATH\n'\ 88162306a36Sopenharmony_ci ' [redo]\n'\ 88262306a36Sopenharmony_ci ' -dmesg file Create HTML output using dmesg input (used with -ftrace)\n'\ 88362306a36Sopenharmony_ci ' -ftrace file Create HTML output using ftrace input (used with -dmesg)\n'\ 88462306a36Sopenharmony_ci '' % (sysvals.title, sysvals.version)) 88562306a36Sopenharmony_ci return True 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci# ----------------- MAIN -------------------- 88862306a36Sopenharmony_ci# exec start (skipped if script is loaded as library) 88962306a36Sopenharmony_ciif __name__ == '__main__': 89062306a36Sopenharmony_ci # loop through the command line arguments 89162306a36Sopenharmony_ci cmd = '' 89262306a36Sopenharmony_ci testrun = True 89362306a36Sopenharmony_ci switchoff = ['disable', 'off', 'false', '0'] 89462306a36Sopenharmony_ci simplecmds = ['-sysinfo', '-kpupdate', '-flistall', '-checkbl'] 89562306a36Sopenharmony_ci cgskip = '' 89662306a36Sopenharmony_ci if '-f' in sys.argv: 89762306a36Sopenharmony_ci cgskip = sysvals.configFile('cgskip.txt') 89862306a36Sopenharmony_ci args = iter(sys.argv[1:]) 89962306a36Sopenharmony_ci mdset = False 90062306a36Sopenharmony_ci for arg in args: 90162306a36Sopenharmony_ci if(arg == '-h'): 90262306a36Sopenharmony_ci printHelp() 90362306a36Sopenharmony_ci sys.exit() 90462306a36Sopenharmony_ci elif(arg == '-v'): 90562306a36Sopenharmony_ci pprint("Version %s" % sysvals.version) 90662306a36Sopenharmony_ci sys.exit() 90762306a36Sopenharmony_ci elif(arg == '-verbose'): 90862306a36Sopenharmony_ci sysvals.verbose = True 90962306a36Sopenharmony_ci elif(arg in simplecmds): 91062306a36Sopenharmony_ci cmd = arg[1:] 91162306a36Sopenharmony_ci elif(arg == '-fstat'): 91262306a36Sopenharmony_ci sysvals.useftrace = True 91362306a36Sopenharmony_ci elif(arg == '-callgraph' or arg == '-f'): 91462306a36Sopenharmony_ci sysvals.useftrace = True 91562306a36Sopenharmony_ci sysvals.usecallgraph = True 91662306a36Sopenharmony_ci elif(arg == '-cgdump'): 91762306a36Sopenharmony_ci sysvals.cgdump = True 91862306a36Sopenharmony_ci elif(arg == '-mincg'): 91962306a36Sopenharmony_ci sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0) 92062306a36Sopenharmony_ci elif(arg == '-cgfilter'): 92162306a36Sopenharmony_ci try: 92262306a36Sopenharmony_ci val = next(args) 92362306a36Sopenharmony_ci except: 92462306a36Sopenharmony_ci doError('No callgraph functions supplied', True) 92562306a36Sopenharmony_ci sysvals.setCallgraphFilter(val) 92662306a36Sopenharmony_ci elif(arg == '-cgskip'): 92762306a36Sopenharmony_ci try: 92862306a36Sopenharmony_ci val = next(args) 92962306a36Sopenharmony_ci except: 93062306a36Sopenharmony_ci doError('No file supplied', True) 93162306a36Sopenharmony_ci if val.lower() in switchoff: 93262306a36Sopenharmony_ci cgskip = '' 93362306a36Sopenharmony_ci else: 93462306a36Sopenharmony_ci cgskip = sysvals.configFile(val) 93562306a36Sopenharmony_ci if(not cgskip): 93662306a36Sopenharmony_ci doError('%s does not exist' % cgskip) 93762306a36Sopenharmony_ci elif(arg == '-bl'): 93862306a36Sopenharmony_ci try: 93962306a36Sopenharmony_ci val = next(args) 94062306a36Sopenharmony_ci except: 94162306a36Sopenharmony_ci doError('No boot loader name supplied', True) 94262306a36Sopenharmony_ci if val.lower() not in ['grub']: 94362306a36Sopenharmony_ci doError('Unknown boot loader: %s' % val, True) 94462306a36Sopenharmony_ci sysvals.bootloader = val.lower() 94562306a36Sopenharmony_ci elif(arg == '-timeprec'): 94662306a36Sopenharmony_ci sysvals.setPrecision(aslib.getArgInt('-timeprec', args, 0, 6)) 94762306a36Sopenharmony_ci elif(arg == '-maxdepth'): 94862306a36Sopenharmony_ci mdset = True 94962306a36Sopenharmony_ci sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000) 95062306a36Sopenharmony_ci elif(arg == '-func'): 95162306a36Sopenharmony_ci try: 95262306a36Sopenharmony_ci val = next(args) 95362306a36Sopenharmony_ci except: 95462306a36Sopenharmony_ci doError('No filter functions supplied', True) 95562306a36Sopenharmony_ci sysvals.useftrace = True 95662306a36Sopenharmony_ci sysvals.usecallgraph = True 95762306a36Sopenharmony_ci sysvals.rootCheck(True) 95862306a36Sopenharmony_ci sysvals.setGraphFilter(val) 95962306a36Sopenharmony_ci elif(arg == '-ftrace'): 96062306a36Sopenharmony_ci try: 96162306a36Sopenharmony_ci val = next(args) 96262306a36Sopenharmony_ci except: 96362306a36Sopenharmony_ci doError('No ftrace file supplied', True) 96462306a36Sopenharmony_ci if(os.path.exists(val) == False): 96562306a36Sopenharmony_ci doError('%s does not exist' % val) 96662306a36Sopenharmony_ci testrun = False 96762306a36Sopenharmony_ci sysvals.ftracefile = val 96862306a36Sopenharmony_ci elif(arg == '-addlogs'): 96962306a36Sopenharmony_ci sysvals.dmesglog = True 97062306a36Sopenharmony_ci elif(arg == '-expandcg'): 97162306a36Sopenharmony_ci sysvals.cgexp = True 97262306a36Sopenharmony_ci elif(arg == '-dmesg'): 97362306a36Sopenharmony_ci try: 97462306a36Sopenharmony_ci val = next(args) 97562306a36Sopenharmony_ci except: 97662306a36Sopenharmony_ci doError('No dmesg file supplied', True) 97762306a36Sopenharmony_ci if(os.path.exists(val) == False): 97862306a36Sopenharmony_ci doError('%s does not exist' % val) 97962306a36Sopenharmony_ci testrun = False 98062306a36Sopenharmony_ci sysvals.dmesgfile = val 98162306a36Sopenharmony_ci elif(arg == '-o'): 98262306a36Sopenharmony_ci try: 98362306a36Sopenharmony_ci val = next(args) 98462306a36Sopenharmony_ci except: 98562306a36Sopenharmony_ci doError('No subdirectory name supplied', True) 98662306a36Sopenharmony_ci sysvals.testdir = sysvals.setOutputFolder(val) 98762306a36Sopenharmony_ci elif(arg == '-result'): 98862306a36Sopenharmony_ci try: 98962306a36Sopenharmony_ci val = next(args) 99062306a36Sopenharmony_ci except: 99162306a36Sopenharmony_ci doError('No result file supplied', True) 99262306a36Sopenharmony_ci sysvals.result = val 99362306a36Sopenharmony_ci elif(arg == '-reboot'): 99462306a36Sopenharmony_ci sysvals.reboot = True 99562306a36Sopenharmony_ci elif(arg == '-manual'): 99662306a36Sopenharmony_ci sysvals.reboot = True 99762306a36Sopenharmony_ci sysvals.manual = True 99862306a36Sopenharmony_ci # remaining options are only for cron job use 99962306a36Sopenharmony_ci elif(arg == '-cronjob'): 100062306a36Sopenharmony_ci sysvals.iscronjob = True 100162306a36Sopenharmony_ci elif(arg == '-which'): 100262306a36Sopenharmony_ci try: 100362306a36Sopenharmony_ci val = next(args) 100462306a36Sopenharmony_ci except: 100562306a36Sopenharmony_ci doError('No executable supplied', True) 100662306a36Sopenharmony_ci out = sysvals.getExec(val) 100762306a36Sopenharmony_ci if not out: 100862306a36Sopenharmony_ci print('%s not found' % val) 100962306a36Sopenharmony_ci sys.exit(1) 101062306a36Sopenharmony_ci print(out) 101162306a36Sopenharmony_ci sys.exit(0) 101262306a36Sopenharmony_ci else: 101362306a36Sopenharmony_ci doError('Invalid argument: '+arg, True) 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci # compatibility errors and access checks 101662306a36Sopenharmony_ci if(sysvals.iscronjob and (sysvals.reboot or \ 101762306a36Sopenharmony_ci sysvals.dmesgfile or sysvals.ftracefile or cmd)): 101862306a36Sopenharmony_ci doError('-cronjob is meant for batch purposes only') 101962306a36Sopenharmony_ci if(sysvals.reboot and (sysvals.dmesgfile or sysvals.ftracefile)): 102062306a36Sopenharmony_ci doError('-reboot and -dmesg/-ftrace are incompatible') 102162306a36Sopenharmony_ci if cmd or sysvals.reboot or sysvals.iscronjob or testrun: 102262306a36Sopenharmony_ci sysvals.rootCheck(True) 102362306a36Sopenharmony_ci if (testrun and sysvals.useftrace) or cmd == 'flistall': 102462306a36Sopenharmony_ci if not sysvals.verifyFtrace(): 102562306a36Sopenharmony_ci doError('Ftrace is not properly enabled') 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci # run utility commands 102862306a36Sopenharmony_ci sysvals.cpuInfo() 102962306a36Sopenharmony_ci if cmd != '': 103062306a36Sopenharmony_ci if cmd == 'kpupdate': 103162306a36Sopenharmony_ci updateKernelParams() 103262306a36Sopenharmony_ci elif cmd == 'flistall': 103362306a36Sopenharmony_ci for f in sysvals.getBootFtraceFilterFunctions(): 103462306a36Sopenharmony_ci print(f) 103562306a36Sopenharmony_ci elif cmd == 'checkbl': 103662306a36Sopenharmony_ci sysvals.getBootLoader() 103762306a36Sopenharmony_ci pprint('Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec)) 103862306a36Sopenharmony_ci elif(cmd == 'sysinfo'): 103962306a36Sopenharmony_ci sysvals.printSystemInfo(True) 104062306a36Sopenharmony_ci sys.exit() 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci # reboot: update grub, setup a cronjob, and reboot 104362306a36Sopenharmony_ci if sysvals.reboot: 104462306a36Sopenharmony_ci if (sysvals.useftrace or sysvals.usecallgraph) and \ 104562306a36Sopenharmony_ci not sysvals.checkFtraceKernelVersion(): 104662306a36Sopenharmony_ci doError('Ftrace functionality requires kernel v4.10 or newer') 104762306a36Sopenharmony_ci if not sysvals.manual: 104862306a36Sopenharmony_ci updateKernelParams() 104962306a36Sopenharmony_ci updateCron() 105062306a36Sopenharmony_ci call('reboot') 105162306a36Sopenharmony_ci else: 105262306a36Sopenharmony_ci sysvals.manualRebootRequired() 105362306a36Sopenharmony_ci sys.exit() 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if sysvals.usecallgraph and cgskip: 105662306a36Sopenharmony_ci sysvals.vprint('Using cgskip file: %s' % cgskip) 105762306a36Sopenharmony_ci sysvals.setCallgraphBlacklist(cgskip) 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci # cronjob: remove the cronjob, grub changes, and disable ftrace 106062306a36Sopenharmony_ci if sysvals.iscronjob: 106162306a36Sopenharmony_ci updateCron(True) 106262306a36Sopenharmony_ci updateKernelParams(True) 106362306a36Sopenharmony_ci try: 106462306a36Sopenharmony_ci sysvals.fsetVal('0', 'tracing_on') 106562306a36Sopenharmony_ci except: 106662306a36Sopenharmony_ci pass 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci # testrun: generate copies of the logs 106962306a36Sopenharmony_ci if testrun: 107062306a36Sopenharmony_ci retrieveLogs() 107162306a36Sopenharmony_ci else: 107262306a36Sopenharmony_ci sysvals.setOutputFile() 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci # process the log data 107562306a36Sopenharmony_ci if sysvals.dmesgfile: 107662306a36Sopenharmony_ci if not mdset: 107762306a36Sopenharmony_ci sysvals.max_graph_depth = 0 107862306a36Sopenharmony_ci data = parseKernelLog() 107962306a36Sopenharmony_ci if(not data.valid): 108062306a36Sopenharmony_ci doError('No initcall data found in %s' % sysvals.dmesgfile) 108162306a36Sopenharmony_ci if sysvals.useftrace and sysvals.ftracefile: 108262306a36Sopenharmony_ci parseTraceLog(data) 108362306a36Sopenharmony_ci if sysvals.cgdump: 108462306a36Sopenharmony_ci data.debugPrint() 108562306a36Sopenharmony_ci sys.exit() 108662306a36Sopenharmony_ci else: 108762306a36Sopenharmony_ci doError('dmesg file required') 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile) 109062306a36Sopenharmony_ci sysvals.vprint('Command:\n %s' % sysvals.cmdline) 109162306a36Sopenharmony_ci sysvals.vprint('Kernel parameters:\n %s' % sysvals.kparams) 109262306a36Sopenharmony_ci data.printDetails() 109362306a36Sopenharmony_ci createBootGraph(data) 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci # if running as root, change output dir owner to sudo_user 109662306a36Sopenharmony_ci if testrun and os.path.isdir(sysvals.testdir) and \ 109762306a36Sopenharmony_ci os.getuid() == 0 and 'SUDO_USER' in os.environ: 109862306a36Sopenharmony_ci cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' 109962306a36Sopenharmony_ci call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True) 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci sysvals.stamp['boot'] = (data.tUserMode - data.start) * 1000 110262306a36Sopenharmony_ci sysvals.stamp['lastinit'] = data.end * 1000 110362306a36Sopenharmony_ci sysvals.outputResult(sysvals.stamp) 1104