mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-22 16:06:04 -05:00
pm-graph v5.13
- fix link to pm-graph homepage and in comments - add usleep_range() kprobe to -dev mode - add SIGUSR1 and SIGUSR2 to list of captured signals - kill -s USR1 causes sleepgraph to print out stack trace - kill -s USR2 prints stack trace and exits - stack trace is also printed to -result file - add legacy support for /sys/kernel/debug/tracing/ - allow multiple instances of trace funcs in the same phase - update javascript to draw device detail for multiple trace func instances - add -debugtiming option to print out timestamps on all outputs Signed-off-by: Todd Brandt <todd.e.brandt@intel.com> Link: https://patch.msgid.link/20240912055956.30108-1-todd.e.brandt@intel.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
8e929cb546
commit
8c763ffafe
2 changed files with 48 additions and 16 deletions
|
@ -81,6 +81,9 @@ as resume failures.
|
||||||
.TP
|
.TP
|
||||||
\fB-wifitrace\fR
|
\fB-wifitrace\fR
|
||||||
Trace through the wifi reconnect time and include it in the timeline.
|
Trace through the wifi reconnect time and include it in the timeline.
|
||||||
|
.TP
|
||||||
|
\fB-debugtiming\fR
|
||||||
|
Add timestamp to each printed output line, accurate to the millisecond.
|
||||||
|
|
||||||
.SS "advanced"
|
.SS "advanced"
|
||||||
.TP
|
.TP
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#
|
#
|
||||||
# Links:
|
# Links:
|
||||||
# Home Page
|
# Home Page
|
||||||
# https://01.org/pm-graph
|
# https://www.intel.com/content/www/us/en/developer/topic-technology/open/pm-graph/overview.html
|
||||||
# Source repo
|
# Source repo
|
||||||
# git@github.com:intel/pm-graph
|
# git@github.com:intel/pm-graph
|
||||||
#
|
#
|
||||||
|
@ -65,6 +65,7 @@ import gzip
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from subprocess import call, Popen, PIPE
|
from subprocess import call, Popen, PIPE
|
||||||
import base64
|
import base64
|
||||||
|
import traceback
|
||||||
|
|
||||||
debugtiming = False
|
debugtiming = False
|
||||||
mystarttime = time.time()
|
mystarttime = time.time()
|
||||||
|
@ -86,7 +87,7 @@ def ascii(text):
|
||||||
# store system values and test parameters
|
# store system values and test parameters
|
||||||
class SystemValues:
|
class SystemValues:
|
||||||
title = 'SleepGraph'
|
title = 'SleepGraph'
|
||||||
version = '5.12'
|
version = '5.13'
|
||||||
ansi = False
|
ansi = False
|
||||||
rs = 0
|
rs = 0
|
||||||
display = ''
|
display = ''
|
||||||
|
@ -236,7 +237,11 @@ class SystemValues:
|
||||||
'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 },
|
'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 },
|
||||||
'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
|
'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
|
||||||
'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 },
|
'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 },
|
||||||
'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 },
|
'usleep_range': {
|
||||||
|
'func':'usleep_range_state',
|
||||||
|
'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'},
|
||||||
|
'ub': 1
|
||||||
|
},
|
||||||
'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 },
|
'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 },
|
||||||
'acpi_os_stall': {'ub': 1},
|
'acpi_os_stall': {'ub': 1},
|
||||||
'rt_mutex_slowlock': {'ub': 1},
|
'rt_mutex_slowlock': {'ub': 1},
|
||||||
|
@ -342,15 +347,21 @@ class SystemValues:
|
||||||
if self.verbose or msg.startswith('WARNING:'):
|
if self.verbose or msg.startswith('WARNING:'):
|
||||||
pprint(msg)
|
pprint(msg)
|
||||||
def signalHandler(self, signum, frame):
|
def signalHandler(self, signum, frame):
|
||||||
if not self.result:
|
|
||||||
return
|
|
||||||
signame = self.signames[signum] if signum in self.signames else 'UNKNOWN'
|
signame = self.signames[signum] if signum in self.signames else 'UNKNOWN'
|
||||||
msg = 'Signal %s caused a tool exit, line %d' % (signame, frame.f_lineno)
|
if signame in ['SIGUSR1', 'SIGUSR2', 'SIGSEGV']:
|
||||||
|
traceback.print_stack()
|
||||||
|
stack = traceback.format_list(traceback.extract_stack())
|
||||||
|
self.outputResult({'stack':stack})
|
||||||
|
if signame == 'SIGUSR1':
|
||||||
|
return
|
||||||
|
msg = '%s caused a tool exit, line %d' % (signame, frame.f_lineno)
|
||||||
|
pprint(msg)
|
||||||
self.outputResult({'error':msg})
|
self.outputResult({'error':msg})
|
||||||
|
os.kill(os.getpid(), signal.SIGKILL)
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
def signalHandlerInit(self):
|
def signalHandlerInit(self):
|
||||||
capture = ['BUS', 'SYS', 'XCPU', 'XFSZ', 'PWR', 'HUP', 'INT', 'QUIT',
|
capture = ['BUS', 'SYS', 'XCPU', 'XFSZ', 'PWR', 'HUP', 'INT', 'QUIT',
|
||||||
'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM']
|
'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM', 'USR1', 'USR2']
|
||||||
self.signames = dict()
|
self.signames = dict()
|
||||||
for i in capture:
|
for i in capture:
|
||||||
s = 'SIG'+i
|
s = 'SIG'+i
|
||||||
|
@ -859,6 +870,11 @@ class SystemValues:
|
||||||
# files needed for any trace data
|
# files needed for any trace data
|
||||||
files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock',
|
files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock',
|
||||||
'trace_marker', 'trace_options', 'tracing_on']
|
'trace_marker', 'trace_options', 'tracing_on']
|
||||||
|
# legacy check for old systems
|
||||||
|
if not os.path.exists(self.tpath+'trace'):
|
||||||
|
self.tpath = '/sys/kernel/debug/tracing/'
|
||||||
|
if not os.path.exists(self.epath):
|
||||||
|
self.epath = '/sys/kernel/debug/tracing/events/power/'
|
||||||
# files needed for callgraph trace data
|
# files needed for callgraph trace data
|
||||||
tp = self.tpath
|
tp = self.tpath
|
||||||
if(self.usecallgraph):
|
if(self.usecallgraph):
|
||||||
|
@ -911,6 +927,13 @@ class SystemValues:
|
||||||
if num > 0:
|
if num > 0:
|
||||||
n = '%d' % num
|
n = '%d' % num
|
||||||
fp = open(self.result, 'a')
|
fp = open(self.result, 'a')
|
||||||
|
if 'stack' in testdata:
|
||||||
|
fp.write('Printing stack trace:\n')
|
||||||
|
for line in testdata['stack']:
|
||||||
|
fp.write(line)
|
||||||
|
fp.close()
|
||||||
|
self.sudoUserchown(self.result)
|
||||||
|
return
|
||||||
if 'error' in testdata:
|
if 'error' in testdata:
|
||||||
fp.write('result%s: fail\n' % n)
|
fp.write('result%s: fail\n' % n)
|
||||||
fp.write('error%s: %s\n' % (n, testdata['error']))
|
fp.write('error%s: %s\n' % (n, testdata['error']))
|
||||||
|
@ -1980,7 +2003,7 @@ class Data:
|
||||||
length = -1.0
|
length = -1.0
|
||||||
if(start >= 0 and end >= 0):
|
if(start >= 0 and end >= 0):
|
||||||
length = end - start
|
length = end - start
|
||||||
if pid == -2 or name not in sysvals.tracefuncs.keys():
|
if pid >= -2:
|
||||||
i = 2
|
i = 2
|
||||||
origname = name
|
origname = name
|
||||||
while(name in list):
|
while(name in list):
|
||||||
|
@ -2753,7 +2776,8 @@ class Timeline:
|
||||||
def createHeader(self, sv, stamp):
|
def createHeader(self, sv, stamp):
|
||||||
if(not stamp['time']):
|
if(not stamp['time']):
|
||||||
return
|
return
|
||||||
self.html += '<div class="version"><a href="https://01.org/pm-graph">%s v%s</a></div>' \
|
self.html += '<div class="version"><a href="https://www.intel.com/content/www/'+\
|
||||||
|
'us/en/developer/topic-technology/open/pm-graph/overview.html">%s v%s</a></div>' \
|
||||||
% (sv.title, sv.version)
|
% (sv.title, sv.version)
|
||||||
if sv.logmsg and sv.testlog:
|
if sv.logmsg and sv.testlog:
|
||||||
self.html += '<button id="showtest" class="logbtn btnfmt">log</button>'
|
self.html += '<button id="showtest" class="logbtn btnfmt">log</button>'
|
||||||
|
@ -5238,12 +5262,16 @@ def addScriptCode(hf, testruns):
|
||||||
}
|
}
|
||||||
var info = dev[i].title.split(" ");
|
var info = dev[i].title.split(" ");
|
||||||
var pname = info[info.length-1];
|
var pname = info[info.length-1];
|
||||||
pd[pname] = parseFloat(info[info.length-3].slice(1));
|
var length = parseFloat(info[info.length-3].slice(1));
|
||||||
total[0] += pd[pname];
|
if (pname in pd)
|
||||||
if(pname.indexOf("suspend") >= 0)
|
pd[pname] += length;
|
||||||
total[tidx] += pd[pname];
|
|
||||||
else
|
else
|
||||||
total[tidx+1] += pd[pname];
|
pd[pname] = length;
|
||||||
|
total[0] += length;
|
||||||
|
if(pname.indexOf("suspend") >= 0)
|
||||||
|
total[tidx] += length;
|
||||||
|
else
|
||||||
|
total[tidx+1] += length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var devname = deviceTitle(this.title, total, cpu);
|
var devname = deviceTitle(this.title, total, cpu);
|
||||||
|
@ -5262,7 +5290,7 @@ def addScriptCode(hf, testruns):
|
||||||
phases[i].style.left = left+"%";
|
phases[i].style.left = left+"%";
|
||||||
phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";
|
phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";
|
||||||
left += w;
|
left += w;
|
||||||
var time = "<t4 style=\"font-size:"+fs+"px\">"+pd[phases[i].id]+" ms<br></t4>";
|
var time = "<t4 style=\"font-size:"+fs+"px\">"+pd[phases[i].id].toFixed(3)+" ms<br></t4>";
|
||||||
var pname = "<t3 style=\"font-size:"+fs2+"px\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";
|
var pname = "<t3 style=\"font-size:"+fs2+"px\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";
|
||||||
phases[i].innerHTML = time+pname;
|
phases[i].innerHTML = time+pname;
|
||||||
} else {
|
} else {
|
||||||
|
@ -6742,6 +6770,7 @@ def printHelp():
|
||||||
' -wifi If a wifi connection is available, check that it reconnects after resume.\n'\
|
' -wifi If a wifi connection is available, check that it reconnects after resume.\n'\
|
||||||
' -wifitrace Trace kernel execution through wifi reconnect.\n'\
|
' -wifitrace Trace kernel execution through wifi reconnect.\n'\
|
||||||
' -netfix Use netfix to reset the network in the event it fails to resume.\n'\
|
' -netfix Use netfix to reset the network in the event it fails to resume.\n'\
|
||||||
|
' -debugtiming Add timestamp to each printed line\n'\
|
||||||
' [testprep]\n'\
|
' [testprep]\n'\
|
||||||
' -sync Sync the filesystems before starting the test\n'\
|
' -sync Sync the filesystems before starting the test\n'\
|
||||||
' -rs on/off Enable/disable runtime suspend for all devices, restore all after test\n'\
|
' -rs on/off Enable/disable runtime suspend for all devices, restore all after test\n'\
|
||||||
|
@ -7047,7 +7076,6 @@ if __name__ == '__main__':
|
||||||
except:
|
except:
|
||||||
doError('No result file supplied', True)
|
doError('No result file supplied', True)
|
||||||
sysvals.result = val
|
sysvals.result = val
|
||||||
sysvals.signalHandlerInit()
|
|
||||||
else:
|
else:
|
||||||
doError('Invalid argument: '+arg, True)
|
doError('Invalid argument: '+arg, True)
|
||||||
|
|
||||||
|
@ -7057,6 +7085,7 @@ if __name__ == '__main__':
|
||||||
if(sysvals.usecallgraph and sysvals.useprocmon):
|
if(sysvals.usecallgraph and sysvals.useprocmon):
|
||||||
doError('-proc is not compatible with -f')
|
doError('-proc is not compatible with -f')
|
||||||
|
|
||||||
|
sysvals.signalHandlerInit()
|
||||||
if sysvals.usecallgraph and sysvals.cgskip:
|
if sysvals.usecallgraph and sysvals.cgskip:
|
||||||
sysvals.vprint('Using cgskip file: %s' % sysvals.cgskip)
|
sysvals.vprint('Using cgskip file: %s' % sysvals.cgskip)
|
||||||
sysvals.setCallgraphBlacklist(sysvals.cgskip)
|
sysvals.setCallgraphBlacklist(sysvals.cgskip)
|
||||||
|
|
Loading…
Reference in a new issue