Commit 1446794a authored by Todd Brandt's avatar Todd Brandt Committed by Rafael J. Wysocki

pm-graph v5.5

Upgrade bootgraph/sleepgraph to be able to run on python2 and python3.
Both now simply require python, the system can choose which to use.

bootgraph python3 update:
- add floor function to handle integer arithmetic
- change argument loop to use next() instead of args.next()
- open dmesg log and popen in binary, use decode(ascii, ignore)
- sort all html data to allow diff between python versions
- change exception handler to use python3 as instead of comma

sleepgraph python3 update:
- import configparser not ConfigParser (p2 needs python-configparser)
- add floor function to handle integer arithmetic
- change argument loop to use next() instead of args.next()
- handle popen output in binary, use decode(ascii, ignore)
- sort all html/output data to allow diff between python versions
- force gzip open to use text mode, same for file open
- ensure no binary data is written to logs (ascii convert devprops info)
- use codecs library to handle zlib encoding for mcelog data
- remove all uses of python3.7 keyword "async" as members or vars
- assume all FPDT and DMI data is in binary string form

sleepgraph:
- turbostat will be used by default if it's found & the mode is freeze
- a new option "-noturbostat" will disable its use
- fix bug where two callgraphs with the same start time overwrite.
- fix s2idle processing where two suspend/resume_machines occur back2back
- update getexec function to use which first (assuming PATH exists)
- new platforminfo data in log with: lspci, gpe counts, /proc/interrupts
- new data is zipped, b64 encoded, and tacked on the end of ftrace
Signed-off-by: default avatarTodd Brandt <todd.e.brandt@linux.intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent d1abaeb3
p m - g r a p h p m - g r a p h
pm-graph: suspend/resume/boot timing analysis tools pm-graph: suspend/resume/boot timing analysis tools
Version: 5.4 Version: 5.5
Author: Todd Brandt <todd.e.brandt@intel.com> Author: Todd Brandt <todd.e.brandt@intel.com>
Home Page: https://01.org/pm-graph Home Page: https://01.org/pm-graph
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
- upstream version in git: - upstream version in git:
https://github.com/intel/pm-graph/ https://github.com/intel/pm-graph/
Requirements:
- runs with python2 or python3, choice is made by /usr/bin/python link
- python2 now requires python-configparser be installed
Table of Contents Table of Contents
- Overview - Overview
- Setup - Setup
......
#!/usr/bin/python2 #!/usr/bin/python
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
# #
# Tool for analyzing boot timing # Tool for analyzing boot timing
# Copyright (c) 2013, Intel Corporation. # Copyright (c) 2013, Intel Corporation.
# #
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# Authors: # Authors:
# Todd Brandt <todd.e.brandt@linux.intel.com> # Todd Brandt <todd.e.brandt@linux.intel.com>
# #
...@@ -81,7 +90,7 @@ class SystemValues(aslib.SystemValues): ...@@ -81,7 +90,7 @@ class SystemValues(aslib.SystemValues):
cmdline = 'initcall_debug log_buf_len=32M' cmdline = 'initcall_debug log_buf_len=32M'
if self.useftrace: if self.useftrace:
if self.cpucount > 0: if self.cpucount > 0:
bs = min(self.memtotal / 2, 2*1024*1024) / self.cpucount bs = min(self.memtotal // 2, 2*1024*1024) // self.cpucount
else: else:
bs = 131072 bs = 131072
cmdline += ' trace_buf_size=%dK trace_clock=global '\ cmdline += ' trace_buf_size=%dK trace_clock=global '\
...@@ -137,13 +146,13 @@ class SystemValues(aslib.SystemValues): ...@@ -137,13 +146,13 @@ class SystemValues(aslib.SystemValues):
if arg in ['-h', '-v', '-cronjob', '-reboot', '-verbose']: if arg in ['-h', '-v', '-cronjob', '-reboot', '-verbose']:
continue continue
elif arg in ['-o', '-dmesg', '-ftrace', '-func']: elif arg in ['-o', '-dmesg', '-ftrace', '-func']:
args.next() next(args)
continue continue
elif arg == '-result': elif arg == '-result':
cmdline += ' %s "%s"' % (arg, os.path.abspath(args.next())) cmdline += ' %s "%s"' % (arg, os.path.abspath(next(args)))
continue continue
elif arg == '-cgskip': elif arg == '-cgskip':
file = self.configFile(args.next()) file = self.configFile(next(args))
cmdline += ' %s "%s"' % (arg, os.path.abspath(file)) cmdline += ' %s "%s"' % (arg, os.path.abspath(file))
continue continue
cmdline += ' '+arg cmdline += ' '+arg
...@@ -292,11 +301,11 @@ def parseKernelLog(): ...@@ -292,11 +301,11 @@ def parseKernelLog():
tp = aslib.TestProps() tp = aslib.TestProps()
devtemp = dict() devtemp = dict()
if(sysvals.dmesgfile): if(sysvals.dmesgfile):
lf = open(sysvals.dmesgfile, 'r') lf = open(sysvals.dmesgfile, 'rb')
else: else:
lf = Popen('dmesg', stdout=PIPE).stdout lf = Popen('dmesg', stdout=PIPE).stdout
for line in lf: for line in lf:
line = line.replace('\r\n', '') line = aslib.ascii(line).replace('\r\n', '')
# grab the stamp and sysinfo # grab the stamp and sysinfo
if re.match(tp.stampfmt, line): if re.match(tp.stampfmt, line):
tp.stamp = line tp.stamp = line
...@@ -649,7 +658,7 @@ def createBootGraph(data): ...@@ -649,7 +658,7 @@ def createBootGraph(data):
statinfo += '\t"%s": [\n\t\t"%s",\n' % (n, devstats[n]['info']) statinfo += '\t"%s": [\n\t\t"%s",\n' % (n, devstats[n]['info'])
if 'fstat' in devstats[n]: if 'fstat' in devstats[n]:
funcs = devstats[n]['fstat'] funcs = devstats[n]['fstat']
for f in sorted(funcs, key=funcs.get, reverse=True): for f in sorted(funcs, key=lambda k:(funcs[k], k), reverse=True):
if funcs[f][0] < 0.01 and len(funcs) > 10: if funcs[f][0] < 0.01 and len(funcs) > 10:
break break
statinfo += '\t\t"%f|%s|%d",\n' % (funcs[f][0], f, funcs[f][1]) statinfo += '\t\t"%f|%s|%d",\n' % (funcs[f][0], f, funcs[f][1])
...@@ -729,7 +738,7 @@ def updateCron(restore=False): ...@@ -729,7 +738,7 @@ def updateCron(restore=False):
op.write('@reboot python %s\n' % sysvals.cronjobCmdString()) op.write('@reboot python %s\n' % sysvals.cronjobCmdString())
op.close() op.close()
res = call([cmd, cronfile]) res = call([cmd, cronfile])
except Exception, e: except Exception as e:
pprint('Exception: %s' % str(e)) pprint('Exception: %s' % str(e))
shutil.move(backfile, cronfile) shutil.move(backfile, cronfile)
res = -1 res = -1
...@@ -745,7 +754,7 @@ def updateGrub(restore=False): ...@@ -745,7 +754,7 @@ def updateGrub(restore=False):
try: try:
call(sysvals.blexec, stderr=PIPE, stdout=PIPE, call(sysvals.blexec, stderr=PIPE, stdout=PIPE,
env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'}) env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'})
except Exception, e: except Exception as e:
pprint('Exception: %s\n' % str(e)) pprint('Exception: %s\n' % str(e))
return return
# extract the option and create a grub config without it # extract the option and create a grub config without it
...@@ -792,7 +801,7 @@ def updateGrub(restore=False): ...@@ -792,7 +801,7 @@ def updateGrub(restore=False):
op.close() op.close()
res = call(sysvals.blexec) res = call(sysvals.blexec)
os.remove(grubfile) os.remove(grubfile)
except Exception, e: except Exception as e:
pprint('Exception: %s' % str(e)) pprint('Exception: %s' % str(e))
res = -1 res = -1
# cleanup # cleanup
...@@ -866,6 +875,7 @@ def printHelp(): ...@@ -866,6 +875,7 @@ def printHelp():
'Other commands:\n'\ 'Other commands:\n'\
' -flistall Print all functions capable of being captured in ftrace\n'\ ' -flistall Print all functions capable of being captured in ftrace\n'\
' -sysinfo Print out system info extracted from BIOS\n'\ ' -sysinfo Print out system info extracted from BIOS\n'\
' -which exec Print an executable path, should function even without PATH\n'\
' [redo]\n'\ ' [redo]\n'\
' -dmesg file Create HTML output using dmesg input (used with -ftrace)\n'\ ' -dmesg file Create HTML output using dmesg input (used with -ftrace)\n'\
' -ftrace file Create HTML output using ftrace input (used with -dmesg)\n'\ ' -ftrace file Create HTML output using ftrace input (used with -dmesg)\n'\
...@@ -907,13 +917,13 @@ if __name__ == '__main__': ...@@ -907,13 +917,13 @@ if __name__ == '__main__':
sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0) sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0)
elif(arg == '-cgfilter'): elif(arg == '-cgfilter'):
try: try:
val = args.next() val = next(args)
except: except:
doError('No callgraph functions supplied', True) doError('No callgraph functions supplied', True)
sysvals.setCallgraphFilter(val) sysvals.setCallgraphFilter(val)
elif(arg == '-cgskip'): elif(arg == '-cgskip'):
try: try:
val = args.next() val = next(args)
except: except:
doError('No file supplied', True) doError('No file supplied', True)
if val.lower() in switchoff: if val.lower() in switchoff:
...@@ -924,7 +934,7 @@ if __name__ == '__main__': ...@@ -924,7 +934,7 @@ if __name__ == '__main__':
doError('%s does not exist' % cgskip) doError('%s does not exist' % cgskip)
elif(arg == '-bl'): elif(arg == '-bl'):
try: try:
val = args.next() val = next(args)
except: except:
doError('No boot loader name supplied', True) doError('No boot loader name supplied', True)
if val.lower() not in ['grub']: if val.lower() not in ['grub']:
...@@ -937,7 +947,7 @@ if __name__ == '__main__': ...@@ -937,7 +947,7 @@ if __name__ == '__main__':
sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000) sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000)
elif(arg == '-func'): elif(arg == '-func'):
try: try:
val = args.next() val = next(args)
except: except:
doError('No filter functions supplied', True) doError('No filter functions supplied', True)
sysvals.useftrace = True sysvals.useftrace = True
...@@ -946,7 +956,7 @@ if __name__ == '__main__': ...@@ -946,7 +956,7 @@ if __name__ == '__main__':
sysvals.setGraphFilter(val) sysvals.setGraphFilter(val)
elif(arg == '-ftrace'): elif(arg == '-ftrace'):
try: try:
val = args.next() val = next(args)
except: except:
doError('No ftrace file supplied', True) doError('No ftrace file supplied', True)
if(os.path.exists(val) == False): if(os.path.exists(val) == False):
...@@ -959,7 +969,7 @@ if __name__ == '__main__': ...@@ -959,7 +969,7 @@ if __name__ == '__main__':
sysvals.cgexp = True sysvals.cgexp = True
elif(arg == '-dmesg'): elif(arg == '-dmesg'):
try: try:
val = args.next() val = next(args)
except: except:
doError('No dmesg file supplied', True) doError('No dmesg file supplied', True)
if(os.path.exists(val) == False): if(os.path.exists(val) == False):
...@@ -968,13 +978,13 @@ if __name__ == '__main__': ...@@ -968,13 +978,13 @@ if __name__ == '__main__':
sysvals.dmesgfile = val sysvals.dmesgfile = val
elif(arg == '-o'): elif(arg == '-o'):
try: try:
val = args.next() val = next(args)
except: except:
doError('No subdirectory name supplied', True) doError('No subdirectory name supplied', True)
sysvals.testdir = sysvals.setOutputFolder(val) sysvals.testdir = sysvals.setOutputFolder(val)
elif(arg == '-result'): elif(arg == '-result'):
try: try:
val = args.next() val = next(args)
except: except:
doError('No result file supplied', True) doError('No result file supplied', True)
sysvals.result = val sysvals.result = val
...@@ -986,6 +996,17 @@ if __name__ == '__main__': ...@@ -986,6 +996,17 @@ if __name__ == '__main__':
# remaining options are only for cron job use # remaining options are only for cron job use
elif(arg == '-cronjob'): elif(arg == '-cronjob'):
sysvals.iscronjob = True sysvals.iscronjob = True
elif(arg == '-which'):
try:
val = next(args)
except:
doError('No executable supplied', True)
out = sysvals.getExec(val)
if not out:
print('%s not found' % val)
sys.exit(1)
print(out)
sys.exit(0)
else: else:
doError('Invalid argument: '+arg, True) doError('Invalid argument: '+arg, True)
......
...@@ -53,10 +53,10 @@ disable rtcwake and require a user keypress to resume. ...@@ -53,10 +53,10 @@ disable rtcwake and require a user keypress to resume.
Add the dmesg and ftrace logs to the html output. They will be viewable by Add the dmesg and ftrace logs to the html output. They will be viewable by
clicking buttons in the timeline. clicking buttons in the timeline.
.TP .TP
\fB-turbostat\fR \fB-noturbostat\fR
Use turbostat to execute the command in freeze mode (default: disabled). This By default, if turbostat is found and the requested mode is freeze, sleepgraph
will provide turbostat output in the log which will tell you which actual will execute the suspend via turbostat and collect data in the timeline log.
power modes were entered. This option disables the use of turbostat.
.TP .TP
\fB-result \fIfile\fR \fB-result \fIfile\fR
Export a results table to a text file for parsing. Export a results table to a text file for parsing.
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment