Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    1) #!/usr/bin/env python3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    2) # SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    3) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    4) # Tool for analyzing boot timing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    5) # Copyright (c) 2013, Intel Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    6) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    7) # This program is free software; you can redistribute it and/or modify it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    8) # under the terms and conditions of the GNU General Public License,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    9) # version 2, as published by the Free Software Foundation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   10) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   11) # This program is distributed in the hope it will be useful, but WITHOUT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   12) # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   13) # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   14) # more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   15) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   16) # Authors:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   17) #	 Todd Brandt <todd.e.brandt@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   18) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   19) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   20) #	 This tool is designed to assist kernel and OS developers in optimizing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   21) #	 their linux stack's boot time. It creates an html representation of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   22) #	 the kernel boot timeline up to the start of the init process.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   23) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   25) # ----------------- LIBRARIES --------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   27) import sys
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   28) import time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   29) import os
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   30) import string
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   31) import re
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   32) import platform
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   33) import shutil
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   34) from datetime import datetime, timedelta
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   35) from subprocess import call, Popen, PIPE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   36) import sleepgraph as aslib
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   37) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   38) def pprint(msg):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   39) 	print(msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   40) 	sys.stdout.flush()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   42) # ----------------- CLASSES --------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   44) # Class: SystemValues
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   45) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   46) #	 A global, single-instance container used to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   47) #	 store system values and test parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   48) class SystemValues(aslib.SystemValues):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   49) 	title = 'BootGraph'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   50) 	version = '2.2'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   51) 	hostname = 'localhost'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   52) 	testtime = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   53) 	kernel = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   54) 	dmesgfile = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   55) 	ftracefile = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   56) 	htmlfile = 'bootgraph.html'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   57) 	testdir = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   58) 	kparams = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   59) 	result = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   60) 	useftrace = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   61) 	usecallgraph = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   62) 	suspendmode = 'boot'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   63) 	max_graph_depth = 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   64) 	graph_filter = 'do_one_initcall'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   65) 	reboot = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   66) 	manual = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   67) 	iscronjob = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   68) 	timeformat = '%.6f'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   69) 	bootloader = 'grub'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   70) 	blexec = []
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   71) 	def __init__(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   72) 		self.hostname = platform.node()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   73) 		self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   74) 		if os.path.exists('/proc/version'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   75) 			fp = open('/proc/version', 'r')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   76) 			val = fp.read().strip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   77) 			fp.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   78) 			self.kernel = self.kernelVersion(val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   79) 		else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   80) 			self.kernel = 'unknown'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   81) 		self.testdir = datetime.now().strftime('boot-%y%m%d-%H%M%S')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   82) 	def kernelVersion(self, msg):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   83) 		return msg.split()[2]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   84) 	def checkFtraceKernelVersion(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   85) 		val = tuple(map(int, self.kernel.split('-')[0].split('.')))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   86) 		if val >= (4, 10, 0):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   87) 			return True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   88) 		return False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   89) 	def kernelParams(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   90) 		cmdline = 'initcall_debug log_buf_len=32M'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   91) 		if self.useftrace:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   92) 			if self.cpucount > 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   93) 				bs = min(self.memtotal // 2, 2*1024*1024) // self.cpucount
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   94) 			else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   95) 				bs = 131072
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   96) 			cmdline += ' trace_buf_size=%dK trace_clock=global '\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   97) 			'trace_options=nooverwrite,funcgraph-abstime,funcgraph-cpu,'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   98) 			'funcgraph-duration,funcgraph-proc,funcgraph-tail,'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   99) 			'nofuncgraph-overhead,context-info,graph-time '\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  100) 			'ftrace=function_graph '\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  101) 			'ftrace_graph_max_depth=%d '\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  102) 			'ftrace_graph_filter=%s' % \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  103) 				(bs, self.max_graph_depth, self.graph_filter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  104) 		return cmdline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  105) 	def setGraphFilter(self, val):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  106) 		master = self.getBootFtraceFilterFunctions()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  107) 		fs = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  108) 		for i in val.split(','):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  109) 			func = i.strip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  110) 			if func == '':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  111) 				doError('badly formatted filter function string')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  112) 			if '[' in func or ']' in func:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  113) 				doError('loadable module functions not allowed - "%s"' % func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  114) 			if ' ' in func:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  115) 				doError('spaces found in filter functions - "%s"' % func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  116) 			if func not in master:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  117) 				doError('function "%s" not available for ftrace' % func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  118) 			if not fs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  119) 				fs = func
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  120) 			else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  121) 				fs += ','+func
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  122) 		if not fs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  123) 			doError('badly formatted filter function string')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  124) 		self.graph_filter = fs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  125) 	def getBootFtraceFilterFunctions(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  126) 		self.rootCheck(True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  127) 		fp = open(self.tpath+'available_filter_functions')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  128) 		fulllist = fp.read().split('\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  129) 		fp.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  130) 		list = []
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  131) 		for i in fulllist:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  132) 			if not i or ' ' in i or '[' in i or ']' in i:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  133) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  134) 			list.append(i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  135) 		return list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  136) 	def myCronJob(self, line):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  137) 		if '@reboot' not in line:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  138) 			return False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  139) 		if 'bootgraph' in line or 'analyze_boot.py' in line or '-cronjob' in line:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  140) 			return True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  141) 		return False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  142) 	def cronjobCmdString(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  143) 		cmdline = '%s -cronjob' % os.path.abspath(sys.argv[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  144) 		args = iter(sys.argv[1:])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  145) 		for arg in args:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  146) 			if arg in ['-h', '-v', '-cronjob', '-reboot', '-verbose']:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  147) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  148) 			elif arg in ['-o', '-dmesg', '-ftrace', '-func']:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  149) 				next(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  150) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  151) 			elif arg == '-result':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  152) 				cmdline += ' %s "%s"' % (arg, os.path.abspath(next(args)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  153) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  154) 			elif arg == '-cgskip':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  155) 				file = self.configFile(next(args))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  156) 				cmdline += ' %s "%s"' % (arg, os.path.abspath(file))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  157) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  158) 			cmdline += ' '+arg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  159) 		if self.graph_filter != 'do_one_initcall':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  160) 			cmdline += ' -func "%s"' % self.graph_filter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  161) 		cmdline += ' -o "%s"' % os.path.abspath(self.testdir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  162) 		return cmdline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  163) 	def manualRebootRequired(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  164) 		cmdline = self.kernelParams()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  165) 		pprint('To generate a new timeline manually, follow these steps:\n\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  166) 		'1. Add the CMDLINE string to your kernel command line.\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  167) 		'2. Reboot the system.\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  168) 		'3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  169) 		'CMDLINE="%s"' % cmdline)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  170) 		sys.exit()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  171) 	def blGrub(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  172) 		blcmd = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  173) 		for cmd in ['update-grub', 'grub-mkconfig', 'grub2-mkconfig']:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  174) 			if blcmd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  175) 				break
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  176) 			blcmd = self.getExec(cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  177) 		if not blcmd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  178) 			doError('[GRUB] missing update command')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  179) 		if not os.path.exists('/etc/default/grub'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  180) 			doError('[GRUB] missing /etc/default/grub')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  181) 		if 'grub2' in blcmd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  182) 			cfg = '/boot/grub2/grub.cfg'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  183) 		else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  184) 			cfg = '/boot/grub/grub.cfg'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  185) 		if not os.path.exists(cfg):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  186) 			doError('[GRUB] missing %s' % cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  187) 		if 'update-grub' in blcmd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  188) 			self.blexec = [blcmd]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  189) 		else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  190) 			self.blexec = [blcmd, '-o', cfg]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  191) 	def getBootLoader(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  192) 		if self.bootloader == 'grub':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  193) 			self.blGrub()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  194) 		else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  195) 			doError('unknown boot loader: %s' % self.bootloader)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  196) 	def writeDatafileHeader(self, filename):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  197) 		self.kparams = open('/proc/cmdline', 'r').read().strip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  198) 		fp = open(filename, 'w')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  199) 		fp.write(self.teststamp+'\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  200) 		fp.write(self.sysstamp+'\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  201) 		fp.write('# command | %s\n' % self.cmdline)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  202) 		fp.write('# kparams | %s\n' % self.kparams)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  203) 		fp.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  204) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  205) sysvals = SystemValues()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  207) # Class: Data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  208) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  209) #	 The primary container for test data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  210) class Data(aslib.Data):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  211) 	dmesg = {}  # root data structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  212) 	start = 0.0 # test start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  213) 	end = 0.0   # test end
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  214) 	dmesgtext = []   # dmesg text file in memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  215) 	testnumber = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  216) 	idstr = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  217) 	html_device_id = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  218) 	valid = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  219) 	tUserMode = 0.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  220) 	boottime = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  221) 	phases = ['kernel', 'user']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  222) 	do_one_initcall = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  223) 	def __init__(self, num):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  224) 		self.testnumber = num
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  225) 		self.idstr = 'a'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  226) 		self.dmesgtext = []
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  227) 		self.dmesg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  228) 			'kernel': {'list': dict(), 'start': -1.0, 'end': -1.0, 'row': 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  229) 				'order': 0, 'color': 'linear-gradient(to bottom, #fff, #bcf)'},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  230) 			'user': {'list': dict(), 'start': -1.0, 'end': -1.0, 'row': 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  231) 				'order': 1, 'color': '#fff'}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  232) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  233) 	def deviceTopology(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  234) 		return ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  235) 	def newAction(self, phase, name, pid, start, end, ret, ulen):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  236) 		# new device callback for a specific phase
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  237) 		self.html_device_id += 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  238) 		devid = '%s%d' % (self.idstr, self.html_device_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  239) 		list = self.dmesg[phase]['list']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  240) 		length = -1.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  241) 		if(start >= 0 and end >= 0):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  242) 			length = end - start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  243) 		i = 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  244) 		origname = name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  245) 		while(name in list):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  246) 			name = '%s[%d]' % (origname, i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  247) 			i += 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  248) 		list[name] = {'name': name, 'start': start, 'end': end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  249) 			'pid': pid, 'length': length, 'row': 0, 'id': devid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  250) 			'ret': ret, 'ulen': ulen }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  251) 		return name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  252) 	def deviceMatch(self, pid, cg):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  253) 		if cg.end - cg.start == 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  254) 			return ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  255) 		for p in data.phases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  256) 			list = self.dmesg[p]['list']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  257) 			for devname in list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  258) 				dev = list[devname]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  259) 				if pid != dev['pid']:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  260) 					continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  261) 				if cg.name == 'do_one_initcall':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  262) 					if(cg.start <= dev['start'] and cg.end >= dev['end'] and dev['length'] > 0):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  263) 						dev['ftrace'] = cg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  264) 						self.do_one_initcall = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  265) 						return devname
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  266) 				else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  267) 					if(cg.start > dev['start'] and cg.end < dev['end']):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  268) 						if 'ftraces' not in dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  269) 							dev['ftraces'] = []
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  270) 						dev['ftraces'].append(cg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  271) 						return devname
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  272) 		return ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  273) 	def printDetails(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  274) 		sysvals.vprint('Timeline Details:')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  275) 		sysvals.vprint('          Host: %s' % sysvals.hostname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  276) 		sysvals.vprint('        Kernel: %s' % sysvals.kernel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  277) 		sysvals.vprint('     Test time: %s' % sysvals.testtime)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  278) 		sysvals.vprint('     Boot time: %s' % self.boottime)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  279) 		for phase in self.phases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  280) 			dc = len(self.dmesg[phase]['list'])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  281) 			sysvals.vprint('%9s mode: %.3f - %.3f (%d initcalls)' % (phase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  282) 				self.dmesg[phase]['start']*1000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  283) 				self.dmesg[phase]['end']*1000, dc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  284) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  285) # ----------------- FUNCTIONS --------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  286) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  287) # Function: parseKernelLog
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  288) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  289) #	 parse a kernel log for boot data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  290) def parseKernelLog():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  291) 	sysvals.vprint('Analyzing the dmesg data (%s)...' % \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  292) 		os.path.basename(sysvals.dmesgfile))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  293) 	phase = 'kernel'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  294) 	data = Data(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  295) 	data.dmesg['kernel']['start'] = data.start = ktime = 0.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  296) 	sysvals.stamp = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  297) 		'time': datetime.now().strftime('%B %d %Y, %I:%M:%S %p'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  298) 		'host': sysvals.hostname,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  299) 		'mode': 'boot', 'kernel': ''}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  300) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  301) 	tp = aslib.TestProps()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  302) 	devtemp = dict()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  303) 	if(sysvals.dmesgfile):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  304) 		lf = open(sysvals.dmesgfile, 'rb')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  305) 	else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  306) 		lf = Popen('dmesg', stdout=PIPE).stdout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  307) 	for line in lf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  308) 		line = aslib.ascii(line).replace('\r\n', '')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  309) 		# grab the stamp and sysinfo
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  310) 		if re.match(tp.stampfmt, line):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  311) 			tp.stamp = line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  312) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  313) 		elif re.match(tp.sysinfofmt, line):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  314) 			tp.sysinfo = line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  315) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  316) 		elif re.match(tp.cmdlinefmt, line):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  317) 			tp.cmdline = line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  318) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  319) 		elif re.match(tp.kparamsfmt, line):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  320) 			tp.kparams = line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  321) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  322) 		idx = line.find('[')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  323) 		if idx > 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  324) 			line = line[idx:]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  325) 		m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  326) 		if(not m):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  327) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  328) 		ktime = float(m.group('ktime'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  329) 		if(ktime > 120):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  330) 			break
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  331) 		msg = m.group('msg')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  332) 		data.dmesgtext.append(line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  333) 		if(ktime == 0.0 and re.match('^Linux version .*', msg)):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  334) 			if(not sysvals.stamp['kernel']):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  335) 				sysvals.stamp['kernel'] = sysvals.kernelVersion(msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  336) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  337) 		m = re.match('.* setting system clock to (?P<d>[0-9\-]*)[ A-Z](?P<t>[0-9:]*) UTC.*', msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  338) 		if(m):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  339) 			bt = datetime.strptime(m.group('d')+' '+m.group('t'), '%Y-%m-%d %H:%M:%S')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  340) 			bt = bt - timedelta(seconds=int(ktime))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  341) 			data.boottime = bt.strftime('%Y-%m-%d_%H:%M:%S')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  342) 			sysvals.stamp['time'] = bt.strftime('%B %d %Y, %I:%M:%S %p')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  343) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  344) 		m = re.match('^calling *(?P<f>.*)\+.* @ (?P<p>[0-9]*)', msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  345) 		if(m):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  346) 			func = m.group('f')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  347) 			pid = int(m.group('p'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  348) 			devtemp[func] = (ktime, pid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  349) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  350) 		m = re.match('^initcall *(?P<f>.*)\+.* returned (?P<r>.*) after (?P<t>.*) usecs', msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  351) 		if(m):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  352) 			data.valid = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  353) 			data.end = ktime
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  354) 			f, r, t = m.group('f', 'r', 't')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  355) 			if(f in devtemp):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  356) 				start, pid = devtemp[f]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  357) 				data.newAction(phase, f, pid, start, ktime, int(r), int(t))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  358) 				del devtemp[f]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  359) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  360) 		if(re.match('^Freeing unused kernel .*', msg)):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  361) 			data.tUserMode = ktime
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  362) 			data.dmesg['kernel']['end'] = ktime
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  363) 			data.dmesg['user']['start'] = ktime
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  364) 			phase = 'user'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  365) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  366) 	if tp.stamp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  367) 		sysvals.stamp = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  368) 		tp.parseStamp(data, sysvals)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  369) 	data.dmesg['user']['end'] = data.end
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  370) 	lf.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  371) 	return data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  372) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  373) # Function: parseTraceLog
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  374) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  375) #	 Check if trace is available and copy to a temp file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  376) def parseTraceLog(data):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  377) 	sysvals.vprint('Analyzing the ftrace data (%s)...' % \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  378) 		os.path.basename(sysvals.ftracefile))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  379) 	# if available, calculate cgfilter allowable ranges
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  380) 	cgfilter = []
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  381) 	if len(sysvals.cgfilter) > 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  382) 		for p in data.phases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  383) 			list = data.dmesg[p]['list']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  384) 			for i in sysvals.cgfilter:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  385) 				if i in list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  386) 					cgfilter.append([list[i]['start']-0.0001,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  387) 						list[i]['end']+0.0001])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  388) 	# parse the trace log
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  389) 	ftemp = dict()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  390) 	tp = aslib.TestProps()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  391) 	tp.setTracerType('function_graph')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  392) 	tf = open(sysvals.ftracefile, 'r')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  393) 	for line in tf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  394) 		if line[0] == '#':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  395) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  396) 		m = re.match(tp.ftrace_line_fmt, line.strip())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  397) 		if(not m):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  398) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  399) 		m_time, m_proc, m_pid, m_msg, m_dur = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  400) 			m.group('time', 'proc', 'pid', 'msg', 'dur')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  401) 		t = float(m_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  402) 		if len(cgfilter) > 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  403) 			allow = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  404) 			for r in cgfilter:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  405) 				if t >= r[0] and t < r[1]:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  406) 					allow = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  407) 					break
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  408) 			if not allow:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  409) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  410) 		if t > data.end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  411) 			break
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  412) 		if(m_time and m_pid and m_msg):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  413) 			t = aslib.FTraceLine(m_time, m_msg, m_dur)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  414) 			pid = int(m_pid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  415) 		else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  416) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  417) 		if t.fevent or t.fkprobe:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  418) 			continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  419) 		key = (m_proc, pid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  420) 		if(key not in ftemp):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  421) 			ftemp[key] = []
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  422) 			ftemp[key].append(aslib.FTraceCallGraph(pid, sysvals))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  423) 		cg = ftemp[key][-1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  424) 		res = cg.addLine(t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  425) 		if(res != 0):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  426) 			ftemp[key].append(aslib.FTraceCallGraph(pid, sysvals))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  427) 		if(res == -1):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  428) 			ftemp[key][-1].addLine(t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  429) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  430) 	tf.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  431) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  432) 	# add the callgraph data to the device hierarchy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  433) 	for key in ftemp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  434) 		proc, pid = key
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  435) 		for cg in ftemp[key]:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  436) 			if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  437) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  438) 			if(not cg.postProcess()):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  439) 				pprint('Sanity check failed for %s-%d' % (proc, pid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  440) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  441) 			# match cg data to devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  442) 			devname = data.deviceMatch(pid, cg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  443) 			if not devname:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  444) 				kind = 'Orphan'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  445) 				if cg.partial:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  446) 					kind = 'Partial'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  447) 				sysvals.vprint('%s callgraph found for %s %s-%d [%f - %f]' %\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  448) 					(kind, cg.name, proc, pid, cg.start, cg.end))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  449) 			elif len(cg.list) > 1000000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  450) 				pprint('WARNING: the callgraph found for %s is massive! (%d lines)' %\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  451) 					(devname, len(cg.list)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  452) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  453) # Function: retrieveLogs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  454) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  455) #	 Create copies of dmesg and/or ftrace for later processing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  456) def retrieveLogs():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  457) 	# check ftrace is configured first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  458) 	if sysvals.useftrace:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  459) 		tracer = sysvals.fgetVal('current_tracer').strip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  460) 		if tracer != 'function_graph':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  461) 			doError('ftrace not configured for a boot callgraph')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  462) 	# create the folder and get dmesg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  463) 	sysvals.systemInfo(aslib.dmidecode(sysvals.mempath))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  464) 	sysvals.initTestOutput('boot')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  465) 	sysvals.writeDatafileHeader(sysvals.dmesgfile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  466) 	call('dmesg >> '+sysvals.dmesgfile, shell=True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  467) 	if not sysvals.useftrace:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  468) 		return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  469) 	# get ftrace
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  470) 	sysvals.writeDatafileHeader(sysvals.ftracefile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  471) 	call('cat '+sysvals.tpath+'trace >> '+sysvals.ftracefile, shell=True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  472) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  473) # Function: colorForName
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  474) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  475) #	 Generate a repeatable color from a list for a given name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  476) def colorForName(name):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  477) 	list = [
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  478) 		('c1', '#ec9999'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  479) 		('c2', '#ffc1a6'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  480) 		('c3', '#fff0a6'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  481) 		('c4', '#adf199'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  482) 		('c5', '#9fadea'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  483) 		('c6', '#a699c1'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  484) 		('c7', '#ad99b4'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  485) 		('c8', '#eaffea'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  486) 		('c9', '#dcecfb'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  487) 		('c10', '#ffffea')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  488) 	]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  489) 	i = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  490) 	total = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  491) 	count = len(list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  492) 	while i < len(name):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  493) 		total += ord(name[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  494) 		i += 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  495) 	return list[total % count]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  496) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  497) def cgOverview(cg, minlen):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  498) 	stats = dict()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  499) 	large = []
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  500) 	for l in cg.list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  501) 		if l.fcall and l.depth == 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  502) 			if l.length >= minlen:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  503) 				large.append(l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  504) 			if l.name not in stats:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  505) 				stats[l.name] = [0, 0.0]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  506) 			stats[l.name][0] += (l.length * 1000.0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  507) 			stats[l.name][1] += 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  508) 	return (large, stats)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  509) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  510) # Function: createBootGraph
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  511) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  512) #	 Create the output html file from the resident test data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  513) # Arguments:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  514) #	 testruns: array of Data objects from parseKernelLog or parseTraceLog
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  515) # Output:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  516) #	 True if the html file was created, false if it failed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  517) def createBootGraph(data):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  518) 	# html function templates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  519) 	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'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  520) 	html_timetotal = '<table class="time1">\n<tr>'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  521) 		'<td class="blue">Init process starts @ <b>{0} ms</b></td>'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  522) 		'<td class="blue">Last initcall ends @ <b>{1} ms</b></td>'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  523) 		'</tr>\n</table>\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  524) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  525) 	# device timeline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  526) 	devtl = aslib.Timeline(100, 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  527) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  528) 	# write the test title and general info header
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  529) 	devtl.createHeader(sysvals, sysvals.stamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  530) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  531) 	# Generate the header for this timeline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  532) 	t0 = data.start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  533) 	tMax = data.end
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  534) 	tTotal = tMax - t0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  535) 	if(tTotal == 0):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  536) 		pprint('ERROR: No timeline data')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  537) 		return False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  538) 	user_mode = '%.0f'%(data.tUserMode*1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  539) 	last_init = '%.0f'%(tTotal*1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  540) 	devtl.html += html_timetotal.format(user_mode, last_init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  541) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  542) 	# determine the maximum number of rows we need to draw
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  543) 	devlist = []
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  544) 	for p in data.phases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  545) 		list = data.dmesg[p]['list']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  546) 		for devname in list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  547) 			d = aslib.DevItem(0, p, list[devname])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  548) 			devlist.append(d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  549) 		devtl.getPhaseRows(devlist, 0, 'start')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  550) 	devtl.calcTotalRows()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  551) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  552) 	# draw the timeline background
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  553) 	devtl.createZoomBox()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  554) 	devtl.html += devtl.html_tblock.format('boot', '0', '100', devtl.scaleH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  555) 	for p in data.phases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  556) 		phase = data.dmesg[p]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  557) 		length = phase['end']-phase['start']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  558) 		left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  559) 		width = '%.3f' % ((length*100.0)/tTotal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  560) 		devtl.html += devtl.html_phase.format(left, width, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  561) 			'%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  562) 			phase['color'], '')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  563) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  564) 	# draw the device timeline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  565) 	num = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  566) 	devstats = dict()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  567) 	for phase in data.phases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  568) 		list = data.dmesg[phase]['list']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  569) 		for devname in sorted(list):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  570) 			cls, color = colorForName(devname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  571) 			dev = list[devname]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  572) 			info = '@|%.3f|%.3f|%.3f|%d' % (dev['start']*1000.0, dev['end']*1000.0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  573) 				dev['ulen']/1000.0, dev['ret'])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  574) 			devstats[dev['id']] = {'info':info}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  575) 			dev['color'] = color
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  576) 			height = devtl.phaseRowHeight(0, phase, dev['row'])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  577) 			top = '%.6f' % ((dev['row']*height) + devtl.scaleH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  578) 			left = '%.6f' % (((dev['start']-t0)*100)/tTotal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  579) 			width = '%.6f' % (((dev['end']-dev['start'])*100)/tTotal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  580) 			length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  581) 			devtl.html += devtl.html_device.format(dev['id'],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  582) 				devname+length+phase+'_mode', left, top, '%.3f'%height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  583) 				width, devname, ' '+cls, '')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  584) 			rowtop = devtl.phaseRowTop(0, phase, dev['row'])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  585) 			height = '%.6f' % (devtl.rowH / 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  586) 			top = '%.6f' % (rowtop + devtl.scaleH + (devtl.rowH / 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  587) 			if data.do_one_initcall:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  588) 				if('ftrace' not in dev):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  589) 					continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  590) 				cg = dev['ftrace']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  591) 				large, stats = cgOverview(cg, 0.001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  592) 				devstats[dev['id']]['fstat'] = stats
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  593) 				for l in large:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  594) 					left = '%f' % (((l.time-t0)*100)/tTotal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  595) 					width = '%f' % (l.length*100/tTotal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  596) 					title = '%s (%0.3fms)' % (l.name, l.length * 1000.0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  597) 					devtl.html += html_srccall.format(l.name, left,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  598) 						top, height, width, title, 'x%d'%num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  599) 					num += 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  600) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  601) 			if('ftraces' not in dev):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  602) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  603) 			for cg in dev['ftraces']:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  604) 				left = '%f' % (((cg.start-t0)*100)/tTotal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  605) 				width = '%f' % ((cg.end-cg.start)*100/tTotal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  606) 				cglen = (cg.end - cg.start) * 1000.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  607) 				title = '%s (%0.3fms)' % (cg.name, cglen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  608) 				cg.id = 'x%d' % num
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  609) 				devtl.html += html_srccall.format(cg.name, left,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  610) 					top, height, width, title, dev['id']+cg.id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  611) 				num += 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  612) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  613) 	# draw the time scale, try to make the number of labels readable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  614) 	devtl.createTimeScale(t0, tMax, tTotal, 'boot')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  615) 	devtl.html += '</div>\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  616) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  617) 	# timeline is finished
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  618) 	devtl.html += '</div>\n</div>\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  619) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  620) 	# draw a legend which describes the phases by color
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  621) 	devtl.html += '<div class="legend">\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  622) 	pdelta = 20.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  623) 	pmargin = 36.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  624) 	for phase in data.phases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  625) 		order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  626) 		devtl.html += devtl.html_legend.format(order, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  627) 			data.dmesg[phase]['color'], phase+'_mode', phase[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  628) 	devtl.html += '</div>\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  629) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  630) 	hf = open(sysvals.htmlfile, 'w')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  631) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  632) 	# add the css
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  633) 	extra = '\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  634) 		.c1 {background:rgba(209,0,0,0.4);}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  635) 		.c2 {background:rgba(255,102,34,0.4);}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  636) 		.c3 {background:rgba(255,218,33,0.4);}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  637) 		.c4 {background:rgba(51,221,0,0.4);}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  638) 		.c5 {background:rgba(17,51,204,0.4);}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  639) 		.c6 {background:rgba(34,0,102,0.4);}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  640) 		.c7 {background:rgba(51,0,68,0.4);}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  641) 		.c8 {background:rgba(204,255,204,0.4);}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  642) 		.c9 {background:rgba(169,208,245,0.4);}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  643) 		.c10 {background:rgba(255,255,204,0.4);}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  644) 		.vt {transform:rotate(-60deg);transform-origin:0 0;}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  645) 		table.fstat {table-layout:fixed;padding:150px 15px 0 0;font-size:10px;column-width:30px;}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  646) 		.fstat th {width:55px;}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  647) 		.fstat td {text-align:left;width:35px;}\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  648) 		.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\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  649) 		.srccall:hover {color:white;font-weight:bold;border:1px solid white;}\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  650) 	aslib.addCSS(hf, sysvals, 1, False, extra)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  651) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  652) 	# write the device timeline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  653) 	hf.write(devtl.html)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  654) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  655) 	# add boot specific html
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  656) 	statinfo = 'var devstats = {\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  657) 	for n in sorted(devstats):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  658) 		statinfo += '\t"%s": [\n\t\t"%s",\n' % (n, devstats[n]['info'])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  659) 		if 'fstat' in devstats[n]:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  660) 			funcs = devstats[n]['fstat']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  661) 			for f in sorted(funcs, key=lambda k:(funcs[k], k), reverse=True):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  662) 				if funcs[f][0] < 0.01 and len(funcs) > 10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  663) 					break
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  664) 				statinfo += '\t\t"%f|%s|%d",\n' % (funcs[f][0], f, funcs[f][1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  665) 		statinfo += '\t],\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  666) 	statinfo += '};\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  667) 	html = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  668) 		'<div id="devicedetailtitle"></div>\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  669) 		'<div id="devicedetail" style="display:none;">\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  670) 		'<div id="devicedetail0">\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  671) 	for p in data.phases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  672) 		phase = data.dmesg[p]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  673) 		html += devtl.html_phaselet.format(p+'_mode', '0', '100', phase['color'])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  674) 	html += '</div>\n</div>\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  675) 		'<script type="text/javascript">\n'+statinfo+\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  676) 		'</script>\n'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  677) 	hf.write(html)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  678) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  679) 	# add the callgraph html
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  680) 	if(sysvals.usecallgraph):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  681) 		aslib.addCallgraphs(sysvals, hf, data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  682) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  683) 	# add the test log as a hidden div
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  684) 	if sysvals.testlog and sysvals.logmsg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  685) 		hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  686) 	# add the dmesg log as a hidden div
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  687) 	if sysvals.dmesglog:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  688) 		hf.write('<div id="dmesglog" style="display:none;">\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  689) 		for line in data.dmesgtext:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  690) 			line = line.replace('<', '&lt').replace('>', '&gt')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  691) 			hf.write(line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  692) 		hf.write('</div>\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  693) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  694) 	# write the footer and close
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  695) 	aslib.addScriptCode(hf, [data])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  696) 	hf.write('</body>\n</html>\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  697) 	hf.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  698) 	return True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  699) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  700) # Function: updateCron
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  701) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  702) #    (restore=False) Set the tool to run automatically on reboot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  703) #    (restore=True) Restore the original crontab
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  704) def updateCron(restore=False):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  705) 	if not restore:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  706) 		sysvals.rootUser(True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  707) 	crondir = '/var/spool/cron/crontabs/'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  708) 	if not os.path.exists(crondir):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  709) 		crondir = '/var/spool/cron/'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  710) 	if not os.path.exists(crondir):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  711) 		doError('%s not found' % crondir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  712) 	cronfile = crondir+'root'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  713) 	backfile = crondir+'root-analyze_boot-backup'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  714) 	cmd = sysvals.getExec('crontab')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  715) 	if not cmd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  716) 		doError('crontab not found')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  717) 	# on restore: move the backup cron back into place
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  718) 	if restore:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  719) 		if os.path.exists(backfile):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  720) 			shutil.move(backfile, cronfile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  721) 			call([cmd, cronfile])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  722) 		return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  723) 	# backup current cron and install new one with reboot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  724) 	if os.path.exists(cronfile):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  725) 		shutil.move(cronfile, backfile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  726) 	else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  727) 		fp = open(backfile, 'w')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  728) 		fp.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  729) 	res = -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  730) 	try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  731) 		fp = open(backfile, 'r')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  732) 		op = open(cronfile, 'w')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  733) 		for line in fp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  734) 			if not sysvals.myCronJob(line):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  735) 				op.write(line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  736) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  737) 		fp.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  738) 		op.write('@reboot python %s\n' % sysvals.cronjobCmdString())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  739) 		op.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  740) 		res = call([cmd, cronfile])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  741) 	except Exception as e:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  742) 		pprint('Exception: %s' % str(e))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  743) 		shutil.move(backfile, cronfile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  744) 		res = -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  745) 	if res != 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  746) 		doError('crontab failed')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  747) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  748) # Function: updateGrub
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  749) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  750) #	 update grub.cfg for all kernels with our parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  751) def updateGrub(restore=False):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  752) 	# call update-grub on restore
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  753) 	if restore:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  754) 		try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  755) 			call(sysvals.blexec, stderr=PIPE, stdout=PIPE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  756) 				env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'})
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  757) 		except Exception as e:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  758) 			pprint('Exception: %s\n' % str(e))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  759) 		return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  760) 	# extract the option and create a grub config without it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  761) 	sysvals.rootUser(True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  762) 	tgtopt = 'GRUB_CMDLINE_LINUX_DEFAULT'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  763) 	cmdline = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  764) 	grubfile = '/etc/default/grub'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  765) 	tempfile = '/etc/default/grub.analyze_boot'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  766) 	shutil.move(grubfile, tempfile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  767) 	res = -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  768) 	try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  769) 		fp = open(tempfile, 'r')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  770) 		op = open(grubfile, 'w')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  771) 		cont = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  772) 		for line in fp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  773) 			line = line.strip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  774) 			if len(line) == 0 or line[0] == '#':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  775) 				continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  776) 			opt = line.split('=')[0].strip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  777) 			if opt == tgtopt:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  778) 				cmdline = line.split('=', 1)[1].strip('\\')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  779) 				if line[-1] == '\\':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  780) 					cont = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  781) 			elif cont:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  782) 				cmdline += line.strip('\\')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  783) 				if line[-1] != '\\':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  784) 					cont = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  785) 			else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  786) 				op.write('%s\n' % line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  787) 		fp.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  788) 		# if the target option value is in quotes, strip them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  789) 		sp = '"'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  790) 		val = cmdline.strip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  791) 		if val and (val[0] == '\'' or val[0] == '"'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  792) 			sp = val[0]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  793) 			val = val.strip(sp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  794) 		cmdline = val
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  795) 		# append our cmd line options
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  796) 		if len(cmdline) > 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  797) 			cmdline += ' '
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  798) 		cmdline += sysvals.kernelParams()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  799) 		# write out the updated target option
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  800) 		op.write('\n%s=%s%s%s\n' % (tgtopt, sp, cmdline, sp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  801) 		op.close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  802) 		res = call(sysvals.blexec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  803) 		os.remove(grubfile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  804) 	except Exception as e:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  805) 		pprint('Exception: %s' % str(e))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  806) 		res = -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  807) 	# cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  808) 	shutil.move(tempfile, grubfile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  809) 	if res != 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  810) 		doError('update grub failed')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  811) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  812) # Function: updateKernelParams
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  813) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  814) #	 update boot conf for all kernels with our parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  815) def updateKernelParams(restore=False):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  816) 	# find the boot loader
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  817) 	sysvals.getBootLoader()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  818) 	if sysvals.bootloader == 'grub':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  819) 		updateGrub(restore)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  820) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  821) # Function: doError Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  822) #	 generic error function for catastrphic failures
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  823) # Arguments:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  824) #	 msg: the error message to print
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  825) #	 help: True if printHelp should be called after, False otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  826) def doError(msg, help=False):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  827) 	if help == True:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  828) 		printHelp()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  829) 	pprint('ERROR: %s\n' % msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  830) 	sysvals.outputResult({'error':msg})
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  831) 	sys.exit()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  832) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  833) # Function: printHelp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  834) # Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  835) #	 print out the help text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  836) def printHelp():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  837) 	pprint('\n%s v%s\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  838) 	'Usage: bootgraph <options> <command>\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  839) 	'\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  840) 	'Description:\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  841) 	'  This tool reads in a dmesg log of linux kernel boot and\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  842) 	'  creates an html representation of the boot timeline up to\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  843) 	'  the start of the init process.\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  844) 	'\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  845) 	'  If no specific command is given the tool reads the current dmesg\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  846) 	'  and/or ftrace log and creates a timeline\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  847) 	'\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  848) 	'  Generates output files in subdirectory: boot-yymmdd-HHMMSS\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  849) 	'   HTML output:                    <hostname>_boot.html\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  850) 	'   raw dmesg output:               <hostname>_boot_dmesg.txt\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  851) 	'   raw ftrace output:              <hostname>_boot_ftrace.txt\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  852) 	'\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  853) 	'Options:\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  854) 	'  -h            Print this help text\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  855) 	'  -v            Print the current tool version\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  856) 	'  -verbose      Print extra information during execution and analysis\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  857) 	'  -addlogs      Add the dmesg log to the html output\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  858) 	'  -result fn    Export a results table to a text file for parsing.\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  859) 	'  -o name       Overrides the output subdirectory name when running a new test\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  860) 	'                default: boot-{date}-{time}\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  861) 	' [advanced]\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  862) 	'  -fstat        Use ftrace to add function detail and statistics (default: disabled)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  863) 	'  -f/-callgraph Add callgraph detail, can be very large (default: disabled)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  864) 	'  -maxdepth N   limit the callgraph data to N call levels (default: 2)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  865) 	'  -mincg ms     Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  866) 	'  -timeprec N   Number of significant digits in timestamps (0:S, 3:ms, [6:us])\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  867) 	'  -expandcg     pre-expand the callgraph data in the html output (default: disabled)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  868) 	'  -func list    Limit ftrace to comma-delimited list of functions (default: do_one_initcall)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  869) 	'  -cgfilter S   Filter the callgraph output in the timeline\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  870) 	'  -cgskip file  Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  871) 	'  -bl name      Use the following boot loader for kernel params (default: grub)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  872) 	'  -reboot       Reboot the machine automatically and generate a new timeline\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  873) 	'  -manual       Show the steps to generate a new timeline manually (used with -reboot)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  874) 	'\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  875) 	'Other commands:\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  876) 	'  -flistall     Print all functions capable of being captured in ftrace\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  877) 	'  -sysinfo      Print out system info extracted from BIOS\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  878) 	'  -which exec   Print an executable path, should function even without PATH\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  879) 	' [redo]\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  880) 	'  -dmesg file   Create HTML output using dmesg input (used with -ftrace)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  881) 	'  -ftrace file  Create HTML output using ftrace input (used with -dmesg)\n'\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  882) 	'' % (sysvals.title, sysvals.version))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  883) 	return True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  884) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  885) # ----------------- MAIN --------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  886) # exec start (skipped if script is loaded as library)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  887) if __name__ == '__main__':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  888) 	# loop through the command line arguments
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  889) 	cmd = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  890) 	testrun = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  891) 	switchoff = ['disable', 'off', 'false', '0']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  892) 	simplecmds = ['-sysinfo', '-kpupdate', '-flistall', '-checkbl']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  893) 	cgskip = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  894) 	if '-f' in sys.argv:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  895) 		cgskip = sysvals.configFile('cgskip.txt')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  896) 	args = iter(sys.argv[1:])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  897) 	mdset = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  898) 	for arg in args:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  899) 		if(arg == '-h'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  900) 			printHelp()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  901) 			sys.exit()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  902) 		elif(arg == '-v'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  903) 			pprint("Version %s" % sysvals.version)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  904) 			sys.exit()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  905) 		elif(arg == '-verbose'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  906) 			sysvals.verbose = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  907) 		elif(arg in simplecmds):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  908) 			cmd = arg[1:]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  909) 		elif(arg == '-fstat'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  910) 			sysvals.useftrace = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  911) 		elif(arg == '-callgraph' or arg == '-f'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  912) 			sysvals.useftrace = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  913) 			sysvals.usecallgraph = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  914) 		elif(arg == '-cgdump'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  915) 			sysvals.cgdump = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  916) 		elif(arg == '-mincg'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  917) 			sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  918) 		elif(arg == '-cgfilter'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  919) 			try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  920) 				val = next(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  921) 			except:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  922) 				doError('No callgraph functions supplied', True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  923) 			sysvals.setCallgraphFilter(val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  924) 		elif(arg == '-cgskip'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  925) 			try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  926) 				val = next(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  927) 			except:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  928) 				doError('No file supplied', True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  929) 			if val.lower() in switchoff:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  930) 				cgskip = ''
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  931) 			else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  932) 				cgskip = sysvals.configFile(val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  933) 				if(not cgskip):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  934) 					doError('%s does not exist' % cgskip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  935) 		elif(arg == '-bl'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  936) 			try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  937) 				val = next(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  938) 			except:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  939) 				doError('No boot loader name supplied', True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  940) 			if val.lower() not in ['grub']:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  941) 				doError('Unknown boot loader: %s' % val, True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  942) 			sysvals.bootloader = val.lower()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  943) 		elif(arg == '-timeprec'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  944) 			sysvals.setPrecision(aslib.getArgInt('-timeprec', args, 0, 6))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  945) 		elif(arg == '-maxdepth'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  946) 			mdset = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  947) 			sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  948) 		elif(arg == '-func'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  949) 			try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  950) 				val = next(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  951) 			except:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  952) 				doError('No filter functions supplied', True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  953) 			sysvals.useftrace = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  954) 			sysvals.usecallgraph = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  955) 			sysvals.rootCheck(True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  956) 			sysvals.setGraphFilter(val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  957) 		elif(arg == '-ftrace'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  958) 			try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  959) 				val = next(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  960) 			except:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  961) 				doError('No ftrace file supplied', True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  962) 			if(os.path.exists(val) == False):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  963) 				doError('%s does not exist' % val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  964) 			testrun = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  965) 			sysvals.ftracefile = val
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  966) 		elif(arg == '-addlogs'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  967) 			sysvals.dmesglog = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  968) 		elif(arg == '-expandcg'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  969) 			sysvals.cgexp = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  970) 		elif(arg == '-dmesg'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  971) 			try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  972) 				val = next(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  973) 			except:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  974) 				doError('No dmesg file supplied', True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  975) 			if(os.path.exists(val) == False):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  976) 				doError('%s does not exist' % val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  977) 			testrun = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  978) 			sysvals.dmesgfile = val
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  979) 		elif(arg == '-o'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  980) 			try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  981) 				val = next(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  982) 			except:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  983) 				doError('No subdirectory name supplied', True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  984) 			sysvals.testdir = sysvals.setOutputFolder(val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  985) 		elif(arg == '-result'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  986) 			try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  987) 				val = next(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  988) 			except:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  989) 				doError('No result file supplied', True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  990) 			sysvals.result = val
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  991) 		elif(arg == '-reboot'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  992) 			sysvals.reboot = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  993) 		elif(arg == '-manual'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  994) 			sysvals.reboot = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  995) 			sysvals.manual = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  996) 		# remaining options are only for cron job use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  997) 		elif(arg == '-cronjob'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  998) 			sysvals.iscronjob = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  999) 		elif(arg == '-which'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) 			try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) 				val = next(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) 			except:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) 				doError('No executable supplied', True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) 			out = sysvals.getExec(val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) 			if not out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) 				print('%s not found' % val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) 				sys.exit(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) 			print(out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) 			sys.exit(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) 		else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) 			doError('Invalid argument: '+arg, True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) 	# compatibility errors and access checks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) 	if(sysvals.iscronjob and (sysvals.reboot or \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) 		sysvals.dmesgfile or sysvals.ftracefile or cmd)):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) 		doError('-cronjob is meant for batch purposes only')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) 	if(sysvals.reboot and (sysvals.dmesgfile or sysvals.ftracefile)):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) 		doError('-reboot and -dmesg/-ftrace are incompatible')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) 	if cmd or sysvals.reboot or sysvals.iscronjob or testrun:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) 		sysvals.rootCheck(True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) 	if (testrun and sysvals.useftrace) or cmd == 'flistall':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) 		if not sysvals.verifyFtrace():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) 			doError('Ftrace is not properly enabled')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) 	# run utility commands
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) 	sysvals.cpuInfo()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) 	if cmd != '':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) 		if cmd == 'kpupdate':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) 			updateKernelParams()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) 		elif cmd == 'flistall':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) 			for f in sysvals.getBootFtraceFilterFunctions():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) 				print(f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) 		elif cmd == 'checkbl':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) 			sysvals.getBootLoader()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) 			pprint('Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) 		elif(cmd == 'sysinfo'):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) 			sysvals.printSystemInfo(True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) 		sys.exit()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) 	# reboot: update grub, setup a cronjob, and reboot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) 	if sysvals.reboot:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) 		if (sysvals.useftrace or sysvals.usecallgraph) and \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) 			not sysvals.checkFtraceKernelVersion():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) 			doError('Ftrace functionality requires kernel v4.10 or newer')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) 		if not sysvals.manual:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) 			updateKernelParams()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) 			updateCron()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) 			call('reboot')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) 		else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) 			sysvals.manualRebootRequired()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) 		sys.exit()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) 	if sysvals.usecallgraph and cgskip:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) 		sysvals.vprint('Using cgskip file: %s' % cgskip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) 		sysvals.setCallgraphBlacklist(cgskip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) 	# cronjob: remove the cronjob, grub changes, and disable ftrace
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) 	if sysvals.iscronjob:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) 		updateCron(True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) 		updateKernelParams(True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) 		try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) 			sysvals.fsetVal('0', 'tracing_on')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) 		except:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) 			pass
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) 	# testrun: generate copies of the logs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) 	if testrun:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) 		retrieveLogs()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) 	else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) 		sysvals.setOutputFile()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) 	# process the log data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) 	if sysvals.dmesgfile:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) 		if not mdset:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) 			sysvals.max_graph_depth = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) 		data = parseKernelLog()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) 		if(not data.valid):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) 			doError('No initcall data found in %s' % sysvals.dmesgfile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) 		if sysvals.useftrace and sysvals.ftracefile:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) 			parseTraceLog(data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) 		if sysvals.cgdump:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) 			data.debugPrint()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) 			sys.exit()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) 	else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) 		doError('dmesg file required')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) 	sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) 	sysvals.vprint('Command:\n    %s' % sysvals.cmdline)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) 	sysvals.vprint('Kernel parameters:\n    %s' % sysvals.kparams)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) 	data.printDetails()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) 	createBootGraph(data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) 	# if running as root, change output dir owner to sudo_user
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) 	if testrun and os.path.isdir(sysvals.testdir) and \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) 		os.getuid() == 0 and 'SUDO_USER' in os.environ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) 		cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) 		call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) 	sysvals.stamp['boot'] = (data.tUserMode - data.start) * 1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) 	sysvals.stamp['lastinit'] = data.end * 1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) 	sysvals.outputResult(sysvals.stamp)