mirror of https://gitee.com/openkylin/linux.git
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: Todd Brandt <todd.e.brandt@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
d1abaeb3be
commit
1446794a89
|
@ -1,7 +1,7 @@
|
||||||
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 @@
|
||||||
- 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
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
#!/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):
|
||||||
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):
|
||||||
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():
|
||||||
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):
|
||||||
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):
|
||||||
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):
|
||||||
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):
|
||||||
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():
|
||||||
'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__':
|
||||||
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__':
|
||||||
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__':
|
||||||
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__':
|
||||||
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__':
|
||||||
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__':
|
||||||
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__':
|
||||||
# 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.
|
||||||
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.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue