History

Merge branch 'pm-tools'

* pm-tools: tools/power/x86: Debug utility for intel_pstate driver AnalyzeSuspend: fix drag and zoom bug in javascript scripts: analyze_suspend.py: Update to upstream v4.5 scripts: analyze_suspend.py: Update to upstream v4.4 scripts: analyze_suspend.py: Update to upstream v4.3

Rafael J. Wysocki committed 9 years ago

Commit eee77a82 parents fccddb2 48385dd2 files · +1704 −798Browse files

Showing the changes to scripts (1 of 2 files). Show all

Unified · Split

scripts/analyze_suspend.py+1135−798
@@ -24,11 +24,6 @@ · 23 unmodified lines
24# https://01.org/suspendresume24# https://01.org/suspendresume
25# Source repo25# Source repo
26# https://github.com/01org/suspendresume26# https://github.com/01org/suspendresume
27# Documentation
28# Getting Started
29# https://01.org/suspendresume/documentation/getting-started
30# Command List:
31# https://01.org/suspendresume/documentation/command-list
32#27#
33# Description:28# Description:
34# This tool is designed to assist kernel and OS developers in optimizing29# This tool is designed to assist kernel and OS developers in optimizing
@@ -66,6 +61,8 @@ import platform · 31 unmodified lines
66from datetime import datetime61from datetime import datetime
67import struct62import struct
68import ConfigParser63import ConfigParser
64from threading import Thread
65from subprocess import call, Popen, PIPE
69 66
70# ----------------- CLASSES --------------------67# ----------------- CLASSES --------------------
71 68
@@ -75,11 +72,15 @@ import ConfigParser · 3 unmodified lines
75# store system values and test parameters72# store system values and test parameters
76class SystemValues:73class SystemValues:
77 ansi = False74 ansi = False
78 version = '4.2'75 version = '4.5'
79 verbose = False76 verbose = False
80 addlogs = False77 addlogs = False
81 mindevlen = 0.00178 mindevlen = 0.0
82 mincglen = 1.079 mincglen = 0.0
80 cgphase = ''
81 cgtest = -1
82 callloopmaxgap = 0.0001
83 callloopmaxlen = 0.005
83 srgap = 084 srgap = 0
84 cgexp = False85 cgexp = False
85 outdir = ''86 outdir = ''
@@ -92,6 +93,7 @@ class SystemValues: · 6 unmodified lines
92 'device_pm_callback_end',93 'device_pm_callback_end',
93 'device_pm_callback_start'94 'device_pm_callback_start'
94 ]95 ]
96 logmsg = ''
95 testcommand = ''97 testcommand = ''
96 mempath = '/dev/mem'98 mempath = '/dev/mem'
97 powerfile = '/sys/power/state'99 powerfile = '/sys/power/state'
@@ -117,19 +119,19 @@ class SystemValues: · 19 unmodified lines
117 usetracemarkers = True119 usetracemarkers = True
118 usekprobes = True120 usekprobes = True
119 usedevsrc = False121 usedevsrc = False
122 useprocmon = False
120 notestrun = False123 notestrun = False
124 mixedphaseheight = True
121 devprops = dict()125 devprops = dict()
122 postresumetime = 0126 predelay = 0
127 postdelay = 0
128 procexecfmt = 'ps - (?P<ps>.*)$'
123 devpropfmt = '# Device Properties: .*'129 devpropfmt = '# Device Properties: .*'
124 tracertypefmt = '# tracer: (?P<t>.*)'130 tracertypefmt = '# tracer: (?P<t>.*)'
125 firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$'131 firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$'
126 postresumefmt = '# post resume time (?P<t>[0-9]*)$'
127 stampfmt = '# suspend-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\132 stampfmt = '# suspend-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\
128 '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\133 '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\
129 ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$'134 ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$'
130 kprobecolor = 'rgba(204,204,204,0.5)'
131 synccolor = 'rgba(204,204,204,0.5)'
132 debugfuncs = []
133 tracefuncs = {135 tracefuncs = {
134 'sys_sync': dict(),136 'sys_sync': dict(),
135 'pm_prepare_console': dict(),137 'pm_prepare_console': dict(),
@@ -152,44 +154,66 @@ class SystemValues: · 16 unmodified lines
152 'CPU_OFF': {154 'CPU_OFF': {
153 'func':'_cpu_down',155 'func':'_cpu_down',
154 'args_x86_64': {'cpu':'%di:s32'},156 'args_x86_64': {'cpu':'%di:s32'},
155 'format': 'CPU_OFF[{cpu}]',157 'format': 'CPU_OFF[{cpu}]'
156 'mask': 'CPU_.*_DOWN'
157 },158 },
158 'CPU_ON': {159 'CPU_ON': {
159 'func':'_cpu_up',160 'func':'_cpu_up',
160 'args_x86_64': {'cpu':'%di:s32'},161 'args_x86_64': {'cpu':'%di:s32'},
161 'format': 'CPU_ON[{cpu}]',162 'format': 'CPU_ON[{cpu}]'
162 'mask': 'CPU_.*_UP'
163 },163 },
164 }164 }
165 dev_tracefuncs = {165 dev_tracefuncs = {
166 # general wait/delay/sleep166 # general wait/delay/sleep
167 'msleep': { 'args_x86_64': {'time':'%di:s32'} },167 'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 },
168 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'} },168 'schedule_timeout_uninterruptible': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
169 'acpi_os_stall': dict(),169 'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
170 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 },
171 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 },
172 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 },
173 'acpi_os_stall': {'ub': 1},
170 # ACPI174 # ACPI
171 'acpi_resume_power_resources': dict(),175 'acpi_resume_power_resources': dict(),
172 'acpi_ps_parse_aml': dict(),176 'acpi_ps_parse_aml': dict(),
173 # filesystem177 # filesystem
174 'ext4_sync_fs': dict(),178 'ext4_sync_fs': dict(),
179 # 80211
180 'iwlagn_mac_start': dict(),
181 'iwlagn_alloc_bcast_station': dict(),
182 'iwl_trans_pcie_start_hw': dict(),
183 'iwl_trans_pcie_start_fw': dict(),
184 'iwl_run_init_ucode': dict(),
185 'iwl_load_ucode_wait_alive': dict(),
186 'iwl_alive_start': dict(),
187 'iwlagn_mac_stop': dict(),
188 'iwlagn_mac_suspend': dict(),
189 'iwlagn_mac_resume': dict(),
190 'iwlagn_mac_add_interface': dict(),
191 'iwlagn_mac_remove_interface': dict(),
192 'iwlagn_mac_change_interface': dict(),
193 'iwlagn_mac_config': dict(),
194 'iwlagn_configure_filter': dict(),
195 'iwlagn_mac_hw_scan': dict(),
196 'iwlagn_bss_info_changed': dict(),
197 'iwlagn_mac_channel_switch': dict(),
198 'iwlagn_mac_flush': dict(),
175 # ATA199 # ATA
176 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} },200 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} },
177 # i915201 # i915
178 'i915_gem_restore_gtt_mappings': dict(),202 'i915_gem_resume': dict(),
203 'i915_restore_state': dict(),
179 'intel_opregion_setup': dict(),204 'intel_opregion_setup': dict(),
205 'g4x_pre_enable_dp': dict(),
206 'vlv_pre_enable_dp': dict(),
207 'chv_pre_enable_dp': dict(),
208 'g4x_enable_dp': dict(),
209 'vlv_enable_dp': dict(),
210 'intel_hpd_init': dict(),
211 'intel_opregion_register': dict(),
180 'intel_dp_detect': dict(),212 'intel_dp_detect': dict(),
181 'intel_hdmi_detect': dict(),213 'intel_hdmi_detect': dict(),
182 'intel_opregion_init': dict(),214 'intel_opregion_init': dict(),
215 'intel_fbdev_set_suspend': dict(),
183 }216 }
184 kprobes_postresume = [
185 {
186 'name': 'ataportrst',
187 'func': 'ata_eh_recover',
188 'args': {'port':'+36(%di):s32'},
189 'format': 'ata{port}_port_reset',
190 'mask': 'ata.*_port_reset'
191 }
192 ]
193 kprobes = dict()217 kprobes = dict()
194 timeformat = '%.3f'218 timeformat = '%.3f'
195 def __init__(self):219 def __init__(self):
@@ -198,6 +222,7 @@ class SystemValues: · 2 unmodified lines
198 self.embedded = True222 self.embedded = True
199 self.addlogs = True223 self.addlogs = True
200 self.htmlfile = os.environ['LOG_FILE']224 self.htmlfile = os.environ['LOG_FILE']
225 self.archargs = 'args_'+platform.machine()
201 self.hostname = platform.node()226 self.hostname = platform.node()
202 if(self.hostname == ''):227 if(self.hostname == ''):
203 self.hostname = 'localhost'228 self.hostname = 'localhost'
@@ -214,6 +239,13 @@ class SystemValues: · 10 unmodified lines
214 if num < 0 or num > 6:239 if num < 0 or num > 6:
215 return240 return
216 self.timeformat = '%.{0}f'.format(num)241 self.timeformat = '%.{0}f'.format(num)
242 def setOutputFolder(self, value):
243 args = dict()
244 n = datetime.now()
245 args['date'] = n.strftime('%y%m%d')
246 args['time'] = n.strftime('%H%M%S')
247 args['hostname'] = self.hostname
248 self.outdir = value.format(**args)
217 def setOutputFile(self):249 def setOutputFile(self):
218 if((self.htmlfile == '') and (self.dmesgfile != '')):250 if((self.htmlfile == '') and (self.dmesgfile != '')):
219 m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile)251 m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile)
@@ -253,10 +285,14 @@ class SystemValues: · 33 unmodified lines
253 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html'285 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html'
254 if not os.path.isdir(self.testdir):286 if not os.path.isdir(self.testdir):
255 os.mkdir(self.testdir)287 os.mkdir(self.testdir)
256 def setDeviceFilter(self, devnames):288 def setDeviceFilter(self, value):
257 self.devicefilter = string.split(devnames)289 self.devicefilter = []
290 if value:
291 value = value.split(',')
292 for i in value:
293 self.devicefilter.append(i.strip())
258 def rtcWakeAlarmOn(self):294 def rtcWakeAlarmOn(self):
259 os.system('echo 0 > '+self.rtcpath+'/wakealarm')295 call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True)
260 outD = open(self.rtcpath+'/date', 'r').read().strip()296 outD = open(self.rtcpath+'/date', 'r').read().strip()
261 outT = open(self.rtcpath+'/time', 'r').read().strip()297 outT = open(self.rtcpath+'/time', 'r').read().strip()
262 mD = re.match('^(?P<y>[0-9]*)-(?P<m>[0-9]*)-(?P<d>[0-9]*)', outD)298 mD = re.match('^(?P<y>[0-9]*)-(?P<m>[0-9]*)-(?P<d>[0-9]*)', outD)
@@ -272,12 +308,12 @@ class SystemValues: · 9 unmodified lines
272 # if hardware time fails, use the software time308 # if hardware time fails, use the software time
273 nowtime = int(datetime.now().strftime('%s'))309 nowtime = int(datetime.now().strftime('%s'))
274 alarm = nowtime + self.rtcwaketime310 alarm = nowtime + self.rtcwaketime
275 os.system('echo %d > %s/wakealarm' % (alarm, self.rtcpath))311 call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True)
276 def rtcWakeAlarmOff(self):312 def rtcWakeAlarmOff(self):
277 os.system('echo 0 > %s/wakealarm' % self.rtcpath)313 call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True)
278 def initdmesg(self):314 def initdmesg(self):
279 # get the latest time stamp from the dmesg log315 # get the latest time stamp from the dmesg log
280 fp = os.popen('dmesg')316 fp = Popen('dmesg', stdout=PIPE).stdout
281 ktime = '0'317 ktime = '0'
282 for line in fp:318 for line in fp:
283 line = line.replace('\r\n', '')319 line = line.replace('\r\n', '')
@@ -291,7 +327,7 @@ class SystemValues: · 7 unmodified lines
291 self.dmesgstart = float(ktime)327 self.dmesgstart = float(ktime)
292 def getdmesg(self):328 def getdmesg(self):
293 # store all new dmesg lines since initdmesg was called329 # store all new dmesg lines since initdmesg was called
294 fp = os.popen('dmesg')330 fp = Popen('dmesg', stdout=PIPE).stdout
295 op = open(self.dmesgfile, 'a')331 op = open(self.dmesgfile, 'a')
296 for line in fp:332 for line in fp:
297 line = line.replace('\r\n', '')333 line = line.replace('\r\n', '')
@@ -317,25 +353,18 @@ class SystemValues: · 19 unmodified lines
317 def getFtraceFilterFunctions(self, current):353 def getFtraceFilterFunctions(self, current):
318 rootCheck(True)354 rootCheck(True)
319 if not current:355 if not current:
320 os.system('cat '+self.tpath+'available_filter_functions')356 call('cat '+self.tpath+'available_filter_functions', shell=True)
321 return357 return
322 fp = open(self.tpath+'available_filter_functions')358 fp = open(self.tpath+'available_filter_functions')
323 master = fp.read().split('\n')359 master = fp.read().split('\n')
324 fp.close()360 fp.close()
325 if len(self.debugfuncs) > 0:361 for i in self.tracefuncs:
326 for i in self.debugfuncs:362 if 'func' in self.tracefuncs[i]:
327 if i in master:363 i = self.tracefuncs[i]['func']
328 print i364 if i in master:
329 else:365 print i
330 print self.colorText(i)366 else:
331 else:367 print self.colorText(i)
332 for i in self.tracefuncs:
333 if 'func' in self.tracefuncs[i]:
334 i = self.tracefuncs[i]['func']
335 if i in master:
336 print i
337 else:
338 print self.colorText(i)
339 def setFtraceFilterFunctions(self, list):368 def setFtraceFilterFunctions(self, list):
340 fp = open(self.tpath+'available_filter_functions')369 fp = open(self.tpath+'available_filter_functions')
341 master = fp.read().split('\n')370 master = fp.read().split('\n')
@@ -351,22 +380,15 @@ class SystemValues: · 9 unmodified lines
351 fp = open(self.tpath+'set_graph_function', 'w')380 fp = open(self.tpath+'set_graph_function', 'w')
352 fp.write(flist)381 fp.write(flist)
353 fp.close()382 fp.close()
354 def kprobeMatch(self, name, target):
355 if name not in self.kprobes:
356 return False
357 if re.match(self.kprobes[name]['mask'], target):
358 return True
359 return False
360 def basicKprobe(self, name):383 def basicKprobe(self, name):
361 self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name,'mask': name}384 self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name}
362 def defaultKprobe(self, name, kdata):385 def defaultKprobe(self, name, kdata):
363 k = kdata386 k = kdata
364 for field in ['name', 'format', 'mask', 'func']:387 for field in ['name', 'format', 'func']:
365 if field not in k:388 if field not in k:
366 k[field] = name389 k[field] = name
367 archargs = 'args_'+platform.machine()390 if self.archargs in k:
368 if archargs in k:391 k['args'] = k[self.archargs]
369 k['args'] = k[archargs]
370 else:392 else:
371 k['args'] = dict()393 k['args'] = dict()
372 k['format'] = name394 k['format'] = name
@@ -403,49 +425,80 @@ class SystemValues: · 30 unmodified lines
403 out = fmt.format(**arglist)425 out = fmt.format(**arglist)
404 out = out.replace(' ', '_').replace('"', '')426 out = out.replace(' ', '_').replace('"', '')
405 return out427 return out
406 def kprobeText(self, kprobe):428 def kprobeText(self, kname, kprobe):
407 name, fmt, func, args = kprobe['name'], kprobe['format'], kprobe['func'], kprobe['args']429 name = fmt = func = kname
430 args = dict()
431 if 'name' in kprobe:
432 name = kprobe['name']
433 if 'format' in kprobe:
434 fmt = kprobe['format']
435 if 'func' in kprobe:
436 func = kprobe['func']
437 if self.archargs in kprobe:
438 args = kprobe[self.archargs]
439 if 'args' in kprobe:
440 args = kprobe['args']
408 if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func):441 if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func):
409 doError('Kprobe "%s" has format info in the function name "%s"' % (name, func), False)442 doError('Kprobe "%s" has format info in the function name "%s"' % (name, func))
410 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt):443 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt):
411 if arg not in args:444 if arg not in args:
412 doError('Kprobe "%s" is missing argument "%s"' % (name, arg), False)445 doError('Kprobe "%s" is missing argument "%s"' % (name, arg))
413 val = 'p:%s_cal %s' % (name, func)446 val = 'p:%s_cal %s' % (name, func)
414 for i in sorted(args):447 for i in sorted(args):
415 val += ' %s=%s' % (i, args[i])448 val += ' %s=%s' % (i, args[i])
416 val += '\nr:%s_ret %s $retval\n' % (name, func)449 val += '\nr:%s_ret %s $retval\n' % (name, func)
417 return val450 return val
418 def addKprobes(self):451 def addKprobes(self, output=False):
452 if len(sysvals.kprobes) < 1:
453 return
454 if output:
455 print(' kprobe functions in this kernel:')
419 # first test each kprobe456 # first test each kprobe
420 print('INITIALIZING KPROBES...')
421 rejects = []457 rejects = []
458 # sort kprobes: trace, ub-dev, custom, dev
459 kpl = [[], [], [], []]
422 for name in sorted(self.kprobes):460 for name in sorted(self.kprobes):
423 if not self.testKprobe(self.kprobes[name]):461 res = self.colorText('YES', 32)
462 if not self.testKprobe(name, self.kprobes[name]):
463 res = self.colorText('NO')
424 rejects.append(name)464 rejects.append(name)
465 else:
466 if name in self.tracefuncs:
467 kpl[0].append(name)
468 elif name in self.dev_tracefuncs:
469 if 'ub' in self.dev_tracefuncs[name]:
470 kpl[1].append(name)
471 else:
472 kpl[3].append(name)
473 else:
474 kpl[2].append(name)
475 if output:
476 print(' %s: %s' % (name, res))
477 kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3]
425 # remove all failed ones from the list478 # remove all failed ones from the list
426 for name in rejects:479 for name in rejects:
427 vprint('Skipping KPROBE: %s' % name)
428 self.kprobes.pop(name)480 self.kprobes.pop(name)
481 # set the kprobes all at once
429 self.fsetVal('', 'kprobe_events')482 self.fsetVal('', 'kprobe_events')
430 kprobeevents = ''483 kprobeevents = ''
431 # set the kprobes all at once484 for kp in kplist:
432 for kp in self.kprobes:485 kprobeevents += self.kprobeText(kp, self.kprobes[kp])
433 val = self.kprobeText(self.kprobes[kp])
434 vprint('Adding KPROBE: %s\n%s' % (kp, val.strip()))
435 kprobeevents += self.kprobeText(self.kprobes[kp])
436 self.fsetVal(kprobeevents, 'kprobe_events')486 self.fsetVal(kprobeevents, 'kprobe_events')
437 # verify that the kprobes were set as ordered487 # verify that the kprobes were set as ordered
438 check = self.fgetVal('kprobe_events')488 check = self.fgetVal('kprobe_events')
439 linesout = len(kprobeevents.split('\n'))489 linesout = len(kprobeevents.split('\n')) - 1
440 linesack = len(check.split('\n'))490 linesack = len(check.split('\n')) - 1
441 if linesack < linesout:491 if output:
442 # if not, try appending the kprobes 1 by 1492 res = '%d/%d' % (linesack, linesout)
443 for kp in self.kprobes:493 if linesack < linesout:
444 kprobeevents = self.kprobeText(self.kprobes[kp])494 res = self.colorText(res, 31)
445 self.fsetVal(kprobeevents, 'kprobe_events', 'a')495 else:
496 res = self.colorText(res, 32)
497 print(' working kprobe functions enabled: %s' % res)
446 self.fsetVal('1', 'events/kprobes/enable')498 self.fsetVal('1', 'events/kprobes/enable')
447 def testKprobe(self, kprobe):499 def testKprobe(self, kname, kprobe):
448 kprobeevents = self.kprobeText(kprobe)500 self.fsetVal('0', 'events/kprobes/enable')
501 kprobeevents = self.kprobeText(kname, kprobe)
449 if not kprobeevents:502 if not kprobeevents:
450 return False503 return False
451 try:504 try:
@@ -463,8 +516,9 @@ class SystemValues: · 11 unmodified lines
463 if not os.path.exists(file):516 if not os.path.exists(file):
464 return False517 return False
465 try:518 try:
466 fp = open(file, mode)519 fp = open(file, mode, 0)
467 fp.write(val)520 fp.write(val)
521 fp.flush()
468 fp.close()522 fp.close()
469 except:523 except:
470 pass524 pass
@@ -491,21 +545,17 @@ class SystemValues: · 20 unmodified lines
491 for name in self.dev_tracefuncs:545 for name in self.dev_tracefuncs:
492 self.defaultKprobe(name, self.dev_tracefuncs[name])546 self.defaultKprobe(name, self.dev_tracefuncs[name])
493 def isCallgraphFunc(self, name):547 def isCallgraphFunc(self, name):
494 if len(self.debugfuncs) < 1 and self.suspendmode == 'command':548 if len(self.tracefuncs) < 1 and self.suspendmode == 'command':
495 return True
496 if name in self.debugfuncs:
497 return True549 return True
498 funclist = []
499 for i in self.tracefuncs:550 for i in self.tracefuncs:
500 if 'func' in self.tracefuncs[i]:551 if 'func' in self.tracefuncs[i]:
501 funclist.append(self.tracefuncs[i]['func'])552 f = self.tracefuncs[i]['func']
502 else:553 else:
503 funclist.append(i)554 f = i
504 if name in funclist:555 if name == f:
505 return True556 return True
506 return False557 return False
507 def initFtrace(self, testing=False):558 def initFtrace(self, testing=False):
508 tp = self.tpath
509 print('INITIALIZING FTRACE...')559 print('INITIALIZING FTRACE...')
510 # turn trace off560 # turn trace off
511 self.fsetVal('0', 'tracing_on')561 self.fsetVal('0', 'tracing_on')
@@ -518,18 +568,7 @@ class SystemValues: · 6 unmodified lines
518 # go no further if this is just a status check568 # go no further if this is just a status check
519 if testing:569 if testing:
520 return570 return
521 if self.usekprobes:571 # initialize the callgraph trace
522 # add tracefunc kprobes so long as were not using full callgraph
523 if(not self.usecallgraph or len(self.debugfuncs) > 0):
524 for name in self.tracefuncs:
525 self.defaultKprobe(name, self.tracefuncs[name])
526 if self.usedevsrc:
527 for name in self.dev_tracefuncs:
528 self.defaultKprobe(name, self.dev_tracefuncs[name])
529 else:
530 self.usedevsrc = False
531 self.addKprobes()
532 # initialize the callgraph trace, unless this is an x2 run
533 if(self.usecallgraph):572 if(self.usecallgraph):
534 # set trace type573 # set trace type
535 self.fsetVal('function_graph', 'current_tracer')574 self.fsetVal('function_graph', 'current_tracer')
@@ -545,20 +584,24 @@ class SystemValues: · 9 unmodified lines
545 self.fsetVal('context-info', 'trace_options')584 self.fsetVal('context-info', 'trace_options')
546 self.fsetVal('graph-time', 'trace_options')585 self.fsetVal('graph-time', 'trace_options')
547 self.fsetVal('0', 'max_graph_depth')586 self.fsetVal('0', 'max_graph_depth')
548 if len(self.debugfuncs) > 0:587 cf = ['dpm_run_callback']
549 self.setFtraceFilterFunctions(self.debugfuncs)588 if(self.usetraceeventsonly):
550 elif self.suspendmode == 'command':589 cf += ['dpm_prepare', 'dpm_complete']
551 self.fsetVal('', 'set_graph_function')590 for fn in self.tracefuncs:
552 else:591 if 'func' in self.tracefuncs[fn]:
553 cf = ['dpm_run_callback']592 cf.append(self.tracefuncs[fn]['func'])
554 if(self.usetraceeventsonly):593 else:
555 cf += ['dpm_prepare', 'dpm_complete']594 cf.append(fn)
556 for fn in self.tracefuncs:595 self.setFtraceFilterFunctions(cf)
557 if 'func' in self.tracefuncs[fn]:596 # initialize the kprobe trace
558 cf.append(self.tracefuncs[fn]['func'])597 elif self.usekprobes:
559 else:598 for name in self.tracefuncs:
560 cf.append(fn)599 self.defaultKprobe(name, self.tracefuncs[name])
561 self.setFtraceFilterFunctions(cf)600 if self.usedevsrc:
601 for name in self.dev_tracefuncs:
602 self.defaultKprobe(name, self.dev_tracefuncs[name])
603 print('INITIALIZING KPROBES...')
604 self.addKprobes(self.verbose)
562 if(self.usetraceevents):605 if(self.usetraceevents):
563 # turn trace events on606 # turn trace events on
564 events = iter(self.traceevents)607 events = iter(self.traceevents)
@@ -590,10 +633,10 @@ class SystemValues: · 25 unmodified lines
590 if(os.path.exists(tp+f) == False):633 if(os.path.exists(tp+f) == False):
591 return False634 return False
592 return True635 return True
593 def colorText(self, str):636 def colorText(self, str, color=31):
594 if not self.ansi:637 if not self.ansi:
595 return str638 return str
596 return '\x1B[31;40m'+str+'\x1B[m'639 return '\x1B[%d;40m%s\x1B[m' % (color, str)
597 640
598sysvals = SystemValues()641sysvals = SystemValues()
599 642
@@ -625,8 +668,8 @@ class DevProps: · 25 unmodified lines
625 if self.xtraclass:668 if self.xtraclass:
626 return ' '+self.xtraclass669 return ' '+self.xtraclass
627 if self.async:670 if self.async:
628 return ' async'671 return ' async_device'
629 return ' sync'672 return ' sync_device'
630 673
631# Class: DeviceNode674# Class: DeviceNode
632# Description:675# Description:
@@ -646,8 +689,6 @@ class DeviceNode: · 13 unmodified lines
646# The primary container for suspend/resume test data. There is one for689# The primary container for suspend/resume test data. There is one for
647# each test run. The data is organized into a cronological hierarchy:690# each test run. The data is organized into a cronological hierarchy:
648# Data.dmesg {691# Data.dmesg {
649# root structure, started as dmesg & ftrace, but now only ftrace
650# contents: times for suspend start/end, resume start/end, fwdata
651# phases {692# phases {
652# 10 sequential, non-overlapping phases of S/R693# 10 sequential, non-overlapping phases of S/R
653# contents: times for phase start/end, order/color data for html694# contents: times for phase start/end, order/color data for html
@@ -658,7 +699,7 @@ class DeviceNode: · 4 unmodified lines
658# contents: start/stop times, pid/cpu/driver info699# contents: start/stop times, pid/cpu/driver info
659# parents/children, html id for timeline/callgraph700# parents/children, html id for timeline/callgraph
660# optionally includes an ftrace callgraph701# optionally includes an ftrace callgraph
661# optionally includes intradev trace events702# optionally includes dev/ps data
662# }703# }
663# }704# }
664# }705# }
@@ -671,19 +712,24 @@ class Data: · 6 unmodified lines
671 end = 0.0 # test end712 end = 0.0 # test end
672 tSuspended = 0.0 # low-level suspend start713 tSuspended = 0.0 # low-level suspend start
673 tResumed = 0.0 # low-level resume start714 tResumed = 0.0 # low-level resume start
715 tKernSus = 0.0 # kernel level suspend start
716 tKernRes = 0.0 # kernel level resume end
674 tLow = 0.0 # time spent in low-level suspend (standby/freeze)717 tLow = 0.0 # time spent in low-level suspend (standby/freeze)
675 fwValid = False # is firmware data available718 fwValid = False # is firmware data available
676 fwSuspend = 0 # time spent in firmware suspend719 fwSuspend = 0 # time spent in firmware suspend
677 fwResume = 0 # time spent in firmware resume720 fwResume = 0 # time spent in firmware resume
678 dmesgtext = [] # dmesg text file in memory721 dmesgtext = [] # dmesg text file in memory
722 pstl = 0 # process timeline
679 testnumber = 0723 testnumber = 0
680 idstr = ''724 idstr = ''
681 html_device_id = 0725 html_device_id = 0
682 stamp = 0726 stamp = 0
683 outfile = ''727 outfile = ''
684 dev_ubiquitous = ['msleep', 'udelay']728 devpids = []
729 kerror = False
685 def __init__(self, num):730 def __init__(self, num):
686 idchar = 'abcdefghijklmnopqrstuvwxyz'731 idchar = 'abcdefghij'
732 self.pstl = dict()
687 self.testnumber = num733 self.testnumber = num
688 self.idstr = idchar[num]734 self.idstr = idchar[num]
689 self.dmesgtext = []735 self.dmesgtext = []
@@ -714,16 +760,39 @@ class Data: · 24 unmodified lines
714 self.devicegroups = []760 self.devicegroups = []
715 for phase in self.phases:761 for phase in self.phases:
716 self.devicegroups.append([phase])762 self.devicegroups.append([phase])
717 def getStart(self):763 self.errorinfo = {'suspend':[],'resume':[]}
718 return self.dmesg[self.phases[0]]['start']764 def extractErrorInfo(self, dmesg):
765 error = ''
766 tm = 0.0
767 for i in range(len(dmesg)):
768 if 'Call Trace:' in dmesg[i]:
769 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) .*', dmesg[i])
770 if not m:
771 continue
772 tm = float(m.group('ktime'))
773 if tm < self.start or tm > self.end:
774 continue
775 for j in range(i-10, i+1):
776 error += dmesg[j]
777 continue
778 if error:
779 m = re.match('[ \t]*\[ *[0-9\.]*\] \[\<[0-9a-fA-F]*\>\] .*', dmesg[i])
780 if m:
781 error += dmesg[i]
782 else:
783 if tm < self.tSuspended:
784 dir = 'suspend'
785 else:
786 dir = 'resume'
787 error = error.replace('<', '&lt').replace('>', '&gt')
788 vprint('kernel error found in %s at %f' % (dir, tm))
789 self.errorinfo[dir].append((tm, error))
790 self.kerror = True
791 error = ''
719 def setStart(self, time):792 def setStart(self, time):
720 self.start = time793 self.start = time
721 self.dmesg[self.phases[0]]['start'] = time
722 def getEnd(self):
723 return self.dmesg[self.phases[-1]]['end']
724 def setEnd(self, time):794 def setEnd(self, time):
725 self.end = time795 self.end = time
726 self.dmesg[self.phases[-1]]['end'] = time
727 def isTraceEventOutsideDeviceCalls(self, pid, time):796 def isTraceEventOutsideDeviceCalls(self, pid, time):
728 for phase in self.phases:797 for phase in self.phases:
729 list = self.dmesg[phase]['list']798 list = self.dmesg[phase]['list']
@@ -733,39 +802,67 @@ class Data: · 3 unmodified lines
733 time < d['end']):802 time < d['end']):
734 return False803 return False
735 return True804 return True
736 def targetDevice(self, phaselist, start, end, pid=-1):805 def sourcePhase(self, start):
806 for phase in self.phases:
807 pend = self.dmesg[phase]['end']
808 if start <= pend:
809 return phase
810 return 'resume_complete'
811 def sourceDevice(self, phaselist, start, end, pid, type):
737 tgtdev = ''812 tgtdev = ''
738 for phase in phaselist:813 for phase in phaselist:
739 list = self.dmesg[phase]['list']814 list = self.dmesg[phase]['list']
740 for devname in list:815 for devname in list:
741 dev = list[devname]816 dev = list[devname]
742 if(pid >= 0 and dev['pid'] != pid):817 # pid must match
818 if dev['pid'] != pid:
743 continue819 continue
744 devS = dev['start']820 devS = dev['start']
745 devE = dev['end']821 devE = dev['end']
746 if(start < devS or start >= devE or end <= devS or end > devE):822 if type == 'device':
747 continue823 # device target event is entirely inside the source boundary
824 if(start < devS or start >= devE or end <= devS or end > devE):
825 continue
826 elif type == 'thread':
827 # thread target event will expand the source boundary
828 if start < devS:
829 dev['start'] = start
830 if end > devE:
831 dev['end'] = end
748 tgtdev = dev832 tgtdev = dev
749 break833 break
750 return tgtdev834 return tgtdev
751 def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata):835 def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata):
752 machstart = self.dmesg['suspend_machine']['start']836 # try to place the call in a device
753 machend = self.dmesg['resume_machine']['end']837 tgtdev = self.sourceDevice(self.phases, start, end, pid, 'device')
754 tgtdev = self.targetDevice(self.phases, start, end, pid)838 # calls with device pids that occur outside device bounds are dropped
755 if not tgtdev and start >= machstart and end < machend:839 # TODO: include these somehow
756 # device calls in machine phases should be serial840 if not tgtdev and pid in self.devpids:
757 tgtdev = self.targetDevice(['suspend_machine', 'resume_machine'], start, end)841 return False
842 # try to place the call in a thread
758 if not tgtdev:843 if not tgtdev:
759 if 'scsi_eh' in proc:844 tgtdev = self.sourceDevice(self.phases, start, end, pid, 'thread')
760 self.newActionGlobal(proc, start, end, pid)845 # create new thread blocks, expand as new calls are found
761 self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata)846 if not tgtdev:
847 if proc == '<...>':
848 threadname = 'kthread-%d' % (pid)
762 else:849 else:
763 vprint('IGNORE: %s[%s](%d) [%f - %f] | %s | %s | %s' % (displayname, kprobename,850 threadname = '%s-%d' % (proc, pid)
764 pid, start, end, cdata, rdata, proc))851 tgtphase = self.sourcePhase(start)
852 self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '')
853 return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata)
854 # this should not happen
855 if not tgtdev:
856 vprint('[%f - %f] %s-%d %s %s %s' % \
857 (start, end, proc, pid, kprobename, cdata, rdata))
765 return False858 return False
766 # detail block fits within tgtdev859 # place the call data inside the src element of the tgtdev
767 if('src' not in tgtdev):860 if('src' not in tgtdev):
768 tgtdev['src'] = []861 tgtdev['src'] = []
862 dtf = sysvals.dev_tracefuncs
863 ubiquitous = False
864 if kprobename in dtf and 'ub' in dtf[kprobename]:
865 ubiquitous = True
769 title = cdata+' '+rdata866 title = cdata+' '+rdata
770 mstr = '\(.*\) *(?P<args>.*) *\((?P<caller>.*)\+.* arg1=(?P<ret>.*)'867 mstr = '\(.*\) *(?P<args>.*) *\((?P<caller>.*)\+.* arg1=(?P<ret>.*)'
771 m = re.match(mstr, title)868 m = re.match(mstr, title)
@@ -777,14 +874,81 @@ class Data: · 5 unmodified lines
777 r = ''874 r = ''
778 else:875 else:
779 r = 'ret=%s ' % r876 r = 'ret=%s ' % r
780 l = '%0.3fms' % ((end - start) * 1000)877 if ubiquitous and c in dtf and 'ub' in dtf[c]:
781 if kprobename in self.dev_ubiquitous:878 return False
782 title = '%s(%s) <- %s, %s(%s)' % (displayname, a, c, r, l)879 color = sysvals.kprobeColor(kprobename)
783 else:880 e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color)
784 title = '%s(%s) %s(%s)' % (displayname, a, r, l)
785 e = TraceEvent(title, kprobename, start, end - start)
786 tgtdev['src'].append(e)881 tgtdev['src'].append(e)
787 return True882 return True
883 def overflowDevices(self):
884 # get a list of devices that extend beyond the end of this test run
885 devlist = []
886 for phase in self.phases:
887 list = self.dmesg[phase]['list']
888 for devname in list:
889 dev = list[devname]
890 if dev['end'] > self.end:
891 devlist.append(dev)
892 return devlist
893 def mergeOverlapDevices(self, devlist):
894 # merge any devices that overlap devlist
895 for dev in devlist:
896 devname = dev['name']
897 for phase in self.phases:
898 list = self.dmesg[phase]['list']
899 if devname not in list:
900 continue
901 tdev = list[devname]
902 o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start'])
903 if o <= 0:
904 continue
905 dev['end'] = tdev['end']
906 if 'src' not in dev or 'src' not in tdev:
907 continue
908 dev['src'] += tdev['src']
909 del list[devname]
910 def usurpTouchingThread(self, name, dev):
911 # the caller test has priority of this thread, give it to him
912 for phase in self.phases:
913 list = self.dmesg[phase]['list']
914 if name in list:
915 tdev = list[name]
916 if tdev['start'] - dev['end'] < 0.1:
917 dev['end'] = tdev['end']
918 if 'src' not in dev:
919 dev['src'] = []
920 if 'src' in tdev:
921 dev['src'] += tdev['src']
922 del list[name]
923 break
924 def stitchTouchingThreads(self, testlist):
925 # merge any threads between tests that touch
926 for phase in self.phases:
927 list = self.dmesg[phase]['list']
928 for devname in list:
929 dev = list[devname]
930 if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']:
931 continue
932 for data in testlist:
933 data.usurpTouchingThread(devname, dev)
934 def optimizeDevSrc(self):
935 # merge any src call loops to reduce timeline size
936 for phase in self.phases:
937 list = self.dmesg[phase]['list']
938 for dev in list:
939 if 'src' not in list[dev]:
940 continue
941 src = list[dev]['src']
942 p = 0
943 for e in sorted(src, key=lambda event: event.time):
944 if not p or not e.repeat(p):
945 p = e
946 continue
947 # e is another iteration of p, move it into p
948 p.end = e.end
949 p.length = p.end - p.time
950 p.count += 1
951 src.remove(e)
788 def trimTimeVal(self, t, t0, dT, left):952 def trimTimeVal(self, t, t0, dT, left):
789 if left:953 if left:
790 if(t > t0):954 if(t > t0):
@@ -804,6 +968,8 @@ class Data: · 13 unmodified lines
804 self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left)968 self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left)
805 self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left)969 self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left)
806 self.start = self.trimTimeVal(self.start, t0, dT, left)970 self.start = self.trimTimeVal(self.start, t0, dT, left)
971 self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left)
972 self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left)
807 self.end = self.trimTimeVal(self.end, t0, dT, left)973 self.end = self.trimTimeVal(self.end, t0, dT, left)
808 for phase in self.phases:974 for phase in self.phases:
809 p = self.dmesg[phase]975 p = self.dmesg[phase]
@@ -832,36 +998,6 @@ class Data: · 22 unmodified lines
832 else:998 else:
833 self.trimTime(self.tSuspended, \999 self.trimTime(self.tSuspended, \
834 self.tResumed-self.tSuspended, False)1000 self.tResumed-self.tSuspended, False)
835 def newPhaseWithSingleAction(self, phasename, devname, start, end, color):
836 for phase in self.phases:
837 self.dmesg[phase]['order'] += 1
838 self.html_device_id += 1
839 devid = '%s%d' % (self.idstr, self.html_device_id)
840 list = dict()
841 list[devname] = \
842 {'start': start, 'end': end, 'pid': 0, 'par': '',
843 'length': (end-start), 'row': 0, 'id': devid, 'drv': '' };
844 self.dmesg[phasename] = \
845 {'list': list, 'start': start, 'end': end,
846 'row': 0, 'color': color, 'order': 0}
847 self.phases = self.sortedPhases()
848 def newPhase(self, phasename, start, end, color, order):
849 if(order < 0):
850 order = len(self.phases)
851 for phase in self.phases[order:]:
852 self.dmesg[phase]['order'] += 1
853 if(order > 0):
854 p = self.phases[order-1]
855 self.dmesg[p]['end'] = start
856 if(order < len(self.phases)):
857 p = self.phases[order]
858 self.dmesg[p]['start'] = end
859 list = dict()
860 self.dmesg[phasename] = \
861 {'list': list, 'start': start, 'end': end,
862 'row': 0, 'color': color, 'order': order}
863 self.phases = self.sortedPhases()
864 self.devicegroups.append([phasename])
865 def setPhase(self, phase, ktime, isbegin):1001 def setPhase(self, phase, ktime, isbegin):
866 if(isbegin):1002 if(isbegin):
867 self.dmesg[phase]['start'] = ktime1003 self.dmesg[phase]['start'] = ktime
@@ -881,7 +1017,7 @@ class Data: · 13 unmodified lines
881 for t in sorted(tmp):1017 for t in sorted(tmp):
882 slist.append(tmp[t])1018 slist.append(tmp[t])
883 return slist1019 return slist
884 def fixupInitcalls(self, phase, end):1020 def fixupInitcalls(self, phase):
885 # if any calls never returned, clip them at system resume end1021 # if any calls never returned, clip them at system resume end
886 phaselist = self.dmesg[phase]['list']1022 phaselist = self.dmesg[phase]['list']
887 for devname in phaselist:1023 for devname in phaselist:
@@ -893,37 +1029,23 @@ class Data: · 5 unmodified lines
893 break1029 break
894 vprint('%s (%s): callback didnt return' % (devname, phase))1030 vprint('%s (%s): callback didnt return' % (devname, phase))
895 def deviceFilter(self, devicefilter):1031 def deviceFilter(self, devicefilter):
896 # remove all by the relatives of the filter devnames
897 filter = []
898 for phase in self.phases:
899 list = self.dmesg[phase]['list']
900 for name in devicefilter:
901 dev = name
902 while(dev in list):
903 if(dev not in filter):
904 filter.append(dev)
905 dev = list[dev]['par']
906 children = self.deviceDescendants(name, phase)
907 for dev in children:
908 if(dev not in filter):
909 filter.append(dev)
910 for phase in self.phases:1032 for phase in self.phases:
911 list = self.dmesg[phase]['list']1033 list = self.dmesg[phase]['list']
912 rmlist = []1034 rmlist = []
913 for name in list:1035 for name in list:
914 pid = list[name]['pid']1036 keep = False
915 if(name not in filter and pid >= 0):1037 for filter in devicefilter:
1038 if filter in name or \
1039 ('drv' in list[name] and filter in list[name]['drv']):
1040 keep = True
1041 if not keep:
916 rmlist.append(name)1042 rmlist.append(name)
917 for name in rmlist:1043 for name in rmlist:
918 del list[name]1044 del list[name]
919 def fixupInitcallsThatDidntReturn(self):1045 def fixupInitcallsThatDidntReturn(self):
920 # if any calls never returned, clip them at system resume end1046 # if any calls never returned, clip them at system resume end
921 for phase in self.phases:1047 for phase in self.phases:
922 self.fixupInitcalls(phase, self.getEnd())1048 self.fixupInitcalls(phase)
923 def isInsideTimeline(self, start, end):
924 if(self.start <= start and self.end > start):
925 return True
926 return False
927 def phaseOverlap(self, phases):1049 def phaseOverlap(self, phases):
928 rmgroups = []1050 rmgroups = []
929 newgroup = []1051 newgroup = []
@@ -940,30 +1062,35 @@ class Data: · 10 unmodified lines
940 self.devicegroups.remove(group)1062 self.devicegroups.remove(group)
941 self.devicegroups.append(newgroup)1063 self.devicegroups.append(newgroup)
942 def newActionGlobal(self, name, start, end, pid=-1, color=''):1064 def newActionGlobal(self, name, start, end, pid=-1, color=''):
943 # if event starts before timeline start, expand timeline1065 # which phase is this device callback or action in
944 if(start < self.start):1066 targetphase = 'none'
945 self.setStart(start)
946 # if event ends after timeline end, expand the timeline
947 if(end > self.end):
948 self.setEnd(end)
949 # which phase is this device callback or action "in"
950 targetphase = "none"
951 htmlclass = ''1067 htmlclass = ''
952 overlap = 0.01068 overlap = 0.0
953 phases = []1069 phases = []
954 for phase in self.phases:1070 for phase in self.phases:
955 pstart = self.dmesg[phase]['start']1071 pstart = self.dmesg[phase]['start']
956 pend = self.dmesg[phase]['end']1072 pend = self.dmesg[phase]['end']
1073 # see if the action overlaps this phase
957 o = max(0, min(end, pend) - max(start, pstart))1074 o = max(0, min(end, pend) - max(start, pstart))
958 if o > 0:1075 if o > 0:
959 phases.append(phase)1076 phases.append(phase)
1077 # set the target phase to the one that overlaps most
960 if o > overlap:1078 if o > overlap:
961 if overlap > 0 and phase == 'post_resume':1079 if overlap > 0 and phase == 'post_resume':
962 continue1080 continue
963 targetphase = phase1081 targetphase = phase
964 overlap = o1082 overlap = o
1083 # if no target phase was found, pin it to the edge
1084 if targetphase == 'none':
1085 p0start = self.dmesg[self.phases[0]]['start']
1086 if start <= p0start:
1087 targetphase = self.phases[0]
1088 else:
1089 targetphase = self.phases[-1]
965 if pid == -2:1090 if pid == -2:
966 htmlclass = ' bg'1091 htmlclass = ' bg'
1092 elif pid == -3:
1093 htmlclass = ' ps'
967 if len(phases) > 1:1094 if len(phases) > 1:
968 htmlclass = ' bg'1095 htmlclass = ' bg'
969 self.phaseOverlap(phases)1096 self.phaseOverlap(phases)
@@ -985,29 +1112,13 @@ class Data: · 15 unmodified lines
985 while(name in list):1112 while(name in list):
986 name = '%s[%d]' % (origname, i)1113 name = '%s[%d]' % (origname, i)
987 i += 11114 i += 1
988 list[name] = {'start': start, 'end': end, 'pid': pid, 'par': parent,1115 list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid,
989 'length': length, 'row': 0, 'id': devid, 'drv': drv }1116 'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv }
990 if htmlclass:1117 if htmlclass:
991 list[name]['htmlclass'] = htmlclass1118 list[name]['htmlclass'] = htmlclass
992 if color:1119 if color:
993 list[name]['color'] = color1120 list[name]['color'] = color
994 return name1121 return name
995 def deviceIDs(self, devlist, phase):
996 idlist = []
997 list = self.dmesg[phase]['list']
998 for devname in list:
999 if devname in devlist:
1000 idlist.append(list[devname]['id'])
1001 return idlist
1002 def deviceParentID(self, devname, phase):
1003 pdev = ''
1004 pdevid = ''
1005 list = self.dmesg[phase]['list']
1006 if devname in list:
1007 pdev = list[devname]['par']
1008 if pdev in list:
1009 return list[pdev]['id']
1010 return pdev
1011 def deviceChildren(self, devname, phase):1122 def deviceChildren(self, devname, phase):
1012 devlist = []1123 devlist = []
1013 list = self.dmesg[phase]['list']1124 list = self.dmesg[phase]['list']
@@ -1015,21 +1126,15 @@ class Data: · 1 unmodified line
1015 if(list[child]['par'] == devname):1126 if(list[child]['par'] == devname):
1016 devlist.append(child)1127 devlist.append(child)
1017 return devlist1128 return devlist
1018 def deviceDescendants(self, devname, phase):
1019 children = self.deviceChildren(devname, phase)
1020 family = children
1021 for child in children:
1022 family += self.deviceDescendants(child, phase)
1023 return family
1024 def deviceChildrenIDs(self, devname, phase):
1025 devlist = self.deviceChildren(devname, phase)
1026 return self.deviceIDs(devlist, phase)
1027 def printDetails(self):1129 def printDetails(self):
1130 vprint('Timeline Details:')
1028 vprint(' test start: %f' % self.start)1131 vprint(' test start: %f' % self.start)
1132 vprint('kernel suspend start: %f' % self.tKernSus)
1029 for phase in self.phases:1133 for phase in self.phases:
1030 dc = len(self.dmesg[phase]['list'])1134 dc = len(self.dmesg[phase]['list'])
1031 vprint(' %16s: %f - %f (%d devices)' % (phase, \1135 vprint(' %16s: %f - %f (%d devices)' % (phase, \
1032 self.dmesg[phase]['start'], self.dmesg[phase]['end'], dc))1136 self.dmesg[phase]['start'], self.dmesg[phase]['end'], dc))
1137 vprint(' kernel resume end: %f' % self.tKernRes)
1033 vprint(' test end: %f' % self.end)1138 vprint(' test end: %f' % self.end)
1034 def deviceChildrenAllPhases(self, devname):1139 def deviceChildrenAllPhases(self, devname):
1035 devlist = []1140 devlist = []
@@ -1108,21 +1213,134 @@ class Data: · 72 unmodified lines
1108 if width != '0.000000' and length >= mindevlen:1213 if width != '0.000000' and length >= mindevlen:
1109 devlist.append(dev)1214 devlist.append(dev)
1110 self.tdevlist[phase] = devlist1215 self.tdevlist[phase] = devlist
1111 1216 def addHorizontalDivider(self, devname, devend):
1112# Class: TraceEvent1217 phase = 'suspend_prepare'
1218 self.newAction(phase, devname, -2, '', \
1219 self.start, devend, '', ' sec', '')
1220 if phase not in self.tdevlist:
1221 self.tdevlist[phase] = []
1222 self.tdevlist[phase].append(devname)
1223 d = DevItem(0, phase, self.dmesg[phase]['list'][devname])
1224 return d
1225 def addProcessUsageEvent(self, name, times):
1226 # get the start and end times for this process
1227 maxC = 0
1228 tlast = 0
1229 start = -1
1230 end = -1
1231 for t in sorted(times):
1232 if tlast == 0:
1233 tlast = t
1234 continue
1235 if name in self.pstl[t]:
1236 if start == -1 or tlast < start:
1237 start = tlast
1238 if end == -1 or t > end:
1239 end = t
1240 tlast = t
1241 if start == -1 or end == -1:
1242 return 0
1243 # add a new action for this process and get the object
1244 out = self.newActionGlobal(name, start, end, -3)
1245 if not out:
1246 return 0
1247 phase, devname = out
1248 dev = self.dmesg[phase]['list'][devname]
1249 # get the cpu exec data
1250 tlast = 0
1251 clast = 0
1252 cpuexec = dict()
1253 for t in sorted(times):
1254 if tlast == 0 or t <= start or t > end:
1255 tlast = t
1256 continue
1257 list = self.pstl[t]
1258 c = 0
1259 if name in list:
1260 c = list[name]
1261 if c > maxC:
1262 maxC = c
1263 if c != clast:
1264 key = (tlast, t)
1265 cpuexec[key] = c
1266 tlast = t
1267 clast = c
1268 dev['cpuexec'] = cpuexec
1269 return maxC
1270 def createProcessUsageEvents(self):
1271 # get an array of process names
1272 proclist = []
1273 for t in self.pstl:
1274 pslist = self.pstl[t]
1275 for ps in pslist:
1276 if ps not in proclist:
1277 proclist.append(ps)
1278 # get a list of data points for suspend and resume
1279 tsus = []
1280 tres = []
1281 for t in sorted(self.pstl):
1282 if t < self.tSuspended:
1283 tsus.append(t)
1284 else:
1285 tres.append(t)
1286 # process the events for suspend and resume
1287 if len(proclist) > 0:
1288 vprint('Process Execution:')
1289 for ps in proclist:
1290 c = self.addProcessUsageEvent(ps, tsus)
1291 if c > 0:
1292 vprint('%25s (sus): %d' % (ps, c))
1293 c = self.addProcessUsageEvent(ps, tres)
1294 if c > 0:
1295 vprint('%25s (res): %d' % (ps, c))
1296
1297# Class: DevFunction
1113# Description:1298# Description:
1114# A container for trace event data found in the ftrace file1299# A container for kprobe function data we want in the dev timeline
1115class TraceEvent:1300class DevFunction:
1116 text = ''
1117 time = 0.0
1118 length = 0.0
1119 title = ''
1120 row = 01301 row = 0
1121 def __init__(self, a, n, t, l):1302 count = 1
1122 self.title = a1303 def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color):
1123 self.text = n1304 self.name = name
1124 self.time = t1305 self.args = args
1125 self.length = l1306 self.caller = caller
1307 self.ret = ret
1308 self.time = start
1309 self.length = end - start
1310 self.end = end
1311 self.ubiquitous = u
1312 self.proc = proc
1313 self.pid = pid
1314 self.color = color
1315 def title(self):
1316 cnt = ''
1317 if self.count > 1:
1318 cnt = '(x%d)' % self.count
1319 l = '%0.3fms' % (self.length * 1000)
1320 if self.ubiquitous:
1321 title = '%s(%s)%s <- %s, %s(%s)' % \
1322 (self.name, self.args, cnt, self.caller, self.ret, l)
1323 else:
1324 title = '%s(%s) %s%s(%s)' % (self.name, self.args, self.ret, cnt, l)
1325 return title.replace('"', '')
1326 def text(self):
1327 if self.count > 1:
1328 text = '%s(x%d)' % (self.name, self.count)
1329 else:
1330 text = self.name
1331 return text
1332 def repeat(self, tgt):
1333 # is the tgt call just a repeat of this call (e.g. are we in a loop)
1334 dt = self.time - tgt.end
1335 # only combine calls if -all- attributes are identical
1336 if tgt.caller == self.caller and \
1337 tgt.name == self.name and tgt.args == self.args and \
1338 tgt.proc == self.proc and tgt.pid == self.pid and \
1339 tgt.ret == self.ret and dt >= 0 and \
1340 dt <= sysvals.callloopmaxgap and \
1341 self.length < sysvals.callloopmaxlen:
1342 return True
1343 return False
1126 1344
1127# Class: FTraceLine1345# Class: FTraceLine
1128# Description:1346# Description:
@@ -1226,7 +1444,6 @@ class FTraceLine: · 97 unmodified lines
1226 print('%s -- %f (%02d): %s() { (%.3f us)' % (dev, self.time, \1444 print('%s -- %f (%02d): %s() { (%.3f us)' % (dev, self.time, \
1227 self.depth, self.name, self.length*1000000))1445 self.depth, self.name, self.length*1000000))
1228 def startMarker(self):1446 def startMarker(self):
1229 global sysvals
1230 # Is this the starting line of a suspend?1447 # Is this the starting line of a suspend?
1231 if not self.fevent:1448 if not self.fevent:
1232 return False1449 return False
@@ -1506,6 +1723,16 @@ class FTraceCallGraph: · 273 unmodified lines
1506 l.depth, l.name, l.length*1000000))1723 l.depth, l.name, l.length*1000000))
1507 print(' ')1724 print(' ')
1508 1725
1726class DevItem:
1727 def __init__(self, test, phase, dev):
1728 self.test = test
1729 self.phase = phase
1730 self.dev = dev
1731 def isa(self, cls):
1732 if 'htmlclass' in self.dev and cls in self.dev['htmlclass']:
1733 return True
1734 return False
1735
1509# Class: Timeline1736# Class: Timeline
1510# Description:1737# Description:
1511# A container for a device timeline which calculates1738# A container for a device timeline which calculates
@@ -1517,12 +1744,11 @@ class Timeline: · 5 unmodified lines
1517 rowH = 30 # device row height1744 rowH = 30 # device row height
1518 bodyH = 0 # body height1745 bodyH = 0 # body height
1519 rows = 0 # total timeline rows1746 rows = 0 # total timeline rows
1520 phases = []1747 rowlines = dict()
1521 rowmaxlines = dict()
1522 rowcount = dict()
1523 rowheight = dict()1748 rowheight = dict()
1524 def __init__(self, rowheight):1749 def __init__(self, rowheight, scaleheight):
1525 self.rowH = rowheight1750 self.rowH = rowheight
1751 self.scaleH = scaleheight
1526 self.html = {1752 self.html = {
1527 'header': '',1753 'header': '',
1528 'timeline': '',1754 'timeline': '',
@@ -1537,21 +1763,19 @@ class Timeline: · 8 unmodified lines
1537 # The total number of rows needed to display this phase of the timeline1763 # The total number of rows needed to display this phase of the timeline
1538 def getDeviceRows(self, rawlist):1764 def getDeviceRows(self, rawlist):
1539 # clear all rows and set them to undefined1765 # clear all rows and set them to undefined
1540 lendict = dict()1766 sortdict = dict()
1541 for item in rawlist:1767 for item in rawlist:
1542 item.row = -11768 item.row = -1
1543 lendict[item] = item.length1769 sortdict[item] = item.length
1544 list = []1770 sortlist = sorted(sortdict, key=sortdict.get, reverse=True)
1545 for i in sorted(lendict, key=lendict.get, reverse=True):1771 remaining = len(sortlist)
1546 list.append(i)
1547 remaining = len(list)
1548 rowdata = dict()1772 rowdata = dict()
1549 row = 11773 row = 1
1550 # try to pack each row with as many ranges as possible1774 # try to pack each row with as many ranges as possible
1551 while(remaining > 0):1775 while(remaining > 0):
1552 if(row not in rowdata):1776 if(row not in rowdata):
1553 rowdata[row] = []1777 rowdata[row] = []
1554 for i in list:1778 for i in sortlist:
1555 if(i.row >= 0):1779 if(i.row >= 0):
1556 continue1780 continue
1557 s = i.time1781 s = i.time
@@ -1575,81 +1799,86 @@ class Timeline: · 17 unmodified lines
1575 # Organize the timeline entries into the smallest1799 # Organize the timeline entries into the smallest
1576 # number of rows possible, with no entry overlapping1800 # number of rows possible, with no entry overlapping
1577 # Arguments:1801 # Arguments:
1578 # list: the list of devices/actions for a single phase1802 # devlist: the list of devices/actions in a group of contiguous phases
1579 # devlist: string list of device names to use
1580 # Output:1803 # Output:
1581 # The total number of rows needed to display this phase of the timeline1804 # The total number of rows needed to display this phase of the timeline
1582 def getPhaseRows(self, dmesg, devlist):1805 def getPhaseRows(self, devlist, row=0):
1583 # clear all rows and set them to undefined1806 # clear all rows and set them to undefined
1584 remaining = len(devlist)1807 remaining = len(devlist)
1585 rowdata = dict()1808 rowdata = dict()
1586 row = 01809 sortdict = dict()
1587 lendict = dict()
1588 myphases = []1810 myphases = []
1811 # initialize all device rows to -1 and calculate devrows
1589 for item in devlist:1812 for item in devlist:
1590 if item[0] not in self.phases:1813 dev = item.dev
1591 self.phases.append(item[0])1814 tp = (item.test, item.phase)
1592 if item[0] not in myphases:1815 if tp not in myphases:
1593 myphases.append(item[0])1816 myphases.append(tp)
1594 self.rowmaxlines[item[0]] = dict()
1595 self.rowheight[item[0]] = dict()
1596 dev = dmesg[item[0]]['list'][item[1]]
1597 dev['row'] = -11817 dev['row'] = -1
1598 lendict[item] = float(dev['end']) - float(dev['start'])1818 # sort by length 1st, then name 2nd
1819 sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name'])
1599 if 'src' in dev:1820 if 'src' in dev:
1600 dev['devrows'] = self.getDeviceRows(dev['src'])1821 dev['devrows'] = self.getDeviceRows(dev['src'])
1601 lenlist = []1822 # sort the devlist by length so that large items graph on top
1602 for i in sorted(lendict, key=lendict.get, reverse=True):1823 sortlist = sorted(sortdict, key=sortdict.get, reverse=True)
1603 lenlist.append(i)
1604 orderedlist = []1824 orderedlist = []
1605 for item in lenlist:1825 for item in sortlist:
1606 dev = dmesg[item[0]]['list'][item[1]]1826 if item.dev['pid'] == -2:
1607 if dev['pid'] == -2:
1608 orderedlist.append(item)1827 orderedlist.append(item)
1609 for item in lenlist:1828 for item in sortlist:
1610 if item not in orderedlist:1829 if item not in orderedlist:
1611 orderedlist.append(item)1830 orderedlist.append(item)
1612 # try to pack each row with as many ranges as possible1831 # try to pack each row with as many devices as possible
1613 while(remaining > 0):1832 while(remaining > 0):
1614 rowheight = 11833 rowheight = 1
1615 if(row not in rowdata):1834 if(row not in rowdata):
1616 rowdata[row] = []1835 rowdata[row] = []
1617 for item in orderedlist:1836 for item in orderedlist:
1618 dev = dmesg[item[0]]['list'][item[1]]1837 dev = item.dev
1619 if(dev['row'] < 0):1838 if(dev['row'] < 0):
1620 s = dev['start']1839 s = dev['start']
1621 e = dev['end']1840 e = dev['end']
1622 valid = True1841 valid = True
1623 for ritem in rowdata[row]:1842 for ritem in rowdata[row]:
1624 rs = ritem['start']1843 rs = ritem.dev['start']
1625 re = ritem['end']1844 re = ritem.dev['end']
1626 if(not (((s <= rs) and (e <= rs)) or1845 if(not (((s <= rs) and (e <= rs)) or
1627 ((s >= re) and (e >= re)))):1846 ((s >= re) and (e >= re)))):
1628 valid = False1847 valid = False
1629 break1848 break
1630 if(valid):1849 if(valid):
1631 rowdata[row].append(dev)1850 rowdata[row].append(item)
1632 dev['row'] = row1851 dev['row'] = row
1633 remaining -= 11852 remaining -= 1
1634 if 'devrows' in dev and dev['devrows'] > rowheight:1853 if 'devrows' in dev and dev['devrows'] > rowheight:
1635 rowheight = dev['devrows']1854 rowheight = dev['devrows']
1636 for phase in myphases:1855 for t, p in myphases:
1637 self.rowmaxlines[phase][row] = rowheight1856 if t not in self.rowlines or t not in self.rowheight:
1638 self.rowheight[phase][row] = rowheight * self.rowH1857 self.rowlines[t] = dict()
1858 self.rowheight[t] = dict()
1859 if p not in self.rowlines[t] or p not in self.rowheight[t]:
1860 self.rowlines[t][p] = dict()
1861 self.rowheight[t][p] = dict()
1862 rh = self.rowH
1863 # section headers should use a different row height
1864 if len(rowdata[row]) == 1 and \
1865 'htmlclass' in rowdata[row][0].dev and \
1866 'sec' in rowdata[row][0].dev['htmlclass']:
1867 rh = 15
1868 self.rowlines[t][p][row] = rowheight
1869 self.rowheight[t][p][row] = rowheight * rh
1639 row += 11870 row += 1
1640 if(row > self.rows):1871 if(row > self.rows):
1641 self.rows = int(row)1872 self.rows = int(row)
1642 for phase in myphases:
1643 self.rowcount[phase] = row
1644 return row1873 return row
1645 def phaseRowHeight(self, phase, row):1874 def phaseRowHeight(self, test, phase, row):
1646 return self.rowheight[phase][row]1875 return self.rowheight[test][phase][row]
1647 def phaseRowTop(self, phase, row):1876 def phaseRowTop(self, test, phase, row):
1648 top = 01877 top = 0
1649 for i in sorted(self.rowheight[phase]):1878 for i in sorted(self.rowheight[test][phase]):
1650 if i >= row:1879 if i >= row:
1651 break1880 break
1652 top += self.rowheight[phase][i]1881 top += self.rowheight[test][phase][i]
1653 return top1882 return top
1654 # Function: calcTotalRows1883 # Function: calcTotalRows
1655 # Description:1884 # Description:
@@ -1657,19 +1886,21 @@ class Timeline: · 1 unmodified line
1657 def calcTotalRows(self):1886 def calcTotalRows(self):
1658 maxrows = 01887 maxrows = 0
1659 standardphases = []1888 standardphases = []
1660 for phase in self.phases:1889 for t in self.rowlines:
1661 total = 01890 for p in self.rowlines[t]:
1662 for i in sorted(self.rowmaxlines[phase]):1891 total = 0
1663 total += self.rowmaxlines[phase][i]1892 for i in sorted(self.rowlines[t][p]):
1664 if total > maxrows:1893 total += self.rowlines[t][p][i]
1665 maxrows = total1894 if total > maxrows:
1666 if total == self.rowcount[phase]:1895 maxrows = total
1667 standardphases.append(phase)1896 if total == len(self.rowlines[t][p]):
1897 standardphases.append((t, p))
1668 self.height = self.scaleH + (maxrows*self.rowH)1898 self.height = self.scaleH + (maxrows*self.rowH)
1669 self.bodyH = self.height - self.scaleH1899 self.bodyH = self.height - self.scaleH
1670 for phase in standardphases:1900 # if there is 1 line per row, draw them the standard way
1671 for i in sorted(self.rowheight[phase]):1901 for t, p in standardphases:
1672 self.rowheight[phase][i] = self.bodyH/self.rowcount[phase]1902 for i in sorted(self.rowheight[t][p]):
1903 self.rowheight[t][p][i] = self.bodyH/len(self.rowlines[t][p])
1673 # Function: createTimeScale1904 # Function: createTimeScale
1674 # Description:1905 # Description:
1675 # Create the timescale for a timeline block1906 # Create the timescale for a timeline block
@@ -1716,7 +1947,6 @@ class Timeline: · 40 unmodified lines
1716# A list of values describing the properties of these test runs1947# A list of values describing the properties of these test runs
1717class TestProps:1948class TestProps:
1718 stamp = ''1949 stamp = ''
1719 tracertype = ''
1720 S0i3 = False1950 S0i3 = False
1721 fwdata = []1951 fwdata = []
1722 ftrace_line_fmt_fg = \1952 ftrace_line_fmt_fg = \
@@ -1734,14 +1964,13 @@ class TestProps: · 11 unmodified lines
1734 def __init__(self):1964 def __init__(self):
1735 self.ktemp = dict()1965 self.ktemp = dict()
1736 def setTracerType(self, tracer):1966 def setTracerType(self, tracer):
1737 self.tracertype = tracer
1738 if(tracer == 'function_graph'):1967 if(tracer == 'function_graph'):
1739 self.cgformat = True1968 self.cgformat = True
1740 self.ftrace_line_fmt = self.ftrace_line_fmt_fg1969 self.ftrace_line_fmt = self.ftrace_line_fmt_fg
1741 elif(tracer == 'nop'):1970 elif(tracer == 'nop'):
1742 self.ftrace_line_fmt = self.ftrace_line_fmt_nop1971 self.ftrace_line_fmt = self.ftrace_line_fmt_nop
1743 else:1972 else:
1744 doError('Invalid tracer format: [%s]' % tracer, False)1973 doError('Invalid tracer format: [%s]' % tracer)
1745 1974
1746# Class: TestRun1975# Class: TestRun
1747# Description:1976# Description:
@@ -1756,6 +1985,51 @@ class TestRun: · 8 unmodified lines
1756 self.ftemp = dict()1985 self.ftemp = dict()
1757 self.ttemp = dict()1986 self.ttemp = dict()
1758 1987
1988class ProcessMonitor:
1989 proclist = dict()
1990 running = False
1991 def procstat(self):
1992 c = ['cat /proc/[1-9]*/stat 2>/dev/null']
1993 process = Popen(c, shell=True, stdout=PIPE)
1994 running = dict()
1995 for line in process.stdout:
1996 data = line.split()
1997 pid = data[0]
1998 name = re.sub('[()]', '', data[1])
1999 user = int(data[13])
2000 kern = int(data[14])
2001 kjiff = ujiff = 0
2002 if pid not in self.proclist:
2003 self.proclist[pid] = {'name' : name, 'user' : user, 'kern' : kern}
2004 else:
2005 val = self.proclist[pid]
2006 ujiff = user - val['user']
2007 kjiff = kern - val['kern']
2008 val['user'] = user
2009 val['kern'] = kern
2010 if ujiff > 0 or kjiff > 0:
2011 running[pid] = ujiff + kjiff
2012 result = process.wait()
2013 out = ''
2014 for pid in running:
2015 jiffies = running[pid]
2016 val = self.proclist[pid]
2017 if out:
2018 out += ','
2019 out += '%s-%s %d' % (val['name'], pid, jiffies)
2020 return 'ps - '+out
2021 def processMonitor(self, tid):
2022 while self.running:
2023 out = self.procstat()
2024 if out:
2025 sysvals.fsetVal(out, 'trace_marker')
2026 def start(self):
2027 self.thread = Thread(target=self.processMonitor, args=(0,))
2028 self.running = True
2029 self.thread.start()
2030 def stop(self):
2031 self.running = False
2032
1759# ----------------- FUNCTIONS --------------------2033# ----------------- FUNCTIONS --------------------
1760 2034
1761# Function: vprint2035# Function: vprint
@@ -1764,7 +2038,7 @@ class TestRun: · 2 unmodified lines
1764# Arguments:2038# Arguments:
1765# msg: the debug/log message to print2039# msg: the debug/log message to print
1766def vprint(msg):2040def vprint(msg):
1767 global sysvals2041 sysvals.logmsg += msg+'\n'
1768 if(sysvals.verbose):2042 if(sysvals.verbose):
1769 print(msg)2043 print(msg)
1770 2044
@@ -1775,8 +2049,6 @@ def vprint(msg): · 4 unmodified lines
1775# Arguments:2049# Arguments:
1776# m: the valid re.match output for the stamp line2050# m: the valid re.match output for the stamp line
1777def parseStamp(line, data):2051def parseStamp(line, data):
1778 global sysvals
1779
1780 m = re.match(sysvals.stampfmt, line)2052 m = re.match(sysvals.stampfmt, line)
1781 data.stamp = {'time': '', 'host': '', 'mode': ''}2053 data.stamp = {'time': '', 'host': '', 'mode': ''}
1782 dt = datetime(int(m.group('y'))+2000, int(m.group('m')),2054 dt = datetime(int(m.group('y'))+2000, int(m.group('m')),
@@ -1788,6 +2060,14 @@ def parseStamp(line, data): · 5 unmodified lines
1788 data.stamp['kernel'] = m.group('kernel')2060 data.stamp['kernel'] = m.group('kernel')
1789 sysvals.hostname = data.stamp['host']2061 sysvals.hostname = data.stamp['host']
1790 sysvals.suspendmode = data.stamp['mode']2062 sysvals.suspendmode = data.stamp['mode']
2063 if sysvals.suspendmode == 'command' and sysvals.ftracefile != '':
2064 modes = ['on', 'freeze', 'standby', 'mem']
2065 out = Popen(['grep', 'suspend_enter', sysvals.ftracefile],
2066 stderr=PIPE, stdout=PIPE).stdout.read()
2067 m = re.match('.* suspend_enter\[(?P<mode>.*)\]', out)
2068 if m and m.group('mode') in ['1', '2', '3']:
2069 sysvals.suspendmode = modes[int(m.group('mode'))]
2070 data.stamp['mode'] = sysvals.suspendmode
1791 if not sysvals.stamp:2071 if not sysvals.stamp:
1792 sysvals.stamp = data.stamp2072 sysvals.stamp = data.stamp
1793 2073
@@ -1817,18 +2097,17 @@ def diffStamp(stamp1, stamp2): · 23 unmodified lines
1817# required for primary parsing. Set the usetraceevents and/or2097# required for primary parsing. Set the usetraceevents and/or
1818# usetraceeventsonly flags in the global sysvals object2098# usetraceeventsonly flags in the global sysvals object
1819def doesTraceLogHaveTraceEvents():2099def doesTraceLogHaveTraceEvents():
1820 global sysvals
1821
1822 # check for kprobes2100 # check for kprobes
1823 sysvals.usekprobes = False2101 sysvals.usekprobes = False
1824 out = os.system('grep -q "_cal: (" '+sysvals.ftracefile)2102 out = call('grep -q "_cal: (" '+sysvals.ftracefile, shell=True)
1825 if(out == 0):2103 if(out == 0):
1826 sysvals.usekprobes = True2104 sysvals.usekprobes = True
1827 # check for callgraph data on trace event blocks2105 # check for callgraph data on trace event blocks
1828 out = os.system('grep -q "_cpu_down()" '+sysvals.ftracefile)2106 out = call('grep -q "_cpu_down()" '+sysvals.ftracefile, shell=True)
1829 if(out == 0):2107 if(out == 0):
1830 sysvals.usekprobes = True2108 sysvals.usekprobes = True
1831 out = os.popen('head -1 '+sysvals.ftracefile).read().replace('\n', '')2109 out = Popen(['head', '-1', sysvals.ftracefile],
2110 stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
1832 m = re.match(sysvals.stampfmt, out)2111 m = re.match(sysvals.stampfmt, out)
1833 if m and m.group('mode') == 'command':2112 if m and m.group('mode') == 'command':
1834 sysvals.usetraceeventsonly = True2113 sysvals.usetraceeventsonly = True
@@ -1838,14 +2117,14 @@ def doesTraceLogHaveTraceEvents(): · 3 unmodified lines
1838 sysvals.usetraceeventsonly = True2117 sysvals.usetraceeventsonly = True
1839 sysvals.usetraceevents = False2118 sysvals.usetraceevents = False
1840 for e in sysvals.traceevents:2119 for e in sysvals.traceevents:
1841 out = os.system('grep -q "'+e+': " '+sysvals.ftracefile)2120 out = call('grep -q "'+e+': " '+sysvals.ftracefile, shell=True)
1842 if(out != 0):2121 if(out != 0):
1843 sysvals.usetraceeventsonly = False2122 sysvals.usetraceeventsonly = False
1844 if(e == 'suspend_resume' and out == 0):2123 if(e == 'suspend_resume' and out == 0):
1845 sysvals.usetraceevents = True2124 sysvals.usetraceevents = True
1846 # determine is this log is properly formatted2125 # determine is this log is properly formatted
1847 for e in ['SUSPEND START', 'RESUME COMPLETE']:2126 for e in ['SUSPEND START', 'RESUME COMPLETE']:
1848 out = os.system('grep -q "'+e+'" '+sysvals.ftracefile)2127 out = call('grep -q "'+e+'" '+sysvals.ftracefile, shell=True)
1849 if(out != 0):2128 if(out != 0):
1850 sysvals.usetracemarkers = False2129 sysvals.usetracemarkers = False
1851 2130
@@ -1860,8 +2139,6 @@ def doesTraceLogHaveTraceEvents(): · 8 unmodified lines
1860# Arguments:2139# Arguments:
1861# testruns: the array of Data objects obtained from parseKernelLog2140# testruns: the array of Data objects obtained from parseKernelLog
1862def appendIncompleteTraceLog(testruns):2141def appendIncompleteTraceLog(testruns):
1863 global sysvals
1864
1865 # create TestRun vessels for ftrace parsing2142 # create TestRun vessels for ftrace parsing
1866 testcnt = len(testruns)2143 testcnt = len(testruns)
1867 testidx = 02144 testidx = 0
@@ -2052,8 +2329,7 @@ def appendIncompleteTraceLog(testruns): · 184 unmodified lines
2052 dev['ftrace'] = cg2329 dev['ftrace'] = cg
2053 break2330 break
2054 2331
2055 if(sysvals.verbose):2332 test.data.printDetails()
2056 test.data.printDetails()
2057 2333
2058# Function: parseTraceLog2334# Function: parseTraceLog
2059# Description:2335# Description:
@@ -2064,14 +2340,12 @@ def appendIncompleteTraceLog(testruns): · 4 unmodified lines
2064# Output:2340# Output:
2065# An array of Data objects2341# An array of Data objects
2066def parseTraceLog():2342def parseTraceLog():
2067 global sysvals
2068
2069 vprint('Analyzing the ftrace data...')2343 vprint('Analyzing the ftrace data...')
2070 if(os.path.exists(sysvals.ftracefile) == False):2344 if(os.path.exists(sysvals.ftracefile) == False):
2071 doError('%s does not exist' % sysvals.ftracefile, False)2345 doError('%s does not exist' % sysvals.ftracefile)
2072 2346
2073 sysvals.setupAllKprobes()2347 sysvals.setupAllKprobes()
2074 tracewatch = ['suspend_enter']2348 tracewatch = []
2075 if sysvals.usekprobes:2349 if sysvals.usekprobes:
2076 tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend',2350 tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend',
2077 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 'CPU_OFF']2351 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 'CPU_OFF']
@@ -2102,17 +2376,13 @@ def parseTraceLog(): · 24 unmodified lines
2102 if(m):2376 if(m):
2103 tp.setTracerType(m.group('t'))2377 tp.setTracerType(m.group('t'))
2104 continue2378 continue
2105 # post resume time line: did this test run include post-resume data
2106 m = re.match(sysvals.postresumefmt, line)
2107 if(m):
2108 t = int(m.group('t'))
2109 if(t > 0):
2110 sysvals.postresumetime = t
2111 continue
2112 # device properties line2379 # device properties line
2113 if(re.match(sysvals.devpropfmt, line)):2380 if(re.match(sysvals.devpropfmt, line)):
2114 devProps(line)2381 devProps(line)
2115 continue2382 continue
2383 # ignore all other commented lines
2384 if line[0] == '#':
2385 continue
2116 # ftrace line: parse only valid lines2386 # ftrace line: parse only valid lines
2117 m = re.match(tp.ftrace_line_fmt, line)2387 m = re.match(tp.ftrace_line_fmt, line)
2118 if(not m):2388 if(not m):
@@ -2142,20 +2412,36 @@ def parseTraceLog(): · 23 unmodified lines
2142 testrun = TestRun(data)2412 testrun = TestRun(data)
2143 testruns.append(testrun)2413 testruns.append(testrun)
2144 parseStamp(tp.stamp, data)2414 parseStamp(tp.stamp, data)
2145 if len(tp.fwdata) > data.testnumber:
2146 data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
2147 if(data.fwSuspend > 0 or data.fwResume > 0):
2148 data.fwValid = True
2149 data.setStart(t.time)2415 data.setStart(t.time)
2416 data.tKernSus = t.time
2150 continue2417 continue
2151 if(not data):2418 if(not data):
2152 continue2419 continue
2420 # process cpu exec line
2421 if t.type == 'tracing_mark_write':
2422 m = re.match(sysvals.procexecfmt, t.name)
2423 if(m):
2424 proclist = dict()
2425 for ps in m.group('ps').split(','):
2426 val = ps.split()
2427 if not val:
2428 continue
2429 name = val[0].replace('--', '-')
2430 proclist[name] = int(val[1])
2431 data.pstl[t.time] = proclist
2432 continue
2153 # find the end of resume2433 # find the end of resume
2154 if(t.endMarker()):2434 if(t.endMarker()):
2155 if(sysvals.usetracemarkers and sysvals.postresumetime > 0):
2156 phase = 'post_resume'
2157 data.newPhase(phase, t.time, t.time, '#F0F0F0', -1)
2158 data.setEnd(t.time)2435 data.setEnd(t.time)
2436 if data.tKernRes == 0.0:
2437 data.tKernRes = t.time
2438 if data.dmesg['resume_complete']['end'] < 0:
2439 data.dmesg['resume_complete']['end'] = t.time
2440 if sysvals.suspendmode == 'mem' and len(tp.fwdata) > data.testnumber:
2441 data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
2442 if(data.tSuspended != 0 and data.tResumed != 0 and \
2443 (data.fwSuspend > 0 or data.fwResume > 0)):
2444 data.fwValid = True
2159 if(not sysvals.usetracemarkers):2445 if(not sysvals.usetracemarkers):
2160 # no trace markers? then quit and be sure to finish recording2446 # no trace markers? then quit and be sure to finish recording
2161 # the event we used to trigger resume end2447 # the event we used to trigger resume end
@@ -2190,8 +2476,14 @@ def parseTraceLog(): · 28 unmodified lines
2190 if(name.split('[')[0] in tracewatch):2476 if(name.split('[')[0] in tracewatch):
2191 continue2477 continue
2192 # -- phase changes --2478 # -- phase changes --
2479 # start of kernel suspend
2480 if(re.match('suspend_enter\[.*', t.name)):
2481 if(isbegin):
2482 data.dmesg[phase]['start'] = t.time
2483 data.tKernSus = t.time
2484 continue
2193 # suspend_prepare start2485 # suspend_prepare start
2194 if(re.match('dpm_prepare\[.*', t.name)):2486 elif(re.match('dpm_prepare\[.*', t.name)):
2195 phase = 'suspend_prepare'2487 phase = 'suspend_prepare'
2196 if(not isbegin):2488 if(not isbegin):
2197 data.dmesg[phase]['end'] = t.time2489 data.dmesg[phase]['end'] = t.time
@@ -2291,6 +2583,8 @@ def parseTraceLog(): · 93 unmodified lines
2291 p = m.group('p')2583 p = m.group('p')
2292 if(n and p):2584 if(n and p):
2293 data.newAction(phase, n, pid, p, t.time, -1, drv)2585 data.newAction(phase, n, pid, p, t.time, -1, drv)
2586 if pid not in data.devpids:
2587 data.devpids.append(pid)
2294 # device callback finish2588 # device callback finish
2295 elif(t.type == 'device_pm_callback_end'):2589 elif(t.type == 'device_pm_callback_end'):
2296 m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name);2590 m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name);
@@ -2332,6 +2626,12 @@ def parseTraceLog(): · 35 unmodified lines
2332 else:2626 else:
2333 e['end'] = t.time2627 e['end'] = t.time
2334 e['rdata'] = kprobedata2628 e['rdata'] = kprobedata
2629 # end of kernel resume
2630 if(kprobename == 'pm_notifier_call_chain' or \
2631 kprobename == 'pm_restore_console'):
2632 data.dmesg[phase]['end'] = t.time
2633 data.tKernRes = t.time
2634
2335 # callgraph processing2635 # callgraph processing
2336 elif sysvals.usecallgraph:2636 elif sysvals.usecallgraph:
2337 # create a callgraph object for the data2637 # create a callgraph object for the data
@@ -2348,24 +2648,37 @@ def parseTraceLog(): · 10 unmodified lines
2348 if sysvals.suspendmode == 'command':2648 if sysvals.suspendmode == 'command':
2349 for test in testruns:2649 for test in testruns:
2350 for p in test.data.phases:2650 for p in test.data.phases:
2351 if p == 'resume_complete':2651 if p == 'suspend_prepare':
2352 test.data.dmesg[p]['start'] = test.data.start2652 test.data.dmesg[p]['start'] = test.data.start
2353 test.data.dmesg[p]['end'] = test.data.end2653 test.data.dmesg[p]['end'] = test.data.end
2354 else:2654 else:
2355 test.data.dmesg[p]['start'] = test.data.start2655 test.data.dmesg[p]['start'] = test.data.end
2356 test.data.dmesg[p]['end'] = test.data.start2656 test.data.dmesg[p]['end'] = test.data.end
2357 test.data.tSuspended = test.data.start2657 test.data.tSuspended = test.data.end
2358 test.data.tResumed = test.data.start2658 test.data.tResumed = test.data.end
2359 test.data.tLow = 02659 test.data.tLow = 0
2360 test.data.fwValid = False2660 test.data.fwValid = False
2361 2661
2362 for test in testruns:2662 # dev source and procmon events can be unreadable with mixed phase height
2663 if sysvals.usedevsrc or sysvals.useprocmon:
2664 sysvals.mixedphaseheight = False
2665
2666 for i in range(len(testruns)):
2667 test = testruns[i]
2668 data = test.data
2669 # find the total time range for this test (begin, end)
2670 tlb, tle = data.start, data.end
2671 if i < len(testruns) - 1:
2672 tle = testruns[i+1].data.start
2673 # add the process usage data to the timeline
2674 if sysvals.useprocmon:
2675 data.createProcessUsageEvents()
2363 # add the traceevent data to the device hierarchy2676 # add the traceevent data to the device hierarchy
2364 if(sysvals.usetraceevents):2677 if(sysvals.usetraceevents):
2365 # add actual trace funcs2678 # add actual trace funcs
2366 for name in test.ttemp:2679 for name in test.ttemp:
2367 for event in test.ttemp[name]:2680 for event in test.ttemp[name]:
2368 test.data.newActionGlobal(name, event['begin'], event['end'], event['pid'])2681 data.newActionGlobal(name, event['begin'], event['end'], event['pid'])
2369 # add the kprobe based virtual tracefuncs as actual devices2682 # add the kprobe based virtual tracefuncs as actual devices
2370 for key in tp.ktemp:2683 for key in tp.ktemp:
2371 name, pid = key2684 name, pid = key
@@ -2373,24 +2686,20 @@ def parseTraceLog(): · 1 unmodified line
2373 continue2686 continue
2374 for e in tp.ktemp[key]:2687 for e in tp.ktemp[key]:
2375 kb, ke = e['begin'], e['end']2688 kb, ke = e['begin'], e['end']
2376 if kb == ke or not test.data.isInsideTimeline(kb, ke):2689 if kb == ke or tlb > kb or tle <= kb:
2377 continue2690 continue
2378 test.data.newActionGlobal(e['name'], kb, ke, pid)2691 color = sysvals.kprobeColor(name)
2692 data.newActionGlobal(e['name'], kb, ke, pid, color)
2379 # add config base kprobes and dev kprobes2693 # add config base kprobes and dev kprobes
2380 for key in tp.ktemp:2694 if sysvals.usedevsrc:
2381 name, pid = key2695 for key in tp.ktemp:
2382 if name in sysvals.tracefuncs:2696 name, pid = key
2383 continue2697 if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs:
2384 for e in tp.ktemp[key]:
2385 kb, ke = e['begin'], e['end']
2386 if kb == ke or not test.data.isInsideTimeline(kb, ke):
2387 continue2698 continue
2388 color = sysvals.kprobeColor(e['name'])2699 for e in tp.ktemp[key]:
2389 if name not in sysvals.dev_tracefuncs:2700 kb, ke = e['begin'], e['end']
2390 # config base kprobe2701 if kb == ke or tlb > kb or tle <= kb:
2391 test.data.newActionGlobal(e['name'], kb, ke, -2, color)2702 continue
2392 elif sysvals.usedevsrc:
2393 # dev kprobe
2394 data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb,2703 data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb,
2395 ke, e['cdata'], e['rdata'])2704 ke, e['cdata'], e['rdata'])
2396 if sysvals.usecallgraph:2705 if sysvals.usecallgraph:
@@ -2407,7 +2716,7 @@ def parseTraceLog(): · 10 unmodified lines
2407 id+', ignoring this callback')2716 id+', ignoring this callback')
2408 continue2717 continue
2409 # match cg data to devices2718 # match cg data to devices
2410 if sysvals.suspendmode == 'command' or not cg.deviceMatch(pid, test.data):2719 if sysvals.suspendmode == 'command' or not cg.deviceMatch(pid, data):
2411 sortkey = '%f%f%d' % (cg.start, cg.end, pid)2720 sortkey = '%f%f%d' % (cg.start, cg.end, pid)
2412 sortlist[sortkey] = cg2721 sortlist[sortkey] = cg
2413 # create blocks for orphan cg data2722 # create blocks for orphan cg data
@@ -2416,12 +2725,11 @@ def parseTraceLog(): · 2 unmodified lines
2416 name = cg.list[0].name2725 name = cg.list[0].name
2417 if sysvals.isCallgraphFunc(name):2726 if sysvals.isCallgraphFunc(name):
2418 vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name))2727 vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name))
2419 cg.newActionFromFunction(test.data)2728 cg.newActionFromFunction(data)
2420 2729
2421 if sysvals.suspendmode == 'command':2730 if sysvals.suspendmode == 'command':
2422 if(sysvals.verbose):2731 for data in testdata:
2423 for data in testdata:2732 data.printDetails()
2424 data.printDetails()
2425 return testdata2733 return testdata
2426 2734
2427 # fill in any missing phases2735 # fill in any missing phases
@@ -2429,7 +2737,7 @@ def parseTraceLog(): · 1 unmodified line
2429 lp = data.phases[0]2737 lp = data.phases[0]
2430 for p in data.phases:2738 for p in data.phases:
2431 if(data.dmesg[p]['start'] < 0 and data.dmesg[p]['end'] < 0):2739 if(data.dmesg[p]['start'] < 0 and data.dmesg[p]['end'] < 0):
2432 print('WARNING: phase "%s" is missing!' % p)2740 vprint('WARNING: phase "%s" is missing!' % p)
2433 if(data.dmesg[p]['start'] < 0):2741 if(data.dmesg[p]['start'] < 0):
2434 data.dmesg[p]['start'] = data.dmesg[lp]['end']2742 data.dmesg[p]['start'] = data.dmesg[lp]['end']
2435 if(p == 'resume_machine'):2743 if(p == 'resume_machine'):
@@ -2438,60 +2746,27 @@ def parseTraceLog(): · 2 unmodified lines
2438 data.tLow = 02746 data.tLow = 0
2439 if(data.dmesg[p]['end'] < 0):2747 if(data.dmesg[p]['end'] < 0):
2440 data.dmesg[p]['end'] = data.dmesg[p]['start']2748 data.dmesg[p]['end'] = data.dmesg[p]['start']
2749 if(p != lp and not ('machine' in p and 'machine' in lp)):
2750 data.dmesg[lp]['end'] = data.dmesg[p]['start']
2441 lp = p2751 lp = p
2442 2752
2443 if(len(sysvals.devicefilter) > 0):2753 if(len(sysvals.devicefilter) > 0):
2444 data.deviceFilter(sysvals.devicefilter)2754 data.deviceFilter(sysvals.devicefilter)
2445 data.fixupInitcallsThatDidntReturn()2755 data.fixupInitcallsThatDidntReturn()
2446 if(sysvals.verbose):2756 if sysvals.usedevsrc:
2447 data.printDetails()2757 data.optimizeDevSrc()
2758 data.printDetails()
2448 2759
2760 # x2: merge any overlapping devices between test runs
2761 if sysvals.usedevsrc and len(testdata) > 1:
2762 tc = len(testdata)
2763 for i in range(tc - 1):
2764 devlist = testdata[i].overflowDevices()
2765 for j in range(i + 1, tc):
2766 testdata[j].mergeOverlapDevices(devlist)
2767 testdata[0].stitchTouchingThreads(testdata[1:])
2449 return testdata2768 return testdata
2450 2769
2451# Function: loadRawKernelLog
2452# Description:
2453# Load a raw kernel log that wasn't created by this tool, it might be
2454# possible to extract a valid suspend/resume log
2455def loadRawKernelLog(dmesgfile):
2456 global sysvals
2457
2458 stamp = {'time': '', 'host': '', 'mode': 'mem', 'kernel': ''}
2459 stamp['time'] = datetime.now().strftime('%B %d %Y, %I:%M:%S %p')
2460 stamp['host'] = sysvals.hostname
2461
2462 testruns = []
2463 data = 0
2464 lf = open(dmesgfile, 'r')
2465 for line in lf:
2466 line = line.replace('\r\n', '')
2467 idx = line.find('[')
2468 if idx > 1:
2469 line = line[idx:]
2470 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
2471 if(not m):
2472 continue
2473 msg = m.group("msg")
2474 m = re.match('PM: Syncing filesystems.*', msg)
2475 if(m):
2476 if(data):
2477 testruns.append(data)
2478 data = Data(len(testruns))
2479 data.stamp = stamp
2480 if(data):
2481 m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg)
2482 if(m):
2483 stamp['kernel'] = m.group('k')
2484 m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg)
2485 if(m):
2486 stamp['mode'] = m.group('m')
2487 data.dmesgtext.append(line)
2488 if(data):
2489 testruns.append(data)
2490 sysvals.stamp = stamp
2491 sysvals.suspendmode = stamp['mode']
2492 lf.close()
2493 return testruns
2494
2495# Function: loadKernelLog2770# Function: loadKernelLog
2496# Description:2771# Description:
2497# [deprecated for kernel 3.15.0 or newer]2772# [deprecated for kernel 3.15.0 or newer]
@@ -2499,15 +2774,16 @@ def loadRawKernelLog(dmesgfile): · 1 unmodified line
2499# The dmesg filename is taken from sysvals2774# The dmesg filename is taken from sysvals
2500# Output:2775# Output:
2501# An array of empty Data objects with only their dmesgtext attributes set2776# An array of empty Data objects with only their dmesgtext attributes set
2502def loadKernelLog():2777def loadKernelLog(justtext=False):
2503 global sysvals
2504
2505 vprint('Analyzing the dmesg data...')2778 vprint('Analyzing the dmesg data...')
2506 if(os.path.exists(sysvals.dmesgfile) == False):2779 if(os.path.exists(sysvals.dmesgfile) == False):
2507 doError('%s does not exist' % sysvals.dmesgfile, False)2780 doError('%s does not exist' % sysvals.dmesgfile)
2508 2781
2782 if justtext:
2783 dmesgtext = []
2509 # there can be multiple test runs in a single file2784 # there can be multiple test runs in a single file
2510 tp = TestProps()2785 tp = TestProps()
2786 tp.stamp = datetime.now().strftime('# suspend-%m%d%y-%H%M%S localhost mem unknown')
2511 testruns = []2787 testruns = []
2512 data = 02788 data = 0
2513 lf = open(sysvals.dmesgfile, 'r')2789 lf = open(sysvals.dmesgfile, 'r')
@@ -2528,6 +2804,9 @@ def loadKernelLog(): · 14 unmodified lines
2528 if(not m):2804 if(not m):
2529 continue2805 continue
2530 msg = m.group("msg")2806 msg = m.group("msg")
2807 if justtext:
2808 dmesgtext.append(line)
2809 continue
2531 if(re.match('PM: Syncing filesystems.*', msg)):2810 if(re.match('PM: Syncing filesystems.*', msg)):
2532 if(data):2811 if(data):
2533 testruns.append(data)2812 testruns.append(data)
@@ -2537,24 +2816,24 @@ def loadKernelLog(): · 3 unmodified lines
2537 data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]2816 data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
2538 if(data.fwSuspend > 0 or data.fwResume > 0):2817 if(data.fwSuspend > 0 or data.fwResume > 0):
2539 data.fwValid = True2818 data.fwValid = True
2540 if(re.match('ACPI: resume from mwait', msg)):
2541 print('NOTE: This suspend appears to be freeze rather than'+\
2542 ' %s, it will be treated as such' % sysvals.suspendmode)
2543 sysvals.suspendmode = 'freeze'
2544 if(not data):2819 if(not data):
2545 continue2820 continue
2821 m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg)
2822 if(m):
2823 sysvals.stamp['kernel'] = m.group('k')
2824 m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg)
2825 if(m):
2826 sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m')
2546 data.dmesgtext.append(line)2827 data.dmesgtext.append(line)
2547 if(data):
2548 testruns.append(data)
2549 lf.close()2828 lf.close()
2550 2829
2551 if(len(testruns) < 1):2830 if justtext:
2552 # bad log, but see if you can extract something meaningful anyway2831 return dmesgtext
2553 testruns = loadRawKernelLog(sysvals.dmesgfile)2832 if data:
2554 2833 testruns.append(data)
2555 if(len(testruns) < 1):2834 if len(testruns) < 1:
2556 doError(' dmesg log is completely unreadable: %s' \2835 doError(' dmesg log has no suspend/resume data: %s' \
2557 % sysvals.dmesgfile, False)2836 % sysvals.dmesgfile)
2558 2837
2559 # fix lines with same timestamp/function with the call and return swapped2838 # fix lines with same timestamp/function with the call and return swapped
2560 for data in testruns:2839 for data in testruns:
@@ -2586,8 +2865,6 @@ def loadKernelLog(): · 25 unmodified lines
2586# Output:2865# Output:
2587# The filled Data object2866# The filled Data object
2588def parseKernelLog(data):2867def parseKernelLog(data):
2589 global sysvals
2590
2591 phase = 'suspend_runtime'2868 phase = 'suspend_runtime'
2592 2869
2593 if(data.fwValid):2870 if(data.fwValid):
@@ -2645,7 +2922,6 @@ def parseKernelLog(data): · 51 unmodified lines
2645 prevktime = -1.02922 prevktime = -1.0
2646 actions = dict()2923 actions = dict()
2647 for line in data.dmesgtext:2924 for line in data.dmesgtext:
2648 # -- preprocessing --
2649 # parse each dmesg line into the time and message2925 # parse each dmesg line into the time and message
2650 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)2926 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
2651 if(m):2927 if(m):
@@ -2653,8 +2929,6 @@ def parseKernelLog(data): · 1 unmodified line
2653 try:2929 try:
2654 ktime = float(val)2930 ktime = float(val)
2655 except:2931 except:
2656 doWarning('INVALID DMESG LINE: '+\
2657 line.replace('\n', ''), 'dmesg')
2658 continue2932 continue
2659 msg = m.group('msg')2933 msg = m.group('msg')
2660 # initialize data start to first line time2934 # initialize data start to first line time
@@ -2672,12 +2946,12 @@ def parseKernelLog(data): · 11 unmodified lines
2672 phase = 'resume_noirq'2946 phase = 'resume_noirq'
2673 data.dmesg[phase]['start'] = ktime2947 data.dmesg[phase]['start'] = ktime
2674 2948
2675 # -- phase changes --
2676 # suspend start2949 # suspend start
2677 if(re.match(dm['suspend_prepare'], msg)):2950 if(re.match(dm['suspend_prepare'], msg)):
2678 phase = 'suspend_prepare'2951 phase = 'suspend_prepare'
2679 data.dmesg[phase]['start'] = ktime2952 data.dmesg[phase]['start'] = ktime
2680 data.setStart(ktime)2953 data.setStart(ktime)
2954 data.tKernSus = ktime
2681 # suspend start2955 # suspend start
2682 elif(re.match(dm['suspend'], msg)):2956 elif(re.match(dm['suspend'], msg)):
2683 data.dmesg['suspend_prepare']['end'] = ktime2957 data.dmesg['suspend_prepare']['end'] = ktime
@@ -2734,7 +3008,7 @@ def parseKernelLog(data): · 50 unmodified lines
2734 elif(re.match(dm['post_resume'], msg)):3008 elif(re.match(dm['post_resume'], msg)):
2735 data.dmesg['resume_complete']['end'] = ktime3009 data.dmesg['resume_complete']['end'] = ktime
2736 data.setEnd(ktime)3010 data.setEnd(ktime)
2737 phase = 'post_resume'3011 data.tKernRes = ktime
2738 break3012 break
2739 3013
2740 # -- device callbacks --3014 # -- device callbacks --
@@ -2761,7 +3035,6 @@ def parseKernelLog(data): · 20 unmodified lines
2761 dev['length'] = int(t)3035 dev['length'] = int(t)
2762 dev['end'] = ktime3036 dev['end'] = ktime
2763 3037
2764 # -- non-devicecallback actions --
2765 # if trace events are not available, these are better than nothing3038 # if trace events are not available, these are better than nothing
2766 if(not sysvals.usetraceevents):3039 if(not sysvals.usetraceevents):
2767 # look for known actions3040 # look for known actions
@@ -2821,8 +3094,7 @@ def parseKernelLog(data): · 53 unmodified lines
2821 for event in actions[name]:3094 for event in actions[name]:
2822 data.newActionGlobal(name, event['begin'], event['end'])3095 data.newActionGlobal(name, event['begin'], event['end'])
2823 3096
2824 if(sysvals.verbose):3097 data.printDetails()
2825 data.printDetails()
2826 if(len(sysvals.devicefilter) > 0):3098 if(len(sysvals.devicefilter) > 0):
2827 data.deviceFilter(sysvals.devicefilter)3099 data.deviceFilter(sysvals.devicefilter)
2828 data.fixupInitcallsThatDidntReturn()3100 data.fixupInitcallsThatDidntReturn()
@@ -2834,8 +3106,6 @@ def parseKernelLog(data): · 5 unmodified lines
2834# Arguments:3106# Arguments:
2835# testruns: array of Data objects from parseTraceLog3107# testruns: array of Data objects from parseTraceLog
2836def createHTMLSummarySimple(testruns, htmlfile):3108def createHTMLSummarySimple(testruns, htmlfile):
2837 global sysvals
2838
2839 # print out the basic summary of all the tests3109 # print out the basic summary of all the tests
2840 hf = open(htmlfile, 'w')3110 hf = open(htmlfile, 'w')
2841 3111
@@ -2960,7 +3230,6 @@ def createHTMLSummarySimple(testruns, htmlfile): · 118 unmodified lines
2960 hf.close()3230 hf.close()
2961 3231
2962def htmlTitle():3232def htmlTitle():
2963 global sysvals
2964 modename = {3233 modename = {
2965 'freeze': 'Freeze (S0)',3234 'freeze': 'Freeze (S0)',
2966 'standby': 'Standby (S1)',3235 'standby': 'Standby (S1)',
@@ -2993,13 +3262,14 @@ def ordinal(value): · 26 unmodified lines
2993# Output:3262# Output:
2994# True if the html file was created, false if it failed3263# True if the html file was created, false if it failed
2995def createHTML(testruns):3264def createHTML(testruns):
2996 global sysvals
2997
2998 if len(testruns) < 1:3265 if len(testruns) < 1:
2999 print('ERROR: Not enough test data to build a timeline')3266 print('ERROR: Not enough test data to build a timeline')
3000 return3267 return
3001 3268
3269 kerror = False
3002 for data in testruns:3270 for data in testruns:
3271 if data.kerror:
3272 kerror = True
3003 data.normalizeTime(testruns[-1].tSuspended)3273 data.normalizeTime(testruns[-1].tSuspended)
3004 3274
3005 x2changes = ['', 'absolute']3275 x2changes = ['', 'absolute']
@@ -3009,53 +3279,59 @@ def createHTML(testruns): · 3 unmodified lines
3009 headline_version = '<div class="version"><a href="https://01.org/suspendresume">AnalyzeSuspend v%s</a></div>' % sysvals.version3279 headline_version = '<div class="version"><a href="https://01.org/suspendresume">AnalyzeSuspend v%s</a></div>' % sysvals.version
3010 headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n'3280 headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n'
3011 html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail%s</button>' % x2changes[0]3281 html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail%s</button>' % x2changes[0]
3012 html_zoombox = '<center><button id="zoomin">ZOOM IN</button><button id="zoomout">ZOOM OUT</button><button id="zoomdef">ZOOM 1:1</button></center>\n'3282 html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n'
3013 html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n'3283 html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n'
3014 html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n'3284 html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n'
3015 html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;">\n'3285 html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n'
3016 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'3286 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'
3017 html_traceevent = '<div title="{0}" class="traceevent" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;">{5}</div>\n'3287 html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">ERROR&rarr;</div>\n'
3288 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'
3289 html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n'
3018 html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background-color:{4}">{5}</div>\n'3290 html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background-color:{4}">{5}</div>\n'
3019 html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background-color:{3}"></div>\n'3291 html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n'
3020 html_legend = '<div id="p{3}" class="square" style="left:{0}%;background-color:{1}">&nbsp;{2}</div>\n'3292 html_legend = '<div id="p{3}" class="square" style="left:{0}%;background-color:{1}">&nbsp;{2}</div>\n'
3021 html_timetotal = '<table class="time1">\n<tr>'\3293 html_timetotal = '<table class="time1">\n<tr>'\
3022 '<td class="green">{2} Suspend Time: <b>{0} ms</b></td>'\3294 '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\
3023 '<td class="yellow">{2} Resume Time: <b>{1} ms</b></td>'\3295 '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\
3024 '</tr>\n</table>\n'3296 '</tr>\n</table>\n'
3025 html_timetotal2 = '<table class="time1">\n<tr>'\3297 html_timetotal2 = '<table class="time1">\n<tr>'\
3026 '<td class="green">{3} Suspend Time: <b>{0} ms</b></td>'\3298 '<td class="green" title="{4}">{3} Suspend Time: <b>{0} ms</b></td>'\
3027 '<td class="gray">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\3299 '<td class="gray" title="time spent in low-power mode with clock running">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\
3028 '<td class="yellow">{3} Resume Time: <b>{2} ms</b></td>'\3300 '<td class="yellow" title="{5}">{3} Resume Time: <b>{2} ms</b></td>'\
3029 '</tr>\n</table>\n'3301 '</tr>\n</table>\n'
3030 html_timetotal3 = '<table class="time1">\n<tr>'\3302 html_timetotal3 = '<table class="time1">\n<tr>'\
3031 '<td class="green">Execution Time: <b>{0} ms</b></td>'\3303 '<td class="green">Execution Time: <b>{0} ms</b></td>'\
3032 '<td class="yellow">Command: <b>{1}</b></td>'\3304 '<td class="yellow">Command: <b>{1}</b></td>'\
3033 '</tr>\n</table>\n'3305 '</tr>\n</table>\n'
3034 html_timegroups = '<table class="time2">\n<tr>'\3306 html_timegroups = '<table class="time2">\n<tr>'\
3035 '<td class="green">{4}Kernel Suspend: {0} ms</td>'\3307 '<td class="green" title="time from kernel enter_state({5}) to firmware mode [kernel time only]">{4}Kernel Suspend: {0} ms</td>'\
3036 '<td class="purple">{4}Firmware Suspend: {1} ms</td>'\3308 '<td class="purple">{4}Firmware Suspend: {1} ms</td>'\
3037 '<td class="purple">{4}Firmware Resume: {2} ms</td>'\3309 '<td class="purple">{4}Firmware Resume: {2} ms</td>'\
3038 '<td class="yellow">{4}Kernel Resume: {3} ms</td>'\3310 '<td class="yellow" title="time from firmware mode to return from kernel enter_state({5}) [kernel time only]">{4}Kernel Resume: {3} ms</td>'\
3039 '</tr>\n</table>\n'3311 '</tr>\n</table>\n'
3040 3312
3041 # html format variables3313 # html format variables
3042 rowheight = 303314 hoverZ = 'z-index:8;'
3043 devtextS = '14px'
3044 devtextH = '30px'
3045 hoverZ = 'z-index:10;'
3046
3047 if sysvals.usedevsrc:3315 if sysvals.usedevsrc:
3048 hoverZ = ''3316 hoverZ = ''
3317 scaleH = 20
3318 scaleTH = 20
3319 if kerror:
3320 scaleH = 40
3321 scaleTH = 60
3049 3322
3050 # device timeline3323 # device timeline
3051 vprint('Creating Device Timeline...')3324 vprint('Creating Device Timeline...')
3052 3325
3053 devtl = Timeline(rowheight)3326 devtl = Timeline(30, scaleH)
3054 3327
3055 # Generate the header for this timeline3328 # Generate the header for this timeline
3056 for data in testruns:3329 for data in testruns:
3057 tTotal = data.end - data.start3330 tTotal = data.end - data.start
3058 tEnd = data.dmesg['resume_complete']['end']3331 sktime = (data.dmesg['suspend_machine']['end'] - \
3332 data.tKernSus) * 1000
3333 rktime = (data.dmesg['resume_complete']['end'] - \
3334 data.dmesg['resume_machine']['start']) * 1000
3059 if(tTotal == 0):3335 if(tTotal == 0):
3060 print('ERROR: No timeline data')3336 print('ERROR: No timeline data')
3061 sys.exit()3337 sys.exit()
@@ -3072,59 +3348,85 @@ def createHTML(testruns): · 10 unmodified lines
3072 thtml = html_timetotal3.format(run_time, testdesc)3348 thtml = html_timetotal3.format(run_time, testdesc)
3073 devtl.html['header'] += thtml3349 devtl.html['header'] += thtml
3074 elif data.fwValid:3350 elif data.fwValid:
3075 suspend_time = '%.0f'%((data.tSuspended-data.start)*1000 + \3351 suspend_time = '%.0f'%(sktime + (data.fwSuspend/1000000.0))
3076 (data.fwSuspend/1000000.0))3352 resume_time = '%.0f'%(rktime + (data.fwResume/1000000.0))
3077 resume_time = '%.0f'%((tEnd-data.tSuspended)*1000 + \
3078 (data.fwResume/1000000.0))
3079 testdesc1 = 'Total'3353 testdesc1 = 'Total'
3080 testdesc2 = ''3354 testdesc2 = ''
3355 stitle = 'time from kernel enter_state(%s) to low-power mode [kernel & firmware time]' % sysvals.suspendmode
3356 rtitle = 'time from low-power mode to return from kernel enter_state(%s) [firmware & kernel time]' % sysvals.suspendmode
3081 if(len(testruns) > 1):3357 if(len(testruns) > 1):
3082 testdesc1 = testdesc2 = ordinal(data.testnumber+1)3358 testdesc1 = testdesc2 = ordinal(data.testnumber+1)
3083 testdesc2 += ' '3359 testdesc2 += ' '
3084 if(data.tLow == 0):3360 if(data.tLow == 0):
3085 thtml = html_timetotal.format(suspend_time, \3361 thtml = html_timetotal.format(suspend_time, \
3086 resume_time, testdesc1)3362 resume_time, testdesc1, stitle, rtitle)
3087 else:3363 else:
3088 thtml = html_timetotal2.format(suspend_time, low_time, \3364 thtml = html_timetotal2.format(suspend_time, low_time, \
3089 resume_time, testdesc1)3365 resume_time, testdesc1, stitle, rtitle)
3090 devtl.html['header'] += thtml3366 devtl.html['header'] += thtml
3091 sktime = '%.3f'%((data.dmesg['suspend_machine']['end'] - \
3092 data.getStart())*1000)
3093 sftime = '%.3f'%(data.fwSuspend / 1000000.0)3367 sftime = '%.3f'%(data.fwSuspend / 1000000.0)
3094 rftime = '%.3f'%(data.fwResume / 1000000.0)3368 rftime = '%.3f'%(data.fwResume / 1000000.0)
3095 rktime = '%.3f'%((data.dmesg['resume_complete']['end'] - \3369 devtl.html['header'] += html_timegroups.format('%.3f'%sktime, \
3096 data.dmesg['resume_machine']['start'])*1000)3370 sftime, rftime, '%.3f'%rktime, testdesc2, sysvals.suspendmode)
3097 devtl.html['header'] += html_timegroups.format(sktime, \
3098 sftime, rftime, rktime, testdesc2)
3099 else:3371 else:
3100 suspend_time = '%.0f'%((data.tSuspended-data.start)*1000)3372 suspend_time = '%.3f' % sktime
3101 resume_time = '%.0f'%((tEnd-data.tSuspended)*1000)3373 resume_time = '%.3f' % rktime
3102 testdesc = 'Kernel'3374 testdesc = 'Kernel'
3375 stitle = 'time from kernel enter_state(%s) to firmware mode [kernel time only]' % sysvals.suspendmode
3376 rtitle = 'time from firmware mode to return from kernel enter_state(%s) [kernel time only]' % sysvals.suspendmode
3103 if(len(testruns) > 1):3377 if(len(testruns) > 1):
3104 testdesc = ordinal(data.testnumber+1)+' '+testdesc3378 testdesc = ordinal(data.testnumber+1)+' '+testdesc
3105 if(data.tLow == 0):3379 if(data.tLow == 0):
3106 thtml = html_timetotal.format(suspend_time, \3380 thtml = html_timetotal.format(suspend_time, \
3107 resume_time, testdesc)3381 resume_time, testdesc, stitle, rtitle)
3108 else:3382 else:
3109 thtml = html_timetotal2.format(suspend_time, low_time, \3383 thtml = html_timetotal2.format(suspend_time, low_time, \
3110 resume_time, testdesc)3384 resume_time, testdesc, stitle, rtitle)
3111 devtl.html['header'] += thtml3385 devtl.html['header'] += thtml
3112 3386
3113 # time scale for potentially multiple datasets3387 # time scale for potentially multiple datasets
3114 t0 = testruns[0].start3388 t0 = testruns[0].start
3115 tMax = testruns[-1].end3389 tMax = testruns[-1].end
3116 tSuspended = testruns[-1].tSuspended
3117 tTotal = tMax - t03390 tTotal = tMax - t0
3118 3391
3119 # determine the maximum number of rows we need to draw3392 # determine the maximum number of rows we need to draw
3393 fulllist = []
3394 threadlist = []
3395 pscnt = 0
3396 devcnt = 0
3120 for data in testruns:3397 for data in testruns:
3121 data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen)3398 data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen)
3122 for group in data.devicegroups:3399 for group in data.devicegroups:
3123 devlist = []3400 devlist = []
3124 for phase in group:3401 for phase in group:
3125 for devname in data.tdevlist[phase]:3402 for devname in data.tdevlist[phase]:
3126 devlist.append((phase,devname))3403 d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname])
3127 devtl.getPhaseRows(data.dmesg, devlist)3404 devlist.append(d)
3405 if d.isa('kth'):
3406 threadlist.append(d)
3407 else:
3408 if d.isa('ps'):
3409 pscnt += 1
3410 else:
3411 devcnt += 1
3412 fulllist.append(d)
3413 if sysvals.mixedphaseheight:
3414 devtl.getPhaseRows(devlist)
3415 if not sysvals.mixedphaseheight:
3416 if len(threadlist) > 0 and len(fulllist) > 0:
3417 if pscnt > 0 and devcnt > 0:
3418 msg = 'user processes & device pm callbacks'
3419 elif pscnt > 0:
3420 msg = 'user processes'
3421 else:
3422 msg = 'device pm callbacks'
3423 d = testruns[0].addHorizontalDivider(msg, testruns[-1].end)
3424 fulllist.insert(0, d)
3425 devtl.getPhaseRows(fulllist)
3426 if len(threadlist) > 0:
3427 d = testruns[0].addHorizontalDivider('asynchronous kernel threads', testruns[-1].end)
3428 threadlist.insert(0, d)
3429 devtl.getPhaseRows(threadlist, devtl.rows)
3128 devtl.calcTotalRows()3430 devtl.calcTotalRows()
3129 3431
3130 # create bounding box, add buttons3432 # create bounding box, add buttons
@@ -3145,18 +3447,6 @@ def createHTML(testruns): · 14 unmodified lines
3145 3447
3146 # draw each test run chronologically3448 # draw each test run chronologically
3147 for data in testruns:3449 for data in testruns:
3148 # if nore than one test, draw a block to represent user mode
3149 if(data.testnumber > 0):
3150 m0 = testruns[data.testnumber-1].end
3151 mMax = testruns[data.testnumber].start
3152 mTotal = mMax - m0
3153 name = 'usermode%d' % data.testnumber
3154 top = '%d' % devtl.scaleH
3155 left = '%f' % (((m0-t0)*100.0)/tTotal)
3156 width = '%f' % ((mTotal*100.0)/tTotal)
3157 title = 'user mode (%0.3f ms) ' % (mTotal*1000)
3158 devtl.html['timeline'] += html_device.format(name, \
3159 title, left, top, '%d'%devtl.bodyH, width, '', '', '')
3160 # now draw the actual timeline blocks3450 # now draw the actual timeline blocks
3161 for dir in phases:3451 for dir in phases:
3162 # draw suspend and resume blocks separately3452 # draw suspend and resume blocks separately
@@ -3169,13 +3459,16 @@ def createHTML(testruns): · 6 unmodified lines
3169 else:3459 else:
3170 m0 = testruns[data.testnumber].tSuspended3460 m0 = testruns[data.testnumber].tSuspended
3171 mMax = testruns[data.testnumber].end3461 mMax = testruns[data.testnumber].end
3462 # in an x2 run, remove any gap between blocks
3463 if len(testruns) > 1 and data.testnumber == 0:
3464 mMax = testruns[1].start
3172 mTotal = mMax - m03465 mTotal = mMax - m0
3173 left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal)3466 left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal)
3174 # if a timeline block is 0 length, skip altogether3467 # if a timeline block is 0 length, skip altogether
3175 if mTotal == 0:3468 if mTotal == 0:
3176 continue3469 continue
3177 width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal)3470 width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal)
3178 devtl.html['timeline'] += html_tblock.format(bname, left, width)3471 devtl.html['timeline'] += html_tblock.format(bname, left, width, devtl.scaleH)
3179 for b in sorted(phases[dir]):3472 for b in sorted(phases[dir]):
3180 # draw the phase color background3473 # draw the phase color background
3181 phase = data.dmesg[b]3474 phase = data.dmesg[b]
@@ -3185,6 +3478,12 @@ def createHTML(testruns): · 3 unmodified lines
3185 devtl.html['timeline'] += html_phase.format(left, width, \3478 devtl.html['timeline'] += html_phase.format(left, width, \
3186 '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \3479 '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \
3187 data.dmesg[b]['color'], '')3480 data.dmesg[b]['color'], '')
3481 for e in data.errorinfo[dir]:
3482 # draw red lines for any kernel errors found
3483 t, err = e
3484 right = '%f' % (((mMax-t)*100.0)/mTotal)
3485 devtl.html['timeline'] += html_error.format(right, err)
3486 for b in sorted(phases[dir]):
3188 # draw the devices for this phase3487 # draw the devices for this phase
3189 phaselist = data.dmesg[b]['list']3488 phaselist = data.dmesg[b]['list']
3190 for d in data.tdevlist[b]:3489 for d in data.tdevlist[b]:
@@ -3196,46 +3495,62 @@ def createHTML(testruns): · 5 unmodified lines
3196 xtrastyle = ''3495 xtrastyle = ''
3197 if 'htmlclass' in dev:3496 if 'htmlclass' in dev:
3198 xtraclass = dev['htmlclass']3497 xtraclass = dev['htmlclass']
3199 xtrainfo = dev['htmlclass']
3200 if 'color' in dev:3498 if 'color' in dev:
3201 xtrastyle = 'background-color:%s;' % dev['color']3499 xtrastyle = 'background-color:%s;' % dev['color']
3202 if(d in sysvals.devprops):3500 if(d in sysvals.devprops):
3203 name = sysvals.devprops[d].altName(d)3501 name = sysvals.devprops[d].altName(d)
3204 xtraclass = sysvals.devprops[d].xtraClass()3502 xtraclass = sysvals.devprops[d].xtraClass()
3205 xtrainfo = sysvals.devprops[d].xtraInfo()3503 xtrainfo = sysvals.devprops[d].xtraInfo()
3504 elif xtraclass == ' kth':
3505 xtrainfo = ' kernel_thread'
3206 if('drv' in dev and dev['drv']):3506 if('drv' in dev and dev['drv']):
3207 drv = ' {%s}' % dev['drv']3507 drv = ' {%s}' % dev['drv']
3208 rowheight = devtl.phaseRowHeight(b, dev['row'])3508 rowheight = devtl.phaseRowHeight(data.testnumber, b, dev['row'])
3209 rowtop = devtl.phaseRowTop(b, dev['row'])3509 rowtop = devtl.phaseRowTop(data.testnumber, b, dev['row'])
3210 top = '%.3f' % (rowtop + devtl.scaleH)3510 top = '%.3f' % (rowtop + devtl.scaleH)
3211 left = '%f' % (((dev['start']-m0)*100)/mTotal)3511 left = '%f' % (((dev['start']-m0)*100)/mTotal)
3212 width = '%f' % (((dev['end']-dev['start'])*100)/mTotal)3512 width = '%f' % (((dev['end']-dev['start'])*100)/mTotal)
3213 length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000)3513 length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000)
3514 title = name+drv+xtrainfo+length
3214 if sysvals.suspendmode == 'command':3515 if sysvals.suspendmode == 'command':
3215 title = name+drv+xtrainfo+length+'cmdexec'3516 title += sysvals.testcommand
3517 elif xtraclass == ' ps':
3518 if 'suspend' in b:
3519 title += 'pre_suspend_process'
3520 else:
3521 title += 'post_resume_process'
3216 else:3522 else:
3217 title = name+drv+xtrainfo+length+b3523 title += b
3218 devtl.html['timeline'] += html_device.format(dev['id'], \3524 devtl.html['timeline'] += html_device.format(dev['id'], \
3219 title, left, top, '%.3f'%rowheight, width, \3525 title, left, top, '%.3f'%rowheight, width, \
3220 d+drv, xtraclass, xtrastyle)3526 d+drv, xtraclass, xtrastyle)
3527 if('cpuexec' in dev):
3528 for t in sorted(dev['cpuexec']):
3529 start, end = t
3530 j = float(dev['cpuexec'][t]) / 5
3531 if j > 1.0:
3532 j = 1.0
3533 height = '%.3f' % (rowheight/3)
3534 top = '%.3f' % (rowtop + devtl.scaleH + 2*rowheight/3)
3535 left = '%f' % (((start-m0)*100)/mTotal)
3536 width = '%f' % ((end-start)*100/mTotal)
3537 color = 'rgba(255, 0, 0, %f)' % j
3538 devtl.html['timeline'] += \
3539 html_cpuexec.format(left, top, height, width, color)
3221 if('src' not in dev):3540 if('src' not in dev):
3222 continue3541 continue
3223 # draw any trace events for this device3542 # draw any trace events for this device
3224 vprint('Debug trace events found for device %s' % d)
3225 vprint('%20s %20s %10s %8s' % ('title', \
3226 'name', 'time(ms)', 'length(ms)'))
3227 for e in dev['src']:3543 for e in dev['src']:
3228 vprint('%20s %20s %10.3f %8.3f' % (e.title, \3544 height = '%.3f' % devtl.rowH
3229 e.text, e.time*1000, e.length*1000))
3230 height = devtl.rowH
3231 top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH))3545 top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH))
3232 left = '%f' % (((e.time-m0)*100)/mTotal)3546 left = '%f' % (((e.time-m0)*100)/mTotal)
3233 width = '%f' % (e.length*100/mTotal)3547 width = '%f' % (e.length*100/mTotal)
3234 color = 'rgba(204,204,204,0.5)'3548 xtrastyle = ''
3549 if e.color:
3550 xtrastyle = 'background:%s;' % e.color
3235 devtl.html['timeline'] += \3551 devtl.html['timeline'] += \
3236 html_traceevent.format(e.title, \3552 html_traceevent.format(e.title(), \
3237 left, top, '%.3f'%height, \3553 left, top, height, width, e.text(), '', xtrastyle)
3238 width, e.text)
3239 # draw the time scale, try to make the number of labels readable3554 # draw the time scale, try to make the number of labels readable
3240 devtl.html['timeline'] += devtl.createTimeScale(m0, mMax, tTotal, dir)3555 devtl.html['timeline'] += devtl.createTimeScale(m0, mMax, tTotal, dir)
3241 devtl.html['timeline'] += '</div>\n'3556 devtl.html['timeline'] += '</div>\n'
@@ -3284,8 +3599,7 @@ def createHTML(testruns): · 42 unmodified lines
3284 t2 {color:black;font:25px Times;}\n\3599 t2 {color:black;font:25px Times;}\n\
3285 t3 {color:black;font:20px Times;white-space:nowrap;}\n\3600 t3 {color:black;font:20px Times;white-space:nowrap;}\n\
3286 t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\3601 t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\
3287 cS {color:blue;font:bold 11px Times;}\n\3602 cS {font:bold 13px Times;}\n\
3288 cR {color:red;font:bold 11px Times;}\n\
3289 table {width:100%;}\n\3603 table {width:100%;}\n\
3290 .gray {background-color:rgba(80,80,80,0.1);}\n\3604 .gray {background-color:rgba(80,80,80,0.1);}\n\
3291 .green {background-color:rgba(204,255,204,0.4);}\n\3605 .green {background-color:rgba(204,255,204,0.4);}\n\
@@ -3302,20 +3616,22 @@ def createHTML(testruns): · 10 unmodified lines
3302 .pf:'+cgchk+' + label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\3616 .pf:'+cgchk+' + label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\
3303 .pf:'+cgnchk+' ~ label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\3617 .pf:'+cgnchk+' ~ label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\
3304 .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\3618 .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\
3305 .zoombox {position:relative;width:100%;overflow-x:scroll;}\n\3619 .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\
3306 .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\3620 .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\
3307 .thread {position:absolute;height:0%;overflow:hidden;line-height:'+devtextH+';font-size:'+devtextS+';border:1px solid;text-align:center;white-space:nowrap;background-color:rgba(204,204,204,0.5);}\n\3621 .thread {position:absolute;height:0%;overflow:hidden;z-index:7;line-height:30px;font-size:14px;border:1px solid;text-align:center;white-space:nowrap;}\n\
3308 .thread.sync {background-color:'+sysvals.synccolor+';}\n\3622 .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\
3309 .thread.bg {background-color:'+sysvals.kprobecolor+';}\n\
3310 .thread:hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\3623 .thread:hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\
3624 .thread.sec,.thread.sec:hover {background-color:black;border:0;color:white;line-height:15px;font-size:10px;}\n\
3311 .hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\3625 .hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\
3312 .hover.sync {background-color:white;}\n\3626 .hover.sync {background-color:white;}\n\
3313 .hover.bg {background-color:white;}\n\3627 .hover.bg,.hover.kth,.hover.sync,.hover.ps {background-color:white;}\n\
3314 .traceevent {position:absolute;font-size:10px;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,rgba(204,204,204,1),rgba(150,150,150,1));}\n\3628 .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\
3315 .traceevent:hover {background:white;}\n\3629 .traceevent {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\
3630 .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\
3316 .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\3631 .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\
3317 .phaselet {position:absolute;overflow:hidden;border:0px;text-align:center;height:100px;font-size:24px;}\n\3632 .phaselet {position:absolute;overflow:hidden;border:0px;text-align:center;height:100px;font-size:24px;}\n\
3318 .t {z-index:2;position:absolute;pointer-events:none;top:0%;height:100%;border-right:1px solid black;}\n\3633 .t {position:absolute;line-height:'+('%d'%scaleTH)+'px;pointer-events:none;top:0;height:100%;border-right:1px solid black;z-index:6;}\n\
3634 .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\
3319 .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\3635 .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\
3320 .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\3636 .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\
3321 button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\3637 button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\
@@ -3327,7 +3643,8 @@ def createHTML(testruns): · 5 unmodified lines
3327 a:active {color:white;}\n\3643 a:active {color:white;}\n\
3328 .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\3644 .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\
3329 #devicedetail {height:100px;box-shadow:5px 5px 20px black;}\n\3645 #devicedetail {height:100px;box-shadow:5px 5px 20px black;}\n\
3330 .tblock {position:absolute;height:100%;}\n\3646 .tblock {position:absolute;height:100%;background-color:#ddd;}\n\
3647 .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\
3331 .bg {z-index:1;}\n\3648 .bg {z-index:1;}\n\
3332 </style>\n</head>\n<body>\n'3649 </style>\n</head>\n<body>\n'
3333 3650
@@ -3342,6 +3659,8 @@ def createHTML(testruns): · 8 unmodified lines
3342 # write the test title and general info header3659 # write the test title and general info header
3343 if(sysvals.stamp['time'] != ""):3660 if(sysvals.stamp['time'] != ""):
3344 hf.write(headline_version)3661 hf.write(headline_version)
3662 if sysvals.logmsg:
3663 hf.write('<button id="showtest" class="logbtn">log</button>')
3345 if sysvals.addlogs and sysvals.dmesgfile:3664 if sysvals.addlogs and sysvals.dmesgfile:
3346 hf.write('<button id="showdmesg" class="logbtn">dmesg</button>')3665 hf.write('<button id="showdmesg" class="logbtn">dmesg</button>')
3347 if sysvals.addlogs and sysvals.ftracefile:3666 if sysvals.addlogs and sysvals.ftracefile:
@@ -3359,6 +3678,9 @@ def createHTML(testruns): · 11 unmodified lines
3359 # draw the colored boxes for the device detail section3678 # draw the colored boxes for the device detail section
3360 for data in testruns:3679 for data in testruns:
3361 hf.write('<div id="devicedetail%d">\n' % data.testnumber)3680 hf.write('<div id="devicedetail%d">\n' % data.testnumber)
3681 pscolor = 'linear-gradient(to top left, #ccc, #eee)'
3682 hf.write(html_phaselet.format('pre_suspend_process', \
3683 '0', '0', pscolor))
3362 for b in data.phases:3684 for b in data.phases:
3363 phase = data.dmesg[b]3685 phase = data.dmesg[b]
3364 length = phase['end']-phase['start']3686 length = phase['end']-phase['start']
@@ -3366,14 +3688,18 @@ def createHTML(testruns): · 1 unmodified line
3366 width = '%.3f' % ((length*100.0)/tTotal)3688 width = '%.3f' % ((length*100.0)/tTotal)
3367 hf.write(html_phaselet.format(b, left, width, \3689 hf.write(html_phaselet.format(b, left, width, \
3368 data.dmesg[b]['color']))3690 data.dmesg[b]['color']))
3691 hf.write(html_phaselet.format('post_resume_process', \
3692 '0', '0', pscolor))
3369 if sysvals.suspendmode == 'command':3693 if sysvals.suspendmode == 'command':
3370 hf.write(html_phaselet.format('cmdexec', '0', '0', \3694 hf.write(html_phaselet.format('cmdexec', '0', '0', pscolor))
3371 data.dmesg['resume_complete']['color']))
3372 hf.write('</div>\n')3695 hf.write('</div>\n')
3373 hf.write('</div>\n')3696 hf.write('</div>\n')
3374 3697
3375 # write the ftrace data (callgraph)3698 # write the ftrace data (callgraph)
3376 data = testruns[-1]3699 if sysvals.cgtest >= 0 and len(testruns) > sysvals.cgtest:
3700 data = testruns[sysvals.cgtest]
3701 else:
3702 data = testruns[-1]
3377 if(sysvals.usecallgraph and not sysvals.embedded):3703 if(sysvals.usecallgraph and not sysvals.embedded):
3378 hf.write('<section id="callgraphs" class="callgraph">\n')3704 hf.write('<section id="callgraphs" class="callgraph">\n')
3379 # write out the ftrace data converted to html3705 # write out the ftrace data converted to html
@@ -3383,6 +3709,8 @@ def createHTML(testruns): · 3 unmodified lines
3383 html_func_leaf = '<article>{0} {1}</article>\n'3709 html_func_leaf = '<article>{0} {1}</article>\n'
3384 num = 03710 num = 0
3385 for p in data.phases:3711 for p in data.phases:
3712 if sysvals.cgphase and p != sysvals.cgphase:
3713 continue
3386 list = data.dmesg[p]['list']3714 list = data.dmesg[p]['list']
3387 for devname in data.sortedDevices(p):3715 for devname in data.sortedDevices(p):
3388 if('ftrace' not in list[devname]):3716 if('ftrace' not in list[devname]):
@@ -3420,11 +3748,15 @@ def createHTML(testruns): · 31 unmodified lines
3420 hf.write(html_func_end)3748 hf.write(html_func_end)
3421 hf.write('\n\n </section>\n')3749 hf.write('\n\n </section>\n')
3422 3750
3751 # add the test log as a hidden div
3752 if sysvals.logmsg:
3753 hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n')
3423 # add the dmesg log as a hidden div3754 # add the dmesg log as a hidden div
3424 if sysvals.addlogs and sysvals.dmesgfile:3755 if sysvals.addlogs and sysvals.dmesgfile:
3425 hf.write('<div id="dmesglog" style="display:none;">\n')3756 hf.write('<div id="dmesglog" style="display:none;">\n')
3426 lf = open(sysvals.dmesgfile, 'r')3757 lf = open(sysvals.dmesgfile, 'r')
3427 for line in lf:3758 for line in lf:
3759 line = line.replace('<', '&lt').replace('>', '&gt')
3428 hf.write(line)3760 hf.write(line)
3429 lf.close()3761 lf.close()
3430 hf.write('</div>\n')3762 hf.write('</div>\n')
@@ -3475,8 +3807,9 @@ def addScriptCode(hf, testruns): · 44 unmodified lines
3475 script_code = \3807 script_code = \
3476 '<script type="text/javascript">\n'+detail+\3808 '<script type="text/javascript">\n'+detail+\
3477 ' var resolution = -1;\n'\3809 ' var resolution = -1;\n'\
3810 ' var dragval = [0, 0];\n'\
3478 ' function redrawTimescale(t0, tMax, tS) {\n'\3811 ' function redrawTimescale(t0, tMax, tS) {\n'\
3479 ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;"><cR><-R</cR></div>\';\n'\3812 ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;"><cS>&larr;R</cS></div>\';\n'\
3480 ' var tTotal = tMax - t0;\n'\3813 ' var tTotal = tMax - t0;\n'\
3481 ' var list = document.getElementsByClassName("tblock");\n'\3814 ' var list = document.getElementsByClassName("tblock");\n'\
3482 ' for (var i = 0; i < list.length; i++) {\n'\3815 ' for (var i = 0; i < list.length; i++) {\n'\
@@ -3501,7 +3834,7 @@ def addScriptCode(hf, testruns): · 18 unmodified lines
3501 ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\3834 ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\
3502 ' val = (j-divTotal+1)*tS;\n'\3835 ' val = (j-divTotal+1)*tS;\n'\
3503 ' if(j == divTotal - 1)\n'\3836 ' if(j == divTotal - 1)\n'\
3504 ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S-></cS></div>\';\n'\3837 ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S&rarr;</cS></div>\';\n'\
3505 ' else\n'\3838 ' else\n'\
3506 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\3839 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\
3507 ' }\n'\3840 ' }\n'\
@@ -3513,6 +3846,7 @@ def addScriptCode(hf, testruns): · 5 unmodified lines
3513 ' function zoomTimeline() {\n'\3846 ' function zoomTimeline() {\n'\
3514 ' var dmesg = document.getElementById("dmesg");\n'\3847 ' var dmesg = document.getElementById("dmesg");\n'\
3515 ' var zoombox = document.getElementById("dmesgzoombox");\n'\3848 ' var zoombox = document.getElementById("dmesgzoombox");\n'\
3849 ' var left = zoombox.scrollLeft;\n'\
3516 ' var val = parseFloat(dmesg.style.width);\n'\3850 ' var val = parseFloat(dmesg.style.width);\n'\
3517 ' var newval = 100;\n'\3851 ' var newval = 100;\n'\
3518 ' var sh = window.outerWidth / 2;\n'\3852 ' var sh = window.outerWidth / 2;\n'\
@@ -3520,12 +3854,12 @@ def addScriptCode(hf, testruns): · 1 unmodified line
3520 ' newval = val * 1.2;\n'\3854 ' newval = val * 1.2;\n'\
3521 ' if(newval > 910034) newval = 910034;\n'\3855 ' if(newval > 910034) newval = 910034;\n'\
3522 ' dmesg.style.width = newval+"%";\n'\3856 ' dmesg.style.width = newval+"%";\n'\
3523 ' zoombox.scrollLeft = ((zoombox.scrollLeft + sh) * newval / val) - sh;\n'\3857 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\
3524 ' } else if (this.id == "zoomout") {\n'\3858 ' } else if (this.id == "zoomout") {\n'\
3525 ' newval = val / 1.2;\n'\3859 ' newval = val / 1.2;\n'\
3526 ' if(newval < 100) newval = 100;\n'\3860 ' if(newval < 100) newval = 100;\n'\
3527 ' dmesg.style.width = newval+"%";\n'\3861 ' dmesg.style.width = newval+"%";\n'\
3528 ' zoombox.scrollLeft = ((zoombox.scrollLeft + sh) * newval / val) - sh;\n'\3862 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\
3529 ' } else {\n'\3863 ' } else {\n'\
3530 ' zoombox.scrollLeft = 0;\n'\3864 ' zoombox.scrollLeft = 0;\n'\
3531 ' dmesg.style.width = "100%";\n'\3865 ' dmesg.style.width = "100%";\n'\
@@ -3542,8 +3876,12 @@ def addScriptCode(hf, testruns): · 10 unmodified lines
3542 ' resolution = tS[i];\n'\3876 ' resolution = tS[i];\n'\
3543 ' redrawTimescale(t0, tMax, tS[i]);\n'\3877 ' redrawTimescale(t0, tMax, tS[i]);\n'\
3544 ' }\n'\3878 ' }\n'\
3879 ' function deviceName(title) {\n'\
3880 ' var name = title.slice(0, title.indexOf(" ("));\n'\
3881 ' return name;\n'\
3882 ' }\n'\
3545 ' function deviceHover() {\n'\3883 ' function deviceHover() {\n'\
3546 ' var name = this.title.slice(0, this.title.indexOf(" ("));\n'\3884 ' var name = deviceName(this.title);\n'\
3547 ' var dmesg = document.getElementById("dmesg");\n'\3885 ' var dmesg = document.getElementById("dmesg");\n'\
3548 ' var dev = dmesg.getElementsByClassName("thread");\n'\3886 ' var dev = dmesg.getElementsByClassName("thread");\n'\
3549 ' var cpu = -1;\n'\3887 ' var cpu = -1;\n'\
@@ -3552,7 +3890,7 @@ def addScriptCode(hf, testruns): · 2 unmodified lines
3552 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\3890 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\
3553 ' cpu = parseInt(name.slice(8));\n'\3891 ' cpu = parseInt(name.slice(8));\n'\
3554 ' for (var i = 0; i < dev.length; i++) {\n'\3892 ' for (var i = 0; i < dev.length; i++) {\n'\
3555 ' dname = dev[i].title.slice(0, dev[i].title.indexOf(" ("));\n'\3893 ' dname = deviceName(dev[i].title);\n'\
3556 ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\3894 ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\
3557 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\3895 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\
3558 ' (name == dname))\n'\3896 ' (name == dname))\n'\
@@ -3578,7 +3916,7 @@ def addScriptCode(hf, testruns): · 19 unmodified lines
3578 ' total[2] = (total[2]+total[4])/2;\n'\3916 ' total[2] = (total[2]+total[4])/2;\n'\
3579 ' }\n'\3917 ' }\n'\
3580 ' var devtitle = document.getElementById("devicedetailtitle");\n'\3918 ' var devtitle = document.getElementById("devicedetailtitle");\n'\
3581 ' var name = title.slice(0, title.indexOf(" ("));\n'\3919 ' var name = deviceName(title);\n'\
3582 ' if(cpu >= 0) name = "CPU"+cpu;\n'\3920 ' if(cpu >= 0) name = "CPU"+cpu;\n'\
3583 ' var driver = "";\n'\3921 ' var driver = "";\n'\
3584 ' var tS = "<t2>(</t2>";\n'\3922 ' var tS = "<t2>(</t2>";\n'\
@@ -3600,7 +3938,7 @@ def addScriptCode(hf, testruns): · 15 unmodified lines
3600 ' function deviceDetail() {\n'\3938 ' function deviceDetail() {\n'\
3601 ' var devinfo = document.getElementById("devicedetail");\n'\3939 ' var devinfo = document.getElementById("devicedetail");\n'\
3602 ' devinfo.style.display = "block";\n'\3940 ' devinfo.style.display = "block";\n'\
3603 ' var name = this.title.slice(0, this.title.indexOf(" ("));\n'\3941 ' var name = deviceName(this.title);\n'\
3604 ' var cpu = -1;\n'\3942 ' var cpu = -1;\n'\
3605 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\3943 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\
3606 ' cpu = parseInt(name.slice(7));\n'\3944 ' cpu = parseInt(name.slice(7));\n'\
@@ -3615,7 +3953,7 @@ def addScriptCode(hf, testruns): · 8 unmodified lines
3615 ' var pd = pdata[0];\n'\3953 ' var pd = pdata[0];\n'\
3616 ' var total = [0.0, 0.0, 0.0];\n'\3954 ' var total = [0.0, 0.0, 0.0];\n'\
3617 ' for (var i = 0; i < dev.length; i++) {\n'\3955 ' for (var i = 0; i < dev.length; i++) {\n'\
3618 ' dname = dev[i].title.slice(0, dev[i].title.indexOf(" ("));\n'\3956 ' dname = deviceName(dev[i].title);\n'\
3619 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\3957 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\
3620 ' (name == dname))\n'\3958 ' (name == dname))\n'\
3621 ' {\n'\3959 ' {\n'\
@@ -3656,7 +3994,7 @@ def addScriptCode(hf, testruns): · 34 unmodified lines
3656 ' phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\3994 ' phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\
3657 ' left += w;\n'\3995 ' left += w;\n'\
3658 ' var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\3996 ' var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\
3659 ' var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace("_", " ")+"</t3>";\n'\3997 ' var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";\n'\
3660 ' phases[i].innerHTML = time+pname;\n'\3998 ' phases[i].innerHTML = time+pname;\n'\
3661 ' } else {\n'\3999 ' } else {\n'\
3662 ' phases[i].style.width = "0%";\n'\4000 ' phases[i].style.width = "0%";\n'\
@@ -3677,12 +4015,7 @@ def addScriptCode(hf, testruns): · 14 unmodified lines
3677 ' }\n'\4015 ' }\n'\
3678 ' }\n'\4016 ' }\n'\
3679 ' function devListWindow(e) {\n'\4017 ' function devListWindow(e) {\n'\
3680 ' var sx = e.clientX;\n'\4018 ' var win = window.open();\n'\
3681 ' if(sx > window.innerWidth - 440)\n'\
3682 ' sx = window.innerWidth - 440;\n'\
3683 ' var cfg="top="+e.screenY+", left="+sx+", width=440, height=720, scrollbars=yes";\n'\
3684 ' var win = window.open("", "_blank", cfg);\n'\
3685 ' if(window.chrome) win.moveBy(sx, 0);\n'\
3686 ' var html = "<title>"+e.target.innerHTML+"</title>"+\n'\4019 ' var html = "<title>"+e.target.innerHTML+"</title>"+\n'\
3687 ' "<style type=\\"text/css\\">"+\n'\4020 ' "<style type=\\"text/css\\">"+\n'\
3688 ' " ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\4021 ' " ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\
@@ -3692,6 +4025,12 @@ def addScriptCode(hf, testruns): · 3 unmodified lines
3692 ' dt = devtable[1];\n'\4025 ' dt = devtable[1];\n'\
3693 ' win.document.write(html+dt);\n'\4026 ' win.document.write(html+dt);\n'\
3694 ' }\n'\4027 ' }\n'\
4028 ' function errWindow() {\n'\
4029 ' var text = this.id;\n'\
4030 ' var win = window.open();\n'\
4031 ' win.document.write("<pre>"+text+"</pre>");\n'\
4032 ' win.document.close();\n'\
4033 ' }\n'\
3695 ' function logWindow(e) {\n'\4034 ' function logWindow(e) {\n'\
3696 ' var name = e.target.id.slice(4);\n'\4035 ' var name = e.target.id.slice(4);\n'\
3697 ' var win = window.open();\n'\4036 ' var win = window.open();\n'\
@@ -3702,16 +4041,46 @@ def addScriptCode(hf, testruns): · 4 unmodified lines
3702 ' }\n'\4041 ' }\n'\
3703 ' function onClickPhase(e) {\n'\4042 ' function onClickPhase(e) {\n'\
3704 ' }\n'\4043 ' }\n'\
4044 ' function onMouseDown(e) {\n'\
4045 ' dragval[0] = e.clientX;\n'\
4046 ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\
4047 ' document.onmousemove = onMouseMove;\n'\
4048 ' }\n'\
4049 ' function onMouseMove(e) {\n'\
4050 ' var zoombox = document.getElementById("dmesgzoombox");\n'\
4051 ' zoombox.scrollLeft = dragval[1] + dragval[0] - e.clientX;\n'\
4052 ' }\n'\
4053 ' function onMouseUp(e) {\n'\
4054 ' document.onmousemove = null;\n'\
4055 ' }\n'\
4056 ' function onKeyPress(e) {\n'\
4057 ' var c = e.charCode;\n'\
4058 ' if(c != 42 && c != 43 && c != 45) return;\n'\
4059 ' var click = document.createEvent("Events");\n'\
4060 ' click.initEvent("click", true, false);\n'\
4061 ' if(c == 43) \n'\
4062 ' document.getElementById("zoomin").dispatchEvent(click);\n'\
4063 ' else if(c == 45)\n'\
4064 ' document.getElementById("zoomout").dispatchEvent(click);\n'\
4065 ' else if(c == 42)\n'\
4066 ' document.getElementById("zoomdef").dispatchEvent(click);\n'\
4067 ' }\n'\
3705 ' window.addEventListener("resize", function () {zoomTimeline();});\n'\4068 ' window.addEventListener("resize", function () {zoomTimeline();});\n'\
3706 ' window.addEventListener("load", function () {\n'\4069 ' window.addEventListener("load", function () {\n'\
3707 ' var dmesg = document.getElementById("dmesg");\n'\4070 ' var dmesg = document.getElementById("dmesg");\n'\
3708 ' dmesg.style.width = "100%"\n'\4071 ' dmesg.style.width = "100%"\n'\
4072 ' dmesg.onmousedown = onMouseDown;\n'\
4073 ' document.onmouseup = onMouseUp;\n'\
4074 ' document.onkeypress = onKeyPress;\n'\
3709 ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\4075 ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\
3710 ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\4076 ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\
3711 ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\4077 ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\
3712 ' var list = document.getElementsByClassName("square");\n'\4078 ' var list = document.getElementsByClassName("square");\n'\
3713 ' for (var i = 0; i < list.length; i++)\n'\4079 ' for (var i = 0; i < list.length; i++)\n'\
3714 ' list[i].onclick = onClickPhase;\n'\4080 ' list[i].onclick = onClickPhase;\n'\
4081 ' var list = document.getElementsByClassName("err");\n'\
4082 ' for (var i = 0; i < list.length; i++)\n'\
4083 ' list[i].onclick = errWindow;\n'\
3715 ' var list = document.getElementsByClassName("logbtn");\n'\4084 ' var list = document.getElementsByClassName("logbtn");\n'\
3716 ' for (var i = 0; i < list.length; i++)\n'\4085 ' for (var i = 0; i < list.length; i++)\n'\
3717 ' list[i].onclick = logWindow;\n'\4086 ' list[i].onclick = logWindow;\n'\
@@ -3734,9 +4103,7 @@ def addScriptCode(hf, testruns): · 16 unmodified lines
3734# Execute system suspend through the sysfs interface, then copy the output4103# Execute system suspend through the sysfs interface, then copy the output
3735# dmesg and ftrace files to the test output directory.4104# dmesg and ftrace files to the test output directory.
3736def executeSuspend():4105def executeSuspend():
3737 global sysvals4106 pm = ProcessMonitor()
3738
3739 t0 = time.time()*1000
3740 tp = sysvals.tpath4107 tp = sysvals.tpath
3741 fwdata = []4108 fwdata = []
3742 # mark the start point in the kernel ring buffer just as we start4109 # mark the start point in the kernel ring buffer just as we start
@@ -3745,30 +4112,39 @@ def executeSuspend(): · 2 unmodified lines
3745 if(sysvals.usecallgraph or sysvals.usetraceevents):4112 if(sysvals.usecallgraph or sysvals.usetraceevents):
3746 print('START TRACING')4113 print('START TRACING')
3747 sysvals.fsetVal('1', 'tracing_on')4114 sysvals.fsetVal('1', 'tracing_on')
4115 if sysvals.useprocmon:
4116 pm.start()
3748 # execute however many s/r runs requested4117 # execute however many s/r runs requested
3749 for count in range(1,sysvals.execcount+1):4118 for count in range(1,sysvals.execcount+1):
3750 # if this is test2 and there's a delay, start here4119 # x2delay in between test runs
3751 if(count > 1 and sysvals.x2delay > 0):4120 if(count > 1 and sysvals.x2delay > 0):
3752 tN = time.time()*10004121 sysvals.fsetVal('WAIT %d' % sysvals.x2delay, 'trace_marker')
3753 while (tN - t0) < sysvals.x2delay:4122 time.sleep(sysvals.x2delay/1000.0)
3754 tN = time.time()*10004123 sysvals.fsetVal('WAIT END', 'trace_marker')
3755 time.sleep(0.001)4124 # start message
3756 # initiate suspend4125 if sysvals.testcommand != '':
3757 if(sysvals.usecallgraph or sysvals.usetraceevents):
3758 sysvals.fsetVal('SUSPEND START', 'trace_marker')
3759 if sysvals.suspendmode == 'command':
3760 print('COMMAND START')4126 print('COMMAND START')
3761 if(sysvals.rtcwake):
3762 print('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime)
3763 sysvals.rtcWakeAlarmOn()
3764 os.system(sysvals.testcommand)
3765 else:4127 else:
3766 if(sysvals.rtcwake):4128 if(sysvals.rtcwake):
3767 print('SUSPEND START')4129 print('SUSPEND START')
3768 print('will autoresume in %d seconds' % sysvals.rtcwaketime)
3769 sysvals.rtcWakeAlarmOn()
3770 else:4130 else:
3771 print('SUSPEND START (press a key to resume)')4131 print('SUSPEND START (press a key to resume)')
4132 # set rtcwake
4133 if(sysvals.rtcwake):
4134 print('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime)
4135 sysvals.rtcWakeAlarmOn()
4136 # start of suspend trace marker
4137 if(sysvals.usecallgraph or sysvals.usetraceevents):
4138 sysvals.fsetVal('SUSPEND START', 'trace_marker')
4139 # predelay delay
4140 if(count == 1 and sysvals.predelay > 0):
4141 sysvals.fsetVal('WAIT %d' % sysvals.predelay, 'trace_marker')
4142 time.sleep(sysvals.predelay/1000.0)
4143 sysvals.fsetVal('WAIT END', 'trace_marker')
4144 # initiate suspend or command
4145 if sysvals.testcommand != '':
4146 call(sysvals.testcommand+' 2>&1', shell=True);
4147 else:
3772 pf = open(sysvals.powerfile, 'w')4148 pf = open(sysvals.powerfile, 'w')
3773 pf.write(sysvals.suspendmode)4149 pf.write(sysvals.suspendmode)
3774 # execution will pause here4150 # execution will pause here
@@ -3776,26 +4152,27 @@ def executeSuspend(): · 1 unmodified line
3776 pf.close()4152 pf.close()
3777 except:4153 except:
3778 pass4154 pass
3779 t0 = time.time()*1000
3780 if(sysvals.rtcwake):4155 if(sysvals.rtcwake):
3781 sysvals.rtcWakeAlarmOff()4156 sysvals.rtcWakeAlarmOff()
4157 # postdelay delay
4158 if(count == sysvals.execcount and sysvals.postdelay > 0):
4159 sysvals.fsetVal('WAIT %d' % sysvals.postdelay, 'trace_marker')
4160 time.sleep(sysvals.postdelay/1000.0)
4161 sysvals.fsetVal('WAIT END', 'trace_marker')
3782 # return from suspend4162 # return from suspend
3783 print('RESUME COMPLETE')4163 print('RESUME COMPLETE')
3784 if(sysvals.usecallgraph or sysvals.usetraceevents):4164 if(sysvals.usecallgraph or sysvals.usetraceevents):
3785 sysvals.fsetVal('RESUME COMPLETE', 'trace_marker')4165 sysvals.fsetVal('RESUME COMPLETE', 'trace_marker')
3786 if(sysvals.suspendmode == 'mem'):4166 if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'):
3787 fwdata.append(getFPDT(False))4167 fwdata.append(getFPDT(False))
3788 # look for post resume events after the last test run
3789 t = sysvals.postresumetime
3790 if(t > 0):
3791 print('Waiting %d seconds for POST-RESUME trace events...' % t)
3792 time.sleep(t)
3793 # stop ftrace4168 # stop ftrace
3794 if(sysvals.usecallgraph or sysvals.usetraceevents):4169 if(sysvals.usecallgraph or sysvals.usetraceevents):
4170 if sysvals.useprocmon:
4171 pm.stop()
3795 sysvals.fsetVal('0', 'tracing_on')4172 sysvals.fsetVal('0', 'tracing_on')
3796 print('CAPTURING TRACE')4173 print('CAPTURING TRACE')
3797 writeDatafileHeader(sysvals.ftracefile, fwdata)4174 writeDatafileHeader(sysvals.ftracefile, fwdata)
3798 os.system('cat '+tp+'trace >> '+sysvals.ftracefile)4175 call('cat '+tp+'trace >> '+sysvals.ftracefile, shell=True)
3799 sysvals.fsetVal('', 'trace')4176 sysvals.fsetVal('', 'trace')
3800 devProps()4177 devProps()
3801 # grab a copy of the dmesg output4178 # grab a copy of the dmesg output
@@ -3804,17 +4181,12 @@ def executeSuspend(): · 2 unmodified lines
3804 sysvals.getdmesg()4181 sysvals.getdmesg()
3805 4182
3806def writeDatafileHeader(filename, fwdata):4183def writeDatafileHeader(filename, fwdata):
3807 global sysvals
3808
3809 prt = sysvals.postresumetime
3810 fp = open(filename, 'a')4184 fp = open(filename, 'a')
3811 fp.write(sysvals.teststamp+'\n')4185 fp.write(sysvals.teststamp+'\n')
3812 if(sysvals.suspendmode == 'mem'):4186 if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'):
3813 for fw in fwdata:4187 for fw in fwdata:
3814 if(fw):4188 if(fw):
3815 fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1]))4189 fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1]))
3816 if(prt > 0):
3817 fp.write('# post resume time %u\n' % prt)
3818 fp.close()4190 fp.close()
3819 4191
3820# Function: setUSBDevicesAuto4192# Function: setUSBDevicesAuto
@@ -3824,18 +4196,16 @@ def writeDatafileHeader(filename, fwdata): · 3 unmodified lines
3824# to always-on since the kernel cant determine if the device can4196# to always-on since the kernel cant determine if the device can
3825# properly autosuspend4197# properly autosuspend
3826def setUSBDevicesAuto():4198def setUSBDevicesAuto():
3827 global sysvals
3828
3829 rootCheck(True)4199 rootCheck(True)
3830 for dirname, dirnames, filenames in os.walk('/sys/devices'):4200 for dirname, dirnames, filenames in os.walk('/sys/devices'):
3831 if(re.match('.*/usb[0-9]*.*', dirname) and4201 if(re.match('.*/usb[0-9]*.*', dirname) and
3832 'idVendor' in filenames and 'idProduct' in filenames):4202 'idVendor' in filenames and 'idProduct' in filenames):
3833 os.system('echo auto > %s/power/control' % dirname)4203 call('echo auto > %s/power/control' % dirname, shell=True)
3834 name = dirname.split('/')[-1]4204 name = dirname.split('/')[-1]
3835 desc = os.popen('cat %s/product 2>/dev/null' % \4205 desc = Popen(['cat', '%s/product' % dirname],
3836 dirname).read().replace('\n', '')4206 stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
3837 ctrl = os.popen('cat %s/power/control 2>/dev/null' % \4207 ctrl = Popen(['cat', '%s/power/control' % dirname],
3838 dirname).read().replace('\n', '')4208 stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
3839 print('control is %s for %6s: %s' % (ctrl, name, desc))4209 print('control is %s for %6s: %s' % (ctrl, name, desc))
3840 4210
3841# Function: yesno4211# Function: yesno
@@ -3872,8 +4242,6 @@ def ms2nice(val): · 30 unmodified lines
3872# Detect all the USB hosts and devices currently connected and add4242# Detect all the USB hosts and devices currently connected and add
3873# a list of USB device names to sysvals for better timeline readability4243# a list of USB device names to sysvals for better timeline readability
3874def detectUSB():4244def detectUSB():
3875 global sysvals
3876
3877 field = {'idVendor':'', 'idProduct':'', 'product':'', 'speed':''}4245 field = {'idVendor':'', 'idProduct':'', 'product':'', 'speed':''}
3878 power = {'async':'', 'autosuspend':'', 'autosuspend_delay_ms':'',4246 power = {'async':'', 'autosuspend':'', 'autosuspend_delay_ms':'',
3879 'control':'', 'persist':'', 'runtime_enabled':'',4247 'control':'', 'persist':'', 'runtime_enabled':'',
@@ -3899,12 +4267,12 @@ def detectUSB(): · 19 unmodified lines
3899 if(re.match('.*/usb[0-9]*.*', dirname) and4267 if(re.match('.*/usb[0-9]*.*', dirname) and
3900 'idVendor' in filenames and 'idProduct' in filenames):4268 'idVendor' in filenames and 'idProduct' in filenames):
3901 for i in field:4269 for i in field:
3902 field[i] = os.popen('cat %s/%s 2>/dev/null' % \4270 field[i] = Popen(['cat', '%s/%s' % (dirname, i)],
3903 (dirname, i)).read().replace('\n', '')4271 stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
3904 name = dirname.split('/')[-1]4272 name = dirname.split('/')[-1]
3905 for i in power:4273 for i in power:
3906 power[i] = os.popen('cat %s/power/%s 2>/dev/null' % \4274 power[i] = Popen(['cat', '%s/power/%s' % (dirname, i)],
3907 (dirname, i)).read().replace('\n', '')4275 stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
3908 if(re.match('usb[0-9]*', name)):4276 if(re.match('usb[0-9]*', name)):
3909 first = '%-8s' % name4277 first = '%-8s' % name
3910 else:4278 else:
@@ -3928,7 +4296,6 @@ def detectUSB(): · 17 unmodified lines
3928# Description:4296# Description:
3929# Retrieve a list of properties for all devices in the trace log4297# Retrieve a list of properties for all devices in the trace log
3930def devProps(data=0):4298def devProps(data=0):
3931 global sysvals
3932 props = dict()4299 props = dict()
3933 4300
3934 if data:4301 if data:
@@ -3953,7 +4320,7 @@ def devProps(data=0): · 18 unmodified lines
3953 return4320 return
3954 4321
3955 if(os.path.exists(sysvals.ftracefile) == False):4322 if(os.path.exists(sysvals.ftracefile) == False):
3956 doError('%s does not exist' % sysvals.ftracefile, False)4323 doError('%s does not exist' % sysvals.ftracefile)
3957 4324
3958 # first get the list of devices we need properties for4325 # first get the list of devices we need properties for
3959 msghead = 'Additional data added by AnalyzeSuspend'4326 msghead = 'Additional data added by AnalyzeSuspend'
@@ -3976,7 +4343,7 @@ def devProps(data=0): · 16 unmodified lines
3976 m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg'));4343 m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg'));
3977 if(not m):4344 if(not m):
3978 continue4345 continue
3979 drv, dev, par = m.group('drv'), m.group('d'), m.group('p')4346 dev = m.group('d')
3980 if dev not in props:4347 if dev not in props:
3981 props[dev] = DevProps()4348 props[dev] = DevProps()
3982 tf.close()4349 tf.close()
@@ -4052,7 +4419,6 @@ def devProps(data=0): · 69 unmodified lines
4052# Output:4419# Output:
4053# A string list of the available modes4420# A string list of the available modes
4054def getModes():4421def getModes():
4055 global sysvals
4056 modes = ''4422 modes = ''
4057 if(os.path.exists(sysvals.powerfile)):4423 if(os.path.exists(sysvals.powerfile)):
4058 fp = open(sysvals.powerfile, 'r')4424 fp = open(sysvals.powerfile, 'r')
@@ -4066,8 +4432,6 @@ def getModes(): · 7 unmodified lines
4066# Arguments:4432# Arguments:
4067# output: True to output the info to stdout, False otherwise4433# output: True to output the info to stdout, False otherwise
4068def getFPDT(output):4434def getFPDT(output):
4069 global sysvals
4070
4071 rectype = {}4435 rectype = {}
4072 rectype[0] = 'Firmware Basic Boot Performance Record'4436 rectype[0] = 'Firmware Basic Boot Performance Record'
4073 rectype[1] = 'S3 Performance Table Record'4437 rectype[1] = 'S3 Performance Table Record'
@@ -4078,19 +4442,19 @@ def getFPDT(output): · 4 unmodified lines
4078 rootCheck(True)4442 rootCheck(True)
4079 if(not os.path.exists(sysvals.fpdtpath)):4443 if(not os.path.exists(sysvals.fpdtpath)):
4080 if(output):4444 if(output):
4081 doError('file does not exist: %s' % sysvals.fpdtpath, False)4445 doError('file does not exist: %s' % sysvals.fpdtpath)
4082 return False4446 return False
4083 if(not os.access(sysvals.fpdtpath, os.R_OK)):4447 if(not os.access(sysvals.fpdtpath, os.R_OK)):
4084 if(output):4448 if(output):
4085 doError('file is not readable: %s' % sysvals.fpdtpath, False)4449 doError('file is not readable: %s' % sysvals.fpdtpath)
4086 return False4450 return False
4087 if(not os.path.exists(sysvals.mempath)):4451 if(not os.path.exists(sysvals.mempath)):
4088 if(output):4452 if(output):
4089 doError('file does not exist: %s' % sysvals.mempath, False)4453 doError('file does not exist: %s' % sysvals.mempath)
4090 return False4454 return False
4091 if(not os.access(sysvals.mempath, os.R_OK)):4455 if(not os.access(sysvals.mempath, os.R_OK)):
4092 if(output):4456 if(output):
4093 doError('file is not readable: %s' % sysvals.mempath, False)4457 doError('file is not readable: %s' % sysvals.mempath)
4094 return False4458 return False
4095 4459
4096 fp = open(sysvals.fpdtpath, 'rb')4460 fp = open(sysvals.fpdtpath, 'rb')
@@ -4100,7 +4464,7 @@ def getFPDT(output): · 3 unmodified lines
4100 if(len(buf) < 36):4464 if(len(buf) < 36):
4101 if(output):4465 if(output):
4102 doError('Invalid FPDT table data, should '+\4466 doError('Invalid FPDT table data, should '+\
4103 'be at least 36 bytes', False)4467 'be at least 36 bytes')
4104 return False4468 return False
4105 4469
4106 table = struct.unpack('4sIBB6s8sI4sI', buf[0:36])4470 table = struct.unpack('4sIBB6s8sI4sI', buf[0:36])
@@ -4199,7 +4563,6 @@ def getFPDT(output): · 92 unmodified lines
4199# Output:4563# Output:
4200# True if the test will work, False if not4564# True if the test will work, False if not
4201def statusCheck(probecheck=False):4565def statusCheck(probecheck=False):
4202 global sysvals
4203 status = True4566 status = True
4204 4567
4205 print('Checking this system (%s)...' % platform.node())4568 print('Checking this system (%s)...' % platform.node())
@@ -4282,37 +4645,14 @@ def statusCheck(probecheck=False): · 76 unmodified lines
4282 if not probecheck:4645 if not probecheck:
4283 return status4646 return status
4284 4647
4285 if (sysvals.usecallgraph and len(sysvals.debugfuncs) > 0) or len(sysvals.kprobes) > 0:
4286 sysvals.initFtrace(True)
4287
4288 # verify callgraph debugfuncs
4289 if sysvals.usecallgraph and len(sysvals.debugfuncs) > 0:
4290 print(' verifying these ftrace callgraph functions work:')
4291 sysvals.setFtraceFilterFunctions(sysvals.debugfuncs)
4292 fp = open(sysvals.tpath+'set_graph_function', 'r')
4293 flist = fp.read().split('\n')
4294 fp.close()
4295 for func in sysvals.debugfuncs:
4296 res = sysvals.colorText('NO')
4297 if func in flist:
4298 res = 'YES'
4299 else:
4300 for i in flist:
4301 if ' [' in i and func == i.split(' ')[0]:
4302 res = 'YES'
4303 break
4304 print(' %s: %s' % (func, res))
4305
4306 # verify kprobes4648 # verify kprobes
4307 if len(sysvals.kprobes) > 0:4649 if sysvals.usekprobes:
4308 print(' verifying these kprobes work:')4650 for name in sysvals.tracefuncs:
4309 for name in sorted(sysvals.kprobes):4651 sysvals.defaultKprobe(name, sysvals.tracefuncs[name])
4310 if name in sysvals.tracefuncs:4652 if sysvals.usedevsrc:
4311 continue4653 for name in sysvals.dev_tracefuncs:
4312 res = sysvals.colorText('NO')4654 sysvals.defaultKprobe(name, sysvals.dev_tracefuncs[name])
4313 if sysvals.testKprobe(sysvals.kprobes[name]):4655 sysvals.addKprobes(True)
4314 res = 'YES'
4315 print(' %s: %s' % (name, res))
4316 4656
4317 return status4657 return status
4318 4658
@@ -4322,33 +4662,20 @@ def statusCheck(probecheck=False): · 3 unmodified lines
4322# Arguments:4662# Arguments:
4323# msg: the error message to print4663# msg: the error message to print
4324# help: True if printHelp should be called after, False otherwise4664# help: True if printHelp should be called after, False otherwise
4325def doError(msg, help):4665def doError(msg, help=False):
4326 if(help == True):4666 if(help == True):
4327 printHelp()4667 printHelp()
4328 print('ERROR: %s\n') % msg4668 print('ERROR: %s\n') % msg
4329 sys.exit()4669 sys.exit()
4330 4670
4331# Function: doWarning
4332# Description:
4333# generic warning function for non-catastrophic anomalies
4334# Arguments:
4335# msg: the warning message to print
4336# file: If not empty, a filename to request be sent to the owner for debug
4337def doWarning(msg, file=''):
4338 print('/* %s */') % msg
4339 if(file):
4340 print('/* For a fix, please send this'+\
4341 ' %s file to <todd.e.brandt@intel.com> */' % file)
4342
4343# Function: rootCheck4671# Function: rootCheck
4344# Description:4672# Description:
4345# quick check to see if we have root access4673# quick check to see if we have root access
4346def rootCheck(fatal):4674def rootCheck(fatal):
4347 global sysvals
4348 if(os.access(sysvals.powerfile, os.W_OK)):4675 if(os.access(sysvals.powerfile, os.W_OK)):
4349 return True4676 return True
4350 if fatal:4677 if fatal:
4351 doError('This command must be run as root', False)4678 doError('This command must be run as root')
4352 return False4679 return False
4353 4680
4354# Function: getArgInt4681# Function: getArgInt
@@ -4389,71 +4716,61 @@ def getArgFloat(name, args, min, max, main=True): · 34 unmodified lines
4389 doError(name+': value should be between %f and %f' % (min, max), True)4716 doError(name+': value should be between %f and %f' % (min, max), True)
4390 return val4717 return val
4391 4718
4392# Function: rerunTest4719def processData():
4393# Description:
4394# generate an output from an existing set of ftrace/dmesg logs
4395def rerunTest():
4396 global sysvals
4397
4398 if(sysvals.ftracefile != ''):
4399 doesTraceLogHaveTraceEvents()
4400 if(sysvals.dmesgfile == '' and not sysvals.usetraceeventsonly):
4401 doError('recreating this html output '+\
4402 'requires a dmesg file', False)
4403 sysvals.setOutputFile()
4404 vprint('Output file: %s' % sysvals.htmlfile)
4405 print('PROCESSING DATA')4720 print('PROCESSING DATA')
4406 if(sysvals.usetraceeventsonly):4721 if(sysvals.usetraceeventsonly):
4407 testruns = parseTraceLog()4722 testruns = parseTraceLog()
4723 if sysvals.dmesgfile:
4724 dmesgtext = loadKernelLog(True)
4725 for data in testruns:
4726 data.extractErrorInfo(dmesgtext)
4408 else:4727 else:
4409 testruns = loadKernelLog()4728 testruns = loadKernelLog()
4410 for data in testruns:4729 for data in testruns:
4411 parseKernelLog(data)4730 parseKernelLog(data)
4412 if(sysvals.ftracefile != ''):4731 if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)):
4413 appendIncompleteTraceLog(testruns)4732 appendIncompleteTraceLog(testruns)
4414 createHTML(testruns)4733 createHTML(testruns)
4415 4734
4735# Function: rerunTest
4736# Description:
4737# generate an output from an existing set of ftrace/dmesg logs
4738def rerunTest():
4739 if sysvals.ftracefile:
4740 doesTraceLogHaveTraceEvents()
4741 if not sysvals.dmesgfile and not sysvals.usetraceeventsonly:
4742 doError('recreating this html output requires a dmesg file')
4743 sysvals.setOutputFile()
4744 vprint('Output file: %s' % sysvals.htmlfile)
4745 if(os.path.exists(sysvals.htmlfile) and not os.access(sysvals.htmlfile, os.W_OK)):
4746 doError('missing permission to write to %s' % sysvals.htmlfile)
4747 processData()
4748
4416# Function: runTest4749# Function: runTest
4417# Description:4750# Description:
4418# execute a suspend/resume, gather the logs, and generate the output4751# execute a suspend/resume, gather the logs, and generate the output
4419def runTest(subdir, testpath=''):4752def runTest(subdir, testpath=''):
4420 global sysvals
4421
4422 # prepare for the test4753 # prepare for the test
4423 sysvals.initFtrace()4754 sysvals.initFtrace()
4424 sysvals.initTestOutput(subdir, testpath)4755 sysvals.initTestOutput(subdir, testpath)
4425 4756 vprint('Output files:\n\t%s\n\t%s\n\t%s' % \
4426 vprint('Output files:\n %s' % sysvals.dmesgfile)4757 (sysvals.dmesgfile, sysvals.ftracefile, sysvals.htmlfile))
4427 if(sysvals.usecallgraph or
4428 sysvals.usetraceevents or
4429 sysvals.usetraceeventsonly):
4430 vprint(' %s' % sysvals.ftracefile)
4431 vprint(' %s' % sysvals.htmlfile)
4432 4758
4433 # execute the test4759 # execute the test
4434 executeSuspend()4760 executeSuspend()
4435 sysvals.cleanupFtrace()4761 sysvals.cleanupFtrace()
4762 processData()
4436 4763
4437 # analyze the data and create the html output4764 # if running as root, change output dir owner to sudo_user
4438 print('PROCESSING DATA')4765 if os.path.isdir(sysvals.testdir) and os.getuid() == 0 and \
4439 if(sysvals.usetraceeventsonly):4766 'SUDO_USER' in os.environ:
4440 # data for kernels 3.15 or newer is entirely in ftrace4767 cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1'
4441 testruns = parseTraceLog()4768 call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True)
4442 else:
4443 # data for kernels older than 3.15 is primarily in dmesg
4444 testruns = loadKernelLog()
4445 for data in testruns:
4446 parseKernelLog(data)
4447 if(sysvals.usecallgraph or sysvals.usetraceevents):
4448 appendIncompleteTraceLog(testruns)
4449 createHTML(testruns)
4450 4769
4451# Function: runSummary4770# Function: runSummary
4452# Description:4771# Description:
4453# create a summary of tests in a sub-directory4772# create a summary of tests in a sub-directory
4454def runSummary(subdir, output):4773def runSummary(subdir, output):
4455 global sysvals
4456
4457 # get a list of ftrace output files4774 # get a list of ftrace output files
4458 files = []4775 files = []
4459 for dirname, dirnames, filenames in os.walk(subdir):4776 for dirname, dirnames, filenames in os.walk(subdir):
@@ -4509,12 +4826,12 @@ def checkArgBool(value): · 49 unmodified lines
4509# Description:4826# Description:
4510# Configure the script via the info in a config file4827# Configure the script via the info in a config file
4511def configFromFile(file):4828def configFromFile(file):
4512 global sysvals
4513 Config = ConfigParser.ConfigParser()4829 Config = ConfigParser.ConfigParser()
4514 4830
4515 ignorekprobes = False
4516 Config.read(file)4831 Config.read(file)
4517 sections = Config.sections()4832 sections = Config.sections()
4833 overridekprobes = False
4834 overridedevkprobes = False
4518 if 'Settings' in sections:4835 if 'Settings' in sections:
4519 for opt in Config.options('Settings'):4836 for opt in Config.options('Settings'):
4520 value = Config.get('Settings', opt).lower()4837 value = Config.get('Settings', opt).lower()
@@ -4524,19 +4841,19 @@ def configFromFile(file): · 3 unmodified lines
4524 sysvals.addlogs = checkArgBool(value)4841 sysvals.addlogs = checkArgBool(value)
4525 elif(opt.lower() == 'dev'):4842 elif(opt.lower() == 'dev'):
4526 sysvals.usedevsrc = checkArgBool(value)4843 sysvals.usedevsrc = checkArgBool(value)
4527 elif(opt.lower() == 'ignorekprobes'):4844 elif(opt.lower() == 'proc'):
4528 ignorekprobes = checkArgBool(value)4845 sysvals.useprocmon = checkArgBool(value)
4529 elif(opt.lower() == 'x2'):4846 elif(opt.lower() == 'x2'):
4530 if checkArgBool(value):4847 if checkArgBool(value):
4531 sysvals.execcount = 24848 sysvals.execcount = 2
4532 elif(opt.lower() == 'callgraph'):4849 elif(opt.lower() == 'callgraph'):
4533 sysvals.usecallgraph = checkArgBool(value)4850 sysvals.usecallgraph = checkArgBool(value)
4534 elif(opt.lower() == 'callgraphfunc'):4851 elif(opt.lower() == 'override-timeline-functions'):
4535 sysvals.debugfuncs = []4852 overridekprobes = checkArgBool(value)
4536 if value:4853 elif(opt.lower() == 'override-dev-timeline-functions'):
4537 value = value.split(',')4854 overridedevkprobes = checkArgBool(value)
4538 for i in value:4855 elif(opt.lower() == 'devicefilter'):
4539 sysvals.debugfuncs.append(i.strip())4856 sysvals.setDeviceFilter(value)
4540 elif(opt.lower() == 'expandcg'):4857 elif(opt.lower() == 'expandcg'):
4541 sysvals.cgexp = checkArgBool(value)4858 sysvals.cgexp = checkArgBool(value)
4542 elif(opt.lower() == 'srgap'):4859 elif(opt.lower() == 'srgap'):
@@ -4548,8 +4865,10 @@ def configFromFile(file): · 5 unmodified lines
4548 sysvals.testcommand = value4865 sysvals.testcommand = value
4549 elif(opt.lower() == 'x2delay'):4866 elif(opt.lower() == 'x2delay'):
4550 sysvals.x2delay = getArgInt('-x2delay', value, 0, 60000, False)4867 sysvals.x2delay = getArgInt('-x2delay', value, 0, 60000, False)
4551 elif(opt.lower() == 'postres'):4868 elif(opt.lower() == 'predelay'):
4552 sysvals.postresumetime = getArgInt('-postres', value, 0, 3600, False)4869 sysvals.predelay = getArgInt('-predelay', value, 0, 60000, False)
4870 elif(opt.lower() == 'postdelay'):
4871 sysvals.postdelay = getArgInt('-postdelay', value, 0, 60000, False)
4553 elif(opt.lower() == 'rtcwake'):4872 elif(opt.lower() == 'rtcwake'):
4554 sysvals.rtcwake = True4873 sysvals.rtcwake = True
4555 sysvals.rtcwaketime = getArgInt('-rtcwake', value, 0, 3600, False)4874 sysvals.rtcwaketime = getArgInt('-rtcwake', value, 0, 3600, False)
@@ -4557,53 +4876,50 @@ def configFromFile(file): · 1 unmodified line
4557 sysvals.setPrecision(getArgInt('-timeprec', value, 0, 6, False))4876 sysvals.setPrecision(getArgInt('-timeprec', value, 0, 6, False))
4558 elif(opt.lower() == 'mindev'):4877 elif(opt.lower() == 'mindev'):
4559 sysvals.mindevlen = getArgFloat('-mindev', value, 0.0, 10000.0, False)4878 sysvals.mindevlen = getArgFloat('-mindev', value, 0.0, 10000.0, False)
4879 elif(opt.lower() == 'callloop-maxgap'):
4880 sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', value, 0.0, 1.0, False)
4881 elif(opt.lower() == 'callloop-maxlen'):
4882 sysvals.callloopmaxgap = getArgFloat('-callloop-maxlen', value, 0.0, 1.0, False)
4560 elif(opt.lower() == 'mincg'):4883 elif(opt.lower() == 'mincg'):
4561 sysvals.mincglen = getArgFloat('-mincg', value, 0.0, 10000.0, False)4884 sysvals.mincglen = getArgFloat('-mincg', value, 0.0, 10000.0, False)
4562 elif(opt.lower() == 'kprobecolor'):
4563 try:
4564 val = int(value, 16)
4565 sysvals.kprobecolor = '#'+value
4566 except:
4567 sysvals.kprobecolor = value
4568 elif(opt.lower() == 'synccolor'):
4569 try:
4570 val = int(value, 16)
4571 sysvals.synccolor = '#'+value
4572 except:
4573 sysvals.synccolor = value
4574 elif(opt.lower() == 'output-dir'):4885 elif(opt.lower() == 'output-dir'):
4575 args = dict()4886 sysvals.setOutputFolder(value)
4576 n = datetime.now()
4577 args['date'] = n.strftime('%y%m%d')
4578 args['time'] = n.strftime('%H%M%S')
4579 args['hostname'] = sysvals.hostname
4580 sysvals.outdir = value.format(**args)
4581 4887
4582 if sysvals.suspendmode == 'command' and not sysvals.testcommand:4888 if sysvals.suspendmode == 'command' and not sysvals.testcommand:
4583 doError('No command supplied for mode "command"', False)4889 doError('No command supplied for mode "command"')
4890
4891 # compatibility errors
4584 if sysvals.usedevsrc and sysvals.usecallgraph:4892 if sysvals.usedevsrc and sysvals.usecallgraph:
4585 doError('dev and callgraph cannot both be true', False)4893 doError('-dev is not compatible with -f')
4586 if sysvals.usecallgraph and sysvals.execcount > 1:4894 if sysvals.usecallgraph and sysvals.useprocmon:
4587 doError('-x2 is not compatible with -f', False)4895 doError('-proc is not compatible with -f')
4588 4896
4589 if ignorekprobes:4897 if overridekprobes:
4590 return4898 sysvals.tracefuncs = dict()
4899 if overridedevkprobes:
4900 sysvals.dev_tracefuncs = dict()
4591 4901
4592 kprobes = dict()4902 kprobes = dict()
4593 archkprobe = 'Kprobe_'+platform.machine()4903 kprobesec = 'dev_timeline_functions_'+platform.machine()
4594 if archkprobe in sections:4904 if kprobesec in sections:
4595 for name in Config.options(archkprobe):4905 for name in Config.options(kprobesec):
4596 kprobes[name] = Config.get(archkprobe, name)4906 text = Config.get(kprobesec, name)
4597 if 'Kprobe' in sections:4907 kprobes[name] = (text, True)
4598 for name in Config.options('Kprobe'):4908 kprobesec = 'timeline_functions_'+platform.machine()
4599 kprobes[name] = Config.get('Kprobe', name)4909 if kprobesec in sections:
4910 for name in Config.options(kprobesec):
4911 if name in kprobes:
4912 doError('Duplicate timeline function found "%s"' % (name))
4913 text = Config.get(kprobesec, name)
4914 kprobes[name] = (text, False)
4600 4915
4601 for name in kprobes:4916 for name in kprobes:
4602 function = name4917 function = name
4603 format = name4918 format = name
4604 color = ''4919 color = ''
4605 args = dict()4920 args = dict()
4606 data = kprobes[name].split()4921 text, dev = kprobes[name]
4922 data = text.split()
4607 i = 04923 i = 0
4608 for val in data:4924 for val in data:
4609 # bracketted strings are special formatting, read them separately4925 # bracketted strings are special formatting, read them separately
@@ -4626,28 +4942,30 @@ def configFromFile(file): · 16 unmodified lines
4626 args[d[0]] = d[1]4942 args[d[0]] = d[1]
4627 i += 14943 i += 1
4628 if not function or not format:4944 if not function or not format:
4629 doError('Invalid kprobe: %s' % name, False)4945 doError('Invalid kprobe: %s' % name)
4630 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format):4946 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format):
4631 if arg not in args:4947 if arg not in args:
4632 doError('Kprobe "%s" is missing argument "%s"' % (name, arg), False)4948 doError('Kprobe "%s" is missing argument "%s"' % (name, arg))
4633 if name in sysvals.kprobes:4949 if (dev and name in sysvals.dev_tracefuncs) or (not dev and name in sysvals.tracefuncs):
4634 doError('Duplicate kprobe found "%s"' % (name), False)4950 doError('Duplicate timeline function found "%s"' % (name))
4635 vprint('Adding KPROBE: %s %s %s %s' % (name, function, format, args))4951
4636 sysvals.kprobes[name] = {4952 kp = {
4637 'name': name,4953 'name': name,
4638 'func': function,4954 'func': function,
4639 'format': format,4955 'format': format,
4640 'args': args,4956 sysvals.archargs: args
4641 'mask': re.sub('{(?P<n>[a-z,A-Z,0-9]*)}', '.*', format)
4642 }4957 }
4643 if color:4958 if color:
4644 sysvals.kprobes[name]['color'] = color4959 kp['color'] = color
4960 if dev:
4961 sysvals.dev_tracefuncs[name] = kp
4962 else:
4963 sysvals.tracefuncs[name] = kp
4645 4964
4646# Function: printHelp4965# Function: printHelp
4647# Description:4966# Description:
4648# print out the help text4967# print out the help text
4649def printHelp():4968def printHelp():
4650 global sysvals
4651 modes = getModes()4969 modes = getModes()
4652 4970
4653 print('')4971 print('')
@@ -4670,44 +4988,47 @@ def printHelp(): · 16 unmodified lines
4670 print('')4988 print('')
4671 print('Options:')4989 print('Options:')
4672 print(' [general]')4990 print(' [general]')
4673 print(' -h Print this help text')4991 print(' -h Print this help text')
4674 print(' -v Print the current tool version')4992 print(' -v Print the current tool version')
4675 print(' -config file Pull arguments and config options from a file')4993 print(' -config fn Pull arguments and config options from file fn')
4676 print(' -verbose Print extra information during execution and analysis')4994 print(' -verbose Print extra information during execution and analysis')
4677 print(' -status Test to see if the system is enabled to run this tool')4995 print(' -status Test to see if the system is enabled to run this tool')
4678 print(' -modes List available suspend modes')4996 print(' -modes List available suspend modes')
4679 print(' -m mode Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode)4997 print(' -m mode Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode)
4680 print(' -o subdir Override the output subdirectory')4998 print(' -o subdir Override the output subdirectory')
4999 print(' -rtcwake t Use rtcwake to autoresume after <t> seconds (default: disabled)')
5000 print(' -addlogs Add the dmesg and ftrace logs to the html output')
5001 print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)')
4681 print(' [advanced]')5002 print(' [advanced]')
4682 print(' -rtcwake t Use rtcwake to autoresume after <t> seconds (default: disabled)')5003 print(' -cmd {s} Run the timeline over a custom command, e.g. "sync -d"')
4683 print(' -addlogs Add the dmesg and ftrace logs to the html output')5004 print(' -proc Add usermode process info into the timeline (default: disabled)')
4684 print(' -multi n d Execute <n> consecutive tests at <d> seconds intervals. The outputs will')5005 print(' -dev Add kernel function calls and threads to the timeline (default: disabled)')
5006 print(' -x2 Run two suspend/resumes back to back (default: disabled)')
5007 print(' -x2delay t Include t ms delay between multiple test runs (default: 0 ms)')
5008 print(' -predelay t Include t ms delay before 1st suspend (default: 0 ms)')
5009 print(' -postdelay t Include t ms delay after last resume (default: 0 ms)')
5010 print(' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)')
5011 print(' -multi n d Execute <n> consecutive tests at <d> seconds intervals. The outputs will')
4685 print(' be created in a new subdirectory with a summary page.')5012 print(' be created in a new subdirectory with a summary page.')
4686 print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)')
4687 print(' -cmd {s} Instead of suspend/resume, run a command, e.g. "sync -d"')
4688 print(' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)')
4689 print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
4690 print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)')
4691 print(' [debug]')5013 print(' [debug]')
4692 print(' -f Use ftrace to create device callgraphs (default: disabled)')5014 print(' -f Use ftrace to create device callgraphs (default: disabled)')
4693 print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)')5015 print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)')
4694 print(' -flist Print the list of functions currently being captured in ftrace')5016 print(' -flist Print the list of functions currently being captured in ftrace')
4695 print(' -flistall Print all functions capable of being captured in ftrace')5017 print(' -flistall Print all functions capable of being captured in ftrace')
4696 print(' -fadd file Add functions to be graphed in the timeline from a list in a text file')5018 print(' -fadd file Add functions to be graphed in the timeline from a list in a text file')
4697 print(' -filter "d1 d2 ..." Filter out all but this list of device names')5019 print(' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names')
4698 print(' -dev Display common low level functions in the timeline')5020 print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
4699 print(' [post-resume task analysis]')5021 print(' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)')
4700 print(' -x2 Run two suspend/resumes back to back (default: disabled)')5022 print(' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)')
4701 print(' -x2delay t Minimum millisecond delay <t> between the two test runs (default: 0 ms)')5023 print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)')
4702 print(' -postres t Time after resume completion to wait for post-resume events (default: 0 S)')
4703 print(' [utilities]')5024 print(' [utilities]')
4704 print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table')5025 print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table')
4705 print(' -usbtopo Print out the current USB topology with power info')5026 print(' -usbtopo Print out the current USB topology with power info')
4706 print(' -usbauto Enable autosuspend for all connected USB devices')5027 print(' -usbauto Enable autosuspend for all connected USB devices')
4707 print(' [re-analyze data from previous runs]')5028 print(' [re-analyze data from previous runs]')
4708 print(' -ftrace ftracefile Create HTML output using ftrace input')5029 print(' -ftrace ftracefile Create HTML output using ftrace input')
4709 print(' -dmesg dmesgfile Create HTML output using dmesg (not needed for kernel >= 3.15)')5030 print(' -dmesg dmesgfile Create HTML output using dmesg (not needed for kernel >= 3.15)')
4710 print(' -summary directory Create a summary of all test in this dir')5031 print(' -summary directory Create a summary of all test in this dir')
4711 print('')5032 print('')
4712 return True5033 return True
4713 5034
@@ -4739,26 +5060,22 @@ if __name__ == '__main__': · 25 unmodified lines
4739 sys.exit()5060 sys.exit()
4740 elif(arg == '-x2'):5061 elif(arg == '-x2'):
4741 sysvals.execcount = 25062 sysvals.execcount = 2
4742 if(sysvals.usecallgraph):
4743 doError('-x2 is not compatible with -f', False)
4744 elif(arg == '-x2delay'):5063 elif(arg == '-x2delay'):
4745 sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000)5064 sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000)
4746 elif(arg == '-postres'):5065 elif(arg == '-predelay'):
4747 sysvals.postresumetime = getArgInt('-postres', args, 0, 3600)5066 sysvals.predelay = getArgInt('-predelay', args, 0, 60000)
5067 elif(arg == '-postdelay'):
5068 sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000)
4748 elif(arg == '-f'):5069 elif(arg == '-f'):
4749 sysvals.usecallgraph = True5070 sysvals.usecallgraph = True
4750 if(sysvals.execcount > 1):
4751 doError('-x2 is not compatible with -f', False)
4752 if(sysvals.usedevsrc):
4753 doError('-dev is not compatible with -f', False)
4754 elif(arg == '-addlogs'):5071 elif(arg == '-addlogs'):
4755 sysvals.addlogs = True5072 sysvals.addlogs = True
4756 elif(arg == '-verbose'):5073 elif(arg == '-verbose'):
4757 sysvals.verbose = True5074 sysvals.verbose = True
5075 elif(arg == '-proc'):
5076 sysvals.useprocmon = True
4758 elif(arg == '-dev'):5077 elif(arg == '-dev'):
4759 sysvals.usedevsrc = True5078 sysvals.usedevsrc = True
4760 if(sysvals.usecallgraph):
4761 doError('-dev is not compatible with -f', False)
4762 elif(arg == '-rtcwake'):5079 elif(arg == '-rtcwake'):
4763 sysvals.rtcwake = True5080 sysvals.rtcwake = True
4764 sysvals.rtcwaketime = getArgInt('-rtcwake', args, 0, 3600)5081 sysvals.rtcwaketime = getArgInt('-rtcwake', args, 0, 3600)
@@ -4768,6 +5085,21 @@ if __name__ == '__main__': · 3 unmodified lines
4768 sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0)5085 sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0)
4769 elif(arg == '-mincg'):5086 elif(arg == '-mincg'):
4770 sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0)5087 sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0)
5088 elif(arg == '-cgtest'):
5089 sysvals.cgtest = getArgInt('-cgtest', args, 0, 1)
5090 elif(arg == '-cgphase'):
5091 try:
5092 val = args.next()
5093 except:
5094 doError('No phase name supplied', True)
5095 d = Data(0)
5096 if val not in d.phases:
5097 doError('Invalid phase, valid phaess are %s' % d.phases, True)
5098 sysvals.cgphase = val
5099 elif(arg == '-callloop-maxgap'):
5100 sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', args, 0.0, 1.0)
5101 elif(arg == '-callloop-maxlen'):
5102 sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0)
4771 elif(arg == '-cmd'):5103 elif(arg == '-cmd'):
4772 try:5104 try:
4773 val = args.next()5105 val = args.next()
@@ -4788,14 +5120,14 @@ if __name__ == '__main__': · 14 unmodified lines
4788 val = args.next()5120 val = args.next()
4789 except:5121 except:
4790 doError('No subdirectory name supplied', True)5122 doError('No subdirectory name supplied', True)
4791 sysvals.outdir = val5123 sysvals.setOutputFolder(val)
4792 elif(arg == '-config'):5124 elif(arg == '-config'):
4793 try:5125 try:
4794 val = args.next()5126 val = args.next()
4795 except:5127 except:
4796 doError('No text file supplied', True)5128 doError('No text file supplied', True)
4797 if(os.path.exists(val) == False):5129 if(os.path.exists(val) == False):
4798 doError('%s does not exist' % val, False)5130 doError('%s does not exist' % val)
4799 configFromFile(val)5131 configFromFile(val)
4800 elif(arg == '-fadd'):5132 elif(arg == '-fadd'):
4801 try:5133 try:
@@ -4803,7 +5135,7 @@ if __name__ == '__main__': · 1 unmodified line
4803 except:5135 except:
4804 doError('No text file supplied', True)5136 doError('No text file supplied', True)
4805 if(os.path.exists(val) == False):5137 if(os.path.exists(val) == False):
4806 doError('%s does not exist' % val, False)5138 doError('%s does not exist' % val)
4807 sysvals.addFtraceFilterFunctions(val)5139 sysvals.addFtraceFilterFunctions(val)
4808 elif(arg == '-dmesg'):5140 elif(arg == '-dmesg'):
4809 try:5141 try:
@@ -4813,7 +5145,7 @@ if __name__ == '__main__': · 3 unmodified lines
4813 sysvals.notestrun = True5145 sysvals.notestrun = True
4814 sysvals.dmesgfile = val5146 sysvals.dmesgfile = val
4815 if(os.path.exists(sysvals.dmesgfile) == False):5147 if(os.path.exists(sysvals.dmesgfile) == False):
4816 doError('%s does not exist' % sysvals.dmesgfile, False)5148 doError('%s does not exist' % sysvals.dmesgfile)
4817 elif(arg == '-ftrace'):5149 elif(arg == '-ftrace'):
4818 try:5150 try:
4819 val = args.next()5151 val = args.next()
@@ -4822,7 +5154,7 @@ if __name__ == '__main__': · 2 unmodified lines
4822 sysvals.notestrun = True5154 sysvals.notestrun = True
4823 sysvals.ftracefile = val5155 sysvals.ftracefile = val
4824 if(os.path.exists(sysvals.ftracefile) == False):5156 if(os.path.exists(sysvals.ftracefile) == False):
4825 doError('%s does not exist' % sysvals.ftracefile, False)5157 doError('%s does not exist' % sysvals.ftracefile)
4826 elif(arg == '-summary'):5158 elif(arg == '-summary'):
4827 try:5159 try:
4828 val = args.next()5160 val = args.next()
@@ -4832,7 +5164,7 @@ if __name__ == '__main__': · 3 unmodified lines
4832 cmdarg = val5164 cmdarg = val
4833 sysvals.notestrun = True5165 sysvals.notestrun = True
4834 if(os.path.isdir(val) == False):5166 if(os.path.isdir(val) == False):
4835 doError('%s is not accesible' % val, False)5167 doError('%s is not accesible' % val)
4836 elif(arg == '-filter'):5168 elif(arg == '-filter'):
4837 try:5169 try:
4838 val = args.next()5170 val = args.next()
@@ -4842,6 +5174,12 @@ if __name__ == '__main__': · 3 unmodified lines
4842 else:5174 else:
4843 doError('Invalid argument: '+arg, True)5175 doError('Invalid argument: '+arg, True)
4844 5176
5177 # compatibility errors
5178 if(sysvals.usecallgraph and sysvals.usedevsrc):
5179 doError('-dev is not compatible with -f')
5180 if(sysvals.usecallgraph and sysvals.useprocmon):
5181 doError('-proc is not compatible with -f')
5182
4845 # callgraph size cannot exceed device size5183 # callgraph size cannot exceed device size
4846 if sysvals.mincglen < sysvals.mindevlen:5184 if sysvals.mincglen < sysvals.mindevlen:
4847 sysvals.mincglen = sysvals.mindevlen5185 sysvals.mincglen = sysvals.mindevlen
@@ -4855,8 +5193,7 @@ if __name__ == '__main__': · 7 unmodified lines
4855 elif(cmd == 'usbtopo'):5193 elif(cmd == 'usbtopo'):
4856 detectUSB()5194 detectUSB()
4857 elif(cmd == 'modes'):5195 elif(cmd == 'modes'):
4858 modes = getModes()5196 print getModes()
4859 print modes
4860 elif(cmd == 'flist'):5197 elif(cmd == 'flist'):
4861 sysvals.getFtraceFilterFunctions(True)5198 sysvals.getFtraceFilterFunctions(True)
4862 elif(cmd == 'flistall'):5199 elif(cmd == 'flistall'):

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t