diff options
author | Todd E Brandt <todd.e.brandt@linux.intel.com> | 2017-07-05 17:42:55 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-07-21 19:56:13 -0400 |
commit | 49218edd649ae4922aa776aad5b7a65d028c6e96 (patch) | |
tree | a7787d8ec09ac9817f7521bd36cb125be8e2eca9 | |
parent | 5771a8c08880cdca3bfb4a3fc6d309d6bba20877 (diff) |
pm-graph: AnalyzeSuspend v4.7
- changed -rtcwake parameter to be on & 15 sec by default,
to disable rtcwake use: "-rtcwake off"
- changed behavior of -o: renames HTML file on rerun, subdir on new run
- changed execution_misalignment error to missing_function_name
- add sysinfo to logs and timeline via a custom dmidecode call
it supplants dmidecode tool when used as a library call
- add -sysinfo command, displays dmidecode values and cpu/mem info
- set trace buffer size to lesser of memtotal/2 or 2GB when using callgraph
- add support for /sys/power/mem_sleep. if mem_sleep found:
mem-shallow=standby, mem-s2idle=freeze, mem-deep=mem
- remove redundant javascript
- cosmetic changes to HTML layout
Signed-off-by: Todd Brandt <todd.e.brandt@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rwxr-xr-x | tools/power/pm-graph/analyze_suspend.py | 534 |
1 files changed, 379 insertions, 155 deletions
diff --git a/tools/power/pm-graph/analyze_suspend.py b/tools/power/pm-graph/analyze_suspend.py index a9206e67fc1f..1b60fe203741 100755 --- a/tools/power/pm-graph/analyze_suspend.py +++ b/tools/power/pm-graph/analyze_suspend.py | |||
@@ -68,10 +68,12 @@ from subprocess import call, Popen, PIPE | |||
68 | # store system values and test parameters | 68 | # store system values and test parameters |
69 | class SystemValues: | 69 | class SystemValues: |
70 | title = 'SleepGraph' | 70 | title = 'SleepGraph' |
71 | version = '4.6' | 71 | version = '4.7' |
72 | ansi = False | 72 | ansi = False |
73 | verbose = False | 73 | verbose = False |
74 | addlogs = False | 74 | testlog = True |
75 | dmesglog = False | ||
76 | ftracelog = False | ||
75 | mindevlen = 0.0 | 77 | mindevlen = 0.0 |
76 | mincglen = 0.0 | 78 | mincglen = 0.0 |
77 | cgphase = '' | 79 | cgphase = '' |
@@ -79,10 +81,11 @@ class SystemValues: | |||
79 | max_graph_depth = 0 | 81 | max_graph_depth = 0 |
80 | callloopmaxgap = 0.0001 | 82 | callloopmaxgap = 0.0001 |
81 | callloopmaxlen = 0.005 | 83 | callloopmaxlen = 0.005 |
84 | cpucount = 0 | ||
85 | memtotal = 204800 | ||
82 | srgap = 0 | 86 | srgap = 0 |
83 | cgexp = False | 87 | cgexp = False |
84 | outdir = '' | 88 | testdir = '' |
85 | testdir = '.' | ||
86 | tpath = '/sys/kernel/debug/tracing/' | 89 | tpath = '/sys/kernel/debug/tracing/' |
87 | fpdtpath = '/sys/firmware/acpi/tables/FPDT' | 90 | fpdtpath = '/sys/firmware/acpi/tables/FPDT' |
88 | epath = '/sys/kernel/debug/tracing/events/power/' | 91 | epath = '/sys/kernel/debug/tracing/events/power/' |
@@ -95,14 +98,17 @@ class SystemValues: | |||
95 | testcommand = '' | 98 | testcommand = '' |
96 | mempath = '/dev/mem' | 99 | mempath = '/dev/mem' |
97 | powerfile = '/sys/power/state' | 100 | powerfile = '/sys/power/state' |
101 | mempowerfile = '/sys/power/mem_sleep' | ||
98 | suspendmode = 'mem' | 102 | suspendmode = 'mem' |
103 | memmode = '' | ||
99 | hostname = 'localhost' | 104 | hostname = 'localhost' |
100 | prefix = 'test' | 105 | prefix = 'test' |
101 | teststamp = '' | 106 | teststamp = '' |
107 | sysstamp = '' | ||
102 | dmesgstart = 0.0 | 108 | dmesgstart = 0.0 |
103 | dmesgfile = '' | 109 | dmesgfile = '' |
104 | ftracefile = '' | 110 | ftracefile = '' |
105 | htmlfile = '' | 111 | htmlfile = 'output.html' |
106 | embedded = False | 112 | embedded = False |
107 | rtcwake = True | 113 | rtcwake = True |
108 | rtcwaketime = 15 | 114 | rtcwaketime = 15 |
@@ -127,9 +133,6 @@ class SystemValues: | |||
127 | devpropfmt = '# Device Properties: .*' | 133 | devpropfmt = '# Device Properties: .*' |
128 | tracertypefmt = '# tracer: (?P<t>.*)' | 134 | tracertypefmt = '# tracer: (?P<t>.*)' |
129 | firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' | 135 | firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' |
130 | stampfmt = '# suspend-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ | ||
131 | '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ | ||
132 | ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' | ||
133 | tracefuncs = { | 136 | tracefuncs = { |
134 | 'sys_sync': dict(), | 137 | 'sys_sync': dict(), |
135 | 'pm_prepare_console': dict(), | 138 | 'pm_prepare_console': dict(), |
@@ -218,7 +221,7 @@ class SystemValues: | |||
218 | # if this is a phoronix test run, set some default options | 221 | # if this is a phoronix test run, set some default options |
219 | if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ): | 222 | if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ): |
220 | self.embedded = True | 223 | self.embedded = True |
221 | self.addlogs = True | 224 | self.dmesglog = self.ftracelog = True |
222 | self.htmlfile = os.environ['LOG_FILE'] | 225 | self.htmlfile = os.environ['LOG_FILE'] |
223 | self.archargs = 'args_'+platform.machine() | 226 | self.archargs = 'args_'+platform.machine() |
224 | self.hostname = platform.node() | 227 | self.hostname = platform.node() |
@@ -233,6 +236,13 @@ class SystemValues: | |||
233 | self.rtcpath = rtc | 236 | self.rtcpath = rtc |
234 | if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): | 237 | if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): |
235 | self.ansi = True | 238 | self.ansi = True |
239 | self.testdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S') | ||
240 | def rootCheck(self, fatal=True): | ||
241 | if(os.access(self.powerfile, os.W_OK)): | ||
242 | return True | ||
243 | if fatal: | ||
244 | doError('This command requires sysfs mount and root access') | ||
245 | return False | ||
236 | def rootUser(self, fatal=False): | 246 | def rootUser(self, fatal=False): |
237 | if 'USER' in os.environ and os.environ['USER'] == 'root': | 247 | if 'USER' in os.environ and os.environ['USER'] == 'root': |
238 | return True | 248 | return True |
@@ -249,30 +259,60 @@ class SystemValues: | |||
249 | args['date'] = n.strftime('%y%m%d') | 259 | args['date'] = n.strftime('%y%m%d') |
250 | args['time'] = n.strftime('%H%M%S') | 260 | args['time'] = n.strftime('%H%M%S') |
251 | args['hostname'] = self.hostname | 261 | args['hostname'] = self.hostname |
252 | self.outdir = value.format(**args) | 262 | return value.format(**args) |
253 | def setOutputFile(self): | 263 | def setOutputFile(self): |
254 | if((self.htmlfile == '') and (self.dmesgfile != '')): | 264 | if self.dmesgfile != '': |
255 | m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile) | 265 | m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile) |
256 | if(m): | 266 | if(m): |
257 | self.htmlfile = m.group('name')+'.html' | 267 | self.htmlfile = m.group('name')+'.html' |
258 | if((self.htmlfile == '') and (self.ftracefile != '')): | 268 | if self.ftracefile != '': |
259 | m = re.match('(?P<name>.*)_ftrace\.txt$', self.ftracefile) | 269 | m = re.match('(?P<name>.*)_ftrace\.txt$', self.ftracefile) |
260 | if(m): | 270 | if(m): |
261 | self.htmlfile = m.group('name')+'.html' | 271 | self.htmlfile = m.group('name')+'.html' |
262 | if(self.htmlfile == ''): | 272 | def systemInfo(self, info): |
263 | self.htmlfile = 'output.html' | 273 | p = c = m = b = '' |
264 | def initTestOutput(self, subdir, testpath=''): | 274 | if 'baseboard-manufacturer' in info: |
275 | m = info['baseboard-manufacturer'] | ||
276 | elif 'system-manufacturer' in info: | ||
277 | m = info['system-manufacturer'] | ||
278 | if 'baseboard-product-name' in info: | ||
279 | p = info['baseboard-product-name'] | ||
280 | elif 'system-product-name' in info: | ||
281 | p = info['system-product-name'] | ||
282 | if 'processor-version' in info: | ||
283 | c = info['processor-version'] | ||
284 | if 'bios-version' in info: | ||
285 | b = info['bios-version'] | ||
286 | self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | numcpu:%d | memsz:%d' % \ | ||
287 | (m, p, c, b, self.cpucount, self.memtotal) | ||
288 | def printSystemInfo(self): | ||
289 | self.rootCheck(True) | ||
290 | out = dmidecode(self.mempath, True) | ||
291 | fmt = '%-24s: %s' | ||
292 | for name in sorted(out): | ||
293 | print fmt % (name, out[name]) | ||
294 | print fmt % ('cpucount', ('%d' % self.cpucount)) | ||
295 | print fmt % ('memtotal', ('%d kB' % self.memtotal)) | ||
296 | def cpuInfo(self): | ||
297 | self.cpucount = 0 | ||
298 | fp = open('/proc/cpuinfo', 'r') | ||
299 | for line in fp: | ||
300 | if re.match('^processor[ \t]*:[ \t]*[0-9]*', line): | ||
301 | self.cpucount += 1 | ||
302 | fp.close() | ||
303 | fp = open('/proc/meminfo', 'r') | ||
304 | for line in fp: | ||
305 | m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line) | ||
306 | if m: | ||
307 | self.memtotal = int(m.group('sz')) | ||
308 | break | ||
309 | fp.close() | ||
310 | def initTestOutput(self, name): | ||
265 | self.prefix = self.hostname | 311 | self.prefix = self.hostname |
266 | v = open('/proc/version', 'r').read().strip() | 312 | v = open('/proc/version', 'r').read().strip() |
267 | kver = string.split(v)[2] | 313 | kver = string.split(v)[2] |
268 | n = datetime.now() | 314 | fmt = name+'-%m%d%y-%H%M%S' |
269 | testtime = n.strftime('suspend-%m%d%y-%H%M%S') | 315 | testtime = datetime.now().strftime(fmt) |
270 | if not testpath: | ||
271 | testpath = n.strftime('suspend-%y%m%d-%H%M%S') | ||
272 | if(subdir != "."): | ||
273 | self.testdir = subdir+"/"+testpath | ||
274 | else: | ||
275 | self.testdir = testpath | ||
276 | self.teststamp = \ | 316 | self.teststamp = \ |
277 | '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver | 317 | '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver |
278 | if(self.embedded): | 318 | if(self.embedded): |
@@ -355,7 +395,7 @@ class SystemValues: | |||
355 | continue | 395 | continue |
356 | self.tracefuncs[i] = dict() | 396 | self.tracefuncs[i] = dict() |
357 | def getFtraceFilterFunctions(self, current): | 397 | def getFtraceFilterFunctions(self, current): |
358 | rootCheck(True) | 398 | self.rootCheck(True) |
359 | if not current: | 399 | if not current: |
360 | call('cat '+self.tpath+'available_filter_functions', shell=True) | 400 | call('cat '+self.tpath+'available_filter_functions', shell=True) |
361 | return | 401 | return |
@@ -453,7 +493,7 @@ class SystemValues: | |||
453 | val += '\nr:%s_ret %s $retval\n' % (name, func) | 493 | val += '\nr:%s_ret %s $retval\n' % (name, func) |
454 | return val | 494 | return val |
455 | def addKprobes(self, output=False): | 495 | def addKprobes(self, output=False): |
456 | if len(sysvals.kprobes) < 1: | 496 | if len(self.kprobes) < 1: |
457 | return | 497 | return |
458 | if output: | 498 | if output: |
459 | print(' kprobe functions in this kernel:') | 499 | print(' kprobe functions in this kernel:') |
@@ -525,7 +565,7 @@ class SystemValues: | |||
525 | fp.flush() | 565 | fp.flush() |
526 | fp.close() | 566 | fp.close() |
527 | except: | 567 | except: |
528 | pass | 568 | return False |
529 | return True | 569 | return True |
530 | def fgetVal(self, path): | 570 | def fgetVal(self, path): |
531 | file = self.tpath+path | 571 | file = self.tpath+path |
@@ -566,9 +606,15 @@ class SystemValues: | |||
566 | self.cleanupFtrace() | 606 | self.cleanupFtrace() |
567 | # set the trace clock to global | 607 | # set the trace clock to global |
568 | self.fsetVal('global', 'trace_clock') | 608 | self.fsetVal('global', 'trace_clock') |
569 | # set trace buffer to a huge value | ||
570 | self.fsetVal('nop', 'current_tracer') | 609 | self.fsetVal('nop', 'current_tracer') |
571 | self.fsetVal('131073', 'buffer_size_kb') | 610 | # set trace buffer to a huge value |
611 | if self.usecallgraph or self.usedevsrc: | ||
612 | tgtsize = min(self.memtotal / 2, 2*1024*1024) | ||
613 | maxbuf = '%d' % (tgtsize / max(1, self.cpucount)) | ||
614 | if self.cpucount < 1 or not self.fsetVal(maxbuf, 'buffer_size_kb'): | ||
615 | self.fsetVal('131072', 'buffer_size_kb') | ||
616 | else: | ||
617 | self.fsetVal('16384', 'buffer_size_kb') | ||
572 | # go no further if this is just a status check | 618 | # go no further if this is just a status check |
573 | if testing: | 619 | if testing: |
574 | return | 620 | return |
@@ -641,6 +687,15 @@ class SystemValues: | |||
641 | if not self.ansi: | 687 | if not self.ansi: |
642 | return str | 688 | return str |
643 | return '\x1B[%d;40m%s\x1B[m' % (color, str) | 689 | return '\x1B[%d;40m%s\x1B[m' % (color, str) |
690 | def writeDatafileHeader(self, filename, fwdata=[]): | ||
691 | fp = open(filename, 'w') | ||
692 | fp.write(self.teststamp+'\n') | ||
693 | fp.write(self.sysstamp+'\n') | ||
694 | if(self.suspendmode == 'mem' or self.suspendmode == 'command'): | ||
695 | for fw in fwdata: | ||
696 | if(fw): | ||
697 | fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) | ||
698 | fp.close() | ||
644 | 699 | ||
645 | sysvals = SystemValues() | 700 | sysvals = SystemValues() |
646 | suspendmodename = { | 701 | suspendmodename = { |
@@ -1008,6 +1063,12 @@ class Data: | |||
1008 | else: | 1063 | else: |
1009 | self.trimTime(self.tSuspended, \ | 1064 | self.trimTime(self.tSuspended, \ |
1010 | self.tResumed-self.tSuspended, False) | 1065 | self.tResumed-self.tSuspended, False) |
1066 | def getTimeValues(self): | ||
1067 | sktime = (self.dmesg['suspend_machine']['end'] - \ | ||
1068 | self.tKernSus) * 1000 | ||
1069 | rktime = (self.dmesg['resume_complete']['end'] - \ | ||
1070 | self.dmesg['resume_machine']['start']) * 1000 | ||
1071 | return (sktime, rktime) | ||
1011 | def setPhase(self, phase, ktime, isbegin): | 1072 | def setPhase(self, phase, ktime, isbegin): |
1012 | if(isbegin): | 1073 | if(isbegin): |
1013 | self.dmesg[phase]['start'] = ktime | 1074 | self.dmesg[phase]['start'] = ktime |
@@ -1517,7 +1578,7 @@ class FTraceCallGraph: | |||
1517 | prelinedep += 1 | 1578 | prelinedep += 1 |
1518 | last = 0 | 1579 | last = 0 |
1519 | lasttime = line.time | 1580 | lasttime = line.time |
1520 | virtualfname = 'execution_misalignment' | 1581 | virtualfname = 'missing_function_name' |
1521 | if len(self.list) > 0: | 1582 | if len(self.list) > 0: |
1522 | last = self.list[-1] | 1583 | last = self.list[-1] |
1523 | lasttime = last.time | 1584 | lasttime = last.time |
@@ -1773,24 +1834,30 @@ class Timeline: | |||
1773 | html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n' | 1834 | html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n' |
1774 | html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n' | 1835 | html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n' |
1775 | html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' | 1836 | html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' |
1837 | html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' | ||
1776 | def __init__(self, rowheight, scaleheight): | 1838 | def __init__(self, rowheight, scaleheight): |
1777 | self.rowH = rowheight | 1839 | self.rowH = rowheight |
1778 | self.scaleH = scaleheight | 1840 | self.scaleH = scaleheight |
1779 | self.html = '' | 1841 | self.html = '' |
1780 | def createHeader(self, sv, suppress=''): | 1842 | def createHeader(self, sv): |
1781 | if(not sv.stamp['time']): | 1843 | if(not sv.stamp['time']): |
1782 | return | 1844 | return |
1783 | self.html += '<div class="version"><a href="https://01.org/suspendresume">%s v%s</a></div>' \ | 1845 | self.html += '<div class="version"><a href="https://01.org/suspendresume">%s v%s</a></div>' \ |
1784 | % (sv.title, sv.version) | 1846 | % (sv.title, sv.version) |
1785 | if sv.logmsg and 'log' not in suppress: | 1847 | if sv.logmsg and sv.testlog: |
1786 | self.html += '<button id="showtest" class="logbtn">log</button>' | 1848 | self.html += '<button id="showtest" class="logbtn btnfmt">log</button>' |
1787 | if sv.addlogs and 'dmesg' not in suppress: | 1849 | if sv.dmesglog: |
1788 | self.html += '<button id="showdmesg" class="logbtn">dmesg</button>' | 1850 | self.html += '<button id="showdmesg" class="logbtn btnfmt">dmesg</button>' |
1789 | if sv.addlogs and sv.ftracefile and 'ftrace' not in suppress: | 1851 | if sv.ftracelog: |
1790 | self.html += '<button id="showftrace" class="logbtn">ftrace</button>' | 1852 | self.html += '<button id="showftrace" class="logbtn btnfmt">ftrace</button>' |
1791 | headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' | 1853 | headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' |
1792 | self.html += headline_stamp.format(sv.stamp['host'], sv.stamp['kernel'], | 1854 | self.html += headline_stamp.format(sv.stamp['host'], sv.stamp['kernel'], |
1793 | sv.stamp['mode'], sv.stamp['time']) | 1855 | sv.stamp['mode'], sv.stamp['time']) |
1856 | if 'man' in sv.stamp and 'plat' in sv.stamp and 'cpu' in sv.stamp: | ||
1857 | headline_sysinfo = '<div class="stamp sysinfo">{0} {1} <i>with</i> {2}</div>\n' | ||
1858 | self.html += headline_sysinfo.format(sv.stamp['man'], | ||
1859 | sv.stamp['plat'], sv.stamp['cpu']) | ||
1860 | |||
1794 | # Function: getDeviceRows | 1861 | # Function: getDeviceRows |
1795 | # Description: | 1862 | # Description: |
1796 | # determine how may rows the device funcs will take | 1863 | # determine how may rows the device funcs will take |
@@ -1839,7 +1906,7 @@ class Timeline: | |||
1839 | # devlist: the list of devices/actions in a group of contiguous phases | 1906 | # devlist: the list of devices/actions in a group of contiguous phases |
1840 | # Output: | 1907 | # Output: |
1841 | # The total number of rows needed to display this phase of the timeline | 1908 | # The total number of rows needed to display this phase of the timeline |
1842 | def getPhaseRows(self, devlist, row=0): | 1909 | def getPhaseRows(self, devlist, row=0, sortby='length'): |
1843 | # clear all rows and set them to undefined | 1910 | # clear all rows and set them to undefined |
1844 | remaining = len(devlist) | 1911 | remaining = len(devlist) |
1845 | rowdata = dict() | 1912 | rowdata = dict() |
@@ -1852,8 +1919,12 @@ class Timeline: | |||
1852 | if tp not in myphases: | 1919 | if tp not in myphases: |
1853 | myphases.append(tp) | 1920 | myphases.append(tp) |
1854 | dev['row'] = -1 | 1921 | dev['row'] = -1 |
1855 | # sort by length 1st, then name 2nd | 1922 | if sortby == 'start': |
1856 | sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) | 1923 | # sort by start 1st, then length 2nd |
1924 | sortdict[item] = (-1*float(dev['start']), float(dev['end']) - float(dev['start'])) | ||
1925 | else: | ||
1926 | # sort by length 1st, then name 2nd | ||
1927 | sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) | ||
1857 | if 'src' in dev: | 1928 | if 'src' in dev: |
1858 | dev['devrows'] = self.getDeviceRows(dev['src']) | 1929 | dev['devrows'] = self.getDeviceRows(dev['src']) |
1859 | # sort the devlist by length so that large items graph on top | 1930 | # sort the devlist by length so that large items graph on top |
@@ -1995,8 +2066,13 @@ class Timeline: | |||
1995 | # A list of values describing the properties of these test runs | 2066 | # A list of values describing the properties of these test runs |
1996 | class TestProps: | 2067 | class TestProps: |
1997 | stamp = '' | 2068 | stamp = '' |
2069 | sysinfo = '' | ||
1998 | S0i3 = False | 2070 | S0i3 = False |
1999 | fwdata = [] | 2071 | fwdata = [] |
2072 | stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ | ||
2073 | '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ | ||
2074 | ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' | ||
2075 | sysinfofmt = '^# sysinfo .*' | ||
2000 | ftrace_line_fmt_fg = \ | 2076 | ftrace_line_fmt_fg = \ |
2001 | '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ | 2077 | '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ |
2002 | ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ | 2078 | ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ |
@@ -2019,6 +2095,36 @@ class TestProps: | |||
2019 | self.ftrace_line_fmt = self.ftrace_line_fmt_nop | 2095 | self.ftrace_line_fmt = self.ftrace_line_fmt_nop |
2020 | else: | 2096 | else: |
2021 | doError('Invalid tracer format: [%s]' % tracer) | 2097 | doError('Invalid tracer format: [%s]' % tracer) |
2098 | def parseStamp(self, data, sv): | ||
2099 | m = re.match(self.stampfmt, self.stamp) | ||
2100 | data.stamp = {'time': '', 'host': '', 'mode': ''} | ||
2101 | dt = datetime(int(m.group('y'))+2000, int(m.group('m')), | ||
2102 | int(m.group('d')), int(m.group('H')), int(m.group('M')), | ||
2103 | int(m.group('S'))) | ||
2104 | data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') | ||
2105 | data.stamp['host'] = m.group('host') | ||
2106 | data.stamp['mode'] = m.group('mode') | ||
2107 | data.stamp['kernel'] = m.group('kernel') | ||
2108 | if re.match(self.sysinfofmt, self.sysinfo): | ||
2109 | for f in self.sysinfo.split('|'): | ||
2110 | if '#' in f: | ||
2111 | continue | ||
2112 | tmp = f.strip().split(':', 1) | ||
2113 | key = tmp[0] | ||
2114 | val = tmp[1] | ||
2115 | data.stamp[key] = val | ||
2116 | sv.hostname = data.stamp['host'] | ||
2117 | sv.suspendmode = data.stamp['mode'] | ||
2118 | if sv.suspendmode == 'command' and sv.ftracefile != '': | ||
2119 | modes = ['on', 'freeze', 'standby', 'mem'] | ||
2120 | out = Popen(['grep', 'suspend_enter', sv.ftracefile], | ||
2121 | stderr=PIPE, stdout=PIPE).stdout.read() | ||
2122 | m = re.match('.* suspend_enter\[(?P<mode>.*)\]', out) | ||
2123 | if m and m.group('mode') in ['1', '2', '3']: | ||
2124 | sv.suspendmode = modes[int(m.group('mode'))] | ||
2125 | data.stamp['mode'] = sv.suspendmode | ||
2126 | if not sv.stamp: | ||
2127 | sv.stamp = data.stamp | ||
2022 | 2128 | ||
2023 | # Class: TestRun | 2129 | # Class: TestRun |
2024 | # Description: | 2130 | # Description: |
@@ -2090,35 +2196,6 @@ def vprint(msg): | |||
2090 | if(sysvals.verbose): | 2196 | if(sysvals.verbose): |
2091 | print(msg) | 2197 | print(msg) |
2092 | 2198 | ||
2093 | # Function: parseStamp | ||
2094 | # Description: | ||
2095 | # Pull in the stamp comment line from the data file(s), | ||
2096 | # create the stamp, and add it to the global sysvals object | ||
2097 | # Arguments: | ||
2098 | # m: the valid re.match output for the stamp line | ||
2099 | def parseStamp(line, data): | ||
2100 | m = re.match(sysvals.stampfmt, line) | ||
2101 | data.stamp = {'time': '', 'host': '', 'mode': ''} | ||
2102 | dt = datetime(int(m.group('y'))+2000, int(m.group('m')), | ||
2103 | int(m.group('d')), int(m.group('H')), int(m.group('M')), | ||
2104 | int(m.group('S'))) | ||
2105 | data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') | ||
2106 | data.stamp['host'] = m.group('host') | ||
2107 | data.stamp['mode'] = m.group('mode') | ||
2108 | data.stamp['kernel'] = m.group('kernel') | ||
2109 | sysvals.hostname = data.stamp['host'] | ||
2110 | sysvals.suspendmode = data.stamp['mode'] | ||
2111 | if sysvals.suspendmode == 'command' and sysvals.ftracefile != '': | ||
2112 | modes = ['on', 'freeze', 'standby', 'mem'] | ||
2113 | out = Popen(['grep', 'suspend_enter', sysvals.ftracefile], | ||
2114 | stderr=PIPE, stdout=PIPE).stdout.read() | ||
2115 | m = re.match('.* suspend_enter\[(?P<mode>.*)\]', out) | ||
2116 | if m and m.group('mode') in ['1', '2', '3']: | ||
2117 | sysvals.suspendmode = modes[int(m.group('mode'))] | ||
2118 | data.stamp['mode'] = sysvals.suspendmode | ||
2119 | if not sysvals.stamp: | ||
2120 | sysvals.stamp = data.stamp | ||
2121 | |||
2122 | # Function: doesTraceLogHaveTraceEvents | 2199 | # Function: doesTraceLogHaveTraceEvents |
2123 | # Description: | 2200 | # Description: |
2124 | # Quickly determine if the ftrace log has some or all of the trace events | 2201 | # Quickly determine if the ftrace log has some or all of the trace events |
@@ -2136,11 +2213,6 @@ def doesTraceLogHaveTraceEvents(): | |||
2136 | sysvals.usekprobes = True | 2213 | sysvals.usekprobes = True |
2137 | out = Popen(['head', '-1', sysvals.ftracefile], | 2214 | out = Popen(['head', '-1', sysvals.ftracefile], |
2138 | stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '') | 2215 | stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '') |
2139 | m = re.match(sysvals.stampfmt, out) | ||
2140 | if m and m.group('mode') == 'command': | ||
2141 | sysvals.usetraceeventsonly = True | ||
2142 | sysvals.usetraceevents = True | ||
2143 | return | ||
2144 | # figure out what level of trace events are supported | 2216 | # figure out what level of trace events are supported |
2145 | sysvals.usetraceeventsonly = True | 2217 | sysvals.usetraceeventsonly = True |
2146 | sysvals.usetraceevents = False | 2218 | sysvals.usetraceevents = False |
@@ -2182,11 +2254,13 @@ def appendIncompleteTraceLog(testruns): | |||
2182 | for line in tf: | 2254 | for line in tf: |
2183 | # remove any latent carriage returns | 2255 | # remove any latent carriage returns |
2184 | line = line.replace('\r\n', '') | 2256 | line = line.replace('\r\n', '') |
2185 | # grab the time stamp | 2257 | # grab the stamp and sysinfo |
2186 | m = re.match(sysvals.stampfmt, line) | 2258 | if re.match(tp.stampfmt, line): |
2187 | if(m): | ||
2188 | tp.stamp = line | 2259 | tp.stamp = line |
2189 | continue | 2260 | continue |
2261 | elif re.match(tp.sysinfofmt, line): | ||
2262 | tp.sysinfo = line | ||
2263 | continue | ||
2190 | # determine the trace data type (required for further parsing) | 2264 | # determine the trace data type (required for further parsing) |
2191 | m = re.match(sysvals.tracertypefmt, line) | 2265 | m = re.match(sysvals.tracertypefmt, line) |
2192 | if(m): | 2266 | if(m): |
@@ -2219,7 +2293,7 @@ def appendIncompleteTraceLog(testruns): | |||
2219 | # look for the suspend start marker | 2293 | # look for the suspend start marker |
2220 | if(t.startMarker()): | 2294 | if(t.startMarker()): |
2221 | data = testrun[testidx].data | 2295 | data = testrun[testidx].data |
2222 | parseStamp(tp.stamp, data) | 2296 | tp.parseStamp(data, sysvals) |
2223 | data.setStart(t.time) | 2297 | data.setStart(t.time) |
2224 | continue | 2298 | continue |
2225 | if(not data): | 2299 | if(not data): |
@@ -2389,11 +2463,13 @@ def parseTraceLog(): | |||
2389 | for line in tf: | 2463 | for line in tf: |
2390 | # remove any latent carriage returns | 2464 | # remove any latent carriage returns |
2391 | line = line.replace('\r\n', '') | 2465 | line = line.replace('\r\n', '') |
2392 | # stamp line: each stamp means a new test run | 2466 | # stamp and sysinfo lines |
2393 | m = re.match(sysvals.stampfmt, line) | 2467 | if re.match(tp.stampfmt, line): |
2394 | if(m): | ||
2395 | tp.stamp = line | 2468 | tp.stamp = line |
2396 | continue | 2469 | continue |
2470 | elif re.match(tp.sysinfofmt, line): | ||
2471 | tp.sysinfo = line | ||
2472 | continue | ||
2397 | # firmware line: pull out any firmware data | 2473 | # firmware line: pull out any firmware data |
2398 | m = re.match(sysvals.firmwarefmt, line) | 2474 | m = re.match(sysvals.firmwarefmt, line) |
2399 | if(m): | 2475 | if(m): |
@@ -2439,7 +2515,7 @@ def parseTraceLog(): | |||
2439 | testdata.append(data) | 2515 | testdata.append(data) |
2440 | testrun = TestRun(data) | 2516 | testrun = TestRun(data) |
2441 | testruns.append(testrun) | 2517 | testruns.append(testrun) |
2442 | parseStamp(tp.stamp, data) | 2518 | tp.parseStamp(data, sysvals) |
2443 | data.setStart(t.time) | 2519 | data.setStart(t.time) |
2444 | data.tKernSus = t.time | 2520 | data.tKernSus = t.time |
2445 | continue | 2521 | continue |
@@ -2820,10 +2896,13 @@ def loadKernelLog(justtext=False): | |||
2820 | idx = line.find('[') | 2896 | idx = line.find('[') |
2821 | if idx > 1: | 2897 | if idx > 1: |
2822 | line = line[idx:] | 2898 | line = line[idx:] |
2823 | m = re.match(sysvals.stampfmt, line) | 2899 | # grab the stamp and sysinfo |
2824 | if(m): | 2900 | if re.match(tp.stampfmt, line): |
2825 | tp.stamp = line | 2901 | tp.stamp = line |
2826 | continue | 2902 | continue |
2903 | elif re.match(tp.sysinfofmt, line): | ||
2904 | tp.sysinfo = line | ||
2905 | continue | ||
2827 | m = re.match(sysvals.firmwarefmt, line) | 2906 | m = re.match(sysvals.firmwarefmt, line) |
2828 | if(m): | 2907 | if(m): |
2829 | tp.fwdata.append((int(m.group('s')), int(m.group('r')))) | 2908 | tp.fwdata.append((int(m.group('s')), int(m.group('r')))) |
@@ -2839,7 +2918,7 @@ def loadKernelLog(justtext=False): | |||
2839 | if(data): | 2918 | if(data): |
2840 | testruns.append(data) | 2919 | testruns.append(data) |
2841 | data = Data(len(testruns)) | 2920 | data = Data(len(testruns)) |
2842 | parseStamp(tp.stamp, data) | 2921 | tp.parseStamp(data, sysvals) |
2843 | if len(tp.fwdata) > data.testnumber: | 2922 | if len(tp.fwdata) > data.testnumber: |
2844 | data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber] | 2923 | data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber] |
2845 | if(data.fwSuspend > 0 or data.fwResume > 0): | 2924 | if(data.fwSuspend > 0 or data.fwResume > 0): |
@@ -3170,6 +3249,8 @@ def addCallgraphs(sv, hf, data): | |||
3170 | continue | 3249 | continue |
3171 | list = data.dmesg[p]['list'] | 3250 | list = data.dmesg[p]['list'] |
3172 | for devname in data.sortedDevices(p): | 3251 | for devname in data.sortedDevices(p): |
3252 | if len(sv.devicefilter) > 0 and devname not in sv.devicefilter: | ||
3253 | continue | ||
3173 | dev = list[devname] | 3254 | dev = list[devname] |
3174 | color = 'white' | 3255 | color = 'white' |
3175 | if 'color' in data.dmesg[p]: | 3256 | if 'color' in data.dmesg[p]: |
@@ -3309,7 +3390,6 @@ def createHTML(testruns): | |||
3309 | html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">ERROR→</div>\n' | 3390 | html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">ERROR→</div>\n' |
3310 | html_traceevent = '<div title="{0}" class="traceevent{6}" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;{7}">{5}</div>\n' | 3391 | html_traceevent = '<div title="{0}" class="traceevent{6}" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;{7}">{5}</div>\n' |
3311 | html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n' | 3392 | html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n' |
3312 | html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' | ||
3313 | html_timetotal = '<table class="time1">\n<tr>'\ | 3393 | html_timetotal = '<table class="time1">\n<tr>'\ |
3314 | '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ | 3394 | '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ |
3315 | '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ | 3395 | '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ |
@@ -3346,10 +3426,7 @@ def createHTML(testruns): | |||
3346 | # Generate the header for this timeline | 3426 | # Generate the header for this timeline |
3347 | for data in testruns: | 3427 | for data in testruns: |
3348 | tTotal = data.end - data.start | 3428 | tTotal = data.end - data.start |
3349 | sktime = (data.dmesg['suspend_machine']['end'] - \ | 3429 | sktime, rktime = data.getTimeValues() |
3350 | data.tKernSus) * 1000 | ||
3351 | rktime = (data.dmesg['resume_complete']['end'] - \ | ||
3352 | data.dmesg['resume_machine']['start']) * 1000 | ||
3353 | if(tTotal == 0): | 3430 | if(tTotal == 0): |
3354 | print('ERROR: No timeline data') | 3431 | print('ERROR: No timeline data') |
3355 | sys.exit() | 3432 | sys.exit() |
@@ -3581,7 +3658,7 @@ def createHTML(testruns): | |||
3581 | id += tmp[1][0] | 3658 | id += tmp[1][0] |
3582 | order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin) | 3659 | order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin) |
3583 | name = string.replace(phase, '_', ' ') | 3660 | name = string.replace(phase, '_', ' ') |
3584 | devtl.html += html_legend.format(order, \ | 3661 | devtl.html += devtl.html_legend.format(order, \ |
3585 | data.dmesg[phase]['color'], name, id) | 3662 | data.dmesg[phase]['color'], name, id) |
3586 | devtl.html += '</div>\n' | 3663 | devtl.html += '</div>\n' |
3587 | 3664 | ||
@@ -3628,10 +3705,10 @@ def createHTML(testruns): | |||
3628 | addCallgraphs(sysvals, hf, data) | 3705 | addCallgraphs(sysvals, hf, data) |
3629 | 3706 | ||
3630 | # add the test log as a hidden div | 3707 | # add the test log as a hidden div |
3631 | if sysvals.logmsg: | 3708 | if sysvals.testlog and sysvals.logmsg: |
3632 | hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') | 3709 | hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') |
3633 | # add the dmesg log as a hidden div | 3710 | # add the dmesg log as a hidden div |
3634 | if sysvals.addlogs and sysvals.dmesgfile: | 3711 | if sysvals.dmesglog and sysvals.dmesgfile: |
3635 | hf.write('<div id="dmesglog" style="display:none;">\n') | 3712 | hf.write('<div id="dmesglog" style="display:none;">\n') |
3636 | lf = open(sysvals.dmesgfile, 'r') | 3713 | lf = open(sysvals.dmesgfile, 'r') |
3637 | for line in lf: | 3714 | for line in lf: |
@@ -3640,7 +3717,7 @@ def createHTML(testruns): | |||
3640 | lf.close() | 3717 | lf.close() |
3641 | hf.write('</div>\n') | 3718 | hf.write('</div>\n') |
3642 | # add the ftrace log as a hidden div | 3719 | # add the ftrace log as a hidden div |
3643 | if sysvals.addlogs and sysvals.ftracefile: | 3720 | if sysvals.ftracelog and sysvals.ftracefile: |
3644 | hf.write('<div id="ftracelog" style="display:none;">\n') | 3721 | hf.write('<div id="ftracelog" style="display:none;">\n') |
3645 | lf = open(sysvals.ftracefile, 'r') | 3722 | lf = open(sysvals.ftracefile, 'r') |
3646 | for line in lf: | 3723 | for line in lf: |
@@ -3701,6 +3778,7 @@ def addCSS(hf, sv, testcount=1, kerror=False, extra=''): | |||
3701 | <style type=\'text/css\'>\n\ | 3778 | <style type=\'text/css\'>\n\ |
3702 | body {overflow-y:scroll;}\n\ | 3779 | body {overflow-y:scroll;}\n\ |
3703 | .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ | 3780 | .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ |
3781 | .stamp.sysinfo {font:10px Arial;}\n\ | ||
3704 | .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ | 3782 | .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ |
3705 | .callgraph article * {padding-left:28px;}\n\ | 3783 | .callgraph article * {padding-left:28px;}\n\ |
3706 | h1 {color:black;font:bold 30px Times;}\n\ | 3784 | h1 {color:black;font:bold 30px Times;}\n\ |
@@ -3746,7 +3824,7 @@ def addCSS(hf, sv, testcount=1, kerror=False, extra=''): | |||
3746 | .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ | 3824 | .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ |
3747 | .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ | 3825 | .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ |
3748 | button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ | 3826 | button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ |
3749 | .logbtn {position:relative;float:right;height:25px;width:50px;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ | 3827 | .btnfmt {position:relative;float:right;height:25px;width:auto;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ |
3750 | .devlist {position:'+devlistpos+';width:190px;}\n\ | 3828 | .devlist {position:'+devlistpos+';width:190px;}\n\ |
3751 | a:link {color:white;text-decoration:none;}\n\ | 3829 | a:link {color:white;text-decoration:none;}\n\ |
3752 | a:visited {color:white;}\n\ | 3830 | a:visited {color:white;}\n\ |
@@ -4084,8 +4162,6 @@ def addScriptCode(hf, testruns): | |||
4084 | ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ | 4162 | ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ |
4085 | ' win.document.close();\n'\ | 4163 | ' win.document.close();\n'\ |
4086 | ' }\n'\ | 4164 | ' }\n'\ |
4087 | ' function onClickPhase(e) {\n'\ | ||
4088 | ' }\n'\ | ||
4089 | ' function onMouseDown(e) {\n'\ | 4165 | ' function onMouseDown(e) {\n'\ |
4090 | ' dragval[0] = e.clientX;\n'\ | 4166 | ' dragval[0] = e.clientX;\n'\ |
4091 | ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ | 4167 | ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ |
@@ -4120,9 +4196,6 @@ def addScriptCode(hf, testruns): | |||
4120 | ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ | 4196 | ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ |
4121 | ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ | 4197 | ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ |
4122 | ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ | 4198 | ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ |
4123 | ' var list = document.getElementsByClassName("square");\n'\ | ||
4124 | ' for (var i = 0; i < list.length; i++)\n'\ | ||
4125 | ' list[i].onclick = onClickPhase;\n'\ | ||
4126 | ' var list = document.getElementsByClassName("err");\n'\ | 4199 | ' var list = document.getElementsByClassName("err");\n'\ |
4127 | ' for (var i = 0; i < list.length; i++)\n'\ | 4200 | ' for (var i = 0; i < list.length; i++)\n'\ |
4128 | ' list[i].onclick = errWindow;\n'\ | 4201 | ' list[i].onclick = errWindow;\n'\ |
@@ -4193,8 +4266,14 @@ def executeSuspend(): | |||
4193 | if sysvals.testcommand != '': | 4266 | if sysvals.testcommand != '': |
4194 | call(sysvals.testcommand+' 2>&1', shell=True); | 4267 | call(sysvals.testcommand+' 2>&1', shell=True); |
4195 | else: | 4268 | else: |
4269 | mode = sysvals.suspendmode | ||
4270 | if sysvals.memmode and os.path.exists(sysvals.mempowerfile): | ||
4271 | mode = 'mem' | ||
4272 | pf = open(sysvals.mempowerfile, 'w') | ||
4273 | pf.write(sysvals.memmode) | ||
4274 | pf.close() | ||
4196 | pf = open(sysvals.powerfile, 'w') | 4275 | pf = open(sysvals.powerfile, 'w') |
4197 | pf.write(sysvals.suspendmode) | 4276 | pf.write(mode) |
4198 | # execution will pause here | 4277 | # execution will pause here |
4199 | try: | 4278 | try: |
4200 | pf.close() | 4279 | pf.close() |
@@ -4219,24 +4298,15 @@ def executeSuspend(): | |||
4219 | pm.stop() | 4298 | pm.stop() |
4220 | sysvals.fsetVal('0', 'tracing_on') | 4299 | sysvals.fsetVal('0', 'tracing_on') |
4221 | print('CAPTURING TRACE') | 4300 | print('CAPTURING TRACE') |
4222 | writeDatafileHeader(sysvals.ftracefile, fwdata) | 4301 | sysvals.writeDatafileHeader(sysvals.ftracefile, fwdata) |
4223 | call('cat '+tp+'trace >> '+sysvals.ftracefile, shell=True) | 4302 | call('cat '+tp+'trace >> '+sysvals.ftracefile, shell=True) |
4224 | sysvals.fsetVal('', 'trace') | 4303 | sysvals.fsetVal('', 'trace') |
4225 | devProps() | 4304 | devProps() |
4226 | # grab a copy of the dmesg output | 4305 | # grab a copy of the dmesg output |
4227 | print('CAPTURING DMESG') | 4306 | print('CAPTURING DMESG') |
4228 | writeDatafileHeader(sysvals.dmesgfile, fwdata) | 4307 | sysvals.writeDatafileHeader(sysvals.dmesgfile, fwdata) |
4229 | sysvals.getdmesg() | 4308 | sysvals.getdmesg() |
4230 | 4309 | ||
4231 | def writeDatafileHeader(filename, fwdata): | ||
4232 | fp = open(filename, 'a') | ||
4233 | fp.write(sysvals.teststamp+'\n') | ||
4234 | if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'): | ||
4235 | for fw in fwdata: | ||
4236 | if(fw): | ||
4237 | fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) | ||
4238 | fp.close() | ||
4239 | |||
4240 | # Function: setUSBDevicesAuto | 4310 | # Function: setUSBDevicesAuto |
4241 | # Description: | 4311 | # Description: |
4242 | # Set the autosuspend control parameter of all USB devices to auto | 4312 | # Set the autosuspend control parameter of all USB devices to auto |
@@ -4244,7 +4314,7 @@ def writeDatafileHeader(filename, fwdata): | |||
4244 | # to always-on since the kernel cant determine if the device can | 4314 | # to always-on since the kernel cant determine if the device can |
4245 | # properly autosuspend | 4315 | # properly autosuspend |
4246 | def setUSBDevicesAuto(): | 4316 | def setUSBDevicesAuto(): |
4247 | rootCheck(True) | 4317 | sysvals.rootCheck(True) |
4248 | for dirname, dirnames, filenames in os.walk('/sys/devices'): | 4318 | for dirname, dirnames, filenames in os.walk('/sys/devices'): |
4249 | if(re.match('.*/usb[0-9]*.*', dirname) and | 4319 | if(re.match('.*/usb[0-9]*.*', dirname) and |
4250 | 'idVendor' in filenames and 'idProduct' in filenames): | 4320 | 'idVendor' in filenames and 'idProduct' in filenames): |
@@ -4467,13 +4537,146 @@ def devProps(data=0): | |||
4467 | # Output: | 4537 | # Output: |
4468 | # A string list of the available modes | 4538 | # A string list of the available modes |
4469 | def getModes(): | 4539 | def getModes(): |
4470 | modes = '' | 4540 | modes = [] |
4471 | if(os.path.exists(sysvals.powerfile)): | 4541 | if(os.path.exists(sysvals.powerfile)): |
4472 | fp = open(sysvals.powerfile, 'r') | 4542 | fp = open(sysvals.powerfile, 'r') |
4473 | modes = string.split(fp.read()) | 4543 | modes = string.split(fp.read()) |
4474 | fp.close() | 4544 | fp.close() |
4545 | if(os.path.exists(sysvals.mempowerfile)): | ||
4546 | deep = False | ||
4547 | fp = open(sysvals.mempowerfile, 'r') | ||
4548 | for m in string.split(fp.read()): | ||
4549 | memmode = m.strip('[]') | ||
4550 | if memmode == 'deep': | ||
4551 | deep = True | ||
4552 | else: | ||
4553 | modes.append('mem-%s' % memmode) | ||
4554 | fp.close() | ||
4555 | if 'mem' in modes and not deep: | ||
4556 | modes.remove('mem') | ||
4475 | return modes | 4557 | return modes |
4476 | 4558 | ||
4559 | # Function: dmidecode | ||
4560 | # Description: | ||
4561 | # Read the bios tables and pull out system info | ||
4562 | # Arguments: | ||
4563 | # mempath: /dev/mem or custom mem path | ||
4564 | # fatal: True to exit on error, False to return empty dict | ||
4565 | # Output: | ||
4566 | # A dict object with all available key/values | ||
4567 | def dmidecode(mempath, fatal=False): | ||
4568 | out = dict() | ||
4569 | |||
4570 | # the list of values to retrieve, with hardcoded (type, idx) | ||
4571 | info = { | ||
4572 | 'bios-vendor': (0, 4), | ||
4573 | 'bios-version': (0, 5), | ||
4574 | 'bios-release-date': (0, 8), | ||
4575 | 'system-manufacturer': (1, 4), | ||
4576 | 'system-product-name': (1, 5), | ||
4577 | 'system-version': (1, 6), | ||
4578 | 'system-serial-number': (1, 7), | ||
4579 | 'baseboard-manufacturer': (2, 4), | ||
4580 | 'baseboard-product-name': (2, 5), | ||
4581 | 'baseboard-version': (2, 6), | ||
4582 | 'baseboard-serial-number': (2, 7), | ||
4583 | 'chassis-manufacturer': (3, 4), | ||
4584 | 'chassis-type': (3, 5), | ||
4585 | 'chassis-version': (3, 6), | ||
4586 | 'chassis-serial-number': (3, 7), | ||
4587 | 'processor-manufacturer': (4, 7), | ||
4588 | 'processor-version': (4, 16), | ||
4589 | } | ||
4590 | if(not os.path.exists(mempath)): | ||
4591 | if(fatal): | ||
4592 | doError('file does not exist: %s' % mempath) | ||
4593 | return out | ||
4594 | if(not os.access(mempath, os.R_OK)): | ||
4595 | if(fatal): | ||
4596 | doError('file is not readable: %s' % mempath) | ||
4597 | return out | ||
4598 | |||
4599 | # by default use legacy scan, but try to use EFI first | ||
4600 | memaddr = 0xf0000 | ||
4601 | memsize = 0x10000 | ||
4602 | for ep in ['/sys/firmware/efi/systab', '/proc/efi/systab']: | ||
4603 | if not os.path.exists(ep) or not os.access(ep, os.R_OK): | ||
4604 | continue | ||
4605 | fp = open(ep, 'r') | ||
4606 | buf = fp.read() | ||
4607 | fp.close() | ||
4608 | i = buf.find('SMBIOS=') | ||
4609 | if i >= 0: | ||
4610 | try: | ||
4611 | memaddr = int(buf[i+7:], 16) | ||
4612 | memsize = 0x20 | ||
4613 | except: | ||
4614 | continue | ||
4615 | |||
4616 | # read in the memory for scanning | ||
4617 | fp = open(mempath, 'rb') | ||
4618 | try: | ||
4619 | fp.seek(memaddr) | ||
4620 | buf = fp.read(memsize) | ||
4621 | except: | ||
4622 | if(fatal): | ||
4623 | doError('DMI table is unreachable, sorry') | ||
4624 | else: | ||
4625 | return out | ||
4626 | fp.close() | ||
4627 | |||
4628 | # search for either an SM table or DMI table | ||
4629 | i = base = length = num = 0 | ||
4630 | while(i < memsize): | ||
4631 | if buf[i:i+4] == '_SM_' and i < memsize - 16: | ||
4632 | length = struct.unpack('H', buf[i+22:i+24])[0] | ||
4633 | base, num = struct.unpack('IH', buf[i+24:i+30]) | ||
4634 | break | ||
4635 | elif buf[i:i+5] == '_DMI_': | ||
4636 | length = struct.unpack('H', buf[i+6:i+8])[0] | ||
4637 | base, num = struct.unpack('IH', buf[i+8:i+14]) | ||
4638 | break | ||
4639 | i += 16 | ||
4640 | if base == 0 and length == 0 and num == 0: | ||
4641 | if(fatal): | ||
4642 | doError('Neither SMBIOS nor DMI were found') | ||
4643 | else: | ||
4644 | return out | ||
4645 | |||
4646 | # read in the SM or DMI table | ||
4647 | fp = open(mempath, 'rb') | ||
4648 | try: | ||
4649 | fp.seek(base) | ||
4650 | buf = fp.read(length) | ||
4651 | except: | ||
4652 | if(fatal): | ||
4653 | doError('DMI table is unreachable, sorry') | ||
4654 | else: | ||
4655 | return out | ||
4656 | fp.close() | ||
4657 | |||
4658 | # scan the table for the values we want | ||
4659 | count = i = 0 | ||
4660 | while(count < num and i <= len(buf) - 4): | ||
4661 | type, size, handle = struct.unpack('BBH', buf[i:i+4]) | ||
4662 | n = i + size | ||
4663 | while n < len(buf) - 1: | ||
4664 | if 0 == struct.unpack('H', buf[n:n+2])[0]: | ||
4665 | break | ||
4666 | n += 1 | ||
4667 | data = buf[i+size:n+2].split('\0') | ||
4668 | for name in info: | ||
4669 | itype, idxadr = info[name] | ||
4670 | if itype == type: | ||
4671 | idx = struct.unpack('B', buf[i+idxadr])[0] | ||
4672 | if idx > 0 and idx < len(data) - 1: | ||
4673 | s = data[idx-1].strip() | ||
4674 | if s and s.lower() != 'to be filled by o.e.m.': | ||
4675 | out[name] = data[idx-1] | ||
4676 | i = n + 2 | ||
4677 | count += 1 | ||
4678 | return out | ||
4679 | |||
4477 | # Function: getFPDT | 4680 | # Function: getFPDT |
4478 | # Description: | 4681 | # Description: |
4479 | # Read the acpi bios tables and pull out FPDT, the firmware data | 4682 | # Read the acpi bios tables and pull out FPDT, the firmware data |
@@ -4487,7 +4690,7 @@ def getFPDT(output): | |||
4487 | prectype[0] = 'Basic S3 Resume Performance Record' | 4690 | prectype[0] = 'Basic S3 Resume Performance Record' |
4488 | prectype[1] = 'Basic S3 Suspend Performance Record' | 4691 | prectype[1] = 'Basic S3 Suspend Performance Record' |
4489 | 4692 | ||
4490 | rootCheck(True) | 4693 | sysvals.rootCheck(True) |
4491 | if(not os.path.exists(sysvals.fpdtpath)): | 4694 | if(not os.path.exists(sysvals.fpdtpath)): |
4492 | if(output): | 4695 | if(output): |
4493 | doError('file does not exist: %s' % sysvals.fpdtpath) | 4696 | doError('file does not exist: %s' % sysvals.fpdtpath) |
@@ -4617,7 +4820,7 @@ def statusCheck(probecheck=False): | |||
4617 | 4820 | ||
4618 | # check we have root access | 4821 | # check we have root access |
4619 | res = sysvals.colorText('NO (No features of this tool will work!)') | 4822 | res = sysvals.colorText('NO (No features of this tool will work!)') |
4620 | if(rootCheck(False)): | 4823 | if(sysvals.rootCheck(False)): |
4621 | res = 'YES' | 4824 | res = 'YES' |
4622 | print(' have root access: %s' % res) | 4825 | print(' have root access: %s' % res) |
4623 | if(res != 'YES'): | 4826 | if(res != 'YES'): |
@@ -4716,16 +4919,6 @@ def doError(msg, help=False): | |||
4716 | print('ERROR: %s\n') % msg | 4919 | print('ERROR: %s\n') % msg |
4717 | sys.exit() | 4920 | sys.exit() |
4718 | 4921 | ||
4719 | # Function: rootCheck | ||
4720 | # Description: | ||
4721 | # quick check to see if we have root access | ||
4722 | def rootCheck(fatal): | ||
4723 | if(os.access(sysvals.powerfile, os.W_OK)): | ||
4724 | return True | ||
4725 | if fatal: | ||
4726 | doError('This command requires sysfs mount and root access') | ||
4727 | return False | ||
4728 | |||
4729 | # Function: getArgInt | 4922 | # Function: getArgInt |
4730 | # Description: | 4923 | # Description: |
4731 | # pull out an integer argument from the command line with checks | 4924 | # pull out an integer argument from the command line with checks |
@@ -4779,6 +4972,7 @@ def processData(): | |||
4779 | if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): | 4972 | if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): |
4780 | appendIncompleteTraceLog(testruns) | 4973 | appendIncompleteTraceLog(testruns) |
4781 | createHTML(testruns) | 4974 | createHTML(testruns) |
4975 | return testruns | ||
4782 | 4976 | ||
4783 | # Function: rerunTest | 4977 | # Function: rerunTest |
4784 | # Description: | 4978 | # Description: |
@@ -4790,17 +4984,20 @@ def rerunTest(): | |||
4790 | doError('recreating this html output requires a dmesg file') | 4984 | doError('recreating this html output requires a dmesg file') |
4791 | sysvals.setOutputFile() | 4985 | sysvals.setOutputFile() |
4792 | vprint('Output file: %s' % sysvals.htmlfile) | 4986 | vprint('Output file: %s' % sysvals.htmlfile) |
4793 | if(os.path.exists(sysvals.htmlfile) and not os.access(sysvals.htmlfile, os.W_OK)): | 4987 | if os.path.exists(sysvals.htmlfile): |
4794 | doError('missing permission to write to %s' % sysvals.htmlfile) | 4988 | if not os.path.isfile(sysvals.htmlfile): |
4795 | processData() | 4989 | doError('a directory already exists with this name: %s' % sysvals.htmlfile) |
4990 | elif not os.access(sysvals.htmlfile, os.W_OK): | ||
4991 | doError('missing permission to write to %s' % sysvals.htmlfile) | ||
4992 | return processData() | ||
4796 | 4993 | ||
4797 | # Function: runTest | 4994 | # Function: runTest |
4798 | # Description: | 4995 | # Description: |
4799 | # execute a suspend/resume, gather the logs, and generate the output | 4996 | # execute a suspend/resume, gather the logs, and generate the output |
4800 | def runTest(subdir, testpath=''): | 4997 | def runTest(): |
4801 | # prepare for the test | 4998 | # prepare for the test |
4802 | sysvals.initFtrace() | 4999 | sysvals.initFtrace() |
4803 | sysvals.initTestOutput(subdir, testpath) | 5000 | sysvals.initTestOutput('suspend') |
4804 | vprint('Output files:\n\t%s\n\t%s\n\t%s' % \ | 5001 | vprint('Output files:\n\t%s\n\t%s\n\t%s' % \ |
4805 | (sysvals.dmesgfile, sysvals.ftracefile, sysvals.htmlfile)) | 5002 | (sysvals.dmesgfile, sysvals.ftracefile, sysvals.htmlfile)) |
4806 | 5003 | ||
@@ -4897,7 +5094,7 @@ def configFromFile(file): | |||
4897 | if(opt.lower() == 'verbose'): | 5094 | if(opt.lower() == 'verbose'): |
4898 | sysvals.verbose = checkArgBool(value) | 5095 | sysvals.verbose = checkArgBool(value) |
4899 | elif(opt.lower() == 'addlogs'): | 5096 | elif(opt.lower() == 'addlogs'): |
4900 | sysvals.addlogs = checkArgBool(value) | 5097 | sysvals.dmesglog = sysvals.ftracelog = checkArgBool(value) |
4901 | elif(opt.lower() == 'dev'): | 5098 | elif(opt.lower() == 'dev'): |
4902 | sysvals.usedevsrc = checkArgBool(value) | 5099 | sysvals.usedevsrc = checkArgBool(value) |
4903 | elif(opt.lower() == 'proc'): | 5100 | elif(opt.lower() == 'proc'): |
@@ -4947,7 +5144,7 @@ def configFromFile(file): | |||
4947 | elif(opt.lower() == 'mincg'): | 5144 | elif(opt.lower() == 'mincg'): |
4948 | sysvals.mincglen = getArgFloat('-mincg', value, 0.0, 10000.0, False) | 5145 | sysvals.mincglen = getArgFloat('-mincg', value, 0.0, 10000.0, False) |
4949 | elif(opt.lower() == 'output-dir'): | 5146 | elif(opt.lower() == 'output-dir'): |
4950 | sysvals.setOutputFolder(value) | 5147 | sysvals.testdir = sysvals.setOutputFolder(value) |
4951 | 5148 | ||
4952 | if sysvals.suspendmode == 'command' and not sysvals.testcommand: | 5149 | if sysvals.suspendmode == 'command' and not sysvals.testcommand: |
4953 | doError('No command supplied for mode "command"') | 5150 | doError('No command supplied for mode "command"') |
@@ -5030,8 +5227,6 @@ def configFromFile(file): | |||
5030 | # Description: | 5227 | # Description: |
5031 | # print out the help text | 5228 | # print out the help text |
5032 | def printHelp(): | 5229 | def printHelp(): |
5033 | modes = getModes() | ||
5034 | |||
5035 | print('') | 5230 | print('') |
5036 | print('%s v%s' % (sysvals.title, sysvals.version)) | 5231 | print('%s v%s' % (sysvals.title, sysvals.version)) |
5037 | print('Usage: sudo sleepgraph <options> <commands>') | 5232 | print('Usage: sudo sleepgraph <options> <commands>') |
@@ -5048,7 +5243,7 @@ def printHelp(): | |||
5048 | print(' If no specific command is given, the default behavior is to initiate') | 5243 | print(' If no specific command is given, the default behavior is to initiate') |
5049 | print(' a suspend/resume and capture the dmesg/ftrace output as an html timeline.') | 5244 | print(' a suspend/resume and capture the dmesg/ftrace output as an html timeline.') |
5050 | print('') | 5245 | print('') |
5051 | print(' Generates output files in subdirectory: suspend-mmddyy-HHMMSS') | 5246 | print(' Generates output files in subdirectory: suspend-yymmdd-HHMMSS') |
5052 | print(' HTML output: <hostname>_<mode>.html') | 5247 | print(' HTML output: <hostname>_<mode>.html') |
5053 | print(' raw dmesg output: <hostname>_<mode>_dmesg.txt') | 5248 | print(' raw dmesg output: <hostname>_<mode>_dmesg.txt') |
5054 | print(' raw ftrace output: <hostname>_<mode>_ftrace.txt') | 5249 | print(' raw ftrace output: <hostname>_<mode>_ftrace.txt') |
@@ -5058,8 +5253,9 @@ def printHelp(): | |||
5058 | print(' -v Print the current tool version') | 5253 | print(' -v Print the current tool version') |
5059 | print(' -config fn Pull arguments and config options from file fn') | 5254 | print(' -config fn Pull arguments and config options from file fn') |
5060 | print(' -verbose Print extra information during execution and analysis') | 5255 | print(' -verbose Print extra information during execution and analysis') |
5061 | print(' -m mode Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode) | 5256 | print(' -m mode Mode to initiate for suspend (default: %s)') % (sysvals.suspendmode) |
5062 | print(' -o subdir Override the output subdirectory') | 5257 | print(' -o name Overrides the output subdirectory name when running a new test') |
5258 | print(' default: suspend-{date}-{time}') | ||
5063 | print(' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)') | 5259 | print(' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)') |
5064 | print(' -addlogs Add the dmesg and ftrace logs to the html output') | 5260 | print(' -addlogs Add the dmesg and ftrace logs to the html output') |
5065 | print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)') | 5261 | print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)') |
@@ -5084,17 +5280,20 @@ def printHelp(): | |||
5084 | print(' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)') | 5280 | print(' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)') |
5085 | print(' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)') | 5281 | print(' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)') |
5086 | print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)') | 5282 | print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)') |
5087 | print(' [commands]') | 5283 | print('') |
5088 | print(' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)') | 5284 | print('Other commands:') |
5089 | print(' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)') | ||
5090 | print(' -summary directory Create a summary of all test in this dir') | ||
5091 | print(' -modes List available suspend modes') | 5285 | print(' -modes List available suspend modes') |
5092 | print(' -status Test to see if the system is enabled to run this tool') | 5286 | print(' -status Test to see if the system is enabled to run this tool') |
5093 | print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table') | 5287 | print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table') |
5288 | print(' -sysinfo Print out system info extracted from BIOS') | ||
5094 | print(' -usbtopo Print out the current USB topology with power info') | 5289 | print(' -usbtopo Print out the current USB topology with power info') |
5095 | print(' -usbauto Enable autosuspend for all connected USB devices') | 5290 | print(' -usbauto Enable autosuspend for all connected USB devices') |
5096 | print(' -flist Print the list of functions currently being captured in ftrace') | 5291 | print(' -flist Print the list of functions currently being captured in ftrace') |
5097 | print(' -flistall Print all functions capable of being captured in ftrace') | 5292 | print(' -flistall Print all functions capable of being captured in ftrace') |
5293 | print(' -summary directory Create a summary of all test in this dir') | ||
5294 | print(' [redo]') | ||
5295 | print(' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)') | ||
5296 | print(' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)') | ||
5098 | print('') | 5297 | print('') |
5099 | return True | 5298 | return True |
5100 | 5299 | ||
@@ -5102,9 +5301,9 @@ def printHelp(): | |||
5102 | # exec start (skipped if script is loaded as library) | 5301 | # exec start (skipped if script is loaded as library) |
5103 | if __name__ == '__main__': | 5302 | if __name__ == '__main__': |
5104 | cmd = '' | 5303 | cmd = '' |
5105 | cmdarg = '' | 5304 | outdir = '' |
5106 | multitest = {'run': False, 'count': 0, 'delay': 0} | 5305 | multitest = {'run': False, 'count': 0, 'delay': 0} |
5107 | simplecmds = ['-modes', '-fpdt', '-flist', '-flistall', '-usbtopo', '-usbauto', '-status'] | 5306 | simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall', '-usbtopo', '-usbauto', '-status'] |
5108 | # loop through the command line arguments | 5307 | # loop through the command line arguments |
5109 | args = iter(sys.argv[1:]) | 5308 | args = iter(sys.argv[1:]) |
5110 | for arg in args: | 5309 | for arg in args: |
@@ -5135,7 +5334,7 @@ if __name__ == '__main__': | |||
5135 | elif(arg == '-f'): | 5334 | elif(arg == '-f'): |
5136 | sysvals.usecallgraph = True | 5335 | sysvals.usecallgraph = True |
5137 | elif(arg == '-addlogs'): | 5336 | elif(arg == '-addlogs'): |
5138 | sysvals.addlogs = True | 5337 | sysvals.dmesglog = sysvals.ftracelog = True |
5139 | elif(arg == '-verbose'): | 5338 | elif(arg == '-verbose'): |
5140 | sysvals.verbose = True | 5339 | sysvals.verbose = True |
5141 | elif(arg == '-proc'): | 5340 | elif(arg == '-proc'): |
@@ -5195,7 +5394,7 @@ if __name__ == '__main__': | |||
5195 | val = args.next() | 5394 | val = args.next() |
5196 | except: | 5395 | except: |
5197 | doError('No subdirectory name supplied', True) | 5396 | doError('No subdirectory name supplied', True) |
5198 | sysvals.setOutputFolder(val) | 5397 | outdir = sysvals.setOutputFolder(val) |
5199 | elif(arg == '-config'): | 5398 | elif(arg == '-config'): |
5200 | try: | 5399 | try: |
5201 | val = args.next() | 5400 | val = args.next() |
@@ -5236,7 +5435,7 @@ if __name__ == '__main__': | |||
5236 | except: | 5435 | except: |
5237 | doError('No directory supplied', True) | 5436 | doError('No directory supplied', True) |
5238 | cmd = 'summary' | 5437 | cmd = 'summary' |
5239 | cmdarg = val | 5438 | outdir = val |
5240 | sysvals.notestrun = True | 5439 | sysvals.notestrun = True |
5241 | if(os.path.isdir(val) == False): | 5440 | if(os.path.isdir(val) == False): |
5242 | doError('%s is not accesible' % val) | 5441 | doError('%s is not accesible' % val) |
@@ -5260,11 +5459,14 @@ if __name__ == '__main__': | |||
5260 | sysvals.mincglen = sysvals.mindevlen | 5459 | sysvals.mincglen = sysvals.mindevlen |
5261 | 5460 | ||
5262 | # just run a utility command and exit | 5461 | # just run a utility command and exit |
5462 | sysvals.cpuInfo() | ||
5263 | if(cmd != ''): | 5463 | if(cmd != ''): |
5264 | if(cmd == 'status'): | 5464 | if(cmd == 'status'): |
5265 | statusCheck(True) | 5465 | statusCheck(True) |
5266 | elif(cmd == 'fpdt'): | 5466 | elif(cmd == 'fpdt'): |
5267 | getFPDT(True) | 5467 | getFPDT(True) |
5468 | elif(cmd == 'sysinfo'): | ||
5469 | sysvals.printSystemInfo() | ||
5268 | elif(cmd == 'usbtopo'): | 5470 | elif(cmd == 'usbtopo'): |
5269 | detectUSB() | 5471 | detectUSB() |
5270 | elif(cmd == 'modes'): | 5472 | elif(cmd == 'modes'): |
@@ -5276,7 +5478,7 @@ if __name__ == '__main__': | |||
5276 | elif(cmd == 'usbauto'): | 5478 | elif(cmd == 'usbauto'): |
5277 | setUSBDevicesAuto() | 5479 | setUSBDevicesAuto() |
5278 | elif(cmd == 'summary'): | 5480 | elif(cmd == 'summary'): |
5279 | runSummary(cmdarg, True) | 5481 | runSummary(outdir, True) |
5280 | sys.exit() | 5482 | sys.exit() |
5281 | 5483 | ||
5282 | # if instructed, re-analyze existing data files | 5484 | # if instructed, re-analyze existing data files |
@@ -5289,21 +5491,43 @@ if __name__ == '__main__': | |||
5289 | print('Check FAILED, aborting the test run!') | 5491 | print('Check FAILED, aborting the test run!') |
5290 | sys.exit() | 5492 | sys.exit() |
5291 | 5493 | ||
5494 | # extract mem modes and convert | ||
5495 | mode = sysvals.suspendmode | ||
5496 | if 'mem' == mode[:3]: | ||
5497 | if '-' in mode: | ||
5498 | memmode = mode.split('-')[-1] | ||
5499 | else: | ||
5500 | memmode = 'deep' | ||
5501 | if memmode == 'shallow': | ||
5502 | mode = 'standby' | ||
5503 | elif memmode == 's2idle': | ||
5504 | mode = 'freeze' | ||
5505 | else: | ||
5506 | mode = 'mem' | ||
5507 | sysvals.memmode = memmode | ||
5508 | sysvals.suspendmode = mode | ||
5509 | |||
5510 | sysvals.systemInfo(dmidecode(sysvals.mempath)) | ||
5511 | |||
5292 | if multitest['run']: | 5512 | if multitest['run']: |
5293 | # run multiple tests in a separate subdirectory | 5513 | # run multiple tests in a separate subdirectory |
5294 | s = 'x%d' % multitest['count'] | 5514 | if not outdir: |
5295 | if not sysvals.outdir: | 5515 | s = 'suspend-x%d' % multitest['count'] |
5296 | sysvals.outdir = datetime.now().strftime('suspend-'+s+'-%m%d%y-%H%M%S') | 5516 | outdir = datetime.now().strftime(s+'-%y%m%d-%H%M%S') |
5297 | if not os.path.isdir(sysvals.outdir): | 5517 | if not os.path.isdir(outdir): |
5298 | os.mkdir(sysvals.outdir) | 5518 | os.mkdir(outdir) |
5299 | for i in range(multitest['count']): | 5519 | for i in range(multitest['count']): |
5300 | if(i != 0): | 5520 | if(i != 0): |
5301 | print('Waiting %d seconds...' % (multitest['delay'])) | 5521 | print('Waiting %d seconds...' % (multitest['delay'])) |
5302 | time.sleep(multitest['delay']) | 5522 | time.sleep(multitest['delay']) |
5303 | print('TEST (%d/%d) START' % (i+1, multitest['count'])) | 5523 | print('TEST (%d/%d) START' % (i+1, multitest['count'])) |
5304 | runTest(sysvals.outdir) | 5524 | fmt = 'suspend-%y%m%d-%H%M%S' |
5525 | sysvals.testdir = os.path.join(outdir, datetime.now().strftime(fmt)) | ||
5526 | runTest() | ||
5305 | print('TEST (%d/%d) COMPLETE' % (i+1, multitest['count'])) | 5527 | print('TEST (%d/%d) COMPLETE' % (i+1, multitest['count'])) |
5306 | runSummary(sysvals.outdir, False) | 5528 | runSummary(outdir, False) |
5307 | else: | 5529 | else: |
5530 | if outdir: | ||
5531 | sysvals.testdir = outdir | ||
5308 | # run the test in the current directory | 5532 | # run the test in the current directory |
5309 | runTest('.', sysvals.outdir) | 5533 | runTest() |