Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Todd Brandt and committed by
Rafael J. Wysocki
8c763ffa 8e929cb5

+48 -16
+3
tools/power/pm-graph/sleepgraph.8
··· 81 81 .TP 82 82 \fB-wifitrace\fR 83 83 Trace through the wifi reconnect time and include it in the timeline. 84 + .TP 85 + \fB-debugtiming\fR 86 + Add timestamp to each printed output line, accurate to the millisecond. 84 87 85 88 .SS "advanced" 86 89 .TP
+45 -16
tools/power/pm-graph/sleepgraph.py
··· 18 18 # 19 19 # Links: 20 20 # Home Page 21 - # https://01.org/pm-graph 21 + # https://www.intel.com/content/www/us/en/developer/topic-technology/open/pm-graph/overview.html 22 22 # Source repo 23 23 # git@github.com:intel/pm-graph 24 24 # ··· 65 65 from threading import Thread 66 66 from subprocess import call, Popen, PIPE 67 67 import base64 68 + import traceback 68 69 69 70 debugtiming = False 70 71 mystarttime = time.time() ··· 87 86 # store system values and test parameters 88 87 class SystemValues: 89 88 title = 'SleepGraph' 90 - version = '5.12' 89 + version = '5.13' 91 90 ansi = False 92 91 rs = 0 93 92 display = '' ··· 237 236 'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 }, 238 237 'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 }, 239 238 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 }, 240 - 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 }, 239 + 'usleep_range': { 240 + 'func':'usleep_range_state', 241 + 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 242 + 'ub': 1 243 + }, 241 244 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 }, 242 245 'acpi_os_stall': {'ub': 1}, 243 246 'rt_mutex_slowlock': {'ub': 1}, ··· 347 342 if self.verbose or msg.startswith('WARNING:'): 348 343 pprint(msg) 349 344 def signalHandler(self, signum, frame): 350 - if not self.result: 351 - return 352 345 signame = self.signames[signum] if signum in self.signames else 'UNKNOWN' 353 - msg = 'Signal %s caused a tool exit, line %d' % (signame, frame.f_lineno) 346 + if signame in ['SIGUSR1', 'SIGUSR2', 'SIGSEGV']: 347 + traceback.print_stack() 348 + stack = traceback.format_list(traceback.extract_stack()) 349 + self.outputResult({'stack':stack}) 350 + if signame == 'SIGUSR1': 351 + return 352 + msg = '%s caused a tool exit, line %d' % (signame, frame.f_lineno) 353 + pprint(msg) 354 354 self.outputResult({'error':msg}) 355 + os.kill(os.getpid(), signal.SIGKILL) 355 356 sys.exit(3) 356 357 def signalHandlerInit(self): 357 358 capture = ['BUS', 'SYS', 'XCPU', 'XFSZ', 'PWR', 'HUP', 'INT', 'QUIT', 358 - 'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM'] 359 + 'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM', 'USR1', 'USR2'] 359 360 self.signames = dict() 360 361 for i in capture: 361 362 s = 'SIG'+i ··· 870 859 # files needed for any trace data 871 860 files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock', 872 861 'trace_marker', 'trace_options', 'tracing_on'] 862 + # legacy check for old systems 863 + if not os.path.exists(self.tpath+'trace'): 864 + self.tpath = '/sys/kernel/debug/tracing/' 865 + if not os.path.exists(self.epath): 866 + self.epath = '/sys/kernel/debug/tracing/events/power/' 873 867 # files needed for callgraph trace data 874 868 tp = self.tpath 875 869 if(self.usecallgraph): ··· 927 911 if num > 0: 928 912 n = '%d' % num 929 913 fp = open(self.result, 'a') 914 + if 'stack' in testdata: 915 + fp.write('Printing stack trace:\n') 916 + for line in testdata['stack']: 917 + fp.write(line) 918 + fp.close() 919 + self.sudoUserchown(self.result) 920 + return 930 921 if 'error' in testdata: 931 922 fp.write('result%s: fail\n' % n) 932 923 fp.write('error%s: %s\n' % (n, testdata['error'])) ··· 2003 1980 length = -1.0 2004 1981 if(start >= 0 and end >= 0): 2005 1982 length = end - start 2006 - if pid == -2 or name not in sysvals.tracefuncs.keys(): 1983 + if pid >= -2: 2007 1984 i = 2 2008 1985 origname = name 2009 1986 while(name in list): ··· 2776 2753 def createHeader(self, sv, stamp): 2777 2754 if(not stamp['time']): 2778 2755 return 2779 - self.html += '<div class="version"><a href="https://01.org/pm-graph">%s v%s</a></div>' \ 2756 + self.html += '<div class="version"><a href="https://www.intel.com/content/www/'+\ 2757 + 'us/en/developer/topic-technology/open/pm-graph/overview.html">%s v%s</a></div>' \ 2780 2758 % (sv.title, sv.version) 2781 2759 if sv.logmsg and sv.testlog: 2782 2760 self.html += '<button id="showtest" class="logbtn btnfmt">log</button>' ··· 5262 5238 } 5263 5239 var info = dev[i].title.split(" "); 5264 5240 var pname = info[info.length-1]; 5265 - pd[pname] = parseFloat(info[info.length-3].slice(1)); 5266 - total[0] += pd[pname]; 5267 - if(pname.indexOf("suspend") >= 0) 5268 - total[tidx] += pd[pname]; 5241 + var length = parseFloat(info[info.length-3].slice(1)); 5242 + if (pname in pd) 5243 + pd[pname] += length; 5269 5244 else 5270 - total[tidx+1] += pd[pname]; 5245 + pd[pname] = length; 5246 + total[0] += length; 5247 + if(pname.indexOf("suspend") >= 0) 5248 + total[tidx] += length; 5249 + else 5250 + total[tidx+1] += length; 5271 5251 } 5272 5252 } 5273 5253 var devname = deviceTitle(this.title, total, cpu); ··· 5290 5262 phases[i].style.left = left+"%"; 5291 5263 phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms"; 5292 5264 left += w; 5293 - var time = "<t4 style=\"font-size:"+fs+"px\">"+pd[phases[i].id]+" ms<br></t4>"; 5265 + var time = "<t4 style=\"font-size:"+fs+"px\">"+pd[phases[i].id].toFixed(3)+" ms<br></t4>"; 5294 5266 var pname = "<t3 style=\"font-size:"+fs2+"px\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>"; 5295 5267 phases[i].innerHTML = time+pname; 5296 5268 } else { ··· 6770 6742 ' -wifi If a wifi connection is available, check that it reconnects after resume.\n'\ 6771 6743 ' -wifitrace Trace kernel execution through wifi reconnect.\n'\ 6772 6744 ' -netfix Use netfix to reset the network in the event it fails to resume.\n'\ 6745 + ' -debugtiming Add timestamp to each printed line\n'\ 6773 6746 ' [testprep]\n'\ 6774 6747 ' -sync Sync the filesystems before starting the test\n'\ 6775 6748 ' -rs on/off Enable/disable runtime suspend for all devices, restore all after test\n'\ ··· 7076 7047 except: 7077 7048 doError('No result file supplied', True) 7078 7049 sysvals.result = val 7079 - sysvals.signalHandlerInit() 7080 7050 else: 7081 7051 doError('Invalid argument: '+arg, True) 7082 7052 ··· 7085 7057 if(sysvals.usecallgraph and sysvals.useprocmon): 7086 7058 doError('-proc is not compatible with -f') 7087 7059 7060 + sysvals.signalHandlerInit() 7088 7061 if sysvals.usecallgraph and sysvals.cgskip: 7089 7062 sysvals.vprint('Using cgskip file: %s' % sysvals.cgskip) 7090 7063 sysvals.setCallgraphBlacklist(sysvals.cgskip)