Skip to content

Commit 0417552

Browse files
tebrandtrafaeljw
authored andcommitted
pm-graph: Update to v5.11
install_latest_from_github.sh: - Added a new script which allows users to install the latest pm-graph from the upstream github repo. This is useful if the kernel source version has issues that have already been fixed in github. sleepgraph.py: - Updated all the dmesg suspend/resume PM print formats to be able to process recent timelines using dmesg only. - Added ethtool output to the log for the system's ethernet device id the ethtool exists. This helps in debugging network issues. - Made the tool more robustly handle events where mangled dmesg or ftrace outputs do not include all the requisite data. The tool fails gracefully instead of creating a garbled timeline. Signed-off-by: Todd Brandt <todd.e.brandt@intel.com> [ rjw: Changelog edits ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 197b6b6 commit 0417552

3 files changed

Lines changed: 75 additions & 18 deletions

File tree

tools/power/pm-graph/README

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
|_| |___/ |_|
77

88
pm-graph: suspend/resume/boot timing analysis tools
9-
Version: 5.10
9+
Version: 5.11
1010
Author: Todd Brandt <todd.e.brandt@intel.com>
1111
Home Page: https://www.intel.com/content/www/us/en/developer/topic-technology/open/pm-graph/overview.html
1212

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/bin/sh
2+
# SPDX-License-Identifier: GPL-2.0
3+
#
4+
# Script which clones and installs the latest pm-graph
5+
# from http://github.com/intel/pm-graph.git
6+
7+
OUT=`mktemp -d 2>/dev/null`
8+
if [ -z "$OUT" -o ! -e $OUT ]; then
9+
echo "ERROR: mktemp failed to create folder"
10+
exit
11+
fi
12+
13+
cleanup() {
14+
if [ -e "$OUT" ]; then
15+
cd $OUT
16+
rm -rf pm-graph
17+
cd /tmp
18+
rmdir $OUT
19+
fi
20+
}
21+
22+
git clone http://github.com/intel/pm-graph.git $OUT/pm-graph
23+
if [ ! -e "$OUT/pm-graph/sleepgraph.py" ]; then
24+
echo "ERROR: pm-graph github repo failed to clone"
25+
cleanup
26+
exit
27+
fi
28+
29+
cd $OUT/pm-graph
30+
echo "INSTALLING PM-GRAPH"
31+
sudo make install
32+
if [ $? -eq 0 ]; then
33+
echo "INSTALL SUCCESS"
34+
sleepgraph -v
35+
else
36+
echo "INSTALL FAILED"
37+
fi
38+
cleanup

tools/power/pm-graph/sleepgraph.py

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def ascii(text):
8686
# store system values and test parameters
8787
class SystemValues:
8888
title = 'SleepGraph'
89-
version = '5.10'
89+
version = '5.11'
9090
ansi = False
9191
rs = 0
9292
display = ''
@@ -300,6 +300,7 @@ class SystemValues:
300300
[0, 'acpidevices', 'sh', '-c', 'ls -l /sys/bus/acpi/devices/*/physical_node'],
301301
[0, 's0ix_require', 'cat', '/sys/kernel/debug/pmc_core/substate_requirements'],
302302
[0, 's0ix_debug', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_debug_status'],
303+
[0, 'ethtool', 'ethtool', '{ethdev}'],
303304
[1, 's0ix_residency', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_residency_usec'],
304305
[1, 'interrupts', 'cat', '/proc/interrupts'],
305306
[1, 'wakeups', 'cat', '/sys/kernel/debug/wakeup_sources'],
@@ -1078,18 +1079,35 @@ def dictify(self, text, format):
10781079
else:
10791080
out[data[0].strip()] = data[1]
10801081
return out
1082+
def cmdinfovar(self, arg):
1083+
if arg == 'ethdev':
1084+
try:
1085+
cmd = [self.getExec('ip'), '-4', '-o', '-br', 'addr']
1086+
fp = Popen(cmd, stdout=PIPE, stderr=PIPE).stdout
1087+
info = ascii(fp.read()).strip()
1088+
fp.close()
1089+
except:
1090+
return 'iptoolcrash'
1091+
for line in info.split('\n'):
1092+
if line[0] == 'e' and 'UP' in line:
1093+
return line.split()[0]
1094+
return 'nodevicefound'
1095+
return 'unknown'
10811096
def cmdinfo(self, begin, debug=False):
10821097
out = []
10831098
if begin:
10841099
self.cmd1 = dict()
10851100
for cargs in self.infocmds:
1086-
delta, name = cargs[0], cargs[1]
1087-
cmdline, cmdpath = ' '.join(cargs[2:]), self.getExec(cargs[2])
1101+
delta, name, args = cargs[0], cargs[1], cargs[2:]
1102+
for i in range(len(args)):
1103+
if args[i][0] == '{' and args[i][-1] == '}':
1104+
args[i] = self.cmdinfovar(args[i][1:-1])
1105+
cmdline, cmdpath = ' '.join(args[0:]), self.getExec(args[0])
10881106
if not cmdpath or (begin and not delta):
10891107
continue
10901108
self.dlog('[%s]' % cmdline)
10911109
try:
1092-
fp = Popen([cmdpath]+cargs[3:], stdout=PIPE, stderr=PIPE).stdout
1110+
fp = Popen([cmdpath]+args[1:], stdout=PIPE, stderr=PIPE).stdout
10931111
info = ascii(fp.read()).strip()
10941112
fp.close()
10951113
except:
@@ -1452,6 +1470,7 @@ class Data:
14521470
errlist = {
14531471
'HWERROR' : r'.*\[ *Hardware Error *\].*',
14541472
'FWBUG' : r'.*\[ *Firmware Bug *\].*',
1473+
'TASKFAIL': r'.*Freezing .*after *.*',
14551474
'BUG' : r'(?i).*\bBUG\b.*',
14561475
'ERROR' : r'(?i).*\bERROR\b.*',
14571476
'WARNING' : r'(?i).*\bWARNING\b.*',
@@ -1462,7 +1481,6 @@ class Data:
14621481
'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*',
14631482
'ABORT' : r'(?i).*\bABORT\b.*',
14641483
'IRQ' : r'.*\bgenirq: .*',
1465-
'TASKFAIL': r'.*Freezing .*after *.*',
14661484
'ACPI' : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*',
14671485
'DISKFULL': r'.*\bNo space left on device.*',
14681486
'USBERR' : r'.*usb .*device .*, error [0-9-]*',
@@ -1602,7 +1620,7 @@ def sourcePhase(self, start):
16021620
pend = self.dmesg[phase]['end']
16031621
if start <= pend:
16041622
return phase
1605-
return 'resume_complete'
1623+
return 'resume_complete' if 'resume_complete' in self.dmesg else ''
16061624
def sourceDevice(self, phaselist, start, end, pid, type):
16071625
tgtdev = ''
16081626
for phase in phaselist:
@@ -1645,6 +1663,8 @@ def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end,
16451663
else:
16461664
threadname = '%s-%d' % (proc, pid)
16471665
tgtphase = self.sourcePhase(start)
1666+
if not tgtphase:
1667+
return False
16481668
self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '')
16491669
return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata)
16501670
# this should not happen
@@ -1835,9 +1855,9 @@ def getMemTime(self):
18351855
hwr = self.hwend - timedelta(microseconds=rtime)
18361856
self.tLow.append('%.0f'%((hwr - hws).total_seconds() * 1000))
18371857
def getTimeValues(self):
1838-
sktime = (self.tSuspended - self.tKernSus) * 1000
1839-
rktime = (self.tKernRes - self.tResumed) * 1000
1840-
return (sktime, rktime)
1858+
s = (self.tSuspended - self.tKernSus) * 1000
1859+
r = (self.tKernRes - self.tResumed) * 1000
1860+
return (max(s, 0), max(r, 0))
18411861
def setPhase(self, phase, ktime, isbegin, order=-1):
18421862
if(isbegin):
18431863
# phase start over current phase
@@ -3961,7 +3981,7 @@ def parseKernelLog(data):
39613981
'suspend_machine': ['PM: suspend-to-idle',
39623982
'PM: noirq suspend of devices complete after.*',
39633983
'PM: noirq freeze of devices complete after.*'],
3964-
'resume_machine': ['PM: Timekeeping suspended for.*',
3984+
'resume_machine': ['[PM: ]*Timekeeping suspended for.*',
39653985
'ACPI: Low-level resume complete.*',
39663986
'ACPI: resume from mwait',
39673987
'Suspended for [0-9\.]* seconds'],
@@ -3979,14 +3999,14 @@ def parseKernelLog(data):
39793999
# action table (expected events that occur and show up in dmesg)
39804000
at = {
39814001
'sync_filesystems': {
3982-
'smsg': 'PM: Syncing filesystems.*',
3983-
'emsg': 'PM: Preparing system for mem sleep.*' },
4002+
'smsg': '.*[Ff]+ilesystems.*',
4003+
'emsg': 'PM: Preparing system for[a-z]* sleep.*' },
39844004
'freeze_user_processes': {
3985-
'smsg': 'Freezing user space processes .*',
4005+
'smsg': 'Freezing user space processes.*',
39864006
'emsg': 'Freezing remaining freezable tasks.*' },
39874007
'freeze_tasks': {
39884008
'smsg': 'Freezing remaining freezable tasks.*',
3989-
'emsg': 'PM: Entering (?P<mode>[a-z,A-Z]*) sleep.*' },
4009+
'emsg': 'PM: Suspending system.*' },
39904010
'ACPI prepare': {
39914011
'smsg': 'ACPI: Preparing to enter system sleep state.*',
39924012
'emsg': 'PM: Saving platform NVS memory.*' },
@@ -4120,10 +4140,9 @@ def parseKernelLog(data):
41204140
for a in sorted(at):
41214141
if(re.match(at[a]['smsg'], msg)):
41224142
if(a not in actions):
4123-
actions[a] = []
4124-
actions[a].append({'begin': ktime, 'end': ktime})
4143+
actions[a] = [{'begin': ktime, 'end': ktime}]
41254144
if(re.match(at[a]['emsg'], msg)):
4126-
if(a in actions):
4145+
if(a in actions and actions[a][-1]['begin'] == actions[a][-1]['end']):
41274146
actions[a][-1]['end'] = ktime
41284147
# now look for CPU on/off events
41294148
if(re.match('Disabling non-boot CPUs .*', msg)):

0 commit comments

Comments
 (0)