hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/tools/power/pm-graph/bootgraph.py
....@@ -1,4 +1,5 @@
1
-#!/usr/bin/python2
1
+#!/usr/bin/env python3
2
+# SPDX-License-Identifier: GPL-2.0-only
23 #
34 # Tool for analyzing boot timing
45 # Copyright (c) 2013, Intel Corporation.
....@@ -33,6 +34,10 @@
3334 from datetime import datetime, timedelta
3435 from subprocess import call, Popen, PIPE
3536 import sleepgraph as aslib
37
+
38
+def pprint(msg):
39
+ print(msg)
40
+ sys.stdout.flush()
3641
3742 # ----------------- CLASSES --------------------
3843
....@@ -85,7 +90,7 @@
8590 cmdline = 'initcall_debug log_buf_len=32M'
8691 if self.useftrace:
8792 if self.cpucount > 0:
88
- bs = min(self.memtotal / 2, 2*1024*1024) / self.cpucount
93
+ bs = min(self.memtotal // 2, 2*1024*1024) // self.cpucount
8994 else:
9095 bs = 131072
9196 cmdline += ' trace_buf_size=%dK trace_clock=global '\
....@@ -141,13 +146,13 @@
141146 if arg in ['-h', '-v', '-cronjob', '-reboot', '-verbose']:
142147 continue
143148 elif arg in ['-o', '-dmesg', '-ftrace', '-func']:
144
- args.next()
149
+ next(args)
145150 continue
146151 elif arg == '-result':
147
- cmdline += ' %s "%s"' % (arg, os.path.abspath(args.next()))
152
+ cmdline += ' %s "%s"' % (arg, os.path.abspath(next(args)))
148153 continue
149154 elif arg == '-cgskip':
150
- file = self.configFile(args.next())
155
+ file = self.configFile(next(args))
151156 cmdline += ' %s "%s"' % (arg, os.path.abspath(file))
152157 continue
153158 cmdline += ' '+arg
....@@ -157,11 +162,11 @@
157162 return cmdline
158163 def manualRebootRequired(self):
159164 cmdline = self.kernelParams()
160
- print 'To generate a new timeline manually, follow these steps:\n'
161
- print '1. Add the CMDLINE string to your kernel command line.'
162
- print '2. Reboot the system.'
163
- print '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n'
164
- print 'CMDLINE="%s"' % cmdline
165
+ pprint('To generate a new timeline manually, follow these steps:\n\n'\
166
+ '1. Add the CMDLINE string to your kernel command line.\n'\
167
+ '2. Reboot the system.\n'\
168
+ '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n\n'\
169
+ 'CMDLINE="%s"' % cmdline)
165170 sys.exit()
166171 def blGrub(self):
167172 blcmd = ''
....@@ -296,11 +301,11 @@
296301 tp = aslib.TestProps()
297302 devtemp = dict()
298303 if(sysvals.dmesgfile):
299
- lf = open(sysvals.dmesgfile, 'r')
304
+ lf = open(sysvals.dmesgfile, 'rb')
300305 else:
301306 lf = Popen('dmesg', stdout=PIPE).stdout
302307 for line in lf:
303
- line = line.replace('\r\n', '')
308
+ line = aslib.ascii(line).replace('\r\n', '')
304309 # grab the stamp and sysinfo
305310 if re.match(tp.stampfmt, line):
306311 tp.stamp = line
....@@ -329,9 +334,9 @@
329334 if(not sysvals.stamp['kernel']):
330335 sysvals.stamp['kernel'] = sysvals.kernelVersion(msg)
331336 continue
332
- m = re.match('.* setting system clock to (?P<t>.*) UTC.*', msg)
337
+ m = re.match('.* setting system clock to (?P<d>[0-9\-]*)[ A-Z](?P<t>[0-9:]*) UTC.*', msg)
333338 if(m):
334
- bt = datetime.strptime(m.group('t'), '%Y-%m-%d %H:%M:%S')
339
+ bt = datetime.strptime(m.group('d')+' '+m.group('t'), '%Y-%m-%d %H:%M:%S')
335340 bt = bt - timedelta(seconds=int(ktime))
336341 data.boottime = bt.strftime('%Y-%m-%d_%H:%M:%S')
337342 sysvals.stamp['time'] = bt.strftime('%B %d %Y, %I:%M:%S %p')
....@@ -352,7 +357,7 @@
352357 data.newAction(phase, f, pid, start, ktime, int(r), int(t))
353358 del devtemp[f]
354359 continue
355
- if(re.match('^Freeing unused kernel memory.*', msg)):
360
+ if(re.match('^Freeing unused kernel .*', msg)):
356361 data.tUserMode = ktime
357362 data.dmesg['kernel']['end'] = ktime
358363 data.dmesg['user']['start'] = ktime
....@@ -431,7 +436,7 @@
431436 if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0):
432437 continue
433438 if(not cg.postProcess()):
434
- print('Sanity check failed for %s-%d' % (proc, pid))
439
+ pprint('Sanity check failed for %s-%d' % (proc, pid))
435440 continue
436441 # match cg data to devices
437442 devname = data.deviceMatch(pid, cg)
....@@ -442,8 +447,8 @@
442447 sysvals.vprint('%s callgraph found for %s %s-%d [%f - %f]' %\
443448 (kind, cg.name, proc, pid, cg.start, cg.end))
444449 elif len(cg.list) > 1000000:
445
- print 'WARNING: the callgraph found for %s is massive! (%d lines)' %\
446
- (devname, len(cg.list))
450
+ pprint('WARNING: the callgraph found for %s is massive! (%d lines)' %\
451
+ (devname, len(cg.list)))
447452
448453 # Function: retrieveLogs
449454 # Description:
....@@ -528,7 +533,7 @@
528533 tMax = data.end
529534 tTotal = tMax - t0
530535 if(tTotal == 0):
531
- print('ERROR: No timeline data')
536
+ pprint('ERROR: No timeline data')
532537 return False
533538 user_mode = '%.0f'%(data.tUserMode*1000)
534539 last_init = '%.0f'%(tTotal*1000)
....@@ -653,7 +658,7 @@
653658 statinfo += '\t"%s": [\n\t\t"%s",\n' % (n, devstats[n]['info'])
654659 if 'fstat' in devstats[n]:
655660 funcs = devstats[n]['fstat']
656
- for f in sorted(funcs, key=funcs.get, reverse=True):
661
+ for f in sorted(funcs, key=lambda k:(funcs[k], k), reverse=True):
657662 if funcs[f][0] < 0.01 and len(funcs) > 10:
658663 break
659664 statinfo += '\t\t"%f|%s|%d",\n' % (funcs[f][0], f, funcs[f][1])
....@@ -733,8 +738,8 @@
733738 op.write('@reboot python %s\n' % sysvals.cronjobCmdString())
734739 op.close()
735740 res = call([cmd, cronfile])
736
- except Exception, e:
737
- print 'Exception: %s' % str(e)
741
+ except Exception as e:
742
+ pprint('Exception: %s' % str(e))
738743 shutil.move(backfile, cronfile)
739744 res = -1
740745 if res != 0:
....@@ -749,8 +754,8 @@
749754 try:
750755 call(sysvals.blexec, stderr=PIPE, stdout=PIPE,
751756 env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'})
752
- except Exception, e:
753
- print 'Exception: %s\n' % str(e)
757
+ except Exception as e:
758
+ pprint('Exception: %s\n' % str(e))
754759 return
755760 # extract the option and create a grub config without it
756761 sysvals.rootUser(True)
....@@ -796,8 +801,8 @@
796801 op.close()
797802 res = call(sysvals.blexec)
798803 os.remove(grubfile)
799
- except Exception, e:
800
- print 'Exception: %s' % str(e)
804
+ except Exception as e:
805
+ pprint('Exception: %s' % str(e))
801806 res = -1
802807 # cleanup
803808 shutil.move(tempfile, grubfile)
....@@ -821,7 +826,7 @@
821826 def doError(msg, help=False):
822827 if help == True:
823828 printHelp()
824
- print 'ERROR: %s\n' % msg
829
+ pprint('ERROR: %s\n' % msg)
825830 sysvals.outputResult({'error':msg})
826831 sys.exit()
827832
....@@ -829,52 +834,52 @@
829834 # Description:
830835 # print out the help text
831836 def printHelp():
832
- print('')
833
- print('%s v%s' % (sysvals.title, sysvals.version))
834
- print('Usage: bootgraph <options> <command>')
835
- print('')
836
- print('Description:')
837
- print(' This tool reads in a dmesg log of linux kernel boot and')
838
- print(' creates an html representation of the boot timeline up to')
839
- print(' the start of the init process.')
840
- print('')
841
- print(' If no specific command is given the tool reads the current dmesg')
842
- print(' and/or ftrace log and creates a timeline')
843
- print('')
844
- print(' Generates output files in subdirectory: boot-yymmdd-HHMMSS')
845
- print(' HTML output: <hostname>_boot.html')
846
- print(' raw dmesg output: <hostname>_boot_dmesg.txt')
847
- print(' raw ftrace output: <hostname>_boot_ftrace.txt')
848
- print('')
849
- print('Options:')
850
- print(' -h Print this help text')
851
- print(' -v Print the current tool version')
852
- print(' -verbose Print extra information during execution and analysis')
853
- print(' -addlogs Add the dmesg log to the html output')
854
- print(' -result fn Export a results table to a text file for parsing.')
855
- print(' -o name Overrides the output subdirectory name when running a new test')
856
- print(' default: boot-{date}-{time}')
857
- print(' [advanced]')
858
- print(' -fstat Use ftrace to add function detail and statistics (default: disabled)')
859
- print(' -f/-callgraph Add callgraph detail, can be very large (default: disabled)')
860
- print(' -maxdepth N limit the callgraph data to N call levels (default: 2)')
861
- print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
862
- print(' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])')
863
- print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)')
864
- print(' -func list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)')
865
- print(' -cgfilter S Filter the callgraph output in the timeline')
866
- print(' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)')
867
- print(' -bl name Use the following boot loader for kernel params (default: grub)')
868
- print(' -reboot Reboot the machine automatically and generate a new timeline')
869
- print(' -manual Show the steps to generate a new timeline manually (used with -reboot)')
870
- print('')
871
- print('Other commands:')
872
- print(' -flistall Print all functions capable of being captured in ftrace')
873
- print(' -sysinfo Print out system info extracted from BIOS')
874
- print(' [redo]')
875
- print(' -dmesg file Create HTML output using dmesg input (used with -ftrace)')
876
- print(' -ftrace file Create HTML output using ftrace input (used with -dmesg)')
877
- print('')
837
+ pprint('\n%s v%s\n'\
838
+ 'Usage: bootgraph <options> <command>\n'\
839
+ '\n'\
840
+ 'Description:\n'\
841
+ ' This tool reads in a dmesg log of linux kernel boot and\n'\
842
+ ' creates an html representation of the boot timeline up to\n'\
843
+ ' the start of the init process.\n'\
844
+ '\n'\
845
+ ' If no specific command is given the tool reads the current dmesg\n'\
846
+ ' and/or ftrace log and creates a timeline\n'\
847
+ '\n'\
848
+ ' Generates output files in subdirectory: boot-yymmdd-HHMMSS\n'\
849
+ ' HTML output: <hostname>_boot.html\n'\
850
+ ' raw dmesg output: <hostname>_boot_dmesg.txt\n'\
851
+ ' raw ftrace output: <hostname>_boot_ftrace.txt\n'\
852
+ '\n'\
853
+ 'Options:\n'\
854
+ ' -h Print this help text\n'\
855
+ ' -v Print the current tool version\n'\
856
+ ' -verbose Print extra information during execution and analysis\n'\
857
+ ' -addlogs Add the dmesg log to the html output\n'\
858
+ ' -result fn Export a results table to a text file for parsing.\n'\
859
+ ' -o name Overrides the output subdirectory name when running a new test\n'\
860
+ ' default: boot-{date}-{time}\n'\
861
+ ' [advanced]\n'\
862
+ ' -fstat Use ftrace to add function detail and statistics (default: disabled)\n'\
863
+ ' -f/-callgraph Add callgraph detail, can be very large (default: disabled)\n'\
864
+ ' -maxdepth N limit the callgraph data to N call levels (default: 2)\n'\
865
+ ' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\
866
+ ' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])\n'\
867
+ ' -expandcg pre-expand the callgraph data in the html output (default: disabled)\n'\
868
+ ' -func list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)\n'\
869
+ ' -cgfilter S Filter the callgraph output in the timeline\n'\
870
+ ' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\
871
+ ' -bl name Use the following boot loader for kernel params (default: grub)\n'\
872
+ ' -reboot Reboot the machine automatically and generate a new timeline\n'\
873
+ ' -manual Show the steps to generate a new timeline manually (used with -reboot)\n'\
874
+ '\n'\
875
+ 'Other commands:\n'\
876
+ ' -flistall Print all functions capable of being captured in ftrace\n'\
877
+ ' -sysinfo Print out system info extracted from BIOS\n'\
878
+ ' -which exec Print an executable path, should function even without PATH\n'\
879
+ ' [redo]\n'\
880
+ ' -dmesg file Create HTML output using dmesg input (used with -ftrace)\n'\
881
+ ' -ftrace file Create HTML output using ftrace input (used with -dmesg)\n'\
882
+ '' % (sysvals.title, sysvals.version))
878883 return True
879884
880885 # ----------------- MAIN --------------------
....@@ -895,7 +900,7 @@
895900 printHelp()
896901 sys.exit()
897902 elif(arg == '-v'):
898
- print("Version %s" % sysvals.version)
903
+ pprint("Version %s" % sysvals.version)
899904 sys.exit()
900905 elif(arg == '-verbose'):
901906 sysvals.verbose = True
....@@ -912,13 +917,13 @@
912917 sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0)
913918 elif(arg == '-cgfilter'):
914919 try:
915
- val = args.next()
920
+ val = next(args)
916921 except:
917922 doError('No callgraph functions supplied', True)
918923 sysvals.setCallgraphFilter(val)
919924 elif(arg == '-cgskip'):
920925 try:
921
- val = args.next()
926
+ val = next(args)
922927 except:
923928 doError('No file supplied', True)
924929 if val.lower() in switchoff:
....@@ -929,7 +934,7 @@
929934 doError('%s does not exist' % cgskip)
930935 elif(arg == '-bl'):
931936 try:
932
- val = args.next()
937
+ val = next(args)
933938 except:
934939 doError('No boot loader name supplied', True)
935940 if val.lower() not in ['grub']:
....@@ -942,7 +947,7 @@
942947 sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000)
943948 elif(arg == '-func'):
944949 try:
945
- val = args.next()
950
+ val = next(args)
946951 except:
947952 doError('No filter functions supplied', True)
948953 sysvals.useftrace = True
....@@ -951,7 +956,7 @@
951956 sysvals.setGraphFilter(val)
952957 elif(arg == '-ftrace'):
953958 try:
954
- val = args.next()
959
+ val = next(args)
955960 except:
956961 doError('No ftrace file supplied', True)
957962 if(os.path.exists(val) == False):
....@@ -964,7 +969,7 @@
964969 sysvals.cgexp = True
965970 elif(arg == '-dmesg'):
966971 try:
967
- val = args.next()
972
+ val = next(args)
968973 except:
969974 doError('No dmesg file supplied', True)
970975 if(os.path.exists(val) == False):
....@@ -973,13 +978,13 @@
973978 sysvals.dmesgfile = val
974979 elif(arg == '-o'):
975980 try:
976
- val = args.next()
981
+ val = next(args)
977982 except:
978983 doError('No subdirectory name supplied', True)
979984 sysvals.testdir = sysvals.setOutputFolder(val)
980985 elif(arg == '-result'):
981986 try:
982
- val = args.next()
987
+ val = next(args)
983988 except:
984989 doError('No result file supplied', True)
985990 sysvals.result = val
....@@ -991,6 +996,17 @@
991996 # remaining options are only for cron job use
992997 elif(arg == '-cronjob'):
993998 sysvals.iscronjob = True
999
+ elif(arg == '-which'):
1000
+ try:
1001
+ val = next(args)
1002
+ except:
1003
+ doError('No executable supplied', True)
1004
+ out = sysvals.getExec(val)
1005
+ if not out:
1006
+ print('%s not found' % val)
1007
+ sys.exit(1)
1008
+ print(out)
1009
+ sys.exit(0)
9941010 else:
9951011 doError('Invalid argument: '+arg, True)
9961012
....@@ -1013,10 +1029,10 @@
10131029 updateKernelParams()
10141030 elif cmd == 'flistall':
10151031 for f in sysvals.getBootFtraceFilterFunctions():
1016
- print f
1032
+ print(f)
10171033 elif cmd == 'checkbl':
10181034 sysvals.getBootLoader()
1019
- print 'Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec)
1035
+ pprint('Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec))
10201036 elif(cmd == 'sysinfo'):
10211037 sysvals.printSystemInfo(True)
10221038 sys.exit()