1 #!/usr/bin/env python3 !! 1 #!/usr/bin/python 2 # SPDX-License-Identifier: GPL-2.0-only 2 # SPDX-License-Identifier: GPL-2.0-only 3 # 3 # 4 # Tool for analyzing suspend/resume timing 4 # Tool for analyzing suspend/resume timing 5 # Copyright (c) 2013, Intel Corporation. 5 # Copyright (c) 2013, Intel Corporation. 6 # 6 # 7 # This program is free software; you can redis 7 # This program is free software; you can redistribute it and/or modify it 8 # under the terms and conditions of the GNU Ge 8 # under the terms and conditions of the GNU General Public License, 9 # version 2, as published by the Free Software 9 # version 2, as published by the Free Software Foundation. 10 # 10 # 11 # This program is distributed in the hope it w 11 # This program is distributed in the hope it will be useful, but WITHOUT 12 # ANY WARRANTY; without even the implied warra 12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 # FITNESS FOR A PARTICULAR PURPOSE. See the G 13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 # more details. 14 # more details. 15 # 15 # 16 # Authors: 16 # Authors: 17 # Todd Brandt <todd.e.brandt@linux.intel 17 # Todd Brandt <todd.e.brandt@linux.intel.com> 18 # 18 # 19 # Links: 19 # Links: 20 # Home Page 20 # Home Page 21 # https://01.org/pm-graph 21 # https://01.org/pm-graph 22 # Source repo 22 # Source repo 23 # git@github.com:intel/pm-graph 23 # git@github.com:intel/pm-graph 24 # 24 # 25 # Description: 25 # Description: 26 # This tool is designed to assist kerne 26 # This tool is designed to assist kernel and OS developers in optimizing 27 # their linux stack's suspend/resume ti 27 # their linux stack's suspend/resume time. Using a kernel image built 28 # with a few extra options enabled, the 28 # with a few extra options enabled, the tool will execute a suspend and 29 # will capture dmesg and ftrace data un 29 # will capture dmesg and ftrace data until resume is complete. This data 30 # is transformed into a device timeline 30 # is transformed into a device timeline and a callgraph to give a quick 31 # and detailed view of which devices an 31 # and detailed view of which devices and callbacks are taking the most 32 # time in suspend/resume. The output is 32 # time in suspend/resume. The output is a single html file which can be 33 # viewed in firefox or chrome. 33 # viewed in firefox or chrome. 34 # 34 # 35 # The following kernel build options ar 35 # The following kernel build options are required: 36 # CONFIG_DEVMEM=y 36 # CONFIG_DEVMEM=y 37 # CONFIG_PM_DEBUG=y 37 # CONFIG_PM_DEBUG=y 38 # CONFIG_PM_SLEEP_DEBUG=y 38 # CONFIG_PM_SLEEP_DEBUG=y 39 # CONFIG_FTRACE=y 39 # CONFIG_FTRACE=y 40 # CONFIG_FUNCTION_TRACER=y 40 # CONFIG_FUNCTION_TRACER=y 41 # CONFIG_FUNCTION_GRAPH_TRACER= 41 # CONFIG_FUNCTION_GRAPH_TRACER=y 42 # CONFIG_KPROBES=y 42 # CONFIG_KPROBES=y 43 # CONFIG_KPROBES_ON_FTRACE=y 43 # CONFIG_KPROBES_ON_FTRACE=y 44 # 44 # 45 # For kernel versions older than 3.15: 45 # For kernel versions older than 3.15: 46 # The following additional kernel param 46 # The following additional kernel parameters are required: 47 # (e.g. in file /etc/default/gr 47 # (e.g. in file /etc/default/grub) 48 # GRUB_CMDLINE_LINUX_DEFAULT=". 48 # GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=16M ..." 49 # 49 # 50 50 51 # ----------------- LIBRARIES ---------------- 51 # ----------------- LIBRARIES -------------------- 52 52 53 import sys 53 import sys 54 import time 54 import time 55 import os 55 import os 56 import string 56 import string 57 import re 57 import re 58 import platform 58 import platform 59 import signal 59 import signal 60 import codecs 60 import codecs 61 from datetime import datetime, timedelta !! 61 from datetime import datetime 62 import struct 62 import struct 63 import configparser 63 import configparser 64 import gzip 64 import gzip 65 from threading import Thread 65 from threading import Thread 66 from subprocess import call, Popen, PIPE 66 from subprocess import call, Popen, PIPE 67 import base64 67 import base64 68 68 69 debugtiming = False << 70 mystarttime = time.time() << 71 def pprint(msg): 69 def pprint(msg): 72 if debugtiming: !! 70 print(msg) 73 print('[%09.3f] %s' % (time.ti << 74 else: << 75 print(msg) << 76 sys.stdout.flush() 71 sys.stdout.flush() 77 72 78 def ascii(text): 73 def ascii(text): 79 return text.decode('ascii', 'ignore') 74 return text.decode('ascii', 'ignore') 80 75 81 # ----------------- CLASSES ------------------ 76 # ----------------- CLASSES -------------------- 82 77 83 # Class: SystemValues 78 # Class: SystemValues 84 # Description: 79 # Description: 85 # A global, single-instance container u 80 # A global, single-instance container used to 86 # store system values and test paramete 81 # store system values and test parameters 87 class SystemValues: 82 class SystemValues: 88 title = 'SleepGraph' 83 title = 'SleepGraph' 89 version = '5.12' !! 84 version = '5.5' 90 ansi = False 85 ansi = False 91 rs = 0 86 rs = 0 92 display = '' 87 display = '' 93 gzip = False 88 gzip = False 94 sync = False 89 sync = False 95 wifi = False << 96 netfix = False << 97 verbose = False 90 verbose = False 98 testlog = True 91 testlog = True 99 dmesglog = True 92 dmesglog = True 100 ftracelog = False 93 ftracelog = False 101 acpidebug = True << 102 tstat = True 94 tstat = True 103 wifitrace = False !! 95 mindevlen = 0.0 104 mindevlen = 0.0001 << 105 mincglen = 0.0 96 mincglen = 0.0 106 cgphase = '' 97 cgphase = '' 107 cgtest = -1 98 cgtest = -1 108 cgskip = '' 99 cgskip = '' 109 maxfail = 0 !! 100 multitest = {'run': False, 'count': 0, 'delay': 0} 110 multitest = {'run': False, 'count': 10 << 111 max_graph_depth = 0 101 max_graph_depth = 0 112 callloopmaxgap = 0.0001 102 callloopmaxgap = 0.0001 113 callloopmaxlen = 0.005 103 callloopmaxlen = 0.005 114 bufsize = 0 104 bufsize = 0 115 cpucount = 0 105 cpucount = 0 116 memtotal = 204800 106 memtotal = 204800 117 memfree = 204800 107 memfree = 204800 118 osversion = '' << 119 srgap = 0 108 srgap = 0 120 cgexp = False 109 cgexp = False 121 testdir = '' 110 testdir = '' 122 outdir = '' 111 outdir = '' 123 tpath = '/sys/kernel/tracing/' !! 112 tpath = '/sys/kernel/debug/tracing/' 124 fpdtpath = '/sys/firmware/acpi/tables/ 113 fpdtpath = '/sys/firmware/acpi/tables/FPDT' 125 epath = '/sys/kernel/tracing/events/po !! 114 epath = '/sys/kernel/debug/tracing/events/power/' 126 pmdpath = '/sys/power/pm_debug_message 115 pmdpath = '/sys/power/pm_debug_messages' 127 s0ixpath = '/sys/module/intel_pmc_core << 128 s0ixres = '/sys/devices/system/cpu/cpu << 129 acpipath='/sys/module/acpi/parameters/ << 130 traceevents = [ 116 traceevents = [ 131 'suspend_resume', 117 'suspend_resume', 132 'wakeup_source_activate', 118 'wakeup_source_activate', 133 'wakeup_source_deactivate', 119 'wakeup_source_deactivate', 134 'device_pm_callback_end', 120 'device_pm_callback_end', 135 'device_pm_callback_start' 121 'device_pm_callback_start' 136 ] 122 ] 137 logmsg = '' 123 logmsg = '' 138 testcommand = '' 124 testcommand = '' 139 mempath = '/dev/mem' 125 mempath = '/dev/mem' 140 powerfile = '/sys/power/state' 126 powerfile = '/sys/power/state' 141 mempowerfile = '/sys/power/mem_sleep' 127 mempowerfile = '/sys/power/mem_sleep' 142 diskpowerfile = '/sys/power/disk' 128 diskpowerfile = '/sys/power/disk' 143 suspendmode = 'mem' 129 suspendmode = 'mem' 144 memmode = '' 130 memmode = '' 145 diskmode = '' 131 diskmode = '' 146 hostname = 'localhost' 132 hostname = 'localhost' 147 prefix = 'test' 133 prefix = 'test' 148 teststamp = '' 134 teststamp = '' 149 sysstamp = '' 135 sysstamp = '' 150 dmesgstart = 0.0 136 dmesgstart = 0.0 151 dmesgfile = '' 137 dmesgfile = '' 152 ftracefile = '' 138 ftracefile = '' 153 htmlfile = 'output.html' 139 htmlfile = 'output.html' 154 result = '' 140 result = '' 155 rtcwake = True 141 rtcwake = True 156 rtcwaketime = 15 142 rtcwaketime = 15 157 rtcpath = '' 143 rtcpath = '' 158 devicefilter = [] 144 devicefilter = [] 159 cgfilter = [] 145 cgfilter = [] 160 stamp = 0 146 stamp = 0 161 execcount = 1 147 execcount = 1 162 x2delay = 0 148 x2delay = 0 163 skiphtml = False 149 skiphtml = False 164 usecallgraph = False 150 usecallgraph = False 165 ftopfunc = 'pm_suspend' !! 151 ftopfunc = 'suspend_devices_and_enter' 166 ftop = False 152 ftop = False 167 usetraceevents = False 153 usetraceevents = False 168 usetracemarkers = True 154 usetracemarkers = True 169 useftrace = True << 170 usekprobes = True 155 usekprobes = True 171 usedevsrc = False 156 usedevsrc = False 172 useprocmon = False 157 useprocmon = False 173 notestrun = False 158 notestrun = False 174 cgdump = False 159 cgdump = False 175 devdump = False 160 devdump = False 176 mixedphaseheight = True 161 mixedphaseheight = True 177 devprops = dict() 162 devprops = dict() 178 cfgdef = dict() << 179 platinfo = [] 163 platinfo = [] 180 predelay = 0 164 predelay = 0 181 postdelay = 0 165 postdelay = 0 182 tmstart = 'SUSPEND START %Y%m%d-%H:%M: !! 166 pmdebug = '' 183 tmend = 'RESUME COMPLETE %Y%m%d-%H:%M: << 184 tracefuncs = { 167 tracefuncs = { 185 'async_synchronize_full': {}, << 186 'sys_sync': {}, 168 'sys_sync': {}, 187 'ksys_sync': {}, 169 'ksys_sync': {}, 188 '__pm_notifier_call_chain': {} 170 '__pm_notifier_call_chain': {}, 189 'pm_prepare_console': {}, 171 'pm_prepare_console': {}, 190 'pm_notifier_call_chain': {}, 172 'pm_notifier_call_chain': {}, 191 'freeze_processes': {}, 173 'freeze_processes': {}, 192 'freeze_kernel_threads': {}, 174 'freeze_kernel_threads': {}, 193 'pm_restrict_gfp_mask': {}, 175 'pm_restrict_gfp_mask': {}, 194 'acpi_suspend_begin': {}, 176 'acpi_suspend_begin': {}, 195 'acpi_hibernation_begin': {}, 177 'acpi_hibernation_begin': {}, 196 'acpi_hibernation_enter': {}, 178 'acpi_hibernation_enter': {}, 197 'acpi_hibernation_leave': {}, 179 'acpi_hibernation_leave': {}, 198 'acpi_pm_freeze': {}, 180 'acpi_pm_freeze': {}, 199 'acpi_pm_thaw': {}, 181 'acpi_pm_thaw': {}, 200 'acpi_s2idle_end': {}, 182 'acpi_s2idle_end': {}, 201 'acpi_s2idle_sync': {}, 183 'acpi_s2idle_sync': {}, 202 'acpi_s2idle_begin': {}, 184 'acpi_s2idle_begin': {}, 203 'acpi_s2idle_prepare': {}, 185 'acpi_s2idle_prepare': {}, 204 'acpi_s2idle_prepare_late': {} << 205 'acpi_s2idle_wake': {}, 186 'acpi_s2idle_wake': {}, 206 'acpi_s2idle_wakeup': {}, 187 'acpi_s2idle_wakeup': {}, 207 'acpi_s2idle_restore': {}, 188 'acpi_s2idle_restore': {}, 208 'acpi_s2idle_restore_early': { << 209 'hibernate_preallocate_memory' 189 'hibernate_preallocate_memory': {}, 210 'create_basic_memory_bitmaps': 190 'create_basic_memory_bitmaps': {}, 211 'swsusp_write': {}, 191 'swsusp_write': {}, 212 'suspend_console': {}, 192 'suspend_console': {}, 213 'acpi_pm_prepare': {}, 193 'acpi_pm_prepare': {}, 214 'syscore_suspend': {}, 194 'syscore_suspend': {}, 215 'arch_enable_nonboot_cpus_end' 195 'arch_enable_nonboot_cpus_end': {}, 216 'syscore_resume': {}, 196 'syscore_resume': {}, 217 'acpi_pm_finish': {}, 197 'acpi_pm_finish': {}, 218 'resume_console': {}, 198 'resume_console': {}, 219 'acpi_pm_end': {}, 199 'acpi_pm_end': {}, 220 'pm_restore_gfp_mask': {}, 200 'pm_restore_gfp_mask': {}, 221 'thaw_processes': {}, 201 'thaw_processes': {}, 222 'pm_restore_console': {}, 202 'pm_restore_console': {}, 223 'CPU_OFF': { 203 'CPU_OFF': { 224 'func':'_cpu_down', 204 'func':'_cpu_down', 225 'args_x86_64': {'cpu': 205 'args_x86_64': {'cpu':'%di:s32'}, 226 'format': 'CPU_OFF[{cp 206 'format': 'CPU_OFF[{cpu}]' 227 }, 207 }, 228 'CPU_ON': { 208 'CPU_ON': { 229 'func':'_cpu_up', 209 'func':'_cpu_up', 230 'args_x86_64': {'cpu': 210 'args_x86_64': {'cpu':'%di:s32'}, 231 'format': 'CPU_ON[{cpu 211 'format': 'CPU_ON[{cpu}]' 232 }, 212 }, 233 } 213 } 234 dev_tracefuncs = { 214 dev_tracefuncs = { 235 # general wait/delay/sleep 215 # general wait/delay/sleep 236 'msleep': { 'args_x86_64': {'t 216 'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 }, 237 'schedule_timeout': { 'args_x8 217 'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 }, 238 'udelay': { 'func':'__const_ud 218 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 }, 239 'usleep_range': { 'args_x86_64 219 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 }, 240 'mutex_lock_slowpath': { 'func 220 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 }, 241 'acpi_os_stall': {'ub': 1}, 221 'acpi_os_stall': {'ub': 1}, 242 'rt_mutex_slowlock': {'ub': 1} 222 'rt_mutex_slowlock': {'ub': 1}, 243 # ACPI 223 # ACPI 244 'acpi_resume_power_resources': 224 'acpi_resume_power_resources': {}, 245 'acpi_ps_execute_method': { 'a 225 'acpi_ps_execute_method': { 'args_x86_64': { 246 'fullpath':'+0(+40(%di 226 'fullpath':'+0(+40(%di)):string', 247 }}, 227 }}, 248 # mei_me 228 # mei_me 249 'mei_reset': {}, 229 'mei_reset': {}, 250 # filesystem 230 # filesystem 251 'ext4_sync_fs': {}, 231 'ext4_sync_fs': {}, 252 # 80211 232 # 80211 253 'ath10k_bmi_read_memory': { 'a 233 'ath10k_bmi_read_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 254 'ath10k_bmi_write_memory': { ' 234 'ath10k_bmi_write_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 255 'ath10k_bmi_fast_download': { 235 'ath10k_bmi_fast_download': { 'args_x86_64': {'length':'%cx:s32'} }, 256 'iwlagn_mac_start': {}, 236 'iwlagn_mac_start': {}, 257 'iwlagn_alloc_bcast_station': 237 'iwlagn_alloc_bcast_station': {}, 258 'iwl_trans_pcie_start_hw': {}, 238 'iwl_trans_pcie_start_hw': {}, 259 'iwl_trans_pcie_start_fw': {}, 239 'iwl_trans_pcie_start_fw': {}, 260 'iwl_run_init_ucode': {}, 240 'iwl_run_init_ucode': {}, 261 'iwl_load_ucode_wait_alive': { 241 'iwl_load_ucode_wait_alive': {}, 262 'iwl_alive_start': {}, 242 'iwl_alive_start': {}, 263 'iwlagn_mac_stop': {}, 243 'iwlagn_mac_stop': {}, 264 'iwlagn_mac_suspend': {}, 244 'iwlagn_mac_suspend': {}, 265 'iwlagn_mac_resume': {}, 245 'iwlagn_mac_resume': {}, 266 'iwlagn_mac_add_interface': {} 246 'iwlagn_mac_add_interface': {}, 267 'iwlagn_mac_remove_interface': 247 'iwlagn_mac_remove_interface': {}, 268 'iwlagn_mac_change_interface': 248 'iwlagn_mac_change_interface': {}, 269 'iwlagn_mac_config': {}, 249 'iwlagn_mac_config': {}, 270 'iwlagn_configure_filter': {}, 250 'iwlagn_configure_filter': {}, 271 'iwlagn_mac_hw_scan': {}, 251 'iwlagn_mac_hw_scan': {}, 272 'iwlagn_bss_info_changed': {}, 252 'iwlagn_bss_info_changed': {}, 273 'iwlagn_mac_channel_switch': { 253 'iwlagn_mac_channel_switch': {}, 274 'iwlagn_mac_flush': {}, 254 'iwlagn_mac_flush': {}, 275 # ATA 255 # ATA 276 'ata_eh_recover': { 'args_x86_ 256 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} }, 277 # i915 257 # i915 278 'i915_gem_resume': {}, 258 'i915_gem_resume': {}, 279 'i915_restore_state': {}, 259 'i915_restore_state': {}, 280 'intel_opregion_setup': {}, 260 'intel_opregion_setup': {}, 281 'g4x_pre_enable_dp': {}, 261 'g4x_pre_enable_dp': {}, 282 'vlv_pre_enable_dp': {}, 262 'vlv_pre_enable_dp': {}, 283 'chv_pre_enable_dp': {}, 263 'chv_pre_enable_dp': {}, 284 'g4x_enable_dp': {}, 264 'g4x_enable_dp': {}, 285 'vlv_enable_dp': {}, 265 'vlv_enable_dp': {}, 286 'intel_hpd_init': {}, 266 'intel_hpd_init': {}, 287 'intel_opregion_register': {}, 267 'intel_opregion_register': {}, 288 'intel_dp_detect': {}, 268 'intel_dp_detect': {}, 289 'intel_hdmi_detect': {}, 269 'intel_hdmi_detect': {}, 290 'intel_opregion_init': {}, 270 'intel_opregion_init': {}, 291 'intel_fbdev_set_suspend': {}, 271 'intel_fbdev_set_suspend': {}, 292 } 272 } 293 infocmds = [ << 294 [0, 'sysinfo', 'uname', '-a'], << 295 [0, 'cpuinfo', 'head', '-7', ' << 296 [0, 'kparams', 'cat', '/proc/c << 297 [0, 'mcelog', 'mcelog'], << 298 [0, 'pcidevices', 'lspci', '-t << 299 [0, 'usbdevices', 'lsusb', '-t << 300 [0, 'acpidevices', 'sh', '-c', << 301 [0, 's0ix_require', 'cat', '/s << 302 [0, 's0ix_debug', 'cat', '/sys << 303 [0, 'ethtool', 'ethtool', '{et << 304 [1, 's0ix_residency', 'cat', ' << 305 [1, 'interrupts', 'cat', '/pro << 306 [1, 'wakeups', 'cat', '/sys/ke << 307 [2, 'gpecounts', 'sh', '-c', ' << 308 [2, 'suspendstats', 'sh', '-c' << 309 [2, 'cpuidle', 'sh', '-c', 'gr << 310 [2, 'battery', 'sh', '-c', 'gr << 311 [2, 'thermal', 'sh', '-c', 'gr << 312 ] << 313 cgblacklist = [] 273 cgblacklist = [] 314 kprobes = dict() 274 kprobes = dict() 315 timeformat = '%.3f' 275 timeformat = '%.3f' 316 cmdline = '%s %s' % \ 276 cmdline = '%s %s' % \ 317 (os.path.basename(sys. 277 (os.path.basename(sys.argv[0]), ' '.join(sys.argv[1:])) >> 278 kparams = '' 318 sudouser = '' 279 sudouser = '' 319 def __init__(self): 280 def __init__(self): 320 self.archargs = 'args_'+platfo 281 self.archargs = 'args_'+platform.machine() 321 self.hostname = platform.node( 282 self.hostname = platform.node() 322 if(self.hostname == ''): 283 if(self.hostname == ''): 323 self.hostname = 'local 284 self.hostname = 'localhost' 324 rtc = "rtc0" 285 rtc = "rtc0" 325 if os.path.exists('/dev/rtc'): 286 if os.path.exists('/dev/rtc'): 326 rtc = os.readlink('/de 287 rtc = os.readlink('/dev/rtc') 327 rtc = '/sys/class/rtc/'+rtc 288 rtc = '/sys/class/rtc/'+rtc 328 if os.path.exists(rtc) and os. 289 if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \ 329 os.path.exists(rtc+'/t 290 os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'): 330 self.rtcpath = rtc 291 self.rtcpath = rtc 331 if (hasattr(sys.stdout, 'isatt 292 if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): 332 self.ansi = True 293 self.ansi = True 333 self.testdir = datetime.now(). 294 self.testdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S') 334 if os.getuid() == 0 and 'SUDO_ 295 if os.getuid() == 0 and 'SUDO_USER' in os.environ and \ 335 os.environ['SUDO_USER' 296 os.environ['SUDO_USER']: 336 self.sudouser = os.env 297 self.sudouser = os.environ['SUDO_USER'] 337 def resetlog(self): << 338 self.logmsg = '' << 339 self.platinfo = [] << 340 def vprint(self, msg): 298 def vprint(self, msg): 341 self.logmsg += msg+'\n' 299 self.logmsg += msg+'\n' 342 if self.verbose or msg.startsw 300 if self.verbose or msg.startswith('WARNING:'): 343 pprint(msg) 301 pprint(msg) 344 def signalHandler(self, signum, frame) 302 def signalHandler(self, signum, frame): 345 if not self.result: 303 if not self.result: 346 return 304 return 347 signame = self.signames[signum 305 signame = self.signames[signum] if signum in self.signames else 'UNKNOWN' 348 msg = 'Signal %s caused a tool 306 msg = 'Signal %s caused a tool exit, line %d' % (signame, frame.f_lineno) 349 self.outputResult({'error':msg !! 307 sysvals.outputResult({'error':msg}) 350 sys.exit(3) 308 sys.exit(3) 351 def signalHandlerInit(self): 309 def signalHandlerInit(self): 352 capture = ['BUS', 'SYS', 'XCPU 310 capture = ['BUS', 'SYS', 'XCPU', 'XFSZ', 'PWR', 'HUP', 'INT', 'QUIT', 353 'ILL', 'ABRT', 'FPE', !! 311 'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM', 'TSTP'] 354 self.signames = dict() 312 self.signames = dict() 355 for i in capture: 313 for i in capture: 356 s = 'SIG'+i 314 s = 'SIG'+i 357 try: 315 try: 358 signum = getat 316 signum = getattr(signal, s) 359 signal.signal( 317 signal.signal(signum, self.signalHandler) 360 except: 318 except: 361 continue 319 continue 362 self.signames[signum] 320 self.signames[signum] = s 363 def rootCheck(self, fatal=True): 321 def rootCheck(self, fatal=True): 364 if(os.access(self.powerfile, o 322 if(os.access(self.powerfile, os.W_OK)): 365 return True 323 return True 366 if fatal: 324 if fatal: 367 msg = 'This command re 325 msg = 'This command requires sysfs mount and root access' 368 pprint('ERROR: %s\n' % 326 pprint('ERROR: %s\n' % msg) 369 self.outputResult({'er 327 self.outputResult({'error':msg}) 370 sys.exit(1) 328 sys.exit(1) 371 return False 329 return False 372 def rootUser(self, fatal=False): 330 def rootUser(self, fatal=False): 373 if 'USER' in os.environ and os 331 if 'USER' in os.environ and os.environ['USER'] == 'root': 374 return True 332 return True 375 if fatal: 333 if fatal: 376 msg = 'This command mu 334 msg = 'This command must be run as root' 377 pprint('ERROR: %s\n' % 335 pprint('ERROR: %s\n' % msg) 378 self.outputResult({'er 336 self.outputResult({'error':msg}) 379 sys.exit(1) 337 sys.exit(1) 380 return False 338 return False 381 def usable(self, file, ishtml=False): << 382 if not os.path.exists(file) or << 383 return False << 384 if ishtml: << 385 try: << 386 fp = open(file << 387 res = fp.read( << 388 fp.close() << 389 except: << 390 return False << 391 if '<html>' not in res << 392 return False << 393 return True << 394 def getExec(self, cmd): 339 def getExec(self, cmd): 395 try: 340 try: 396 fp = Popen(['which', c 341 fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout 397 out = ascii(fp.read()) 342 out = ascii(fp.read()).strip() 398 fp.close() 343 fp.close() 399 except: 344 except: 400 out = '' 345 out = '' 401 if out: 346 if out: 402 return out 347 return out 403 for path in ['/sbin', '/bin', 348 for path in ['/sbin', '/bin', '/usr/sbin', '/usr/bin', 404 '/usr/local/sbin', '/u 349 '/usr/local/sbin', '/usr/local/bin']: 405 cmdfull = os.path.join 350 cmdfull = os.path.join(path, cmd) 406 if os.path.exists(cmdf 351 if os.path.exists(cmdfull): 407 return cmdfull 352 return cmdfull 408 return out 353 return out 409 def setPrecision(self, num): 354 def setPrecision(self, num): 410 if num < 0 or num > 6: 355 if num < 0 or num > 6: 411 return 356 return 412 self.timeformat = '%.{0}f'.for 357 self.timeformat = '%.{0}f'.format(num) 413 def setOutputFolder(self, value): 358 def setOutputFolder(self, value): 414 args = dict() 359 args = dict() 415 n = datetime.now() 360 n = datetime.now() 416 args['date'] = n.strftime('%y% 361 args['date'] = n.strftime('%y%m%d') 417 args['time'] = n.strftime('%H% 362 args['time'] = n.strftime('%H%M%S') 418 args['hostname'] = args['host' 363 args['hostname'] = args['host'] = self.hostname 419 args['mode'] = self.suspendmod 364 args['mode'] = self.suspendmode 420 return value.format(**args) 365 return value.format(**args) 421 def setOutputFile(self): 366 def setOutputFile(self): 422 if self.dmesgfile != '': 367 if self.dmesgfile != '': 423 m = re.match(r'(?P<nam !! 368 m = re.match('(?P<name>.*)_dmesg\.txt.*', self.dmesgfile) 424 if(m): 369 if(m): 425 self.htmlfile 370 self.htmlfile = m.group('name')+'.html' 426 if self.ftracefile != '': 371 if self.ftracefile != '': 427 m = re.match(r'(?P<nam !! 372 m = re.match('(?P<name>.*)_ftrace\.txt.*', self.ftracefile) 428 if(m): 373 if(m): 429 self.htmlfile 374 self.htmlfile = m.group('name')+'.html' 430 def systemInfo(self, info): 375 def systemInfo(self, info): 431 p = m = '' 376 p = m = '' 432 if 'baseboard-manufacturer' in 377 if 'baseboard-manufacturer' in info: 433 m = info['baseboard-ma 378 m = info['baseboard-manufacturer'] 434 elif 'system-manufacturer' in 379 elif 'system-manufacturer' in info: 435 m = info['system-manuf 380 m = info['system-manufacturer'] 436 if 'system-product-name' in in 381 if 'system-product-name' in info: 437 p = info['system-produ 382 p = info['system-product-name'] 438 elif 'baseboard-product-name' 383 elif 'baseboard-product-name' in info: 439 p = info['baseboard-pr 384 p = info['baseboard-product-name'] 440 if m[:5].lower() == 'intel' an 385 if m[:5].lower() == 'intel' and 'baseboard-product-name' in info: 441 p = info['baseboard-pr 386 p = info['baseboard-product-name'] 442 c = info['processor-version'] 387 c = info['processor-version'] if 'processor-version' in info else '' 443 b = info['bios-version'] if 'b 388 b = info['bios-version'] if 'bios-version' in info else '' 444 r = info['bios-release-date'] 389 r = info['bios-release-date'] if 'bios-release-date' in info else '' 445 self.sysstamp = '# sysinfo | m 390 self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | biosdate:%s | numcpu:%d | memsz:%d | memfr:%d' % \ 446 (m, p, c, b, r, self.c 391 (m, p, c, b, r, self.cpucount, self.memtotal, self.memfree) 447 if self.osversion: !! 392 try: 448 self.sysstamp += ' | o !! 393 kcmd = open('/proc/cmdline', 'r').read().strip() >> 394 except: >> 395 kcmd = '' >> 396 if kcmd: >> 397 self.sysstamp += '\n# kparams | %s' % kcmd 449 def printSystemInfo(self, fatal=False) 398 def printSystemInfo(self, fatal=False): 450 self.rootCheck(True) 399 self.rootCheck(True) 451 out = dmidecode(self.mempath, 400 out = dmidecode(self.mempath, fatal) 452 if len(out) < 1: 401 if len(out) < 1: 453 return 402 return 454 fmt = '%-24s: %s' 403 fmt = '%-24s: %s' 455 if self.osversion: << 456 print(fmt % ('os-versi << 457 for name in sorted(out): 404 for name in sorted(out): 458 print(fmt % (name, out 405 print(fmt % (name, out[name])) 459 print(fmt % ('cpucount', ('%d' 406 print(fmt % ('cpucount', ('%d' % self.cpucount))) 460 print(fmt % ('memtotal', ('%d 407 print(fmt % ('memtotal', ('%d kB' % self.memtotal))) 461 print(fmt % ('memfree', ('%d k 408 print(fmt % ('memfree', ('%d kB' % self.memfree))) 462 def cpuInfo(self): 409 def cpuInfo(self): 463 self.cpucount = 0 410 self.cpucount = 0 464 if os.path.exists('/proc/cpuin !! 411 fp = open('/proc/cpuinfo', 'r') 465 with open('/proc/cpuin !! 412 for line in fp: 466 for line in fp !! 413 if re.match('^processor[ \t]*:[ \t]*[0-9]*', line): 467 if re. !! 414 self.cpucount += 1 468 !! 415 fp.close() 469 if os.path.exists('/proc/memin !! 416 fp = open('/proc/meminfo', 'r') 470 with open('/proc/memin !! 417 for line in fp: 471 for line in fp !! 418 m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line) 472 m = re !! 419 if m: 473 if m: !! 420 self.memtotal = int(m.group('sz')) 474 !! 421 m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line) 475 m = re !! 422 if m: 476 if m: !! 423 self.memfree = int(m.group('sz')) 477 !! 424 fp.close() 478 if os.path.exists('/etc/os-rel << 479 with open('/etc/os-rel << 480 for line in fp << 481 if lin << 482 << 483 def initTestOutput(self, name): 425 def initTestOutput(self, name): 484 self.prefix = self.hostname 426 self.prefix = self.hostname 485 v = open('/proc/version', 'r') 427 v = open('/proc/version', 'r').read().strip() 486 kver = v.split()[2] 428 kver = v.split()[2] 487 fmt = name+'-%m%d%y-%H%M%S' 429 fmt = name+'-%m%d%y-%H%M%S' 488 testtime = datetime.now().strf 430 testtime = datetime.now().strftime(fmt) 489 self.teststamp = \ 431 self.teststamp = \ 490 '# '+testtime+' '+self 432 '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver 491 ext = '' 433 ext = '' 492 if self.gzip: 434 if self.gzip: 493 ext = '.gz' 435 ext = '.gz' 494 self.dmesgfile = \ 436 self.dmesgfile = \ 495 self.testdir+'/'+self. 437 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt'+ext 496 self.ftracefile = \ 438 self.ftracefile = \ 497 self.testdir+'/'+self. 439 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt'+ext 498 self.htmlfile = \ 440 self.htmlfile = \ 499 self.testdir+'/'+self. 441 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' 500 if not os.path.isdir(self.test 442 if not os.path.isdir(self.testdir): 501 os.makedirs(self.testd 443 os.makedirs(self.testdir) 502 self.sudoUserchown(self.testdi << 503 def getValueList(self, value): 444 def getValueList(self, value): 504 out = [] 445 out = [] 505 for i in value.split(','): 446 for i in value.split(','): 506 if i.strip(): 447 if i.strip(): 507 out.append(i.s 448 out.append(i.strip()) 508 return out 449 return out 509 def setDeviceFilter(self, value): 450 def setDeviceFilter(self, value): 510 self.devicefilter = self.getVa 451 self.devicefilter = self.getValueList(value) 511 def setCallgraphFilter(self, value): 452 def setCallgraphFilter(self, value): 512 self.cgfilter = self.getValueL 453 self.cgfilter = self.getValueList(value) 513 def skipKprobes(self, value): 454 def skipKprobes(self, value): 514 for k in self.getValueList(val 455 for k in self.getValueList(value): 515 if k in self.tracefunc 456 if k in self.tracefuncs: 516 del self.trace 457 del self.tracefuncs[k] 517 if k in self.dev_trace 458 if k in self.dev_tracefuncs: 518 del self.dev_t 459 del self.dev_tracefuncs[k] 519 def setCallgraphBlacklist(self, file): 460 def setCallgraphBlacklist(self, file): 520 self.cgblacklist = self.listFr 461 self.cgblacklist = self.listFromFile(file) 521 def rtcWakeAlarmOn(self): 462 def rtcWakeAlarmOn(self): 522 call('echo 0 > '+self.rtcpath+ 463 call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True) 523 nowtime = open(self.rtcpath+'/ 464 nowtime = open(self.rtcpath+'/since_epoch', 'r').read().strip() 524 if nowtime: 465 if nowtime: 525 nowtime = int(nowtime) 466 nowtime = int(nowtime) 526 else: 467 else: 527 # if hardware time fai 468 # if hardware time fails, use the software time 528 nowtime = int(datetime 469 nowtime = int(datetime.now().strftime('%s')) 529 alarm = nowtime + self.rtcwake 470 alarm = nowtime + self.rtcwaketime 530 call('echo %d > %s/wakealarm' 471 call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True) 531 def rtcWakeAlarmOff(self): 472 def rtcWakeAlarmOff(self): 532 call('echo 0 > %s/wakealarm' % 473 call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True) 533 def initdmesg(self): 474 def initdmesg(self): 534 # get the latest time stamp fr 475 # get the latest time stamp from the dmesg log 535 lines = Popen('dmesg', stdout= !! 476 fp = Popen('dmesg', stdout=PIPE).stdout 536 ktime = '0' 477 ktime = '0' 537 for line in reversed(lines): !! 478 for line in fp: 538 line = ascii(line).rep 479 line = ascii(line).replace('\r\n', '') 539 idx = line.find('[') 480 idx = line.find('[') 540 if idx > 1: 481 if idx > 1: 541 line = line[id 482 line = line[idx:] 542 m = re.match(r'[ \t]*( !! 483 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 543 if(m): 484 if(m): 544 ktime = m.grou 485 ktime = m.group('ktime') 545 break !! 486 fp.close() 546 self.dmesgstart = float(ktime) 487 self.dmesgstart = float(ktime) 547 def getdmesg(self, testdata): 488 def getdmesg(self, testdata): 548 op = self.writeDatafileHeader( !! 489 op = self.writeDatafileHeader(sysvals.dmesgfile, testdata) 549 # store all new dmesg lines si 490 # store all new dmesg lines since initdmesg was called 550 fp = Popen('dmesg', stdout=PIP 491 fp = Popen('dmesg', stdout=PIPE).stdout 551 for line in fp: 492 for line in fp: 552 line = ascii(line).rep 493 line = ascii(line).replace('\r\n', '') 553 idx = line.find('[') 494 idx = line.find('[') 554 if idx > 1: 495 if idx > 1: 555 line = line[id 496 line = line[idx:] 556 m = re.match(r'[ \t]*( !! 497 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 557 if(not m): 498 if(not m): 558 continue 499 continue 559 ktime = float(m.group( 500 ktime = float(m.group('ktime')) 560 if ktime > self.dmesgs 501 if ktime > self.dmesgstart: 561 op.write(line) 502 op.write(line) 562 fp.close() 503 fp.close() 563 op.close() 504 op.close() 564 def listFromFile(self, file): 505 def listFromFile(self, file): 565 list = [] 506 list = [] 566 fp = open(file) 507 fp = open(file) 567 for i in fp.read().split('\n') 508 for i in fp.read().split('\n'): 568 i = i.strip() 509 i = i.strip() 569 if i and i[0] != '#': 510 if i and i[0] != '#': 570 list.append(i) 511 list.append(i) 571 fp.close() 512 fp.close() 572 return list 513 return list 573 def addFtraceFilterFunctions(self, fil 514 def addFtraceFilterFunctions(self, file): 574 for i in self.listFromFile(fil 515 for i in self.listFromFile(file): 575 if len(i) < 2: 516 if len(i) < 2: 576 continue 517 continue 577 self.tracefuncs[i] = d 518 self.tracefuncs[i] = dict() 578 def getFtraceFilterFunctions(self, cur 519 def getFtraceFilterFunctions(self, current): 579 self.rootCheck(True) 520 self.rootCheck(True) 580 if not current: 521 if not current: 581 call('cat '+self.tpath 522 call('cat '+self.tpath+'available_filter_functions', shell=True) 582 return 523 return 583 master = self.listFromFile(sel 524 master = self.listFromFile(self.tpath+'available_filter_functions') 584 for i in sorted(self.tracefunc 525 for i in sorted(self.tracefuncs): 585 if 'func' in self.trac 526 if 'func' in self.tracefuncs[i]: 586 i = self.trace 527 i = self.tracefuncs[i]['func'] 587 if i in master: 528 if i in master: 588 print(i) 529 print(i) 589 else: 530 else: 590 print(self.col 531 print(self.colorText(i)) 591 def setFtraceFilterFunctions(self, lis 532 def setFtraceFilterFunctions(self, list): 592 master = self.listFromFile(sel 533 master = self.listFromFile(self.tpath+'available_filter_functions') 593 flist = '' 534 flist = '' 594 for i in list: 535 for i in list: 595 if i not in master: 536 if i not in master: 596 continue 537 continue 597 if ' [' in i: 538 if ' [' in i: 598 flist += i.spl 539 flist += i.split(' ')[0]+'\n' 599 else: 540 else: 600 flist += i+'\n 541 flist += i+'\n' 601 fp = open(self.tpath+'set_grap 542 fp = open(self.tpath+'set_graph_function', 'w') 602 fp.write(flist) 543 fp.write(flist) 603 fp.close() 544 fp.close() 604 def basicKprobe(self, name): 545 def basicKprobe(self, name): 605 self.kprobes[name] = {'name': 546 self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name} 606 def defaultKprobe(self, name, kdata): 547 def defaultKprobe(self, name, kdata): 607 k = kdata 548 k = kdata 608 for field in ['name', 'format' 549 for field in ['name', 'format', 'func']: 609 if field not in k: 550 if field not in k: 610 k[field] = nam 551 k[field] = name 611 if self.archargs in k: 552 if self.archargs in k: 612 k['args'] = k[self.arc 553 k['args'] = k[self.archargs] 613 else: 554 else: 614 k['args'] = dict() 555 k['args'] = dict() 615 k['format'] = name 556 k['format'] = name 616 self.kprobes[name] = k 557 self.kprobes[name] = k 617 def kprobeColor(self, name): 558 def kprobeColor(self, name): 618 if name not in self.kprobes or 559 if name not in self.kprobes or 'color' not in self.kprobes[name]: 619 return '' 560 return '' 620 return self.kprobes[name]['col 561 return self.kprobes[name]['color'] 621 def kprobeDisplayName(self, name, data 562 def kprobeDisplayName(self, name, dataraw): 622 if name not in self.kprobes: 563 if name not in self.kprobes: 623 self.basicKprobe(name) 564 self.basicKprobe(name) 624 data = '' 565 data = '' 625 quote=0 566 quote=0 626 # first remvoe any spaces insi 567 # first remvoe any spaces inside quotes, and the quotes 627 for c in dataraw: 568 for c in dataraw: 628 if c == '"': 569 if c == '"': 629 quote = (quote 570 quote = (quote + 1) % 2 630 if quote and c == ' ': 571 if quote and c == ' ': 631 data += '_' 572 data += '_' 632 elif c != '"': 573 elif c != '"': 633 data += c 574 data += c 634 fmt, args = self.kprobes[name] 575 fmt, args = self.kprobes[name]['format'], self.kprobes[name]['args'] 635 arglist = dict() 576 arglist = dict() 636 # now process the args 577 # now process the args 637 for arg in sorted(args): 578 for arg in sorted(args): 638 arglist[arg] = '' 579 arglist[arg] = '' 639 m = re.match(r'.* '+ar !! 580 m = re.match('.* '+arg+'=(?P<arg>.*) ', data); 640 if m: 581 if m: 641 arglist[arg] = 582 arglist[arg] = m.group('arg') 642 else: 583 else: 643 m = re.match(r !! 584 m = re.match('.* '+arg+'=(?P<arg>.*)', data); 644 if m: 585 if m: 645 arglis 586 arglist[arg] = m.group('arg') 646 out = fmt.format(**arglist) 587 out = fmt.format(**arglist) 647 out = out.replace(' ', '_').re 588 out = out.replace(' ', '_').replace('"', '') 648 return out 589 return out 649 def kprobeText(self, kname, kprobe): 590 def kprobeText(self, kname, kprobe): 650 name = fmt = func = kname 591 name = fmt = func = kname 651 args = dict() 592 args = dict() 652 if 'name' in kprobe: 593 if 'name' in kprobe: 653 name = kprobe['name'] 594 name = kprobe['name'] 654 if 'format' in kprobe: 595 if 'format' in kprobe: 655 fmt = kprobe['format'] 596 fmt = kprobe['format'] 656 if 'func' in kprobe: 597 if 'func' in kprobe: 657 func = kprobe['func'] 598 func = kprobe['func'] 658 if self.archargs in kprobe: 599 if self.archargs in kprobe: 659 args = kprobe[self.arc 600 args = kprobe[self.archargs] 660 if 'args' in kprobe: 601 if 'args' in kprobe: 661 args = kprobe['args'] 602 args = kprobe['args'] 662 if re.findall('{(?P<n>[a-z,A-Z 603 if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func): 663 doError('Kprobe "%s" h 604 doError('Kprobe "%s" has format info in the function name "%s"' % (name, func)) 664 for arg in re.findall('{(?P<n> 605 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt): 665 if arg not in args: 606 if arg not in args: 666 doError('Kprob 607 doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 667 val = 'p:%s_cal %s' % (name, f 608 val = 'p:%s_cal %s' % (name, func) 668 for i in sorted(args): 609 for i in sorted(args): 669 val += ' %s=%s' % (i, 610 val += ' %s=%s' % (i, args[i]) 670 val += '\nr:%s_ret %s $retval\ 611 val += '\nr:%s_ret %s $retval\n' % (name, func) 671 return val 612 return val 672 def addKprobes(self, output=False): 613 def addKprobes(self, output=False): 673 if len(self.kprobes) < 1: 614 if len(self.kprobes) < 1: 674 return 615 return 675 if output: 616 if output: 676 pprint(' kprobe fun 617 pprint(' kprobe functions in this kernel:') 677 # first test each kprobe 618 # first test each kprobe 678 rejects = [] 619 rejects = [] 679 # sort kprobes: trace, ub-dev, 620 # sort kprobes: trace, ub-dev, custom, dev 680 kpl = [[], [], [], []] 621 kpl = [[], [], [], []] 681 linesout = len(self.kprobes) 622 linesout = len(self.kprobes) 682 for name in sorted(self.kprobe 623 for name in sorted(self.kprobes): 683 res = self.colorText(' 624 res = self.colorText('YES', 32) 684 if not self.testKprobe 625 if not self.testKprobe(name, self.kprobes[name]): 685 res = self.col 626 res = self.colorText('NO') 686 rejects.append 627 rejects.append(name) 687 else: 628 else: 688 if name in sel 629 if name in self.tracefuncs: 689 kpl[0] 630 kpl[0].append(name) 690 elif name in s 631 elif name in self.dev_tracefuncs: 691 if 'ub 632 if 'ub' in self.dev_tracefuncs[name]: 692 633 kpl[1].append(name) 693 else: 634 else: 694 635 kpl[3].append(name) 695 else: 636 else: 696 kpl[2] 637 kpl[2].append(name) 697 if output: 638 if output: 698 pprint(' 639 pprint(' %s: %s' % (name, res)) 699 kplist = kpl[0] + kpl[1] + kpl 640 kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3] 700 # remove all failed ones from 641 # remove all failed ones from the list 701 for name in rejects: 642 for name in rejects: 702 self.kprobes.pop(name) 643 self.kprobes.pop(name) 703 # set the kprobes all at once 644 # set the kprobes all at once 704 self.fsetVal('', 'kprobe_event 645 self.fsetVal('', 'kprobe_events') 705 kprobeevents = '' 646 kprobeevents = '' 706 for kp in kplist: 647 for kp in kplist: 707 kprobeevents += self.k 648 kprobeevents += self.kprobeText(kp, self.kprobes[kp]) 708 self.fsetVal(kprobeevents, 'kp 649 self.fsetVal(kprobeevents, 'kprobe_events') 709 if output: 650 if output: 710 check = self.fgetVal(' 651 check = self.fgetVal('kprobe_events') 711 linesack = (len(check. 652 linesack = (len(check.split('\n')) - 1) // 2 712 pprint(' kprobe fun 653 pprint(' kprobe functions enabled: %d/%d' % (linesack, linesout)) 713 self.fsetVal('1', 'events/kpro 654 self.fsetVal('1', 'events/kprobes/enable') 714 def testKprobe(self, kname, kprobe): 655 def testKprobe(self, kname, kprobe): 715 self.fsetVal('0', 'events/kpro 656 self.fsetVal('0', 'events/kprobes/enable') 716 kprobeevents = self.kprobeText 657 kprobeevents = self.kprobeText(kname, kprobe) 717 if not kprobeevents: 658 if not kprobeevents: 718 return False 659 return False 719 try: 660 try: 720 self.fsetVal(kprobeeve 661 self.fsetVal(kprobeevents, 'kprobe_events') 721 check = self.fgetVal(' 662 check = self.fgetVal('kprobe_events') 722 except: 663 except: 723 return False 664 return False 724 linesout = len(kprobeevents.sp 665 linesout = len(kprobeevents.split('\n')) 725 linesack = len(check.split('\n 666 linesack = len(check.split('\n')) 726 if linesack < linesout: 667 if linesack < linesout: 727 return False 668 return False 728 return True 669 return True 729 def setVal(self, val, file): 670 def setVal(self, val, file): 730 if not os.path.exists(file): 671 if not os.path.exists(file): 731 return False 672 return False 732 try: 673 try: 733 fp = open(file, 'wb', 674 fp = open(file, 'wb', 0) 734 fp.write(val.encode()) 675 fp.write(val.encode()) 735 fp.flush() 676 fp.flush() 736 fp.close() 677 fp.close() 737 except: 678 except: 738 return False 679 return False 739 return True 680 return True 740 def fsetVal(self, val, path): 681 def fsetVal(self, val, path): 741 if not self.useftrace: << 742 return False << 743 return self.setVal(val, self.t 682 return self.setVal(val, self.tpath+path) 744 def getVal(self, file): 683 def getVal(self, file): 745 res = '' 684 res = '' 746 if not os.path.exists(file): 685 if not os.path.exists(file): 747 return res 686 return res 748 try: 687 try: 749 fp = open(file, 'r') 688 fp = open(file, 'r') 750 res = fp.read() 689 res = fp.read() 751 fp.close() 690 fp.close() 752 except: 691 except: 753 pass 692 pass 754 return res 693 return res 755 def fgetVal(self, path): 694 def fgetVal(self, path): 756 if not self.useftrace: << 757 return '' << 758 return self.getVal(self.tpath+ 695 return self.getVal(self.tpath+path) 759 def cleanupFtrace(self): 696 def cleanupFtrace(self): 760 if self.useftrace: !! 697 if(self.usecallgraph or self.usetraceevents or self.usedevsrc): 761 self.fsetVal('0', 'eve 698 self.fsetVal('0', 'events/kprobes/enable') 762 self.fsetVal('', 'kpro 699 self.fsetVal('', 'kprobe_events') 763 self.fsetVal('1024', ' 700 self.fsetVal('1024', 'buffer_size_kb') >> 701 if self.pmdebug: >> 702 self.setVal(self.pmdebug, self.pmdpath) 764 def setupAllKprobes(self): 703 def setupAllKprobes(self): 765 for name in self.tracefuncs: 704 for name in self.tracefuncs: 766 self.defaultKprobe(nam 705 self.defaultKprobe(name, self.tracefuncs[name]) 767 for name in self.dev_tracefunc 706 for name in self.dev_tracefuncs: 768 self.defaultKprobe(nam 707 self.defaultKprobe(name, self.dev_tracefuncs[name]) 769 def isCallgraphFunc(self, name): 708 def isCallgraphFunc(self, name): 770 if len(self.tracefuncs) < 1 an 709 if len(self.tracefuncs) < 1 and self.suspendmode == 'command': 771 return True 710 return True 772 for i in self.tracefuncs: 711 for i in self.tracefuncs: 773 if 'func' in self.trac 712 if 'func' in self.tracefuncs[i]: 774 f = self.trace 713 f = self.tracefuncs[i]['func'] 775 else: 714 else: 776 f = i 715 f = i 777 if name == f: 716 if name == f: 778 return True 717 return True 779 return False 718 return False 780 def initFtrace(self, quiet=False): !! 719 def initFtrace(self): 781 if not self.useftrace: !! 720 self.printSystemInfo(False) 782 return !! 721 pprint('INITIALIZING FTRACE...') 783 if not quiet: << 784 sysvals.printSystemInf << 785 pprint('INITIALIZING F << 786 # turn trace off 722 # turn trace off 787 self.fsetVal('0', 'tracing_on' 723 self.fsetVal('0', 'tracing_on') 788 self.cleanupFtrace() 724 self.cleanupFtrace() >> 725 # pm debug messages >> 726 pv = self.getVal(self.pmdpath) >> 727 if pv != '1': >> 728 self.setVal('1', self.pmdpath) >> 729 self.pmdebug = pv 789 # set the trace clock to globa 730 # set the trace clock to global 790 self.fsetVal('global', 'trace_ 731 self.fsetVal('global', 'trace_clock') 791 self.fsetVal('nop', 'current_t 732 self.fsetVal('nop', 'current_tracer') 792 # set trace buffer to an appro 733 # set trace buffer to an appropriate value 793 cpus = max(1, self.cpucount) 734 cpus = max(1, self.cpucount) 794 if self.bufsize > 0: 735 if self.bufsize > 0: 795 tgtsize = self.bufsize 736 tgtsize = self.bufsize 796 elif self.usecallgraph or self 737 elif self.usecallgraph or self.usedevsrc: 797 bmax = (1*1024*1024) i 738 bmax = (1*1024*1024) if self.suspendmode in ['disk', 'command'] \ 798 else (3*1024*1 739 else (3*1024*1024) 799 tgtsize = min(self.mem 740 tgtsize = min(self.memfree, bmax) 800 else: 741 else: 801 tgtsize = 65536 742 tgtsize = 65536 802 while not self.fsetVal('%d' % 743 while not self.fsetVal('%d' % (tgtsize // cpus), 'buffer_size_kb'): 803 # if the size failed t 744 # if the size failed to set, lower it and keep trying 804 tgtsize -= 65536 745 tgtsize -= 65536 805 if tgtsize < 65536: 746 if tgtsize < 65536: 806 tgtsize = int( 747 tgtsize = int(self.fgetVal('buffer_size_kb')) * cpus 807 break 748 break 808 self.vprint('Setting trace buf !! 749 pprint('Setting trace buffers to %d kB (%d kB per cpu)' % (tgtsize, tgtsize/cpus)) 809 # initialize the callgraph tra 750 # initialize the callgraph trace 810 if(self.usecallgraph): 751 if(self.usecallgraph): 811 # set trace type 752 # set trace type 812 self.fsetVal('function 753 self.fsetVal('function_graph', 'current_tracer') 813 self.fsetVal('', 'set_ 754 self.fsetVal('', 'set_ftrace_filter') 814 # temporary hack to fi << 815 fp = open(self.tpath+' << 816 fp.write('native_queue << 817 fp.close() << 818 # set trace format opt 755 # set trace format options 819 self.fsetVal('print-pa 756 self.fsetVal('print-parent', 'trace_options') 820 self.fsetVal('funcgrap 757 self.fsetVal('funcgraph-abstime', 'trace_options') 821 self.fsetVal('funcgrap 758 self.fsetVal('funcgraph-cpu', 'trace_options') 822 self.fsetVal('funcgrap 759 self.fsetVal('funcgraph-duration', 'trace_options') 823 self.fsetVal('funcgrap 760 self.fsetVal('funcgraph-proc', 'trace_options') 824 self.fsetVal('funcgrap 761 self.fsetVal('funcgraph-tail', 'trace_options') 825 self.fsetVal('nofuncgr 762 self.fsetVal('nofuncgraph-overhead', 'trace_options') 826 self.fsetVal('context- 763 self.fsetVal('context-info', 'trace_options') 827 self.fsetVal('graph-ti 764 self.fsetVal('graph-time', 'trace_options') 828 self.fsetVal('%d' % se 765 self.fsetVal('%d' % self.max_graph_depth, 'max_graph_depth') 829 cf = ['dpm_run_callbac 766 cf = ['dpm_run_callback'] 830 if(self.usetraceevents 767 if(self.usetraceevents): 831 cf += ['dpm_pr 768 cf += ['dpm_prepare', 'dpm_complete'] 832 for fn in self.tracefu 769 for fn in self.tracefuncs: 833 if 'func' in s 770 if 'func' in self.tracefuncs[fn]: 834 cf.app 771 cf.append(self.tracefuncs[fn]['func']) 835 else: 772 else: 836 cf.app 773 cf.append(fn) 837 if self.ftop: 774 if self.ftop: 838 self.setFtrace 775 self.setFtraceFilterFunctions([self.ftopfunc]) 839 else: 776 else: 840 self.setFtrace 777 self.setFtraceFilterFunctions(cf) 841 # initialize the kprobe trace 778 # initialize the kprobe trace 842 elif self.usekprobes: 779 elif self.usekprobes: 843 for name in self.trace 780 for name in self.tracefuncs: 844 self.defaultKp 781 self.defaultKprobe(name, self.tracefuncs[name]) 845 if self.usedevsrc: 782 if self.usedevsrc: 846 for name in se 783 for name in self.dev_tracefuncs: 847 self.d 784 self.defaultKprobe(name, self.dev_tracefuncs[name]) 848 if not quiet: !! 785 pprint('INITIALIZING KPROBES...') 849 pprint('INITIA << 850 self.addKprobes(self.v 786 self.addKprobes(self.verbose) 851 if(self.usetraceevents): 787 if(self.usetraceevents): 852 # turn trace events on 788 # turn trace events on 853 events = iter(self.tra 789 events = iter(self.traceevents) 854 for e in events: 790 for e in events: 855 self.fsetVal(' 791 self.fsetVal('1', 'events/power/'+e+'/enable') 856 # clear the trace buffer 792 # clear the trace buffer 857 self.fsetVal('', 'trace') 793 self.fsetVal('', 'trace') 858 def verifyFtrace(self): 794 def verifyFtrace(self): 859 # files needed for any trace d 795 # files needed for any trace data 860 files = ['buffer_size_kb', 'cu 796 files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock', 861 'trace_marker 797 'trace_marker', 'trace_options', 'tracing_on'] 862 # files needed for callgraph t 798 # files needed for callgraph trace data 863 tp = self.tpath 799 tp = self.tpath 864 if(self.usecallgraph): 800 if(self.usecallgraph): 865 files += [ 801 files += [ 866 'available_fil 802 'available_filter_functions', 867 'set_ftrace_fi 803 'set_ftrace_filter', 868 'set_graph_fun 804 'set_graph_function' 869 ] 805 ] 870 for f in files: 806 for f in files: 871 if(os.path.exists(tp+f 807 if(os.path.exists(tp+f) == False): 872 return False 808 return False 873 return True 809 return True 874 def verifyKprobes(self): 810 def verifyKprobes(self): 875 # files needed for kprobes to 811 # files needed for kprobes to work 876 files = ['kprobe_events', 'eve 812 files = ['kprobe_events', 'events'] 877 tp = self.tpath 813 tp = self.tpath 878 for f in files: 814 for f in files: 879 if(os.path.exists(tp+f 815 if(os.path.exists(tp+f) == False): 880 return False 816 return False 881 return True 817 return True 882 def colorText(self, str, color=31): 818 def colorText(self, str, color=31): 883 if not self.ansi: 819 if not self.ansi: 884 return str 820 return str 885 return '\x1B[%d;40m%s\x1B[m' % 821 return '\x1B[%d;40m%s\x1B[m' % (color, str) 886 def writeDatafileHeader(self, filename 822 def writeDatafileHeader(self, filename, testdata): 887 fp = self.openlog(filename, 'w 823 fp = self.openlog(filename, 'w') 888 fp.write('%s\n%s\n# command | 824 fp.write('%s\n%s\n# command | %s\n' % (self.teststamp, self.sysstamp, self.cmdline)) 889 for test in testdata: 825 for test in testdata: 890 if 'fw' in test: 826 if 'fw' in test: 891 fw = test['fw' 827 fw = test['fw'] 892 if(fw): 828 if(fw): 893 fp.wri 829 fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) >> 830 if 'mcelog' in test: >> 831 fp.write('# mcelog %s\n' % test['mcelog']) 894 if 'turbo' in test: 832 if 'turbo' in test: 895 fp.write('# tu 833 fp.write('# turbostat %s\n' % test['turbo']) >> 834 if 'bat' in test: >> 835 (a1, c1), (a2, c2) = test['bat'] >> 836 fp.write('# battery %s %d %s %d\n' % (a1, c1, a2, c2)) 896 if 'wifi' in test: 837 if 'wifi' in test: 897 fp.write('# wi !! 838 wstr = [] 898 if 'netfix' in test: !! 839 for wifi in test['wifi']: 899 fp.write('# ne !! 840 tmp = [] >> 841 for key in sorted(wifi): >> 842 tmp.append('%s:%s' % (key, wifi[key])) >> 843 wstr.append('|'.join(tmp)) >> 844 fp.write('# wifi %s\n' % (','.join(wstr))) 900 if test['error'] or le 845 if test['error'] or len(testdata) > 1: 901 fp.write('# en 846 fp.write('# enter_sleep_error %s\n' % test['error']) 902 return fp 847 return fp 903 def sudoUserchown(self, dir): 848 def sudoUserchown(self, dir): 904 if os.path.exists(dir) and sel 849 if os.path.exists(dir) and self.sudouser: 905 cmd = 'chown -R {0}:{0 850 cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' 906 call(cmd.format(self.s 851 call(cmd.format(self.sudouser, dir), shell=True) 907 def outputResult(self, testdata, num=0 852 def outputResult(self, testdata, num=0): 908 if not self.result: 853 if not self.result: 909 return 854 return 910 n = '' 855 n = '' 911 if num > 0: 856 if num > 0: 912 n = '%d' % num 857 n = '%d' % num 913 fp = open(self.result, 'a') 858 fp = open(self.result, 'a') 914 if 'error' in testdata: 859 if 'error' in testdata: 915 fp.write('result%s: fa 860 fp.write('result%s: fail\n' % n) 916 fp.write('error%s: %s\ 861 fp.write('error%s: %s\n' % (n, testdata['error'])) 917 else: 862 else: 918 fp.write('result%s: pa 863 fp.write('result%s: pass\n' % n) 919 if 'mode' in testdata: << 920 fp.write('mode%s: %s\n << 921 for v in ['suspend', 'resume', 864 for v in ['suspend', 'resume', 'boot', 'lastinit']: 922 if v in testdata: 865 if v in testdata: 923 fp.write('%s%s 866 fp.write('%s%s: %.3f\n' % (v, n, testdata[v])) 924 for v in ['fwsuspend', 'fwresu 867 for v in ['fwsuspend', 'fwresume']: 925 if v in testdata: 868 if v in testdata: 926 fp.write('%s%s 869 fp.write('%s%s: %.3f\n' % (v, n, testdata[v] / 1000000.0)) 927 if 'bugurl' in testdata: 870 if 'bugurl' in testdata: 928 fp.write('url%s: %s\n' 871 fp.write('url%s: %s\n' % (n, testdata['bugurl'])) 929 fp.close() 872 fp.close() 930 self.sudoUserchown(self.result 873 self.sudoUserchown(self.result) 931 def configFile(self, file): 874 def configFile(self, file): 932 dir = os.path.dirname(os.path. 875 dir = os.path.dirname(os.path.realpath(__file__)) 933 if os.path.exists(file): 876 if os.path.exists(file): 934 return file 877 return file 935 elif os.path.exists(dir+'/'+fi 878 elif os.path.exists(dir+'/'+file): 936 return dir+'/'+file 879 return dir+'/'+file 937 elif os.path.exists(dir+'/conf 880 elif os.path.exists(dir+'/config/'+file): 938 return dir+'/config/'+ 881 return dir+'/config/'+file 939 return '' 882 return '' 940 def openlog(self, filename, mode): 883 def openlog(self, filename, mode): 941 isgz = self.gzip 884 isgz = self.gzip 942 if mode == 'r': 885 if mode == 'r': 943 try: 886 try: 944 with gzip.open 887 with gzip.open(filename, mode+'t') as fp: 945 test = 888 test = fp.read(64) 946 isgz = True 889 isgz = True 947 except: 890 except: 948 isgz = False 891 isgz = False 949 if isgz: 892 if isgz: 950 return gzip.open(filen 893 return gzip.open(filename, mode+'t') 951 return open(filename, mode) 894 return open(filename, mode) 952 def putlog(self, filename, text): << 953 with self.openlog(filename, 'a << 954 fp.write(text) << 955 fp.close() << 956 def dlog(self, text): << 957 if not self.dmesgfile: << 958 return << 959 self.putlog(self.dmesgfile, '# << 960 def flog(self, text): << 961 self.putlog(self.ftracefile, t << 962 def b64unzip(self, data): 895 def b64unzip(self, data): 963 try: 896 try: 964 out = codecs.decode(ba 897 out = codecs.decode(base64.b64decode(data), 'zlib').decode() 965 except: 898 except: 966 out = data 899 out = data 967 return out 900 return out 968 def b64zip(self, data): 901 def b64zip(self, data): 969 out = base64.b64encode(codecs. 902 out = base64.b64encode(codecs.encode(data.encode(), 'zlib')).decode() 970 return out 903 return out 971 def platforminfo(self, cmdafter): !! 904 def mcelog(self, clear=False): >> 905 cmd = self.getExec('mcelog') >> 906 if not cmd: >> 907 return '' >> 908 if clear: >> 909 call(cmd+' > /dev/null 2>&1', shell=True) >> 910 return '' >> 911 try: >> 912 fp = Popen([cmd], stdout=PIPE, stderr=PIPE).stdout >> 913 out = ascii(fp.read()).strip() >> 914 fp.close() >> 915 except: >> 916 return '' >> 917 if not out: >> 918 return '' >> 919 return self.b64zip(out) >> 920 def platforminfo(self): 972 # add platform info on to a co 921 # add platform info on to a completed ftrace file 973 if not os.path.exists(self.ftr 922 if not os.path.exists(self.ftracefile): 974 return False 923 return False 975 footer = '#\n' 924 footer = '#\n' 976 925 977 # add test command string line 926 # add test command string line if need be 978 if self.suspendmode == 'comman 927 if self.suspendmode == 'command' and self.testcommand: 979 footer += '# platform- 928 footer += '# platform-testcmd: %s\n' % (self.testcommand) 980 929 981 # get a list of target devices 930 # get a list of target devices from the ftrace file 982 props = dict() 931 props = dict() 983 tp = TestProps() 932 tp = TestProps() 984 tf = self.openlog(self.ftracef 933 tf = self.openlog(self.ftracefile, 'r') 985 for line in tf: 934 for line in tf: 986 if tp.stampInfo(line, !! 935 # determine the trace data type (required for further parsing) >> 936 m = re.match(tp.tracertypefmt, line) >> 937 if(m): >> 938 tp.setTracerType(m.group('t')) 987 continue 939 continue 988 # parse only valid lin 940 # parse only valid lines, if this is not one move on 989 m = re.match(tp.ftrace 941 m = re.match(tp.ftrace_line_fmt, line) 990 if(not m or 'device_pm 942 if(not m or 'device_pm_callback_start' not in line): 991 continue 943 continue 992 m = re.match(r'.*: (?P !! 944 m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg')); 993 if(not m): 945 if(not m): 994 continue 946 continue 995 dev = m.group('d') 947 dev = m.group('d') 996 if dev not in props: 948 if dev not in props: 997 props[dev] = D 949 props[dev] = DevProps() 998 tf.close() 950 tf.close() 999 951 1000 # now get the syspath for eac 952 # now get the syspath for each target device 1001 for dirname, dirnames, filena 953 for dirname, dirnames, filenames in os.walk('/sys/devices'): 1002 if(re.match(r'.*/powe !! 954 if(re.match('.*/power', dirname) and 'async' in filenames): 1003 dev = dirname 955 dev = dirname.split('/')[-2] 1004 if dev in pro 956 if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)): 1005 props 957 props[dev].syspath = dirname[:-6] 1006 958 1007 # now fill in the properties 959 # now fill in the properties for our target devices 1008 for dev in sorted(props): 960 for dev in sorted(props): 1009 dirname = props[dev]. 961 dirname = props[dev].syspath 1010 if not dirname or not 962 if not dirname or not os.path.exists(dirname): 1011 continue 963 continue 1012 props[dev].isasync = !! 964 with open(dirname+'/power/async') as fp: 1013 if os.path.exists(dir !! 965 text = fp.read() 1014 fp = open(dir !! 966 props[dev].isasync = False 1015 if 'enabled' !! 967 if 'enabled' in text: 1016 props 968 props[dev].isasync = True 1017 fp.close() << 1018 fields = os.listdir(d 969 fields = os.listdir(dirname) 1019 for file in ['product !! 970 if 'product' in fields: 1020 if file not i !! 971 with open(dirname+'/product', 'rb') as fp: 1021 conti !! 972 props[dev].altname = ascii(fp.read()) 1022 try: !! 973 elif 'name' in fields: 1023 with !! 974 with open(dirname+'/name', 'rb') as fp: 1024 !! 975 props[dev].altname = ascii(fp.read()) 1025 except: !! 976 elif 'model' in fields: 1026 conti !! 977 with open(dirname+'/model', 'rb') as fp: 1027 if file == 'i !! 978 props[dev].altname = ascii(fp.read()) 1028 idv, !! 979 elif 'description' in fields: 1029 try: !! 980 with open(dirname+'/description', 'rb') as fp: 1030 !! 981 props[dev].altname = ascii(fp.read()) 1031 !! 982 elif 'id' in fields: 1032 excep !! 983 with open(dirname+'/id', 'rb') as fp: 1033 !! 984 props[dev].altname = ascii(fp.read()) 1034 !! 985 elif 'idVendor' in fields and 'idProduct' in fields: 1035 props !! 986 idv, idp = '', '' 1036 break !! 987 with open(dirname+'/idVendor', 'rb') as fp: >> 988 idv = ascii(fp.read()).strip() >> 989 with open(dirname+'/idProduct', 'rb') as fp: >> 990 idp = ascii(fp.read()).strip() >> 991 props[dev].altname = '%s:%s' % (idv, idp) 1037 if props[dev].altname 992 if props[dev].altname: 1038 out = props[d 993 out = props[dev].altname.strip().replace('\n', ' ')\ 1039 .repl 994 .replace(',', ' ').replace(';', ' ') 1040 props[dev].al 995 props[dev].altname = out 1041 996 1042 # add a devinfo line to the b 997 # add a devinfo line to the bottom of ftrace 1043 out = '' 998 out = '' 1044 for dev in sorted(props): 999 for dev in sorted(props): 1045 out += props[dev].out 1000 out += props[dev].out(dev) 1046 footer += '# platform-devinfo 1001 footer += '# platform-devinfo: %s\n' % self.b64zip(out) 1047 1002 1048 # add a line for each of thes 1003 # add a line for each of these commands with their outputs 1049 for name, cmdline, info in cm !! 1004 cmds = [ 1050 footer += '# platform !! 1005 ['pcidevices', 'lspci', '-tv'], 1051 self.flog(footer) !! 1006 ['interrupts', 'cat', '/proc/interrupts'], 1052 return True !! 1007 ['gpecounts', 'sh', '-c', 'grep -v invalid /sys/firmware/acpi/interrupts/gpe*'], 1053 def commonPrefix(self, list): !! 1008 ] 1054 if len(list) < 2: !! 1009 for cargs in cmds: 1055 return '' !! 1010 name = cargs[0] 1056 prefix = list[0] !! 1011 cmdline = ' '.join(cargs[1:]) 1057 for s in list[1:]: !! 1012 cmdpath = self.getExec(cargs[1]) 1058 while s[:len(prefix)] !! 1013 if not cmdpath: 1059 prefix = pref << 1060 if not prefix: << 1061 break << 1062 if '/' in prefix and prefix[- << 1063 prefix = prefix[0:pre << 1064 return prefix << 1065 def dictify(self, text, format): << 1066 out = dict() << 1067 header = True if format == 1 << 1068 delim = ' ' if format == 1 el << 1069 for line in text.split('\n'): << 1070 if header: << 1071 header, out[' << 1072 continue 1014 continue 1073 line = line.strip() !! 1015 cmd = [cmdpath] + cargs[2:] 1074 if delim in line: << 1075 data = line.s << 1076 num = re.sear << 1077 if format == << 1078 out[d << 1079 else: << 1080 out[d << 1081 return out << 1082 def cmdinfovar(self, arg): << 1083 if arg == 'ethdev': << 1084 try: 1016 try: 1085 cmd = [self.g << 1086 fp = Popen(cm 1017 fp = Popen(cmd, stdout=PIPE, stderr=PIPE).stdout 1087 info = ascii( 1018 info = ascii(fp.read()).strip() 1088 fp.close() 1019 fp.close() 1089 except: 1020 except: 1090 return 'iptoo << 1091 for line in info.spli << 1092 if line[0] == << 1093 retur << 1094 return 'nodevicefound << 1095 return 'unknown' << 1096 def cmdinfo(self, begin, debug=False) << 1097 out = [] << 1098 if begin: << 1099 self.cmd1 = dict() << 1100 for cargs in self.infocmds: << 1101 delta, name, args = c << 1102 for i in range(len(ar << 1103 if args[i][0] << 1104 args[ << 1105 cmdline, cmdpath = ' << 1106 if not cmdpath or (be << 1107 continue 1021 continue 1108 self.dlog('[%s]' % cm !! 1022 if not info: 1109 try: << 1110 fp = Popen([c << 1111 info = ascii( << 1112 fp.close() << 1113 except: << 1114 continue 1023 continue 1115 if not debug and begi !! 1024 footer += '# platform-%s: %s | %s\n' % (name, cmdline, self.b64zip(info)) 1116 self.cmd1[nam !! 1025 1117 elif not debug and de !! 1026 with self.openlog(self.ftracefile, 'a') as fp: 1118 before, after !! 1027 fp.write(footer) 1119 dinfo = ('\t% !! 1028 return True 1120 prefix = self << 1121 for key in so << 1122 if ke << 1123 << 1124 << 1125 << 1126 << 1127 << 1128 << 1129 << 1130 dinfo = '\tno << 1131 out.append((n << 1132 else: << 1133 out.append((n << 1134 return out << 1135 def testVal(self, file, fmt='basic', << 1136 if file == 'restoreall': << 1137 for f in self.cfgdef: << 1138 if os.path.ex << 1139 fp = << 1140 fp.wr << 1141 fp.cl << 1142 self.cfgdef = dict() << 1143 elif value and os.path.exists << 1144 fp = open(file, 'r+') << 1145 if fmt == 'radio': << 1146 m = re.match( << 1147 if m: << 1148 self. << 1149 elif fmt == 'acpi': << 1150 line = fp.rea << 1151 m = re.match( << 1152 if m: << 1153 self. << 1154 else: << 1155 self.cfgdef[f << 1156 fp.write(value) << 1157 fp.close() << 1158 def s0ixSupport(self): << 1159 if not os.path.exists(self.s0 << 1160 return False << 1161 fp = open(sysvals.mempowerfil << 1162 data = fp.read().strip() << 1163 fp.close() << 1164 if '[s2idle]' in data: << 1165 return True << 1166 return False << 1167 def haveTurbostat(self): 1029 def haveTurbostat(self): 1168 if not self.tstat: 1030 if not self.tstat: 1169 return False 1031 return False 1170 cmd = self.getExec('turbostat 1032 cmd = self.getExec('turbostat') 1171 if not cmd: 1033 if not cmd: 1172 return False 1034 return False 1173 fp = Popen([cmd, '-v'], stdou 1035 fp = Popen([cmd, '-v'], stdout=PIPE, stderr=PIPE).stderr 1174 out = ascii(fp.read()).strip( 1036 out = ascii(fp.read()).strip() 1175 fp.close() 1037 fp.close() 1176 if re.match(r'turbostat versi !! 1038 if re.match('turbostat version [0-9\.]* .*', out): 1177 self.vprint(out) !! 1039 sysvals.vprint(out) 1178 return True 1040 return True 1179 return False 1041 return False 1180 def turbostat(self, s0ixready): !! 1042 def turbostat(self): 1181 cmd = self.getExec('turbostat 1043 cmd = self.getExec('turbostat') 1182 rawout = keyline = valline = 1044 rawout = keyline = valline = '' 1183 fullcmd = '%s -q -S echo free 1045 fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile) 1184 fp = Popen(['sh', '-c', fullc !! 1046 fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE).stderr 1185 for line in fp.stderr: !! 1047 for line in fp: 1186 line = ascii(line) 1048 line = ascii(line) 1187 rawout += line 1049 rawout += line 1188 if keyline and vallin 1050 if keyline and valline: 1189 continue 1051 continue 1190 if re.match(r'(?i)Avg !! 1052 if re.match('(?i)Avg_MHz.*', line): 1191 keyline = lin 1053 keyline = line.strip().split() 1192 elif keyline: 1054 elif keyline: 1193 valline = lin 1055 valline = line.strip().split() 1194 fp.wait() !! 1056 fp.close() 1195 if not keyline or not valline 1057 if not keyline or not valline or len(keyline) != len(valline): 1196 errmsg = 'unrecognize 1058 errmsg = 'unrecognized turbostat output:\n'+rawout.strip() 1197 self.vprint(errmsg) !! 1059 sysvals.vprint(errmsg) 1198 if not self.verbose: !! 1060 if not sysvals.verbose: 1199 pprint(errmsg 1061 pprint(errmsg) 1200 return (fp.returncode !! 1062 return '' 1201 if self.verbose: !! 1063 if sysvals.verbose: 1202 pprint(rawout.strip() 1064 pprint(rawout.strip()) 1203 out = [] 1065 out = [] 1204 for key in keyline: 1066 for key in keyline: 1205 idx = keyline.index(k 1067 idx = keyline.index(key) 1206 val = valline[idx] 1068 val = valline[idx] 1207 if key == 'SYS%LPI' a << 1208 continue << 1209 out.append('%s=%s' % 1069 out.append('%s=%s' % (key, val)) 1210 return (fp.returncode, '|'.jo !! 1070 return '|'.join(out) 1211 def netfixon(self, net='both'): !! 1071 def checkWifi(self): 1212 cmd = self.getExec('netfix') !! 1072 out = dict() 1213 if not cmd: !! 1073 iwcmd, ifcmd = self.getExec('iwconfig'), self.getExec('ifconfig') 1214 return '' !! 1074 if not iwcmd or not ifcmd: 1215 fp = Popen([cmd, '-s', net, ' !! 1075 return out 1216 out = ascii(fp.read()).strip( !! 1076 fp = Popen(iwcmd, stdout=PIPE, stderr=PIPE).stdout >> 1077 for line in fp: >> 1078 m = re.match('(?P<dev>\S*) .* ESSID:(?P<ess>\S*)', ascii(line)) >> 1079 if not m: >> 1080 continue >> 1081 out['device'] = m.group('dev') >> 1082 if '"' in m.group('ess'): >> 1083 out['essid'] = m.group('ess').strip('"') >> 1084 break 1217 fp.close() 1085 fp.close() >> 1086 if 'device' in out: >> 1087 fp = Popen([ifcmd, out['device']], stdout=PIPE, stderr=PIPE).stdout >> 1088 for line in fp: >> 1089 m = re.match('.* inet (?P<ip>[0-9\.]*)', ascii(line)) >> 1090 if m: >> 1091 out['ip'] = m.group('ip') >> 1092 break >> 1093 fp.close() 1218 return out 1094 return out 1219 def wifiDetails(self, dev): << 1220 try: << 1221 info = open('/sys/cla << 1222 except: << 1223 return dev << 1224 vals = [dev] << 1225 for prop in info.split('\n'): << 1226 if prop.startswith('D << 1227 vals.append(p << 1228 return ':'.join(vals) << 1229 def checkWifi(self, dev=''): << 1230 try: << 1231 w = open('/proc/net/w << 1232 except: << 1233 return '' << 1234 for line in reversed(w.split( << 1235 m = re.match(r' *(?P< << 1236 if not m or (dev and << 1237 continue << 1238 return m.group('dev') << 1239 return '' << 1240 def pollWifi(self, dev, timeout=10): << 1241 start = time.time() << 1242 while (time.time() - start) < << 1243 w = self.checkWifi(de << 1244 if w: << 1245 return '%s re << 1246 (self << 1247 time.sleep(0.01) << 1248 return '%s timeout %d' % (sel << 1249 def errorSummary(self, errinfo, msg): 1095 def errorSummary(self, errinfo, msg): 1250 found = False 1096 found = False 1251 for entry in errinfo: 1097 for entry in errinfo: 1252 if re.match(entry['ma 1098 if re.match(entry['match'], msg): 1253 entry['count' 1099 entry['count'] += 1 1254 if self.hostn 1100 if self.hostname not in entry['urls']: 1255 entry 1101 entry['urls'][self.hostname] = [self.htmlfile] 1256 elif self.htm 1102 elif self.htmlfile not in entry['urls'][self.hostname]: 1257 entry 1103 entry['urls'][self.hostname].append(self.htmlfile) 1258 found = True 1104 found = True 1259 break 1105 break 1260 if found: 1106 if found: 1261 return 1107 return 1262 arr = msg.split() 1108 arr = msg.split() 1263 for j in range(len(arr)): 1109 for j in range(len(arr)): 1264 if re.match(r'^[0-9,\ !! 1110 if re.match('^[0-9,\-\.]*$', arr[j]): 1265 arr[j] = r'[0 !! 1111 arr[j] = '[0-9,\-\.]*' 1266 else: 1112 else: 1267 arr[j] = arr[ 1113 arr[j] = arr[j]\ 1268 .repl !! 1114 .replace('\\', '\\\\').replace(']', '\]').replace('[', '\[')\ 1269 .repl !! 1115 .replace('.', '\.').replace('+', '\+').replace('*', '\*')\ 1270 .repl !! 1116 .replace('(', '\(').replace(')', '\)') 1271 .repl !! 1117 mstr = ' '.join(arr) 1272 mstr = ' *'.join(arr) << 1273 entry = { 1118 entry = { 1274 'line': msg, 1119 'line': msg, 1275 'match': mstr, 1120 'match': mstr, 1276 'count': 1, 1121 'count': 1, 1277 'urls': {self.hostnam 1122 'urls': {self.hostname: [self.htmlfile]} 1278 } 1123 } 1279 errinfo.append(entry) 1124 errinfo.append(entry) 1280 def multistat(self, start, idx, finis << 1281 if 'time' in self.multitest: << 1282 id = '%d Duration=%dm << 1283 else: << 1284 id = '%d/%d' % (idx+1 << 1285 t = time.time() << 1286 if 'start' not in self.multit << 1287 self.multitest['start << 1288 self.multitest['total << 1289 pprint('TEST (%s) STA << 1290 return << 1291 dt = t - self.multitest['last << 1292 if not start: << 1293 if idx == 0 and self. << 1294 self.multites << 1295 pprint('TEST (%s) COM << 1296 return << 1297 self.multitest['total'] += dt << 1298 self.multitest['last'] = t << 1299 avg = self.multitest['total'] << 1300 if 'time' in self.multitest: << 1301 left = finish - datet << 1302 left -= timedelta(mic << 1303 else: << 1304 left = timedelta(seco << 1305 pprint('TEST (%s) START - Avg << 1306 (id, avg, str(left))) << 1307 def multiinit(self, c, d): << 1308 sz, unit = 'count', 'm' << 1309 if c.endswith('d') or c.endsw << 1310 sz, unit, c = 'time', << 1311 self.multitest['run'] = True << 1312 self.multitest[sz] = getArgIn << 1313 self.multitest['delay'] = get << 1314 if unit == 'd': << 1315 self.multitest[sz] *= << 1316 elif unit == 'h': << 1317 self.multitest[sz] *= << 1318 def displayControl(self, cmd): << 1319 xset, ret = 'timeout 10 xset << 1320 if self.sudouser: << 1321 xset = 'sudo -u %s %s << 1322 if cmd == 'init': << 1323 ret = call(xset.forma << 1324 if not ret: << 1325 ret = call(xs << 1326 elif cmd == 'reset': << 1327 ret = call(xset.forma << 1328 elif cmd in ['on', 'off', 'st << 1329 b4 = self.displayCont << 1330 ret = call(xset.forma << 1331 if not ret: << 1332 curr = self.d << 1333 self.vprint(' << 1334 if curr != cm << 1335 self. << 1336 if ret: << 1337 self.vprint(' << 1338 return ret << 1339 elif cmd == 'stat': << 1340 fp = Popen(xset.forma << 1341 ret = 'unknown' << 1342 for line in fp: << 1343 m = re.match( << 1344 if(m and len( << 1345 out = << 1346 ret = << 1347 break << 1348 fp.close() << 1349 return ret << 1350 def setRuntimeSuspend(self, before=Tr << 1351 if before: << 1352 # runtime suspend dis << 1353 if self.rs > 0: << 1354 self.rstgt, s << 1355 else: << 1356 self.rstgt, s << 1357 pprint('CONFIGURING R << 1358 self.rslist = deviceI << 1359 for i in self.rslist: << 1360 self.setVal(s << 1361 pprint('runtime suspe << 1362 pprint('waiting 5 sec << 1363 time.sleep(5) << 1364 else: << 1365 # runtime suspend re- << 1366 for i in self.rslist: << 1367 self.setVal(s << 1368 pprint('runtime suspe << 1369 def start(self, pm): << 1370 if self.useftrace: << 1371 self.dlog('start ftra << 1372 self.fsetVal('1', 'tr << 1373 if self.useprocmon: << 1374 self.dlog('st << 1375 pm.start() << 1376 def stop(self, pm): << 1377 if self.useftrace: << 1378 if self.useprocmon: << 1379 self.dlog('st << 1380 pm.stop() << 1381 self.dlog('stop ftrac << 1382 self.fsetVal('0', 'tr << 1383 1125 1384 sysvals = SystemValues() 1126 sysvals = SystemValues() 1385 switchvalues = ['enable', 'disable', 'on', 'o 1127 switchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0'] 1386 switchoff = ['disable', 'off', 'false', '0'] 1128 switchoff = ['disable', 'off', 'false', '0'] 1387 suspendmodename = { 1129 suspendmodename = { 1388 'standby': 'standby (S1)', !! 1130 'freeze': 'Freeze (S0)', 1389 'freeze': 'freeze (S2idle)', !! 1131 'standby': 'Standby (S1)', 1390 'mem': 'suspend (S3)', !! 1132 'mem': 'Suspend (S3)', 1391 'disk': 'hibernate (S4)' !! 1133 'disk': 'Hibernate (S4)' 1392 } 1134 } 1393 1135 1394 # Class: DevProps 1136 # Class: DevProps 1395 # Description: 1137 # Description: 1396 # Simple class which holds property va 1138 # Simple class which holds property values collected 1397 # for all the devices used in the time 1139 # for all the devices used in the timeline. 1398 class DevProps: 1140 class DevProps: 1399 def __init__(self): 1141 def __init__(self): 1400 self.syspath = '' 1142 self.syspath = '' 1401 self.altname = '' 1143 self.altname = '' 1402 self.isasync = True 1144 self.isasync = True 1403 self.xtraclass = '' 1145 self.xtraclass = '' 1404 self.xtrainfo = '' 1146 self.xtrainfo = '' 1405 def out(self, dev): 1147 def out(self, dev): 1406 return '%s,%s,%d;' % (dev, se 1148 return '%s,%s,%d;' % (dev, self.altname, self.isasync) 1407 def debug(self, dev): 1149 def debug(self, dev): 1408 pprint('%s:\n\taltname = %s\n 1150 pprint('%s:\n\taltname = %s\n\t async = %s' % (dev, self.altname, self.isasync)) 1409 def altName(self, dev): 1151 def altName(self, dev): 1410 if not self.altname or self.a 1152 if not self.altname or self.altname == dev: 1411 return dev 1153 return dev 1412 return '%s [%s]' % (self.altn 1154 return '%s [%s]' % (self.altname, dev) 1413 def xtraClass(self): 1155 def xtraClass(self): 1414 if self.xtraclass: 1156 if self.xtraclass: 1415 return ' '+self.xtrac 1157 return ' '+self.xtraclass 1416 if not self.isasync: 1158 if not self.isasync: 1417 return ' sync' 1159 return ' sync' 1418 return '' 1160 return '' 1419 def xtraInfo(self): 1161 def xtraInfo(self): 1420 if self.xtraclass: 1162 if self.xtraclass: 1421 return ' '+self.xtrac 1163 return ' '+self.xtraclass 1422 if self.isasync: 1164 if self.isasync: 1423 return ' (async)' !! 1165 return ' async_device' 1424 return ' (sync)' !! 1166 return ' sync_device' 1425 1167 1426 # Class: DeviceNode 1168 # Class: DeviceNode 1427 # Description: 1169 # Description: 1428 # A container used to create a device 1170 # A container used to create a device hierachy, with a single root node 1429 # and a tree of child nodes. Used by D 1171 # and a tree of child nodes. Used by Data.deviceTopology() 1430 class DeviceNode: 1172 class DeviceNode: 1431 def __init__(self, nodename, nodedept 1173 def __init__(self, nodename, nodedepth): 1432 self.name = nodename 1174 self.name = nodename 1433 self.children = [] 1175 self.children = [] 1434 self.depth = nodedepth 1176 self.depth = nodedepth 1435 1177 1436 # Class: Data 1178 # Class: Data 1437 # Description: 1179 # Description: 1438 # The primary container for suspend/re 1180 # The primary container for suspend/resume test data. There is one for 1439 # each test run. The data is organized 1181 # each test run. The data is organized into a cronological hierarchy: 1440 # Data.dmesg { 1182 # Data.dmesg { 1441 # phases { 1183 # phases { 1442 # 10 sequential, non-ov 1184 # 10 sequential, non-overlapping phases of S/R 1443 # contents: times for p 1185 # contents: times for phase start/end, order/color data for html 1444 # devlist { 1186 # devlist { 1445 # device callba 1187 # device callback or action list for this phase 1446 # device { 1188 # device { 1447 # a sin 1189 # a single device callback or generic action 1448 # conte 1190 # contents: start/stop times, pid/cpu/driver info 1449 # 1191 # parents/children, html id for timeline/callgraph 1450 # 1192 # optionally includes an ftrace callgraph 1451 # 1193 # optionally includes dev/ps data 1452 # } 1194 # } 1453 # } 1195 # } 1454 # } 1196 # } 1455 # } 1197 # } 1456 # 1198 # 1457 class Data: 1199 class Data: 1458 phasedef = { 1200 phasedef = { 1459 'suspend_prepare': {'order': 1201 'suspend_prepare': {'order': 0, 'color': '#CCFFCC'}, 1460 'suspend': {'order': 1202 'suspend': {'order': 1, 'color': '#88FF88'}, 1461 'suspend_late': {'order': 1203 'suspend_late': {'order': 2, 'color': '#00AA00'}, 1462 'suspend_noirq': {'order': 1204 'suspend_noirq': {'order': 3, 'color': '#008888'}, 1463 'suspend_machine': {'order': 1205 'suspend_machine': {'order': 4, 'color': '#0000FF'}, 1464 'resume_machine': {'order': 1206 'resume_machine': {'order': 5, 'color': '#FF0000'}, 1465 'resume_noirq': {'order': 1207 'resume_noirq': {'order': 6, 'color': '#FF9900'}, 1466 'resume_early': {'order': 1208 'resume_early': {'order': 7, 'color': '#FFCC00'}, 1467 'resume': {'order': 1209 'resume': {'order': 8, 'color': '#FFFF88'}, 1468 'resume_complete': {'order': 1210 'resume_complete': {'order': 9, 'color': '#FFFFCC'}, 1469 } 1211 } 1470 errlist = { 1212 errlist = { 1471 'HWERROR' : r'.*\[ *Hardware !! 1213 'HWERROR' : '.*\[ *Hardware Error *\].*', 1472 'FWBUG' : r'.*\[ *Firmware !! 1214 'FWBUG' : '.*\[ *Firmware Bug *\].*', 1473 'TASKFAIL': r'.*Freezing .*af !! 1215 'BUG' : '.*BUG.*', 1474 'BUG' : r'(?i).*\bBUG\b.* !! 1216 'ERROR' : '.*ERROR.*', 1475 'ERROR' : r'(?i).*\bERROR\b !! 1217 'WARNING' : '.*WARNING.*', 1476 'WARNING' : r'(?i).*\bWARNING !! 1218 'IRQ' : '.*genirq: .*', 1477 'FAULT' : r'(?i).*\bFAULT\b !! 1219 'TASKFAIL': '.*Freezing of tasks *.*', 1478 'FAIL' : r'(?i).*\bFAILED\ !! 1220 'ACPI' : '.*ACPI *(?P<b>[A-Za-z]*) *Error[: ].*', 1479 'INVALID' : r'(?i).*\bINVALID !! 1221 'DEVFAIL' : '.* failed to (?P<b>[a-z]*) async: .*', 1480 'CRASH' : r'(?i).*\bCRASHED !! 1222 'DISKFULL': '.*No space left on device.*', 1481 'TIMEOUT' : r'(?i).*\bTIMEOUT !! 1223 'USBERR' : '.*usb .*device .*, error [0-9-]*', 1482 'ABORT' : r'(?i).*\bABORT\b !! 1224 'ATAERR' : ' *ata[0-9\.]*: .*failed.*', 1483 'IRQ' : r'.*\bgenirq: .*' !! 1225 'MEIERR' : ' *mei.*: .*failed.*', 1484 'ACPI' : r'.*\bACPI *(?P<b !! 1226 'TPMERR' : '(?i) *tpm *tpm[0-9]*: .*error.*', 1485 'DISKFULL': r'.*\bNo space le << 1486 'USBERR' : r'.*usb .*device << 1487 'ATAERR' : r' *ata[0-9\.]*: << 1488 'MEIERR' : r' *mei.*: .*fail << 1489 'TPMERR' : r'(?i) *tpm *tpm[ << 1490 } 1227 } 1491 def __init__(self, num): 1228 def __init__(self, num): 1492 idchar = 'abcdefghij' 1229 idchar = 'abcdefghij' 1493 self.start = 0.0 # test start 1230 self.start = 0.0 # test start 1494 self.end = 0.0 # test end 1231 self.end = 0.0 # test end 1495 self.hwstart = 0 # rtc test s << 1496 self.hwend = 0 # rtc test e << 1497 self.tSuspended = 0.0 # low-l 1232 self.tSuspended = 0.0 # low-level suspend start 1498 self.tResumed = 0.0 # low-l 1233 self.tResumed = 0.0 # low-level resume start 1499 self.tKernSus = 0.0 # kerne 1234 self.tKernSus = 0.0 # kernel level suspend start 1500 self.tKernRes = 0.0 # kerne 1235 self.tKernRes = 0.0 # kernel level resume end 1501 self.fwValid = False # is fi 1236 self.fwValid = False # is firmware data available 1502 self.fwSuspend = 0 # time 1237 self.fwSuspend = 0 # time spent in firmware suspend 1503 self.fwResume = 0 # time 1238 self.fwResume = 0 # time spent in firmware resume 1504 self.html_device_id = 0 1239 self.html_device_id = 0 1505 self.stamp = 0 1240 self.stamp = 0 1506 self.outfile = '' 1241 self.outfile = '' 1507 self.kerror = False 1242 self.kerror = False 1508 self.wifi = dict() !! 1243 self.battery = 0 >> 1244 self.wifi = 0 1509 self.turbostat = 0 1245 self.turbostat = 0 >> 1246 self.mcelog = 0 1510 self.enterfail = '' 1247 self.enterfail = '' 1511 self.currphase = '' 1248 self.currphase = '' 1512 self.pstl = dict() # proce 1249 self.pstl = dict() # process timeline 1513 self.testnumber = num 1250 self.testnumber = num 1514 self.idstr = idchar[num] 1251 self.idstr = idchar[num] 1515 self.dmesgtext = [] # dmesg 1252 self.dmesgtext = [] # dmesg text file in memory 1516 self.dmesg = dict() # root 1253 self.dmesg = dict() # root data structure 1517 self.errorinfo = {'suspend':[ 1254 self.errorinfo = {'suspend':[],'resume':[]} 1518 self.tLow = [] # time 1255 self.tLow = [] # time spent in low-level suspends (standby/freeze) 1519 self.devpids = [] 1256 self.devpids = [] 1520 self.devicegroups = 0 1257 self.devicegroups = 0 1521 def sortedPhases(self): 1258 def sortedPhases(self): 1522 return sorted(self.dmesg, key 1259 return sorted(self.dmesg, key=lambda k:self.dmesg[k]['order']) 1523 def initDevicegroups(self): 1260 def initDevicegroups(self): 1524 # called when phases are all 1261 # called when phases are all finished being added 1525 for phase in sorted(self.dmes 1262 for phase in sorted(self.dmesg.keys()): 1526 if '*' in phase: 1263 if '*' in phase: 1527 p = phase.spl 1264 p = phase.split('*') 1528 pnew = '%s%d' 1265 pnew = '%s%d' % (p[0], len(p)) 1529 self.dmesg[pn 1266 self.dmesg[pnew] = self.dmesg.pop(phase) 1530 self.devicegroups = [] 1267 self.devicegroups = [] 1531 for phase in self.sortedPhase 1268 for phase in self.sortedPhases(): 1532 self.devicegroups.app 1269 self.devicegroups.append([phase]) 1533 def nextPhase(self, phase, offset): 1270 def nextPhase(self, phase, offset): 1534 order = self.dmesg[phase]['or 1271 order = self.dmesg[phase]['order'] + offset 1535 for p in self.dmesg: 1272 for p in self.dmesg: 1536 if self.dmesg[p]['ord 1273 if self.dmesg[p]['order'] == order: 1537 return p 1274 return p 1538 return '' 1275 return '' 1539 def lastPhase(self, depth=1): !! 1276 def lastPhase(self): 1540 plist = self.sortedPhases() 1277 plist = self.sortedPhases() 1541 if len(plist) < depth: !! 1278 if len(plist) < 1: 1542 return '' 1279 return '' 1543 return plist[-1*depth] !! 1280 return plist[-1] 1544 def turbostatInfo(self): 1281 def turbostatInfo(self): 1545 tp = TestProps() 1282 tp = TestProps() 1546 out = {'syslpi':'N/A','pkgpc1 1283 out = {'syslpi':'N/A','pkgpc10':'N/A'} 1547 for line in self.dmesgtext: 1284 for line in self.dmesgtext: 1548 m = re.match(tp.tstat 1285 m = re.match(tp.tstatfmt, line) 1549 if not m: 1286 if not m: 1550 continue 1287 continue 1551 for i in m.group('t') 1288 for i in m.group('t').split('|'): 1552 if 'SYS%LPI' 1289 if 'SYS%LPI' in i: 1553 out[' 1290 out['syslpi'] = i.split('=')[-1]+'%' 1554 elif 'pc10' i 1291 elif 'pc10' in i: 1555 out[' 1292 out['pkgpc10'] = i.split('=')[-1]+'%' 1556 break 1293 break 1557 return out 1294 return out 1558 def extractErrorInfo(self): 1295 def extractErrorInfo(self): 1559 lf = self.dmesgtext 1296 lf = self.dmesgtext 1560 if len(self.dmesgtext) < 1 an 1297 if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 1561 lf = sysvals.openlog( 1298 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 1562 i = 0 1299 i = 0 1563 tp = TestProps() << 1564 list = [] 1300 list = [] 1565 for line in lf: 1301 for line in lf: 1566 i += 1 1302 i += 1 1567 if tp.stampInfo(line, !! 1303 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 1568 continue << 1569 m = re.match(r'[ \t]* << 1570 if not m: 1304 if not m: 1571 continue 1305 continue 1572 t = float(m.group('kt 1306 t = float(m.group('ktime')) 1573 if t < self.start or 1307 if t < self.start or t > self.end: 1574 continue 1308 continue 1575 dir = 'suspend' if t 1309 dir = 'suspend' if t < self.tSuspended else 'resume' 1576 msg = m.group('msg') 1310 msg = m.group('msg') 1577 if re.match(r'capabil << 1578 continue << 1579 for err in self.errli 1311 for err in self.errlist: 1580 if re.match(s 1312 if re.match(self.errlist[err], msg): 1581 list. 1313 list.append((msg, err, dir, t, i, i)) 1582 self. 1314 self.kerror = True 1583 break 1315 break 1584 tp.msglist = [] !! 1316 msglist = [] 1585 for msg, type, dir, t, idx1, 1317 for msg, type, dir, t, idx1, idx2 in list: 1586 tp.msglist.append(msg !! 1318 msglist.append(msg) >> 1319 sysvals.vprint('kernel %s found in %s at %f' % (type, dir, t)) 1587 self.errorinfo[dir].a 1320 self.errorinfo[dir].append((type, t, idx1, idx2)) 1588 if self.kerror: 1321 if self.kerror: 1589 sysvals.dmesglog = Tr 1322 sysvals.dmesglog = True 1590 if len(self.dmesgtext) < 1 an 1323 if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 1591 lf.close() 1324 lf.close() 1592 return tp !! 1325 return msglist 1593 def setStart(self, time, msg=''): !! 1326 def setStart(self, time): 1594 self.start = time 1327 self.start = time 1595 if msg: !! 1328 def setEnd(self, time): 1596 try: << 1597 self.hwstart << 1598 except: << 1599 self.hwstart << 1600 def setEnd(self, time, msg=''): << 1601 self.end = time 1329 self.end = time 1602 if msg: << 1603 try: << 1604 self.hwend = << 1605 except: << 1606 self.hwend = << 1607 def isTraceEventOutsideDeviceCalls(se 1330 def isTraceEventOutsideDeviceCalls(self, pid, time): 1608 for phase in self.sortedPhase 1331 for phase in self.sortedPhases(): 1609 list = self.dmesg[pha 1332 list = self.dmesg[phase]['list'] 1610 for dev in list: 1333 for dev in list: 1611 d = list[dev] 1334 d = list[dev] 1612 if(d['pid'] = 1335 if(d['pid'] == pid and time >= d['start'] and 1613 time 1336 time < d['end']): 1614 retur 1337 return False 1615 return True 1338 return True 1616 def sourcePhase(self, start): 1339 def sourcePhase(self, start): 1617 for phase in self.sortedPhase 1340 for phase in self.sortedPhases(): 1618 if 'machine' in phase 1341 if 'machine' in phase: 1619 continue 1342 continue 1620 pend = self.dmesg[pha 1343 pend = self.dmesg[phase]['end'] 1621 if start <= pend: 1344 if start <= pend: 1622 return phase 1345 return phase 1623 return 'resume_complete' if ' !! 1346 return 'resume_complete' 1624 def sourceDevice(self, phaselist, sta 1347 def sourceDevice(self, phaselist, start, end, pid, type): 1625 tgtdev = '' 1348 tgtdev = '' 1626 for phase in phaselist: 1349 for phase in phaselist: 1627 list = self.dmesg[pha 1350 list = self.dmesg[phase]['list'] 1628 for devname in list: 1351 for devname in list: 1629 dev = list[de 1352 dev = list[devname] 1630 # pid must ma 1353 # pid must match 1631 if dev['pid'] 1354 if dev['pid'] != pid: 1632 conti 1355 continue 1633 devS = dev['s 1356 devS = dev['start'] 1634 devE = dev['e 1357 devE = dev['end'] 1635 if type == 'd 1358 if type == 'device': 1636 # dev 1359 # device target event is entirely inside the source boundary 1637 if(st 1360 if(start < devS or start >= devE or end <= devS or end > devE): 1638 1361 continue 1639 elif type == 1362 elif type == 'thread': 1640 # thr 1363 # thread target event will expand the source boundary 1641 if st 1364 if start < devS: 1642 1365 dev['start'] = start 1643 if en 1366 if end > devE: 1644 1367 dev['end'] = end 1645 tgtdev = dev 1368 tgtdev = dev 1646 break 1369 break 1647 return tgtdev 1370 return tgtdev 1648 def addDeviceFunctionCall(self, displ 1371 def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata): 1649 # try to place the call in a 1372 # try to place the call in a device 1650 phases = self.sortedPhases() 1373 phases = self.sortedPhases() 1651 tgtdev = self.sourceDevice(ph 1374 tgtdev = self.sourceDevice(phases, start, end, pid, 'device') 1652 # calls with device pids that 1375 # calls with device pids that occur outside device bounds are dropped 1653 # TODO: include these somehow 1376 # TODO: include these somehow 1654 if not tgtdev and pid in self 1377 if not tgtdev and pid in self.devpids: 1655 return False 1378 return False 1656 # try to place the call in a 1379 # try to place the call in a thread 1657 if not tgtdev: 1380 if not tgtdev: 1658 tgtdev = self.sourceD 1381 tgtdev = self.sourceDevice(phases, start, end, pid, 'thread') 1659 # create new thread blocks, e 1382 # create new thread blocks, expand as new calls are found 1660 if not tgtdev: 1383 if not tgtdev: 1661 if proc == '<...>': 1384 if proc == '<...>': 1662 threadname = 1385 threadname = 'kthread-%d' % (pid) 1663 else: 1386 else: 1664 threadname = 1387 threadname = '%s-%d' % (proc, pid) 1665 tgtphase = self.sourc 1388 tgtphase = self.sourcePhase(start) 1666 if not tgtphase: << 1667 return False << 1668 self.newAction(tgtpha 1389 self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '') 1669 return self.addDevice 1390 return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata) 1670 # this should not happen 1391 # this should not happen 1671 if not tgtdev: 1392 if not tgtdev: 1672 sysvals.vprint('[%f - 1393 sysvals.vprint('[%f - %f] %s-%d %s %s %s' % \ 1673 (start, end, 1394 (start, end, proc, pid, kprobename, cdata, rdata)) 1674 return False 1395 return False 1675 # place the call data inside 1396 # place the call data inside the src element of the tgtdev 1676 if('src' not in tgtdev): 1397 if('src' not in tgtdev): 1677 tgtdev['src'] = [] 1398 tgtdev['src'] = [] 1678 dtf = sysvals.dev_tracefuncs 1399 dtf = sysvals.dev_tracefuncs 1679 ubiquitous = False 1400 ubiquitous = False 1680 if kprobename in dtf and 'ub' 1401 if kprobename in dtf and 'ub' in dtf[kprobename]: 1681 ubiquitous = True 1402 ubiquitous = True 1682 mc = re.match(r'\(.*\) *(?P<a !! 1403 title = cdata+' '+rdata 1683 mr = re.match(r'\((?P<caller> !! 1404 mstr = '\(.*\) *(?P<args>.*) *\((?P<caller>.*)\+.* arg1=(?P<ret>.*)' 1684 if mc and mr: !! 1405 m = re.match(mstr, title) 1685 c = mr.group('caller' !! 1406 if m: 1686 a = mc.group('args'). !! 1407 c = m.group('caller') 1687 r = mr.group('ret') !! 1408 a = m.group('args').strip() >> 1409 r = m.group('ret') 1688 if len(r) > 6: 1410 if len(r) > 6: 1689 r = '' 1411 r = '' 1690 else: 1412 else: 1691 r = 'ret=%s ' 1413 r = 'ret=%s ' % r 1692 if ubiquitous and c i 1414 if ubiquitous and c in dtf and 'ub' in dtf[c]: 1693 return False 1415 return False 1694 else: << 1695 return False << 1696 color = sysvals.kprobeColor(k 1416 color = sysvals.kprobeColor(kprobename) 1697 e = DevFunction(displayname, 1417 e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color) 1698 tgtdev['src'].append(e) 1418 tgtdev['src'].append(e) 1699 return True 1419 return True 1700 def overflowDevices(self): 1420 def overflowDevices(self): 1701 # get a list of devices that 1421 # get a list of devices that extend beyond the end of this test run 1702 devlist = [] 1422 devlist = [] 1703 for phase in self.sortedPhase 1423 for phase in self.sortedPhases(): 1704 list = self.dmesg[pha 1424 list = self.dmesg[phase]['list'] 1705 for devname in list: 1425 for devname in list: 1706 dev = list[de 1426 dev = list[devname] 1707 if dev['end'] 1427 if dev['end'] > self.end: 1708 devli 1428 devlist.append(dev) 1709 return devlist 1429 return devlist 1710 def mergeOverlapDevices(self, devlist 1430 def mergeOverlapDevices(self, devlist): 1711 # merge any devices that over 1431 # merge any devices that overlap devlist 1712 for dev in devlist: 1432 for dev in devlist: 1713 devname = dev['name'] 1433 devname = dev['name'] 1714 for phase in self.sor 1434 for phase in self.sortedPhases(): 1715 list = self.d 1435 list = self.dmesg[phase]['list'] 1716 if devname no 1436 if devname not in list: 1717 conti 1437 continue 1718 tdev = list[d 1438 tdev = list[devname] 1719 o = min(dev[' 1439 o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start']) 1720 if o <= 0: 1440 if o <= 0: 1721 conti 1441 continue 1722 dev['end'] = 1442 dev['end'] = tdev['end'] 1723 if 'src' not 1443 if 'src' not in dev or 'src' not in tdev: 1724 conti 1444 continue 1725 dev['src'] += 1445 dev['src'] += tdev['src'] 1726 del list[devn 1446 del list[devname] 1727 def usurpTouchingThread(self, name, d 1447 def usurpTouchingThread(self, name, dev): 1728 # the caller test has priorit 1448 # the caller test has priority of this thread, give it to him 1729 for phase in self.sortedPhase 1449 for phase in self.sortedPhases(): 1730 list = self.dmesg[pha 1450 list = self.dmesg[phase]['list'] 1731 if name in list: 1451 if name in list: 1732 tdev = list[n 1452 tdev = list[name] 1733 if tdev['star 1453 if tdev['start'] - dev['end'] < 0.1: 1734 dev[' 1454 dev['end'] = tdev['end'] 1735 if 's 1455 if 'src' not in dev: 1736 1456 dev['src'] = [] 1737 if 's 1457 if 'src' in tdev: 1738 1458 dev['src'] += tdev['src'] 1739 del l 1459 del list[name] 1740 break 1460 break 1741 def stitchTouchingThreads(self, testl 1461 def stitchTouchingThreads(self, testlist): 1742 # merge any threads between t 1462 # merge any threads between tests that touch 1743 for phase in self.sortedPhase 1463 for phase in self.sortedPhases(): 1744 list = self.dmesg[pha 1464 list = self.dmesg[phase]['list'] 1745 for devname in list: 1465 for devname in list: 1746 dev = list[de 1466 dev = list[devname] 1747 if 'htmlclass 1467 if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']: 1748 conti 1468 continue 1749 for data in t 1469 for data in testlist: 1750 data. 1470 data.usurpTouchingThread(devname, dev) 1751 def optimizeDevSrc(self): 1471 def optimizeDevSrc(self): 1752 # merge any src call loops to 1472 # merge any src call loops to reduce timeline size 1753 for phase in self.sortedPhase 1473 for phase in self.sortedPhases(): 1754 list = self.dmesg[pha 1474 list = self.dmesg[phase]['list'] 1755 for dev in list: 1475 for dev in list: 1756 if 'src' not 1476 if 'src' not in list[dev]: 1757 conti 1477 continue 1758 src = list[de 1478 src = list[dev]['src'] 1759 p = 0 1479 p = 0 1760 for e in sort 1480 for e in sorted(src, key=lambda event: event.time): 1761 if no 1481 if not p or not e.repeat(p): 1762 1482 p = e 1763 1483 continue 1764 # e i 1484 # e is another iteration of p, move it into p 1765 p.end 1485 p.end = e.end 1766 p.len 1486 p.length = p.end - p.time 1767 p.cou 1487 p.count += 1 1768 src.r 1488 src.remove(e) 1769 def trimTimeVal(self, t, t0, dT, left 1489 def trimTimeVal(self, t, t0, dT, left): 1770 if left: 1490 if left: 1771 if(t > t0): 1491 if(t > t0): 1772 if(t - dT < t 1492 if(t - dT < t0): 1773 retur 1493 return t0 1774 return t - dT 1494 return t - dT 1775 else: 1495 else: 1776 return t 1496 return t 1777 else: 1497 else: 1778 if(t < t0 + dT): 1498 if(t < t0 + dT): 1779 if(t > t0): 1499 if(t > t0): 1780 retur 1500 return t0 + dT 1781 return t + dT 1501 return t + dT 1782 else: 1502 else: 1783 return t 1503 return t 1784 def trimTime(self, t0, dT, left): 1504 def trimTime(self, t0, dT, left): 1785 self.tSuspended = self.trimTi 1505 self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left) 1786 self.tResumed = self.trimTime 1506 self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left) 1787 self.start = self.trimTimeVal 1507 self.start = self.trimTimeVal(self.start, t0, dT, left) 1788 self.tKernSus = self.trimTime 1508 self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left) 1789 self.tKernRes = self.trimTime 1509 self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left) 1790 self.end = self.trimTimeVal(s 1510 self.end = self.trimTimeVal(self.end, t0, dT, left) 1791 for phase in self.sortedPhase 1511 for phase in self.sortedPhases(): 1792 p = self.dmesg[phase] 1512 p = self.dmesg[phase] 1793 p['start'] = self.tri 1513 p['start'] = self.trimTimeVal(p['start'], t0, dT, left) 1794 p['end'] = self.trimT 1514 p['end'] = self.trimTimeVal(p['end'], t0, dT, left) 1795 list = p['list'] 1515 list = p['list'] 1796 for name in list: 1516 for name in list: 1797 d = list[name 1517 d = list[name] 1798 d['start'] = 1518 d['start'] = self.trimTimeVal(d['start'], t0, dT, left) 1799 d['end'] = se 1519 d['end'] = self.trimTimeVal(d['end'], t0, dT, left) 1800 d['length'] = 1520 d['length'] = d['end'] - d['start'] 1801 if('ftrace' i 1521 if('ftrace' in d): 1802 cg = 1522 cg = d['ftrace'] 1803 cg.st 1523 cg.start = self.trimTimeVal(cg.start, t0, dT, left) 1804 cg.en 1524 cg.end = self.trimTimeVal(cg.end, t0, dT, left) 1805 for l 1525 for line in cg.list: 1806 1526 line.time = self.trimTimeVal(line.time, t0, dT, left) 1807 if('src' in d 1527 if('src' in d): 1808 for e 1528 for e in d['src']: 1809 1529 e.time = self.trimTimeVal(e.time, t0, dT, left) 1810 << 1811 << 1812 if('cpuexec' << 1813 cpuex << 1814 for e << 1815 << 1816 << 1817 << 1818 << 1819 d['cp << 1820 for dir in ['suspend', 'resum 1530 for dir in ['suspend', 'resume']: 1821 list = [] 1531 list = [] 1822 for e in self.errorin 1532 for e in self.errorinfo[dir]: 1823 type, tm, idx 1533 type, tm, idx1, idx2 = e 1824 tm = self.tri 1534 tm = self.trimTimeVal(tm, t0, dT, left) 1825 list.append(( 1535 list.append((type, tm, idx1, idx2)) 1826 self.errorinfo[dir] = 1536 self.errorinfo[dir] = list 1827 def trimFreezeTime(self, tZero): 1537 def trimFreezeTime(self, tZero): 1828 # trim out any standby or fre 1538 # trim out any standby or freeze clock time 1829 lp = '' 1539 lp = '' 1830 for phase in self.sortedPhase 1540 for phase in self.sortedPhases(): 1831 if 'resume_machine' i 1541 if 'resume_machine' in phase and 'suspend_machine' in lp: 1832 tS, tR = self 1542 tS, tR = self.dmesg[lp]['end'], self.dmesg[phase]['start'] 1833 tL = tR - tS 1543 tL = tR - tS 1834 if tL <= 0: !! 1544 if tL > 0: 1835 conti !! 1545 left = True if tR > tZero else False 1836 left = True i !! 1546 self.trimTime(tS, tL, left) 1837 self.trimTime !! 1547 self.tLow.append('%.0f'%(tL*1000)) 1838 if 'waking' i << 1839 tCnt << 1840 if se << 1841 << 1842 else: << 1843 << 1844 text << 1845 else: << 1846 text << 1847 self.tLow.app << 1848 lp = phase 1548 lp = phase 1849 def getMemTime(self): << 1850 if not self.hwstart or not se << 1851 return << 1852 stime = (self.tSuspended - se << 1853 rtime = (self.end - self.tRes << 1854 hws = self.hwstart + timedelt << 1855 hwr = self.hwend - timedelta( << 1856 self.tLow.append('%.0f'%((hwr << 1857 def getTimeValues(self): 1549 def getTimeValues(self): 1858 s = (self.tSuspended - self.t !! 1550 sktime = (self.tSuspended - self.tKernSus) * 1000 1859 r = (self.tKernRes - self.tRe !! 1551 rktime = (self.tKernRes - self.tResumed) * 1000 1860 return (max(s, 0), max(r, 0)) !! 1552 return (sktime, rktime) 1861 def setPhase(self, phase, ktime, isbe 1553 def setPhase(self, phase, ktime, isbegin, order=-1): 1862 if(isbegin): 1554 if(isbegin): 1863 # phase start over cu 1555 # phase start over current phase 1864 if self.currphase: 1556 if self.currphase: 1865 if 'resume_ma 1557 if 'resume_machine' not in self.currphase: 1866 sysva 1558 sysvals.vprint('WARNING: phase %s failed to end' % self.currphase) 1867 self.dmesg[se 1559 self.dmesg[self.currphase]['end'] = ktime 1868 phases = self.dmesg.k 1560 phases = self.dmesg.keys() 1869 color = self.phasedef 1561 color = self.phasedef[phase]['color'] 1870 count = len(phases) i 1562 count = len(phases) if order < 0 else order 1871 # create unique name 1563 # create unique name for every new phase 1872 while phase in phases 1564 while phase in phases: 1873 phase += '*' 1565 phase += '*' 1874 self.dmesg[phase] = { 1566 self.dmesg[phase] = {'list': dict(), 'start': -1.0, 'end': -1.0, 1875 'row': 0, 'co 1567 'row': 0, 'color': color, 'order': count} 1876 self.dmesg[phase]['st 1568 self.dmesg[phase]['start'] = ktime 1877 self.currphase = phas 1569 self.currphase = phase 1878 else: 1570 else: 1879 # phase end without a 1571 # phase end without a start 1880 if phase not in self. 1572 if phase not in self.currphase: 1881 if self.currp 1573 if self.currphase: 1882 sysva 1574 sysvals.vprint('WARNING: %s ended instead of %s, ftrace corruption?' % (phase, self.currphase)) 1883 else: 1575 else: 1884 sysva 1576 sysvals.vprint('WARNING: %s ended without a start, ftrace corruption?' % phase) 1885 retur 1577 return phase 1886 phase = self.currphas 1578 phase = self.currphase 1887 self.dmesg[phase]['en 1579 self.dmesg[phase]['end'] = ktime 1888 self.currphase = '' 1580 self.currphase = '' 1889 return phase 1581 return phase 1890 def sortedDevices(self, phase): 1582 def sortedDevices(self, phase): 1891 list = self.dmesg[phase]['lis 1583 list = self.dmesg[phase]['list'] 1892 return sorted(list, key=lambd 1584 return sorted(list, key=lambda k:list[k]['start']) 1893 def fixupInitcalls(self, phase): 1585 def fixupInitcalls(self, phase): 1894 # if any calls never returned 1586 # if any calls never returned, clip them at system resume end 1895 phaselist = self.dmesg[phase] 1587 phaselist = self.dmesg[phase]['list'] 1896 for devname in phaselist: 1588 for devname in phaselist: 1897 dev = phaselist[devna 1589 dev = phaselist[devname] 1898 if(dev['end'] < 0): 1590 if(dev['end'] < 0): 1899 for p in self 1591 for p in self.sortedPhases(): 1900 if se 1592 if self.dmesg[p]['end'] > dev['start']: 1901 1593 dev['end'] = self.dmesg[p]['end'] 1902 1594 break 1903 sysvals.vprin 1595 sysvals.vprint('%s (%s): callback didnt return' % (devname, phase)) 1904 def deviceFilter(self, devicefilter): 1596 def deviceFilter(self, devicefilter): 1905 for phase in self.sortedPhase 1597 for phase in self.sortedPhases(): 1906 list = self.dmesg[pha 1598 list = self.dmesg[phase]['list'] 1907 rmlist = [] 1599 rmlist = [] 1908 for name in list: 1600 for name in list: 1909 keep = False 1601 keep = False 1910 for filter in 1602 for filter in devicefilter: 1911 if fi 1603 if filter in name or \ 1912 1604 ('drv' in list[name] and filter in list[name]['drv']): 1913 1605 keep = True 1914 if not keep: 1606 if not keep: 1915 rmlis 1607 rmlist.append(name) 1916 for name in rmlist: 1608 for name in rmlist: 1917 del list[name 1609 del list[name] 1918 def fixupInitcallsThatDidntReturn(sel 1610 def fixupInitcallsThatDidntReturn(self): 1919 # if any calls never returned 1611 # if any calls never returned, clip them at system resume end 1920 for phase in self.sortedPhase 1612 for phase in self.sortedPhases(): 1921 self.fixupInitcalls(p 1613 self.fixupInitcalls(phase) 1922 def phaseOverlap(self, phases): 1614 def phaseOverlap(self, phases): 1923 rmgroups = [] 1615 rmgroups = [] 1924 newgroup = [] 1616 newgroup = [] 1925 for group in self.devicegroup 1617 for group in self.devicegroups: 1926 for phase in phases: 1618 for phase in phases: 1927 if phase not 1619 if phase not in group: 1928 conti 1620 continue 1929 for p in grou 1621 for p in group: 1930 if p 1622 if p not in newgroup: 1931 1623 newgroup.append(p) 1932 if group not 1624 if group not in rmgroups: 1933 rmgro 1625 rmgroups.append(group) 1934 for group in rmgroups: 1626 for group in rmgroups: 1935 self.devicegroups.rem 1627 self.devicegroups.remove(group) 1936 self.devicegroups.append(newg 1628 self.devicegroups.append(newgroup) 1937 def newActionGlobal(self, name, start 1629 def newActionGlobal(self, name, start, end, pid=-1, color=''): 1938 # which phase is this device 1630 # which phase is this device callback or action in 1939 phases = self.sortedPhases() 1631 phases = self.sortedPhases() 1940 targetphase = 'none' 1632 targetphase = 'none' 1941 htmlclass = '' 1633 htmlclass = '' 1942 overlap = 0.0 1634 overlap = 0.0 1943 myphases = [] 1635 myphases = [] 1944 for phase in phases: 1636 for phase in phases: 1945 pstart = self.dmesg[p 1637 pstart = self.dmesg[phase]['start'] 1946 pend = self.dmesg[pha 1638 pend = self.dmesg[phase]['end'] 1947 # see if the action o 1639 # see if the action overlaps this phase 1948 o = max(0, min(end, p 1640 o = max(0, min(end, pend) - max(start, pstart)) 1949 if o > 0: 1641 if o > 0: 1950 myphases.appe 1642 myphases.append(phase) 1951 # set the target phas 1643 # set the target phase to the one that overlaps most 1952 if o > overlap: 1644 if o > overlap: 1953 if overlap > 1645 if overlap > 0 and phase == 'post_resume': 1954 conti 1646 continue 1955 targetphase = 1647 targetphase = phase 1956 overlap = o 1648 overlap = o 1957 # if no target phase was foun 1649 # if no target phase was found, pin it to the edge 1958 if targetphase == 'none': 1650 if targetphase == 'none': 1959 p0start = self.dmesg[ 1651 p0start = self.dmesg[phases[0]]['start'] 1960 if start <= p0start: 1652 if start <= p0start: 1961 targetphase = 1653 targetphase = phases[0] 1962 else: 1654 else: 1963 targetphase = 1655 targetphase = phases[-1] 1964 if pid == -2: 1656 if pid == -2: 1965 htmlclass = ' bg' 1657 htmlclass = ' bg' 1966 elif pid == -3: 1658 elif pid == -3: 1967 htmlclass = ' ps' 1659 htmlclass = ' ps' 1968 if len(myphases) > 1: 1660 if len(myphases) > 1: 1969 htmlclass = ' bg' 1661 htmlclass = ' bg' 1970 self.phaseOverlap(myp 1662 self.phaseOverlap(myphases) 1971 if targetphase in phases: 1663 if targetphase in phases: 1972 newname = self.newAct 1664 newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color) 1973 return (targetphase, 1665 return (targetphase, newname) 1974 return False 1666 return False 1975 def newAction(self, phase, name, pid, 1667 def newAction(self, phase, name, pid, parent, start, end, drv, htmlclass='', color=''): 1976 # new device callback for a s 1668 # new device callback for a specific phase 1977 self.html_device_id += 1 1669 self.html_device_id += 1 1978 devid = '%s%d' % (self.idstr, 1670 devid = '%s%d' % (self.idstr, self.html_device_id) 1979 list = self.dmesg[phase]['lis 1671 list = self.dmesg[phase]['list'] 1980 length = -1.0 1672 length = -1.0 1981 if(start >= 0 and end >= 0): 1673 if(start >= 0 and end >= 0): 1982 length = end - start 1674 length = end - start 1983 if pid == -2 or name not in s !! 1675 if pid == -2: 1984 i = 2 1676 i = 2 1985 origname = name 1677 origname = name 1986 while(name in list): 1678 while(name in list): 1987 name = '%s[%d 1679 name = '%s[%d]' % (origname, i) 1988 i += 1 1680 i += 1 1989 list[name] = {'name': name, ' 1681 list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid, 1990 'par': parent, 'lengt 1682 'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv } 1991 if htmlclass: 1683 if htmlclass: 1992 list[name]['htmlclass 1684 list[name]['htmlclass'] = htmlclass 1993 if color: 1685 if color: 1994 list[name]['color'] = 1686 list[name]['color'] = color 1995 return name 1687 return name 1996 def findDevice(self, phase, name): << 1997 list = self.dmesg[phase]['lis << 1998 mydev = '' << 1999 for devname in sorted(list): << 2000 if name == devname or << 2001 mydev = devna << 2002 if mydev: << 2003 return list[mydev] << 2004 return False << 2005 def deviceChildren(self, devname, pha 1688 def deviceChildren(self, devname, phase): 2006 devlist = [] 1689 devlist = [] 2007 list = self.dmesg[phase]['lis 1690 list = self.dmesg[phase]['list'] 2008 for child in list: 1691 for child in list: 2009 if(list[child]['par'] 1692 if(list[child]['par'] == devname): 2010 devlist.appen 1693 devlist.append(child) 2011 return devlist 1694 return devlist 2012 def maxDeviceNameSize(self, phase): 1695 def maxDeviceNameSize(self, phase): 2013 size = 0 1696 size = 0 2014 for name in self.dmesg[phase] 1697 for name in self.dmesg[phase]['list']: 2015 if len(name) > size: 1698 if len(name) > size: 2016 size = len(na 1699 size = len(name) 2017 return size 1700 return size 2018 def printDetails(self): 1701 def printDetails(self): 2019 sysvals.vprint('Timeline Deta 1702 sysvals.vprint('Timeline Details:') 2020 sysvals.vprint(' tes 1703 sysvals.vprint(' test start: %f' % self.start) 2021 sysvals.vprint('kernel suspen 1704 sysvals.vprint('kernel suspend start: %f' % self.tKernSus) 2022 tS = tR = False 1705 tS = tR = False 2023 for phase in self.sortedPhase 1706 for phase in self.sortedPhases(): 2024 devlist = self.dmesg[ 1707 devlist = self.dmesg[phase]['list'] 2025 dc, ps, pe = len(devl 1708 dc, ps, pe = len(devlist), self.dmesg[phase]['start'], self.dmesg[phase]['end'] 2026 if not tS and ps >= s 1709 if not tS and ps >= self.tSuspended: 2027 sysvals.vprin 1710 sysvals.vprint(' machine suspended: %f' % self.tSuspended) 2028 tS = True 1711 tS = True 2029 if not tR and ps >= s 1712 if not tR and ps >= self.tResumed: 2030 sysvals.vprin 1713 sysvals.vprint(' machine resumed: %f' % self.tResumed) 2031 tR = True 1714 tR = True 2032 sysvals.vprint('%20s: 1715 sysvals.vprint('%20s: %f - %f (%d devices)' % (phase, ps, pe, dc)) 2033 if sysvals.devdump: 1716 if sysvals.devdump: 2034 sysvals.vprin 1717 sysvals.vprint(''.join('-' for i in range(80))) 2035 maxname = '%d 1718 maxname = '%d' % self.maxDeviceNameSize(phase) 2036 fmt = '%3d) % 1719 fmt = '%3d) %'+maxname+'s - %f - %f' 2037 c = 1 1720 c = 1 2038 for name in s 1721 for name in sorted(devlist): 2039 s = d 1722 s = devlist[name]['start'] 2040 e = d 1723 e = devlist[name]['end'] 2041 sysva 1724 sysvals.vprint(fmt % (c, name, s, e)) 2042 c += 1725 c += 1 2043 sysvals.vprin 1726 sysvals.vprint(''.join('-' for i in range(80))) 2044 sysvals.vprint(' kernel res 1727 sysvals.vprint(' kernel resume end: %f' % self.tKernRes) 2045 sysvals.vprint(' t 1728 sysvals.vprint(' test end: %f' % self.end) 2046 def deviceChildrenAllPhases(self, dev 1729 def deviceChildrenAllPhases(self, devname): 2047 devlist = [] 1730 devlist = [] 2048 for phase in self.sortedPhase 1731 for phase in self.sortedPhases(): 2049 list = self.deviceChi 1732 list = self.deviceChildren(devname, phase) 2050 for dev in sorted(lis 1733 for dev in sorted(list): 2051 if dev not in 1734 if dev not in devlist: 2052 devli 1735 devlist.append(dev) 2053 return devlist 1736 return devlist 2054 def masterTopology(self, name, list, 1737 def masterTopology(self, name, list, depth): 2055 node = DeviceNode(name, depth 1738 node = DeviceNode(name, depth) 2056 for cname in list: 1739 for cname in list: 2057 # avoid recursions 1740 # avoid recursions 2058 if name == cname: 1741 if name == cname: 2059 continue 1742 continue 2060 clist = self.deviceCh 1743 clist = self.deviceChildrenAllPhases(cname) 2061 cnode = self.masterTo 1744 cnode = self.masterTopology(cname, clist, depth+1) 2062 node.children.append( 1745 node.children.append(cnode) 2063 return node 1746 return node 2064 def printTopology(self, node): 1747 def printTopology(self, node): 2065 html = '' 1748 html = '' 2066 if node.name: 1749 if node.name: 2067 info = '' 1750 info = '' 2068 drv = '' 1751 drv = '' 2069 for phase in self.sor 1752 for phase in self.sortedPhases(): 2070 list = self.d 1753 list = self.dmesg[phase]['list'] 2071 if node.name 1754 if node.name in list: 2072 s = l 1755 s = list[node.name]['start'] 2073 e = l 1756 e = list[node.name]['end'] 2074 if li 1757 if list[node.name]['drv']: 2075 1758 drv = ' {'+list[node.name]['drv']+'}' 2076 info 1759 info += ('<li>%s: %.3fms</li>' % (phase, (e-s)*1000)) 2077 html += '<li><b>'+nod 1760 html += '<li><b>'+node.name+drv+'</b>' 2078 if info: 1761 if info: 2079 html += '<ul> 1762 html += '<ul>'+info+'</ul>' 2080 html += '</li>' 1763 html += '</li>' 2081 if len(node.children) > 0: 1764 if len(node.children) > 0: 2082 html += '<ul>' 1765 html += '<ul>' 2083 for cnode in node.chi 1766 for cnode in node.children: 2084 html += self. 1767 html += self.printTopology(cnode) 2085 html += '</ul>' 1768 html += '</ul>' 2086 return html 1769 return html 2087 def rootDeviceList(self): 1770 def rootDeviceList(self): 2088 # list of devices graphed 1771 # list of devices graphed 2089 real = [] 1772 real = [] 2090 for phase in self.sortedPhase 1773 for phase in self.sortedPhases(): 2091 list = self.dmesg[pha 1774 list = self.dmesg[phase]['list'] 2092 for dev in sorted(lis 1775 for dev in sorted(list): 2093 if list[dev][ 1776 if list[dev]['pid'] >= 0 and dev not in real: 2094 real. 1777 real.append(dev) 2095 # list of top-most root devic 1778 # list of top-most root devices 2096 rootlist = [] 1779 rootlist = [] 2097 for phase in self.sortedPhase 1780 for phase in self.sortedPhases(): 2098 list = self.dmesg[pha 1781 list = self.dmesg[phase]['list'] 2099 for dev in sorted(lis 1782 for dev in sorted(list): 2100 pdev = list[d 1783 pdev = list[dev]['par'] 2101 pid = list[de 1784 pid = list[dev]['pid'] 2102 if(pid < 0 or !! 1785 if(pid < 0 or re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)): 2103 conti 1786 continue 2104 if pdev and p 1787 if pdev and pdev not in real and pdev not in rootlist: 2105 rootl 1788 rootlist.append(pdev) 2106 return rootlist 1789 return rootlist 2107 def deviceTopology(self): 1790 def deviceTopology(self): 2108 rootlist = self.rootDeviceLis 1791 rootlist = self.rootDeviceList() 2109 master = self.masterTopology( 1792 master = self.masterTopology('', rootlist, 0) 2110 return self.printTopology(mas 1793 return self.printTopology(master) 2111 def selectTimelineDevices(self, widfm 1794 def selectTimelineDevices(self, widfmt, tTotal, mindevlen): 2112 # only select devices that wi 1795 # only select devices that will actually show up in html 2113 self.tdevlist = dict() 1796 self.tdevlist = dict() 2114 for phase in self.dmesg: 1797 for phase in self.dmesg: 2115 devlist = [] 1798 devlist = [] 2116 list = self.dmesg[pha 1799 list = self.dmesg[phase]['list'] 2117 for dev in list: 1800 for dev in list: 2118 length = (lis 1801 length = (list[dev]['end'] - list[dev]['start']) * 1000 2119 width = widfm 1802 width = widfmt % (((list[dev]['end']-list[dev]['start'])*100)/tTotal) 2120 if length >= !! 1803 if width != '0.000000' and length >= mindevlen: 2121 devli 1804 devlist.append(dev) 2122 self.tdevlist[phase] 1805 self.tdevlist[phase] = devlist 2123 def addHorizontalDivider(self, devnam 1806 def addHorizontalDivider(self, devname, devend): 2124 phase = 'suspend_prepare' 1807 phase = 'suspend_prepare' 2125 self.newAction(phase, devname 1808 self.newAction(phase, devname, -2, '', \ 2126 self.start, devend, ' 1809 self.start, devend, '', ' sec', '') 2127 if phase not in self.tdevlist 1810 if phase not in self.tdevlist: 2128 self.tdevlist[phase] 1811 self.tdevlist[phase] = [] 2129 self.tdevlist[phase].append(d 1812 self.tdevlist[phase].append(devname) 2130 d = DevItem(0, phase, self.dm 1813 d = DevItem(0, phase, self.dmesg[phase]['list'][devname]) 2131 return d 1814 return d 2132 def addProcessUsageEvent(self, name, 1815 def addProcessUsageEvent(self, name, times): 2133 # get the start and end times 1816 # get the start and end times for this process 2134 cpuexec = dict() !! 1817 maxC = 0 2135 tlast = start = end = -1 !! 1818 tlast = 0 >> 1819 start = -1 >> 1820 end = -1 2136 for t in sorted(times): 1821 for t in sorted(times): 2137 if tlast < 0: !! 1822 if tlast == 0: 2138 tlast = t 1823 tlast = t 2139 continue 1824 continue 2140 if name in self.pstl[ !! 1825 if name in self.pstl[t]: 2141 if start < 0: !! 1826 if start == -1 or tlast < start: 2142 start 1827 start = tlast 2143 end, key = t, !! 1828 if end == -1 or t > end: 2144 maxj = (t - t !! 1829 end = t 2145 cpuexec[key] << 2146 tlast = t 1830 tlast = t 2147 if start < 0 or end < 0: !! 1831 if start == -1 or end == -1: 2148 return !! 1832 return 0 2149 # add a new action for this p 1833 # add a new action for this process and get the object 2150 out = self.newActionGlobal(na 1834 out = self.newActionGlobal(name, start, end, -3) 2151 if out: !! 1835 if not out: 2152 phase, devname = out !! 1836 return 0 2153 dev = self.dmesg[phas !! 1837 phase, devname = out 2154 dev['cpuexec'] = cpue !! 1838 dev = self.dmesg[phase]['list'][devname] >> 1839 # get the cpu exec data >> 1840 tlast = 0 >> 1841 clast = 0 >> 1842 cpuexec = dict() >> 1843 for t in sorted(times): >> 1844 if tlast == 0 or t <= start or t > end: >> 1845 tlast = t >> 1846 continue >> 1847 list = self.pstl[t] >> 1848 c = 0 >> 1849 if name in list: >> 1850 c = list[name] >> 1851 if c > maxC: >> 1852 maxC = c >> 1853 if c != clast: >> 1854 key = (tlast, t) >> 1855 cpuexec[key] = c >> 1856 tlast = t >> 1857 clast = c >> 1858 dev['cpuexec'] = cpuexec >> 1859 return maxC 2155 def createProcessUsageEvents(self): 1860 def createProcessUsageEvents(self): 2156 # get an array of process nam !! 1861 # get an array of process names 2157 proclist = {'sus': dict(), 'r !! 1862 proclist = [] 2158 tdata = {'sus': [], 'res': [] !! 1863 for t in sorted(self.pstl): >> 1864 pslist = self.pstl[t] >> 1865 for ps in sorted(pslist): >> 1866 if ps not in proclist: >> 1867 proclist.append(ps) >> 1868 # get a list of data points for suspend and resume >> 1869 tsus = [] >> 1870 tres = [] 2159 for t in sorted(self.pstl): 1871 for t in sorted(self.pstl): 2160 dir = 'sus' if t < se !! 1872 if t < self.tSuspended: 2161 for ps in sorted(self !! 1873 tsus.append(t) 2162 if ps not in !! 1874 else: 2163 procl !! 1875 tres.append(t) 2164 tdata[dir].append(t) << 2165 # process the events for susp 1876 # process the events for suspend and resume 2166 if len(proclist['sus']) > 0 o !! 1877 if len(proclist) > 0: 2167 sysvals.vprint('Proce 1878 sysvals.vprint('Process Execution:') 2168 for dir in ['sus', 'res']: !! 1879 for ps in proclist: 2169 for ps in sorted(proc !! 1880 c = self.addProcessUsageEvent(ps, tsus) 2170 self.addProce !! 1881 if c > 0: 2171 def handleEndMarker(self, time, msg=' !! 1882 sysvals.vprint('%25s (sus): %d' % (ps, c)) >> 1883 c = self.addProcessUsageEvent(ps, tres) >> 1884 if c > 0: >> 1885 sysvals.vprint('%25s (res): %d' % (ps, c)) >> 1886 def handleEndMarker(self, time): 2172 dm = self.dmesg 1887 dm = self.dmesg 2173 self.setEnd(time, msg) !! 1888 self.setEnd(time) 2174 self.initDevicegroups() 1889 self.initDevicegroups() 2175 # give suspend_prepare an end 1890 # give suspend_prepare an end if needed 2176 if 'suspend_prepare' in dm an 1891 if 'suspend_prepare' in dm and dm['suspend_prepare']['end'] < 0: 2177 dm['suspend_prepare'] 1892 dm['suspend_prepare']['end'] = time 2178 # assume resume machine ends 1893 # assume resume machine ends at next phase start 2179 if 'resume_machine' in dm and 1894 if 'resume_machine' in dm and dm['resume_machine']['end'] < 0: 2180 np = self.nextPhase(' 1895 np = self.nextPhase('resume_machine', 1) 2181 if np: 1896 if np: 2182 dm['resume_ma 1897 dm['resume_machine']['end'] = dm[np]['start'] 2183 # if kernel resume end not fo 1898 # if kernel resume end not found, assume its the end marker 2184 if self.tKernRes == 0.0: 1899 if self.tKernRes == 0.0: 2185 self.tKernRes = time 1900 self.tKernRes = time 2186 # if kernel suspend start not 1901 # if kernel suspend start not found, assume its the end marker 2187 if self.tKernSus == 0.0: 1902 if self.tKernSus == 0.0: 2188 self.tKernSus = time 1903 self.tKernSus = time 2189 # set resume complete to end 1904 # set resume complete to end at end marker 2190 if 'resume_complete' in dm: 1905 if 'resume_complete' in dm: 2191 dm['resume_complete'] 1906 dm['resume_complete']['end'] = time 2192 def initcall_debug_call(self, line, q << 2193 m = re.match(r'.*(\[ *)(?P<t> << 2194 r'PM: *calling .* @ ( << 2195 if not m: << 2196 m = re.match(r'.*(\[ << 2197 r'calling .* << 2198 if not m: << 2199 m = re.match(r'.*(\[ << 2200 r'(?P<f>.*)\+ << 2201 if m: << 2202 return True if quick << 2203 return False if quick else (' << 2204 def initcall_debug_return(self, line, << 2205 m = re.match(r'.*(\[ *)(?P<t> << 2206 r'.* returned (?P<r>[ << 2207 if not m: << 2208 m = re.match(r'.*(\[ << 2209 r'.* returned << 2210 if not m: << 2211 m = re.match(r'.*(\[ << 2212 r'(?P<f>.*)\+ << 2213 if m: << 2214 return True if quick << 2215 return False if quick else (' << 2216 def debugPrint(self): 1907 def debugPrint(self): 2217 for p in self.sortedPhases(): 1908 for p in self.sortedPhases(): 2218 list = self.dmesg[p][ 1909 list = self.dmesg[p]['list'] 2219 for devname in sorted 1910 for devname in sorted(list): 2220 dev = list[de 1911 dev = list[devname] 2221 if 'ftrace' i 1912 if 'ftrace' in dev: 2222 dev[' 1913 dev['ftrace'].debugPrint(' [%s]' % devname) 2223 1914 2224 # Class: DevFunction 1915 # Class: DevFunction 2225 # Description: 1916 # Description: 2226 # A container for kprobe function data 1917 # A container for kprobe function data we want in the dev timeline 2227 class DevFunction: 1918 class DevFunction: 2228 def __init__(self, name, args, caller 1919 def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color): 2229 self.row = 0 1920 self.row = 0 2230 self.count = 1 1921 self.count = 1 2231 self.name = name 1922 self.name = name 2232 self.args = args 1923 self.args = args 2233 self.caller = caller 1924 self.caller = caller 2234 self.ret = ret 1925 self.ret = ret 2235 self.time = start 1926 self.time = start 2236 self.length = end - start 1927 self.length = end - start 2237 self.end = end 1928 self.end = end 2238 self.ubiquitous = u 1929 self.ubiquitous = u 2239 self.proc = proc 1930 self.proc = proc 2240 self.pid = pid 1931 self.pid = pid 2241 self.color = color 1932 self.color = color 2242 def title(self): 1933 def title(self): 2243 cnt = '' 1934 cnt = '' 2244 if self.count > 1: 1935 if self.count > 1: 2245 cnt = '(x%d)' % self. 1936 cnt = '(x%d)' % self.count 2246 l = '%0.3fms' % (self.length 1937 l = '%0.3fms' % (self.length * 1000) 2247 if self.ubiquitous: 1938 if self.ubiquitous: 2248 title = '%s(%s)%s <- 1939 title = '%s(%s)%s <- %s, %s(%s)' % \ 2249 (self.name, s 1940 (self.name, self.args, cnt, self.caller, self.ret, l) 2250 else: 1941 else: 2251 title = '%s(%s) %s%s( 1942 title = '%s(%s) %s%s(%s)' % (self.name, self.args, self.ret, cnt, l) 2252 return title.replace('"', '') 1943 return title.replace('"', '') 2253 def text(self): 1944 def text(self): 2254 if self.count > 1: 1945 if self.count > 1: 2255 text = '%s(x%d)' % (s 1946 text = '%s(x%d)' % (self.name, self.count) 2256 else: 1947 else: 2257 text = self.name 1948 text = self.name 2258 return text 1949 return text 2259 def repeat(self, tgt): 1950 def repeat(self, tgt): 2260 # is the tgt call just a repe 1951 # is the tgt call just a repeat of this call (e.g. are we in a loop) 2261 dt = self.time - tgt.end 1952 dt = self.time - tgt.end 2262 # only combine calls if -all- 1953 # only combine calls if -all- attributes are identical 2263 if tgt.caller == self.caller 1954 if tgt.caller == self.caller and \ 2264 tgt.name == self.name 1955 tgt.name == self.name and tgt.args == self.args and \ 2265 tgt.proc == self.proc 1956 tgt.proc == self.proc and tgt.pid == self.pid and \ 2266 tgt.ret == self.ret a 1957 tgt.ret == self.ret and dt >= 0 and \ 2267 dt <= sysvals.callloo 1958 dt <= sysvals.callloopmaxgap and \ 2268 self.length < sysvals 1959 self.length < sysvals.callloopmaxlen: 2269 return True 1960 return True 2270 return False 1961 return False 2271 1962 2272 # Class: FTraceLine 1963 # Class: FTraceLine 2273 # Description: 1964 # Description: 2274 # A container for a single line of ftr 1965 # A container for a single line of ftrace data. There are six basic types: 2275 # callgraph line: 1966 # callgraph line: 2276 # call: " dpm_run_ca 1967 # call: " dpm_run_callback() {" 2277 # return: " }" 1968 # return: " }" 2278 # leaf: " dpm_run_cal 1969 # leaf: " dpm_run_callback();" 2279 # trace event: 1970 # trace event: 2280 # tracing_mark_write: 1971 # tracing_mark_write: SUSPEND START or RESUME COMPLETE 2281 # suspend_resume: phas 1972 # suspend_resume: phase or custom exec block data 2282 # device_pm_callback: 1973 # device_pm_callback: device callback info 2283 class FTraceLine: 1974 class FTraceLine: 2284 def __init__(self, t, m='', d=''): 1975 def __init__(self, t, m='', d=''): 2285 self.length = 0.0 1976 self.length = 0.0 2286 self.fcall = False 1977 self.fcall = False 2287 self.freturn = False 1978 self.freturn = False 2288 self.fevent = False 1979 self.fevent = False 2289 self.fkprobe = False 1980 self.fkprobe = False 2290 self.depth = 0 1981 self.depth = 0 2291 self.name = '' 1982 self.name = '' 2292 self.type = '' 1983 self.type = '' 2293 self.time = float(t) 1984 self.time = float(t) 2294 if not m and not d: 1985 if not m and not d: 2295 return 1986 return 2296 # is this a trace event 1987 # is this a trace event 2297 if(d == 'traceevent' or re.ma !! 1988 if(d == 'traceevent' or re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m)): 2298 if(d == 'traceevent') 1989 if(d == 'traceevent'): 2299 # nop format 1990 # nop format trace event 2300 msg = m 1991 msg = m 2301 else: 1992 else: 2302 # function_gr 1993 # function_graph format trace event 2303 em = re.match !! 1994 em = re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m) 2304 msg = em.grou 1995 msg = em.group('msg') 2305 1996 2306 emm = re.match(r'^(?P !! 1997 emm = re.match('^(?P<call>.*?): (?P<msg>.*)', msg) 2307 if(emm): 1998 if(emm): 2308 self.name = e 1999 self.name = emm.group('msg') 2309 self.type = e 2000 self.type = emm.group('call') 2310 else: 2001 else: 2311 self.name = m 2002 self.name = msg 2312 km = re.match(r'^(?P< !! 2003 km = re.match('^(?P<n>.*)_cal$', self.type) 2313 if km: 2004 if km: 2314 self.fcall = 2005 self.fcall = True 2315 self.fkprobe 2006 self.fkprobe = True 2316 self.type = k 2007 self.type = km.group('n') 2317 return 2008 return 2318 km = re.match(r'^(?P< !! 2009 km = re.match('^(?P<n>.*)_ret$', self.type) 2319 if km: 2010 if km: 2320 self.freturn 2011 self.freturn = True 2321 self.fkprobe 2012 self.fkprobe = True 2322 self.type = k 2013 self.type = km.group('n') 2323 return 2014 return 2324 self.fevent = True 2015 self.fevent = True 2325 return 2016 return 2326 # convert the duration to sec 2017 # convert the duration to seconds 2327 if(d): 2018 if(d): 2328 self.length = float(d 2019 self.length = float(d)/1000000 2329 # the indentation determines 2020 # the indentation determines the depth 2330 match = re.match(r'^(?P<d> *) !! 2021 match = re.match('^(?P<d> *)(?P<o>.*)$', m) 2331 if(not match): 2022 if(not match): 2332 return 2023 return 2333 self.depth = self.getDepth(ma 2024 self.depth = self.getDepth(match.group('d')) 2334 m = match.group('o') 2025 m = match.group('o') 2335 # function return 2026 # function return 2336 if(m[0] == '}'): 2027 if(m[0] == '}'): 2337 self.freturn = True 2028 self.freturn = True 2338 if(len(m) > 1): 2029 if(len(m) > 1): 2339 # includes co 2030 # includes comment with function name 2340 match = re.ma !! 2031 match = re.match('^} *\/\* *(?P<n>.*) *\*\/$', m) 2341 if(match): 2032 if(match): 2342 self. 2033 self.name = match.group('n').strip() 2343 # function call 2034 # function call 2344 else: 2035 else: 2345 self.fcall = True 2036 self.fcall = True 2346 # function call with 2037 # function call with children 2347 if(m[-1] == '{'): 2038 if(m[-1] == '{'): 2348 match = re.ma !! 2039 match = re.match('^(?P<n>.*) *\(.*', m) 2349 if(match): 2040 if(match): 2350 self. 2041 self.name = match.group('n').strip() 2351 # function call with 2042 # function call with no children (leaf) 2352 elif(m[-1] == ';'): 2043 elif(m[-1] == ';'): 2353 self.freturn 2044 self.freturn = True 2354 match = re.ma !! 2045 match = re.match('^(?P<n>.*) *\(.*', m) 2355 if(match): 2046 if(match): 2356 self. 2047 self.name = match.group('n').strip() 2357 # something else (pos 2048 # something else (possibly a trace marker) 2358 else: 2049 else: 2359 self.name = m 2050 self.name = m 2360 def isCall(self): 2051 def isCall(self): 2361 return self.fcall and not sel 2052 return self.fcall and not self.freturn 2362 def isReturn(self): 2053 def isReturn(self): 2363 return self.freturn and not s 2054 return self.freturn and not self.fcall 2364 def isLeaf(self): 2055 def isLeaf(self): 2365 return self.fcall and self.fr 2056 return self.fcall and self.freturn 2366 def getDepth(self, str): 2057 def getDepth(self, str): 2367 return len(str)/2 2058 return len(str)/2 2368 def debugPrint(self, info=''): 2059 def debugPrint(self, info=''): 2369 if self.isLeaf(): 2060 if self.isLeaf(): 2370 pprint(' -- %12.6f (d 2061 pprint(' -- %12.6f (depth=%02d): %s(); (%.3f us) %s' % (self.time, \ 2371 self.depth, s 2062 self.depth, self.name, self.length*1000000, info)) 2372 elif self.freturn: 2063 elif self.freturn: 2373 pprint(' -- %12.6f (d 2064 pprint(' -- %12.6f (depth=%02d): %s} (%.3f us) %s' % (self.time, \ 2374 self.depth, s 2065 self.depth, self.name, self.length*1000000, info)) 2375 else: 2066 else: 2376 pprint(' -- %12.6f (d 2067 pprint(' -- %12.6f (depth=%02d): %s() { (%.3f us) %s' % (self.time, \ 2377 self.depth, s 2068 self.depth, self.name, self.length*1000000, info)) 2378 def startMarker(self): 2069 def startMarker(self): 2379 # Is this the starting line o 2070 # Is this the starting line of a suspend? 2380 if not self.fevent: 2071 if not self.fevent: 2381 return False 2072 return False 2382 if sysvals.usetracemarkers: 2073 if sysvals.usetracemarkers: 2383 if(self.name.startswi !! 2074 if(self.name == 'SUSPEND START'): 2384 return True 2075 return True 2385 return False 2076 return False 2386 else: 2077 else: 2387 if(self.type == 'susp 2078 if(self.type == 'suspend_resume' and 2388 re.match(r'su !! 2079 re.match('suspend_enter\[.*\] begin', self.name)): 2389 return True 2080 return True 2390 return False 2081 return False 2391 def endMarker(self): 2082 def endMarker(self): 2392 # Is this the ending line of 2083 # Is this the ending line of a resume? 2393 if not self.fevent: 2084 if not self.fevent: 2394 return False 2085 return False 2395 if sysvals.usetracemarkers: 2086 if sysvals.usetracemarkers: 2396 if(self.name.startswi !! 2087 if(self.name == 'RESUME COMPLETE'): 2397 return True 2088 return True 2398 return False 2089 return False 2399 else: 2090 else: 2400 if(self.type == 'susp 2091 if(self.type == 'suspend_resume' and 2401 re.match(r'th !! 2092 re.match('thaw_processes\[.*\] end', self.name)): 2402 return True 2093 return True 2403 return False 2094 return False 2404 2095 2405 # Class: FTraceCallGraph 2096 # Class: FTraceCallGraph 2406 # Description: 2097 # Description: 2407 # A container for the ftrace callgraph 2098 # A container for the ftrace callgraph of a single recursive function. 2408 # This can be a dpm_run_callback, dpm_ 2099 # This can be a dpm_run_callback, dpm_prepare, or dpm_complete callgraph 2409 # Each instance is tied to a single de 2100 # Each instance is tied to a single device in a single phase, and is 2410 # comprised of an ordered list of FTra 2101 # comprised of an ordered list of FTraceLine objects 2411 class FTraceCallGraph: 2102 class FTraceCallGraph: 2412 vfname = 'missing_function_name' 2103 vfname = 'missing_function_name' 2413 def __init__(self, pid, sv): 2104 def __init__(self, pid, sv): 2414 self.id = '' 2105 self.id = '' 2415 self.invalid = False 2106 self.invalid = False 2416 self.name = '' 2107 self.name = '' 2417 self.partial = False 2108 self.partial = False 2418 self.ignore = False 2109 self.ignore = False 2419 self.start = -1.0 2110 self.start = -1.0 2420 self.end = -1.0 2111 self.end = -1.0 2421 self.list = [] 2112 self.list = [] 2422 self.depth = 0 2113 self.depth = 0 2423 self.pid = pid 2114 self.pid = pid 2424 self.sv = sv 2115 self.sv = sv 2425 def addLine(self, line): 2116 def addLine(self, line): 2426 # if this is already invalid, 2117 # if this is already invalid, just leave 2427 if(self.invalid): 2118 if(self.invalid): 2428 if(line.depth == 0 an 2119 if(line.depth == 0 and line.freturn): 2429 return 1 2120 return 1 2430 return 0 2121 return 0 2431 # invalidate on bad depth 2122 # invalidate on bad depth 2432 if(self.depth < 0): 2123 if(self.depth < 0): 2433 self.invalidate(line) 2124 self.invalidate(line) 2434 return 0 2125 return 0 2435 # ignore data til we return t 2126 # ignore data til we return to the current depth 2436 if self.ignore: 2127 if self.ignore: 2437 if line.depth > self. 2128 if line.depth > self.depth: 2438 return 0 2129 return 0 2439 else: 2130 else: 2440 self.list[-1] 2131 self.list[-1].freturn = True 2441 self.list[-1] 2132 self.list[-1].length = line.time - self.list[-1].time 2442 self.ignore = 2133 self.ignore = False 2443 # if this is 2134 # if this is a return at self.depth, no more work is needed 2444 if line.depth 2135 if line.depth == self.depth and line.isReturn(): 2445 if li 2136 if line.depth == 0: 2446 2137 self.end = line.time 2447 2138 return 1 2448 retur 2139 return 0 2449 # compare current depth with 2140 # compare current depth with this lines pre-call depth 2450 prelinedep = line.depth 2141 prelinedep = line.depth 2451 if line.isReturn(): 2142 if line.isReturn(): 2452 prelinedep += 1 2143 prelinedep += 1 2453 last = 0 2144 last = 0 2454 lasttime = line.time 2145 lasttime = line.time 2455 if len(self.list) > 0: 2146 if len(self.list) > 0: 2456 last = self.list[-1] 2147 last = self.list[-1] 2457 lasttime = last.time 2148 lasttime = last.time 2458 if last.isLeaf(): 2149 if last.isLeaf(): 2459 lasttime += l 2150 lasttime += last.length 2460 # handle low misalignments by 2151 # handle low misalignments by inserting returns 2461 mismatch = prelinedep - self. 2152 mismatch = prelinedep - self.depth 2462 warning = self.sv.verbose and 2153 warning = self.sv.verbose and abs(mismatch) > 1 2463 info = [] 2154 info = [] 2464 if mismatch < 0: 2155 if mismatch < 0: 2465 idx = 0 2156 idx = 0 2466 # add return calls to 2157 # add return calls to get the depth down 2467 while prelinedep < se 2158 while prelinedep < self.depth: 2468 self.depth -= 2159 self.depth -= 1 2469 if idx == 0 a 2160 if idx == 0 and last and last.isCall(): 2470 # spe 2161 # special case, turn last call into a leaf 2471 last. 2162 last.depth = self.depth 2472 last. 2163 last.freturn = True 2473 last. 2164 last.length = line.time - last.time 2474 if wa 2165 if warning: 2475 2166 info.append(('[make leaf]', last)) 2476 else: 2167 else: 2477 vline 2168 vline = FTraceLine(lasttime) 2478 vline 2169 vline.depth = self.depth 2479 vline 2170 vline.name = self.vfname 2480 vline 2171 vline.freturn = True 2481 self. 2172 self.list.append(vline) 2482 if wa 2173 if warning: 2483 2174 if idx == 0: 2484 2175 info.append(('', last)) 2485 2176 info.append(('[add return]', vline)) 2486 idx += 1 2177 idx += 1 2487 if warning: 2178 if warning: 2488 info.append(( 2179 info.append(('', line)) 2489 # handle high misalignments b 2180 # handle high misalignments by inserting calls 2490 elif mismatch > 0: 2181 elif mismatch > 0: 2491 idx = 0 2182 idx = 0 2492 if warning: 2183 if warning: 2493 info.append(( 2184 info.append(('', last)) 2494 # add calls to get th 2185 # add calls to get the depth up 2495 while prelinedep > se 2186 while prelinedep > self.depth: 2496 if idx == 0 a 2187 if idx == 0 and line.isReturn(): 2497 # spe 2188 # special case, turn this return into a leaf 2498 line. 2189 line.fcall = True 2499 preli 2190 prelinedep -= 1 2500 if wa 2191 if warning: 2501 2192 info.append(('[make leaf]', line)) 2502 else: 2193 else: 2503 vline 2194 vline = FTraceLine(lasttime) 2504 vline 2195 vline.depth = self.depth 2505 vline 2196 vline.name = self.vfname 2506 vline 2197 vline.fcall = True 2507 self. 2198 self.list.append(vline) 2508 self. 2199 self.depth += 1 2509 if no 2200 if not last: 2510 2201 self.start = vline.time 2511 if wa 2202 if warning: 2512 2203 info.append(('[add call]', vline)) 2513 idx += 1 2204 idx += 1 2514 if warning and ('[mak 2205 if warning and ('[make leaf]', line) not in info: 2515 info.append(( 2206 info.append(('', line)) 2516 if warning: 2207 if warning: 2517 pprint('WARNING: ftra 2208 pprint('WARNING: ftrace data missing, corrections made:') 2518 for i in info: 2209 for i in info: 2519 t, obj = i 2210 t, obj = i 2520 if obj: 2211 if obj: 2521 obj.d 2212 obj.debugPrint(t) 2522 # process the call and set th 2213 # process the call and set the new depth 2523 skipadd = False 2214 skipadd = False 2524 md = self.sv.max_graph_depth 2215 md = self.sv.max_graph_depth 2525 if line.isCall(): 2216 if line.isCall(): 2526 # ignore blacklisted/ 2217 # ignore blacklisted/overdepth funcs 2527 if (md and self.depth 2218 if (md and self.depth >= md - 1) or (line.name in self.sv.cgblacklist): 2528 self.ignore = 2219 self.ignore = True 2529 else: 2220 else: 2530 self.depth += 2221 self.depth += 1 2531 elif line.isReturn(): 2222 elif line.isReturn(): 2532 self.depth -= 1 2223 self.depth -= 1 2533 # remove blacklisted/ 2224 # remove blacklisted/overdepth/empty funcs that slipped through 2534 if (last and last.isC 2225 if (last and last.isCall() and last.depth == line.depth) or \ 2535 (md and last 2226 (md and last and last.depth >= md) or \ 2536 (line.name in 2227 (line.name in self.sv.cgblacklist): 2537 while len(sel 2228 while len(self.list) > 0 and self.list[-1].depth > line.depth: 2538 self. 2229 self.list.pop(-1) 2539 if len(self.l 2230 if len(self.list) == 0: 2540 self. 2231 self.invalid = True 2541 retur 2232 return 1 2542 self.list[-1] 2233 self.list[-1].freturn = True 2543 self.list[-1] 2234 self.list[-1].length = line.time - self.list[-1].time 2544 self.list[-1] 2235 self.list[-1].name = line.name 2545 skipadd = Tru 2236 skipadd = True 2546 if len(self.list) < 1: 2237 if len(self.list) < 1: 2547 self.start = line.tim 2238 self.start = line.time 2548 # check for a mismatch that r 2239 # check for a mismatch that returned all the way to callgraph end 2549 res = 1 2240 res = 1 2550 if mismatch < 0 and self.list 2241 if mismatch < 0 and self.list[-1].depth == 0 and self.list[-1].freturn: 2551 line = self.list[-1] 2242 line = self.list[-1] 2552 skipadd = True 2243 skipadd = True 2553 res = -1 2244 res = -1 2554 if not skipadd: 2245 if not skipadd: 2555 self.list.append(line 2246 self.list.append(line) 2556 if(line.depth == 0 and line.f 2247 if(line.depth == 0 and line.freturn): 2557 if(self.start < 0): 2248 if(self.start < 0): 2558 self.start = 2249 self.start = line.time 2559 self.end = line.time 2250 self.end = line.time 2560 if line.fcall: 2251 if line.fcall: 2561 self.end += l 2252 self.end += line.length 2562 if self.list[0].name 2253 if self.list[0].name == self.vfname: 2563 self.invalid 2254 self.invalid = True 2564 if res == -1: 2255 if res == -1: 2565 self.partial 2256 self.partial = True 2566 return res 2257 return res 2567 return 0 2258 return 0 2568 def invalidate(self, line): 2259 def invalidate(self, line): 2569 if(len(self.list) > 0): 2260 if(len(self.list) > 0): 2570 first = self.list[0] 2261 first = self.list[0] 2571 self.list = [] 2262 self.list = [] 2572 self.list.append(firs 2263 self.list.append(first) 2573 self.invalid = True 2264 self.invalid = True 2574 id = 'task %s' % (self.pid) 2265 id = 'task %s' % (self.pid) 2575 window = '(%f - %f)' % (self. 2266 window = '(%f - %f)' % (self.start, line.time) 2576 if(self.depth < 0): 2267 if(self.depth < 0): 2577 pprint('Data misalign 2268 pprint('Data misalignment for '+id+\ 2578 ' (buffer ove 2269 ' (buffer overflow), ignoring this callback') 2579 else: 2270 else: 2580 pprint('Too much data 2271 pprint('Too much data for '+id+\ 2581 ' '+window+', 2272 ' '+window+', ignoring this callback') 2582 def slice(self, dev): 2273 def slice(self, dev): 2583 minicg = FTraceCallGraph(dev[ 2274 minicg = FTraceCallGraph(dev['pid'], self.sv) 2584 minicg.name = self.name 2275 minicg.name = self.name 2585 mydepth = -1 2276 mydepth = -1 2586 good = False 2277 good = False 2587 for l in self.list: 2278 for l in self.list: 2588 if(l.time < dev['star 2279 if(l.time < dev['start'] or l.time > dev['end']): 2589 continue 2280 continue 2590 if mydepth < 0: 2281 if mydepth < 0: 2591 if l.name == 2282 if l.name == 'mutex_lock' and l.freturn: 2592 mydep 2283 mydepth = l.depth 2593 continue 2284 continue 2594 elif l.depth == mydep 2285 elif l.depth == mydepth and l.name == 'mutex_unlock' and l.fcall: 2595 good = True 2286 good = True 2596 break 2287 break 2597 l.depth -= mydepth 2288 l.depth -= mydepth 2598 minicg.addLine(l) 2289 minicg.addLine(l) 2599 if not good or len(minicg.lis 2290 if not good or len(minicg.list) < 1: 2600 return 0 2291 return 0 2601 return minicg 2292 return minicg 2602 def repair(self, enddepth): 2293 def repair(self, enddepth): 2603 # bring the depth back to 0 w 2294 # bring the depth back to 0 with additional returns 2604 fixed = False 2295 fixed = False 2605 last = self.list[-1] 2296 last = self.list[-1] 2606 for i in reversed(range(endde 2297 for i in reversed(range(enddepth)): 2607 t = FTraceLine(last.t 2298 t = FTraceLine(last.time) 2608 t.depth = i 2299 t.depth = i 2609 t.freturn = True 2300 t.freturn = True 2610 fixed = self.addLine( 2301 fixed = self.addLine(t) 2611 if fixed != 0: 2302 if fixed != 0: 2612 self.end = la 2303 self.end = last.time 2613 return True 2304 return True 2614 return False 2305 return False 2615 def postProcess(self): 2306 def postProcess(self): 2616 if len(self.list) > 0: 2307 if len(self.list) > 0: 2617 self.name = self.list 2308 self.name = self.list[0].name 2618 stack = dict() 2309 stack = dict() 2619 cnt = 0 2310 cnt = 0 2620 last = 0 2311 last = 0 2621 for l in self.list: 2312 for l in self.list: 2622 # ftrace bug: reporte 2313 # ftrace bug: reported duration is not reliable 2623 # check each leaf and 2314 # check each leaf and clip it at max possible length 2624 if last and last.isLe 2315 if last and last.isLeaf(): 2625 if last.lengt 2316 if last.length > l.time - last.time: 2626 last. 2317 last.length = l.time - last.time 2627 if l.isCall(): 2318 if l.isCall(): 2628 stack[l.depth 2319 stack[l.depth] = l 2629 cnt += 1 2320 cnt += 1 2630 elif l.isReturn(): 2321 elif l.isReturn(): 2631 if(l.depth no 2322 if(l.depth not in stack): 2632 if se 2323 if self.sv.verbose: 2633 2324 pprint('Post Process Error: Depth missing') 2634 2325 l.debugPrint() 2635 retur 2326 return False 2636 # calculate c 2327 # calculate call length from call/return lines 2637 cl = stack[l. 2328 cl = stack[l.depth] 2638 cl.length = l 2329 cl.length = l.time - cl.time 2639 if cl.name == 2330 if cl.name == self.vfname: 2640 cl.na 2331 cl.name = l.name 2641 stack.pop(l.d 2332 stack.pop(l.depth) 2642 l.length = 0 2333 l.length = 0 2643 cnt -= 1 2334 cnt -= 1 2644 last = l 2335 last = l 2645 if(cnt == 0): 2336 if(cnt == 0): 2646 # trace caught the wh 2337 # trace caught the whole call tree 2647 return True 2338 return True 2648 elif(cnt < 0): 2339 elif(cnt < 0): 2649 if self.sv.verbose: 2340 if self.sv.verbose: 2650 pprint('Post 2341 pprint('Post Process Error: Depth is less than 0') 2651 return False 2342 return False 2652 # trace ended before call tre 2343 # trace ended before call tree finished 2653 return self.repair(cnt) 2344 return self.repair(cnt) 2654 def deviceMatch(self, pid, data): 2345 def deviceMatch(self, pid, data): 2655 found = '' 2346 found = '' 2656 # add the callgraph data to t 2347 # add the callgraph data to the device hierarchy 2657 borderphase = { 2348 borderphase = { 2658 'dpm_prepare': 'suspe 2349 'dpm_prepare': 'suspend_prepare', 2659 'dpm_complete': 'resu 2350 'dpm_complete': 'resume_complete' 2660 } 2351 } 2661 if(self.name in borderphase): 2352 if(self.name in borderphase): 2662 p = borderphase[self. 2353 p = borderphase[self.name] 2663 list = data.dmesg[p][ 2354 list = data.dmesg[p]['list'] 2664 for devname in list: 2355 for devname in list: 2665 dev = list[de 2356 dev = list[devname] 2666 if(pid == dev 2357 if(pid == dev['pid'] and 2667 self. 2358 self.start <= dev['start'] and 2668 self. 2359 self.end >= dev['end']): 2669 cg = 2360 cg = self.slice(dev) 2670 if cg 2361 if cg: 2671 2362 dev['ftrace'] = cg 2672 found 2363 found = devname 2673 return found 2364 return found 2674 for p in data.sortedPhases(): 2365 for p in data.sortedPhases(): 2675 if(data.dmesg[p]['sta 2366 if(data.dmesg[p]['start'] <= self.start and 2676 self.start <= 2367 self.start <= data.dmesg[p]['end']): 2677 list = data.d 2368 list = data.dmesg[p]['list'] 2678 for devname i 2369 for devname in sorted(list, key=lambda k:list[k]['start']): 2679 dev = 2370 dev = list[devname] 2680 if(pi 2371 if(pid == dev['pid'] and 2681 2372 self.start <= dev['start'] and 2682 2373 self.end >= dev['end']): 2683 2374 dev['ftrace'] = self 2684 2375 found = devname 2685 2376 break 2686 break 2377 break 2687 return found 2378 return found 2688 def newActionFromFunction(self, data) 2379 def newActionFromFunction(self, data): 2689 name = self.name 2380 name = self.name 2690 if name in ['dpm_run_callback 2381 if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']: 2691 return 2382 return 2692 fs = self.start 2383 fs = self.start 2693 fe = self.end 2384 fe = self.end 2694 if fs < data.start or fe > da 2385 if fs < data.start or fe > data.end: 2695 return 2386 return 2696 phase = '' 2387 phase = '' 2697 for p in data.sortedPhases(): 2388 for p in data.sortedPhases(): 2698 if(data.dmesg[p]['sta 2389 if(data.dmesg[p]['start'] <= self.start and 2699 self.start < 2390 self.start < data.dmesg[p]['end']): 2700 phase = p 2391 phase = p 2701 break 2392 break 2702 if not phase: 2393 if not phase: 2703 return 2394 return 2704 out = data.newActionGlobal(na 2395 out = data.newActionGlobal(name, fs, fe, -2) 2705 if out: 2396 if out: 2706 phase, myname = out 2397 phase, myname = out 2707 data.dmesg[phase]['li 2398 data.dmesg[phase]['list'][myname]['ftrace'] = self 2708 def debugPrint(self, info=''): 2399 def debugPrint(self, info=''): 2709 pprint('%s pid=%d [%f - %f] % 2400 pprint('%s pid=%d [%f - %f] %.3f us' % \ 2710 (self.name, self.pid, 2401 (self.name, self.pid, self.start, self.end, 2711 (self.end - self.star 2402 (self.end - self.start)*1000000)) 2712 for l in self.list: 2403 for l in self.list: 2713 if l.isLeaf(): 2404 if l.isLeaf(): 2714 pprint('%f (% 2405 pprint('%f (%02d): %s(); (%.3f us)%s' % (l.time, \ 2715 l.dep 2406 l.depth, l.name, l.length*1000000, info)) 2716 elif l.freturn: 2407 elif l.freturn: 2717 pprint('%f (% 2408 pprint('%f (%02d): %s} (%.3f us)%s' % (l.time, \ 2718 l.dep 2409 l.depth, l.name, l.length*1000000, info)) 2719 else: 2410 else: 2720 pprint('%f (% 2411 pprint('%f (%02d): %s() { (%.3f us)%s' % (l.time, \ 2721 l.dep 2412 l.depth, l.name, l.length*1000000, info)) 2722 pprint(' ') 2413 pprint(' ') 2723 2414 2724 class DevItem: 2415 class DevItem: 2725 def __init__(self, test, phase, dev): 2416 def __init__(self, test, phase, dev): 2726 self.test = test 2417 self.test = test 2727 self.phase = phase 2418 self.phase = phase 2728 self.dev = dev 2419 self.dev = dev 2729 def isa(self, cls): 2420 def isa(self, cls): 2730 if 'htmlclass' in self.dev an 2421 if 'htmlclass' in self.dev and cls in self.dev['htmlclass']: 2731 return True 2422 return True 2732 return False 2423 return False 2733 2424 2734 # Class: Timeline 2425 # Class: Timeline 2735 # Description: 2426 # Description: 2736 # A container for a device timeline wh 2427 # A container for a device timeline which calculates 2737 # all the html properties to display i 2428 # all the html properties to display it correctly 2738 class Timeline: 2429 class Timeline: 2739 html_tblock = '<div id="block{0}" cla 2430 html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n' 2740 html_device = '<div id="{0}" title="{ 2431 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' 2741 html_phase = '<div class="phase" styl 2432 html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n' 2742 html_phaselet = '<div id="{0}" class= 2433 html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' 2743 html_legend = '<div id="p{3}" class=" 2434 html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' 2744 def __init__(self, rowheight, scalehe 2435 def __init__(self, rowheight, scaleheight): 2745 self.html = '' 2436 self.html = '' 2746 self.height = 0 # total time 2437 self.height = 0 # total timeline height 2747 self.scaleH = scaleheight # t 2438 self.scaleH = scaleheight # timescale (top) row height 2748 self.rowH = rowheight # d 2439 self.rowH = rowheight # device row height 2749 self.bodyH = 0 # body heigh 2440 self.bodyH = 0 # body height 2750 self.rows = 0 # total time 2441 self.rows = 0 # total timeline rows 2751 self.rowlines = dict() 2442 self.rowlines = dict() 2752 self.rowheight = dict() 2443 self.rowheight = dict() 2753 def createHeader(self, sv, stamp): 2444 def createHeader(self, sv, stamp): 2754 if(not stamp['time']): 2445 if(not stamp['time']): 2755 return 2446 return 2756 self.html += '<div class="ver !! 2447 self.html += '<div class="version"><a href="https://01.org/suspendresume">%s v%s</a></div>' \ 2757 % (sv.title, sv.versi 2448 % (sv.title, sv.version) 2758 if sv.logmsg and sv.testlog: 2449 if sv.logmsg and sv.testlog: 2759 self.html += '<button 2450 self.html += '<button id="showtest" class="logbtn btnfmt">log</button>' 2760 if sv.dmesglog: 2451 if sv.dmesglog: 2761 self.html += '<button 2452 self.html += '<button id="showdmesg" class="logbtn btnfmt">dmesg</button>' 2762 if sv.ftracelog: 2453 if sv.ftracelog: 2763 self.html += '<button 2454 self.html += '<button id="showftrace" class="logbtn btnfmt">ftrace</button>' 2764 headline_stamp = '<div class= 2455 headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' 2765 self.html += headline_stamp.f 2456 self.html += headline_stamp.format(stamp['host'], stamp['kernel'], 2766 stamp['mode'], stamp[ 2457 stamp['mode'], stamp['time']) 2767 if 'man' in stamp and 'plat' 2458 if 'man' in stamp and 'plat' in stamp and 'cpu' in stamp and \ 2768 stamp['man'] and stam 2459 stamp['man'] and stamp['plat'] and stamp['cpu']: 2769 headline_sysinfo = '< 2460 headline_sysinfo = '<div class="stamp sysinfo">{0} {1} <i>with</i> {2}</div>\n' 2770 self.html += headline 2461 self.html += headline_sysinfo.format(stamp['man'], stamp['plat'], stamp['cpu']) 2771 2462 2772 # Function: getDeviceRows 2463 # Function: getDeviceRows 2773 # Description: 2464 # Description: 2774 # determine how may rows the devic 2465 # determine how may rows the device funcs will take 2775 # Arguments: 2466 # Arguments: 2776 # rawlist: the list of devices 2467 # rawlist: the list of devices/actions for a single phase 2777 # Output: 2468 # Output: 2778 # The total number of rows nee 2469 # The total number of rows needed to display this phase of the timeline 2779 def getDeviceRows(self, rawlist): 2470 def getDeviceRows(self, rawlist): 2780 # clear all rows and set them 2471 # clear all rows and set them to undefined 2781 sortdict = dict() 2472 sortdict = dict() 2782 for item in rawlist: 2473 for item in rawlist: 2783 item.row = -1 2474 item.row = -1 2784 sortdict[item] = item 2475 sortdict[item] = item.length 2785 sortlist = sorted(sortdict, k 2476 sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 2786 remaining = len(sortlist) 2477 remaining = len(sortlist) 2787 rowdata = dict() 2478 rowdata = dict() 2788 row = 1 2479 row = 1 2789 # try to pack each row with a 2480 # try to pack each row with as many ranges as possible 2790 while(remaining > 0): 2481 while(remaining > 0): 2791 if(row not in rowdata 2482 if(row not in rowdata): 2792 rowdata[row] 2483 rowdata[row] = [] 2793 for i in sortlist: 2484 for i in sortlist: 2794 if(i.row >= 0 2485 if(i.row >= 0): 2795 conti 2486 continue 2796 s = i.time 2487 s = i.time 2797 e = i.time + 2488 e = i.time + i.length 2798 valid = True 2489 valid = True 2799 for ritem in 2490 for ritem in rowdata[row]: 2800 rs = 2491 rs = ritem.time 2801 re = 2492 re = ritem.time + ritem.length 2802 if(no 2493 if(not (((s <= rs) and (e <= rs)) or 2803 2494 ((s >= re) and (e >= re)))): 2804 2495 valid = False 2805 2496 break 2806 if(valid): 2497 if(valid): 2807 rowda 2498 rowdata[row].append(i) 2808 i.row 2499 i.row = row 2809 remai 2500 remaining -= 1 2810 row += 1 2501 row += 1 2811 return row 2502 return row 2812 # Function: getPhaseRows 2503 # Function: getPhaseRows 2813 # Description: 2504 # Description: 2814 # Organize the timeline entrie 2505 # Organize the timeline entries into the smallest 2815 # number of rows possible, wit 2506 # number of rows possible, with no entry overlapping 2816 # Arguments: 2507 # Arguments: 2817 # devlist: the list of devices 2508 # devlist: the list of devices/actions in a group of contiguous phases 2818 # Output: 2509 # Output: 2819 # The total number of rows nee 2510 # The total number of rows needed to display this phase of the timeline 2820 def getPhaseRows(self, devlist, row=0 2511 def getPhaseRows(self, devlist, row=0, sortby='length'): 2821 # clear all rows and set them 2512 # clear all rows and set them to undefined 2822 remaining = len(devlist) 2513 remaining = len(devlist) 2823 rowdata = dict() 2514 rowdata = dict() 2824 sortdict = dict() 2515 sortdict = dict() 2825 myphases = [] 2516 myphases = [] 2826 # initialize all device rows 2517 # initialize all device rows to -1 and calculate devrows 2827 for item in devlist: 2518 for item in devlist: 2828 dev = item.dev 2519 dev = item.dev 2829 tp = (item.test, item 2520 tp = (item.test, item.phase) 2830 if tp not in myphases 2521 if tp not in myphases: 2831 myphases.appe 2522 myphases.append(tp) 2832 dev['row'] = -1 2523 dev['row'] = -1 2833 if sortby == 'start': 2524 if sortby == 'start': 2834 # sort by sta 2525 # sort by start 1st, then length 2nd 2835 sortdict[item 2526 sortdict[item] = (-1*float(dev['start']), float(dev['end']) - float(dev['start'])) 2836 else: 2527 else: 2837 # sort by len 2528 # sort by length 1st, then name 2nd 2838 sortdict[item 2529 sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) 2839 if 'src' in dev: 2530 if 'src' in dev: 2840 dev['devrows' 2531 dev['devrows'] = self.getDeviceRows(dev['src']) 2841 # sort the devlist by length 2532 # sort the devlist by length so that large items graph on top 2842 sortlist = sorted(sortdict, k 2533 sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 2843 orderedlist = [] 2534 orderedlist = [] 2844 for item in sortlist: 2535 for item in sortlist: 2845 if item.dev['pid'] == 2536 if item.dev['pid'] == -2: 2846 orderedlist.a 2537 orderedlist.append(item) 2847 for item in sortlist: 2538 for item in sortlist: 2848 if item not in ordere 2539 if item not in orderedlist: 2849 orderedlist.a 2540 orderedlist.append(item) 2850 # try to pack each row with a 2541 # try to pack each row with as many devices as possible 2851 while(remaining > 0): 2542 while(remaining > 0): 2852 rowheight = 1 2543 rowheight = 1 2853 if(row not in rowdata 2544 if(row not in rowdata): 2854 rowdata[row] 2545 rowdata[row] = [] 2855 for item in orderedli 2546 for item in orderedlist: 2856 dev = item.de 2547 dev = item.dev 2857 if(dev['row'] 2548 if(dev['row'] < 0): 2858 s = d 2549 s = dev['start'] 2859 e = d 2550 e = dev['end'] 2860 valid 2551 valid = True 2861 for r 2552 for ritem in rowdata[row]: 2862 2553 rs = ritem.dev['start'] 2863 2554 re = ritem.dev['end'] 2864 2555 if(not (((s <= rs) and (e <= rs)) or 2865 2556 ((s >= re) and (e >= re)))): 2866 2557 valid = False 2867 2558 break 2868 if(va 2559 if(valid): 2869 2560 rowdata[row].append(item) 2870 2561 dev['row'] = row 2871 2562 remaining -= 1 2872 2563 if 'devrows' in dev and dev['devrows'] > rowheight: 2873 2564 rowheight = dev['devrows'] 2874 for t, p in myphases: 2565 for t, p in myphases: 2875 if t not in s 2566 if t not in self.rowlines or t not in self.rowheight: 2876 self. 2567 self.rowlines[t] = dict() 2877 self. 2568 self.rowheight[t] = dict() 2878 if p not in s 2569 if p not in self.rowlines[t] or p not in self.rowheight[t]: 2879 self. 2570 self.rowlines[t][p] = dict() 2880 self. 2571 self.rowheight[t][p] = dict() 2881 rh = self.row 2572 rh = self.rowH 2882 # section hea 2573 # section headers should use a different row height 2883 if len(rowdat 2574 if len(rowdata[row]) == 1 and \ 2884 'html 2575 'htmlclass' in rowdata[row][0].dev and \ 2885 'sec' 2576 'sec' in rowdata[row][0].dev['htmlclass']: 2886 rh = 2577 rh = 15 2887 self.rowlines 2578 self.rowlines[t][p][row] = rowheight 2888 self.rowheigh 2579 self.rowheight[t][p][row] = rowheight * rh 2889 row += 1 2580 row += 1 2890 if(row > self.rows): 2581 if(row > self.rows): 2891 self.rows = int(row) 2582 self.rows = int(row) 2892 return row 2583 return row 2893 def phaseRowHeight(self, test, phase, 2584 def phaseRowHeight(self, test, phase, row): 2894 return self.rowheight[test][p 2585 return self.rowheight[test][phase][row] 2895 def phaseRowTop(self, test, phase, ro 2586 def phaseRowTop(self, test, phase, row): 2896 top = 0 2587 top = 0 2897 for i in sorted(self.rowheigh 2588 for i in sorted(self.rowheight[test][phase]): 2898 if i >= row: 2589 if i >= row: 2899 break 2590 break 2900 top += self.rowheight 2591 top += self.rowheight[test][phase][i] 2901 return top 2592 return top 2902 def calcTotalRows(self): 2593 def calcTotalRows(self): 2903 # Calculate the heights and o 2594 # Calculate the heights and offsets for the header and rows 2904 maxrows = 0 2595 maxrows = 0 2905 standardphases = [] 2596 standardphases = [] 2906 for t in self.rowlines: 2597 for t in self.rowlines: 2907 for p in self.rowline 2598 for p in self.rowlines[t]: 2908 total = 0 2599 total = 0 2909 for i in sort 2600 for i in sorted(self.rowlines[t][p]): 2910 total 2601 total += self.rowlines[t][p][i] 2911 if total > ma 2602 if total > maxrows: 2912 maxro 2603 maxrows = total 2913 if total == l 2604 if total == len(self.rowlines[t][p]): 2914 stand 2605 standardphases.append((t, p)) 2915 self.height = self.scaleH + ( 2606 self.height = self.scaleH + (maxrows*self.rowH) 2916 self.bodyH = self.height - se 2607 self.bodyH = self.height - self.scaleH 2917 # if there is 1 line per row, 2608 # if there is 1 line per row, draw them the standard way 2918 for t, p in standardphases: 2609 for t, p in standardphases: 2919 for i in sorted(self. 2610 for i in sorted(self.rowheight[t][p]): 2920 self.rowheigh 2611 self.rowheight[t][p][i] = float(self.bodyH)/len(self.rowlines[t][p]) 2921 def createZoomBox(self, mode='command 2612 def createZoomBox(self, mode='command', testcount=1): 2922 # Create bounding box, add bu 2613 # Create bounding box, add buttons 2923 html_zoombox = '<center><butt 2614 html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n' 2924 html_timeline = '<div id="dme 2615 html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' 2925 html_devlist1 = '<button id=" 2616 html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail{0}</button>' 2926 html_devlist2 = '<button id=" 2617 html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' 2927 if mode != 'command': 2618 if mode != 'command': 2928 if testcount > 1: 2619 if testcount > 1: 2929 self.html += 2620 self.html += html_devlist2 2930 self.html += 2621 self.html += html_devlist1.format('1') 2931 else: 2622 else: 2932 self.html += 2623 self.html += html_devlist1.format('') 2933 self.html += html_zoombox 2624 self.html += html_zoombox 2934 self.html += html_timeline.fo 2625 self.html += html_timeline.format('dmesg', self.height) 2935 # Function: createTimeScale 2626 # Function: createTimeScale 2936 # Description: 2627 # Description: 2937 # Create the timescale for a t 2628 # Create the timescale for a timeline block 2938 # Arguments: 2629 # Arguments: 2939 # m0: start time (mode begin) 2630 # m0: start time (mode begin) 2940 # mMax: end time (mode end) 2631 # mMax: end time (mode end) 2941 # tTotal: total timeline time 2632 # tTotal: total timeline time 2942 # mode: suspend or resume 2633 # mode: suspend or resume 2943 # Output: 2634 # Output: 2944 # The html code needed to disp 2635 # The html code needed to display the time scale 2945 def createTimeScale(self, m0, mMax, t 2636 def createTimeScale(self, m0, mMax, tTotal, mode): 2946 timescale = '<div class="t" s 2637 timescale = '<div class="t" style="right:{0}%">{1}</div>\n' 2947 rline = '<div class="t" style 2638 rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">{0}</div>\n' 2948 output = '<div class="timesca 2639 output = '<div class="timescale">\n' 2949 # set scale for timeline 2640 # set scale for timeline 2950 mTotal = mMax - m0 2641 mTotal = mMax - m0 2951 tS = 0.1 2642 tS = 0.1 2952 if(tTotal <= 0): 2643 if(tTotal <= 0): 2953 return output+'</div> 2644 return output+'</div>\n' 2954 if(tTotal > 4): 2645 if(tTotal > 4): 2955 tS = 1 2646 tS = 1 2956 divTotal = int(mTotal/tS) + 1 2647 divTotal = int(mTotal/tS) + 1 2957 divEdge = (mTotal - tS*(divTo 2648 divEdge = (mTotal - tS*(divTotal-1))*100/mTotal 2958 for i in range(divTotal): 2649 for i in range(divTotal): 2959 htmlline = '' 2650 htmlline = '' 2960 if(mode == 'suspend') 2651 if(mode == 'suspend'): 2961 pos = '%0.3f' 2652 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge) 2962 val = '%0.fms 2653 val = '%0.fms' % (float(i-divTotal+1)*tS*1000) 2963 if(i == divTo 2654 if(i == divTotal - 1): 2964 val = 2655 val = mode 2965 htmlline = ti 2656 htmlline = timescale.format(pos, val) 2966 else: 2657 else: 2967 pos = '%0.3f' 2658 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal)) 2968 val = '%0.fms 2659 val = '%0.fms' % (float(i)*tS*1000) 2969 htmlline = ti 2660 htmlline = timescale.format(pos, val) 2970 if(i == 0): 2661 if(i == 0): 2971 htmll 2662 htmlline = rline.format(mode) 2972 output += htmlline 2663 output += htmlline 2973 self.html += output+'</div>\n 2664 self.html += output+'</div>\n' 2974 2665 2975 # Class: TestProps 2666 # Class: TestProps 2976 # Description: 2667 # Description: 2977 # A list of values describing the prop 2668 # A list of values describing the properties of these test runs 2978 class TestProps: 2669 class TestProps: 2979 stampfmt = r'# [a-z]*-(?P<m>[0-9]{2}) !! 2670 stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ 2980 r'(?P<H>[0-9] !! 2671 '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ 2981 r' (?P<host>. !! 2672 ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' 2982 wififmt = r'^# wifi *(?P<d>\S*) *( !! 2673 batteryfmt = '^# battery (?P<a1>\w*) (?P<c1>\d*) (?P<a2>\w*) (?P<c2>\d*)' 2983 tstatfmt = r'^# turbostat (?P<t>\S* !! 2674 wififmt = '^# wifi (?P<w>.*)' 2984 testerrfmt = r'^# enter_sleep_error ( !! 2675 tstatfmt = '^# turbostat (?P<t>\S*)' 2985 sysinfofmt = r'^# sysinfo .*' !! 2676 mcelogfmt = '^# mcelog (?P<m>\S*)' 2986 cmdlinefmt = r'^# command \| (?P<cmd> !! 2677 testerrfmt = '^# enter_sleep_error (?P<e>.*)' 2987 kparamsfmt = r'^# kparams \| (?P<kp>. !! 2678 sysinfofmt = '^# sysinfo .*' 2988 devpropfmt = r'# Device Properties: . !! 2679 cmdlinefmt = '^# command \| (?P<cmd>.*)' 2989 pinfofmt = r'# platform-(?P<val>[a- !! 2680 kparamsfmt = '^# kparams \| (?P<kp>.*)' 2990 tracertypefmt = r'# tracer: (?P<t>.*) !! 2681 devpropfmt = '# Device Properties: .*' 2991 firmwarefmt = r'# fwsuspend (?P<s>[0- !! 2682 pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)' 2992 procexecfmt = r'ps - (?P<ps>.*)$' !! 2683 tracertypefmt = '# tracer: (?P<t>.*)' 2993 procmultifmt = r'@(?P<n>[0-9]*)\|(?P< !! 2684 firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' >> 2685 procexecfmt = 'ps - (?P<ps>.*)$' 2994 ftrace_line_fmt_fg = \ 2686 ftrace_line_fmt_fg = \ 2995 r'^ *(?P<time>[0-9\.]*) *\| * !! 2687 '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ 2996 r' *(?P<proc>.*)-(?P<pid>[0-9 !! 2688 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ 2997 r'[ +!#\*@$]*(?P<dur>[0-9\.]* !! 2689 '[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)' 2998 ftrace_line_fmt_nop = \ 2690 ftrace_line_fmt_nop = \ 2999 r' *(?P<proc>.*)-(?P<pid>[0-9 !! 2691 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\ 3000 r'(?P<flags>\S*) *(?P<time>[0 !! 2692 '(?P<flags>.{4}) *(?P<time>[0-9\.]*): *'+\ 3001 r'(?P<msg>.*)' !! 2693 '(?P<msg>.*)' 3002 machinesuspend = r'machine_suspend\[. << 3003 multiproclist = dict() << 3004 multiproctime = 0.0 << 3005 multiproccnt = 0 << 3006 def __init__(self): 2694 def __init__(self): 3007 self.stamp = '' 2695 self.stamp = '' 3008 self.sysinfo = '' 2696 self.sysinfo = '' 3009 self.cmdline = '' 2697 self.cmdline = '' >> 2698 self.kparams = '' 3010 self.testerror = [] 2699 self.testerror = [] >> 2700 self.mcelog = [] 3011 self.turbostat = [] 2701 self.turbostat = [] >> 2702 self.battery = [] 3012 self.wifi = [] 2703 self.wifi = [] 3013 self.fwdata = [] 2704 self.fwdata = [] 3014 self.ftrace_line_fmt = self.f 2705 self.ftrace_line_fmt = self.ftrace_line_fmt_nop 3015 self.cgformat = False 2706 self.cgformat = False 3016 self.data = 0 2707 self.data = 0 3017 self.ktemp = dict() 2708 self.ktemp = dict() 3018 def setTracerType(self, tracer): 2709 def setTracerType(self, tracer): 3019 if(tracer == 'function_graph' 2710 if(tracer == 'function_graph'): 3020 self.cgformat = True 2711 self.cgformat = True 3021 self.ftrace_line_fmt 2712 self.ftrace_line_fmt = self.ftrace_line_fmt_fg 3022 elif(tracer == 'nop'): 2713 elif(tracer == 'nop'): 3023 self.ftrace_line_fmt 2714 self.ftrace_line_fmt = self.ftrace_line_fmt_nop 3024 else: 2715 else: 3025 doError('Invalid trac 2716 doError('Invalid tracer format: [%s]' % tracer) 3026 def stampInfo(self, line, sv): !! 2717 def stampInfo(self, line): 3027 if re.match(self.stampfmt, li 2718 if re.match(self.stampfmt, line): 3028 self.stamp = line 2719 self.stamp = line 3029 return True 2720 return True 3030 elif re.match(self.sysinfofmt 2721 elif re.match(self.sysinfofmt, line): 3031 self.sysinfo = line 2722 self.sysinfo = line 3032 return True 2723 return True >> 2724 elif re.match(self.kparamsfmt, line): >> 2725 self.kparams = line >> 2726 return True >> 2727 elif re.match(self.cmdlinefmt, line): >> 2728 self.cmdline = line >> 2729 return True >> 2730 elif re.match(self.mcelogfmt, line): >> 2731 self.mcelog.append(line) >> 2732 return True 3033 elif re.match(self.tstatfmt, 2733 elif re.match(self.tstatfmt, line): 3034 self.turbostat.append 2734 self.turbostat.append(line) 3035 return True 2735 return True >> 2736 elif re.match(self.batteryfmt, line): >> 2737 self.battery.append(line) >> 2738 return True 3036 elif re.match(self.wififmt, l 2739 elif re.match(self.wififmt, line): 3037 self.wifi.append(line 2740 self.wifi.append(line) 3038 return True 2741 return True 3039 elif re.match(self.testerrfmt 2742 elif re.match(self.testerrfmt, line): 3040 self.testerror.append 2743 self.testerror.append(line) 3041 return True 2744 return True 3042 elif re.match(self.firmwarefm 2745 elif re.match(self.firmwarefmt, line): 3043 self.fwdata.append(li 2746 self.fwdata.append(line) 3044 return True 2747 return True 3045 elif(re.match(self.devpropfmt << 3046 self.parseDevprops(li << 3047 return True << 3048 elif(re.match(self.pinfofmt, << 3049 self.parsePlatformInf << 3050 return True << 3051 m = re.match(self.cmdlinefmt, << 3052 if m: << 3053 self.cmdline = m.grou << 3054 return True << 3055 m = re.match(self.tracertypef << 3056 if(m): << 3057 self.setTracerType(m. << 3058 return True << 3059 return False 2748 return False 3060 def parseStamp(self, data, sv): 2749 def parseStamp(self, data, sv): 3061 # global test data 2750 # global test data 3062 m = re.match(self.stampfmt, s 2751 m = re.match(self.stampfmt, self.stamp) 3063 if not self.stamp or not m: << 3064 doError('data does no << 3065 data.stamp = {'time': '', 'ho 2752 data.stamp = {'time': '', 'host': '', 'mode': ''} 3066 dt = datetime(int(m.group('y' 2753 dt = datetime(int(m.group('y'))+2000, int(m.group('m')), 3067 int(m.group('d')), in 2754 int(m.group('d')), int(m.group('H')), int(m.group('M')), 3068 int(m.group('S'))) 2755 int(m.group('S'))) 3069 data.stamp['time'] = dt.strft 2756 data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') 3070 data.stamp['host'] = m.group( 2757 data.stamp['host'] = m.group('host') 3071 data.stamp['mode'] = m.group( 2758 data.stamp['mode'] = m.group('mode') 3072 data.stamp['kernel'] = m.grou 2759 data.stamp['kernel'] = m.group('kernel') 3073 if re.match(self.sysinfofmt, 2760 if re.match(self.sysinfofmt, self.sysinfo): 3074 for f in self.sysinfo 2761 for f in self.sysinfo.split('|'): 3075 if '#' in f: 2762 if '#' in f: 3076 conti 2763 continue 3077 tmp = f.strip 2764 tmp = f.strip().split(':', 1) 3078 key = tmp[0] 2765 key = tmp[0] 3079 val = tmp[1] 2766 val = tmp[1] 3080 data.stamp[ke 2767 data.stamp[key] = val 3081 sv.hostname = data.stamp['hos 2768 sv.hostname = data.stamp['host'] 3082 sv.suspendmode = data.stamp[' 2769 sv.suspendmode = data.stamp['mode'] 3083 if sv.suspendmode == 'freeze' << 3084 self.machinesuspend = << 3085 else: << 3086 self.machinesuspend = << 3087 if sv.suspendmode == 'command 2770 if sv.suspendmode == 'command' and sv.ftracefile != '': 3088 modes = ['on', 'freez 2771 modes = ['on', 'freeze', 'standby', 'mem', 'disk'] 3089 fp = sv.openlog(sv.ft !! 2772 fp = sysvals.openlog(sv.ftracefile, 'r') 3090 for line in fp: 2773 for line in fp: 3091 m = re.match( !! 2774 m = re.match('.* machine_suspend\[(?P<mode>.*)\]', line) 3092 if m and m.gr 2775 if m and m.group('mode') in ['1', '2', '3', '4']: 3093 sv.su 2776 sv.suspendmode = modes[int(m.group('mode'))] 3094 data. 2777 data.stamp['mode'] = sv.suspendmode 3095 break 2778 break 3096 fp.close() 2779 fp.close() 3097 sv.cmdline = self.cmdline !! 2780 m = re.match(self.cmdlinefmt, self.cmdline) >> 2781 if m: >> 2782 sv.cmdline = m.group('cmd') >> 2783 if self.kparams: >> 2784 m = re.match(self.kparamsfmt, self.kparams) >> 2785 if m: >> 2786 sv.kparams = m.group('kp') 3098 if not sv.stamp: 2787 if not sv.stamp: 3099 sv.stamp = data.stamp 2788 sv.stamp = data.stamp 3100 # firmware data 2789 # firmware data 3101 if sv.suspendmode == 'mem' an 2790 if sv.suspendmode == 'mem' and len(self.fwdata) > data.testnumber: 3102 m = re.match(self.fir 2791 m = re.match(self.firmwarefmt, self.fwdata[data.testnumber]) 3103 if m: 2792 if m: 3104 data.fwSuspen 2793 data.fwSuspend, data.fwResume = int(m.group('s')), int(m.group('r')) 3105 if(data.fwSus 2794 if(data.fwSuspend > 0 or data.fwResume > 0): 3106 data. 2795 data.fwValid = True >> 2796 # mcelog data >> 2797 if len(self.mcelog) > data.testnumber: >> 2798 m = re.match(self.mcelogfmt, self.mcelog[data.testnumber]) >> 2799 if m: >> 2800 data.mcelog = sv.b64unzip(m.group('m')) 3107 # turbostat data 2801 # turbostat data 3108 if len(self.turbostat) > data 2802 if len(self.turbostat) > data.testnumber: 3109 m = re.match(self.tst 2803 m = re.match(self.tstatfmt, self.turbostat[data.testnumber]) 3110 if m: 2804 if m: 3111 data.turbosta 2805 data.turbostat = m.group('t') >> 2806 # battery data >> 2807 if len(self.battery) > data.testnumber: >> 2808 m = re.match(self.batteryfmt, self.battery[data.testnumber]) >> 2809 if m: >> 2810 data.battery = m.groups() 3112 # wifi data 2811 # wifi data 3113 if len(self.wifi) > data.test 2812 if len(self.wifi) > data.testnumber: 3114 m = re.match(self.wif 2813 m = re.match(self.wififmt, self.wifi[data.testnumber]) 3115 if m: 2814 if m: 3116 data.wifi = { !! 2815 data.wifi = m.group('w') 3117 'time << 3118 data.stamp['w << 3119 # sleep mode enter errors 2816 # sleep mode enter errors 3120 if len(self.testerror) > data 2817 if len(self.testerror) > data.testnumber: 3121 m = re.match(self.tes 2818 m = re.match(self.testerrfmt, self.testerror[data.testnumber]) 3122 if m: 2819 if m: 3123 data.enterfai 2820 data.enterfail = m.group('e') 3124 def devprops(self, data): 2821 def devprops(self, data): 3125 props = dict() 2822 props = dict() 3126 devlist = data.split(';') 2823 devlist = data.split(';') 3127 for dev in devlist: 2824 for dev in devlist: 3128 f = dev.split(',') 2825 f = dev.split(',') 3129 if len(f) < 3: 2826 if len(f) < 3: 3130 continue 2827 continue 3131 dev = f[0] 2828 dev = f[0] 3132 props[dev] = DevProps 2829 props[dev] = DevProps() 3133 props[dev].altname = 2830 props[dev].altname = f[1] 3134 if int(f[2]): 2831 if int(f[2]): 3135 props[dev].is 2832 props[dev].isasync = True 3136 else: 2833 else: 3137 props[dev].is 2834 props[dev].isasync = False 3138 return props 2835 return props 3139 def parseDevprops(self, line, sv): 2836 def parseDevprops(self, line, sv): 3140 idx = line.index(': ') + 2 2837 idx = line.index(': ') + 2 3141 if idx >= len(line): 2838 if idx >= len(line): 3142 return 2839 return 3143 props = self.devprops(line[id 2840 props = self.devprops(line[idx:]) 3144 if sv.suspendmode == 'command 2841 if sv.suspendmode == 'command' and 'testcommandstring' in props: 3145 sv.testcommand = prop 2842 sv.testcommand = props['testcommandstring'].altname 3146 sv.devprops = props 2843 sv.devprops = props 3147 def parsePlatformInfo(self, line, sv) 2844 def parsePlatformInfo(self, line, sv): 3148 m = re.match(self.pinfofmt, l 2845 m = re.match(self.pinfofmt, line) 3149 if not m: 2846 if not m: 3150 return 2847 return 3151 name, info = m.group('val'), 2848 name, info = m.group('val'), m.group('info') 3152 if name == 'devinfo': 2849 if name == 'devinfo': 3153 sv.devprops = self.de 2850 sv.devprops = self.devprops(sv.b64unzip(info)) 3154 return 2851 return 3155 elif name == 'testcmd': 2852 elif name == 'testcmd': 3156 sv.testcommand = info 2853 sv.testcommand = info 3157 return 2854 return 3158 field = info.split('|') 2855 field = info.split('|') 3159 if len(field) < 2: 2856 if len(field) < 2: 3160 return 2857 return 3161 cmdline = field[0].strip() 2858 cmdline = field[0].strip() 3162 output = sv.b64unzip(field[1] 2859 output = sv.b64unzip(field[1].strip()) 3163 sv.platinfo.append([name, cmd 2860 sv.platinfo.append([name, cmdline, output]) 3164 2861 3165 # Class: TestRun 2862 # Class: TestRun 3166 # Description: 2863 # Description: 3167 # A container for a suspend/resume tes 2864 # A container for a suspend/resume test run. This is necessary as 3168 # there could be more than one, and th 2865 # there could be more than one, and they need to be separate. 3169 class TestRun: 2866 class TestRun: 3170 def __init__(self, dataobj): 2867 def __init__(self, dataobj): 3171 self.data = dataobj 2868 self.data = dataobj 3172 self.ftemp = dict() 2869 self.ftemp = dict() 3173 self.ttemp = dict() 2870 self.ttemp = dict() 3174 2871 3175 class ProcessMonitor: 2872 class ProcessMonitor: 3176 maxchars = 512 << 3177 def __init__(self): 2873 def __init__(self): 3178 self.proclist = dict() 2874 self.proclist = dict() 3179 self.running = False 2875 self.running = False 3180 def procstat(self): 2876 def procstat(self): 3181 c = ['cat /proc/[1-9]*/stat 2 2877 c = ['cat /proc/[1-9]*/stat 2>/dev/null'] 3182 process = Popen(c, shell=True 2878 process = Popen(c, shell=True, stdout=PIPE) 3183 running = dict() 2879 running = dict() 3184 for line in process.stdout: 2880 for line in process.stdout: 3185 data = ascii(line).sp 2881 data = ascii(line).split() 3186 pid = data[0] 2882 pid = data[0] 3187 name = re.sub('[()]', 2883 name = re.sub('[()]', '', data[1]) 3188 user = int(data[13]) 2884 user = int(data[13]) 3189 kern = int(data[14]) 2885 kern = int(data[14]) 3190 kjiff = ujiff = 0 2886 kjiff = ujiff = 0 3191 if pid not in self.pr 2887 if pid not in self.proclist: 3192 self.proclist 2888 self.proclist[pid] = {'name' : name, 'user' : user, 'kern' : kern} 3193 else: 2889 else: 3194 val = self.pr 2890 val = self.proclist[pid] 3195 ujiff = user 2891 ujiff = user - val['user'] 3196 kjiff = kern 2892 kjiff = kern - val['kern'] 3197 val['user'] = 2893 val['user'] = user 3198 val['kern'] = 2894 val['kern'] = kern 3199 if ujiff > 0 or kjiff 2895 if ujiff > 0 or kjiff > 0: 3200 running[pid] 2896 running[pid] = ujiff + kjiff 3201 process.wait() 2897 process.wait() 3202 out = [''] !! 2898 out = '' 3203 for pid in running: 2899 for pid in running: 3204 jiffies = running[pid 2900 jiffies = running[pid] 3205 val = self.proclist[p 2901 val = self.proclist[pid] 3206 if len(out[-1]) > sel !! 2902 if out: 3207 out.append('' !! 2903 out += ',' 3208 elif len(out[-1]) > 0 !! 2904 out += '%s-%s %d' % (val['name'], pid, jiffies) 3209 out[-1] += ', !! 2905 return 'ps - '+out 3210 out[-1] += '%s-%s %d' << 3211 if len(out) > 1: << 3212 for line in out: << 3213 sysvals.fsetV << 3214 else: << 3215 sysvals.fsetVal('ps - << 3216 def processMonitor(self, tid): 2906 def processMonitor(self, tid): 3217 while self.running: 2907 while self.running: 3218 self.procstat() !! 2908 out = self.procstat() >> 2909 if out: >> 2910 sysvals.fsetVal(out, 'trace_marker') 3219 def start(self): 2911 def start(self): 3220 self.thread = Thread(target=s 2912 self.thread = Thread(target=self.processMonitor, args=(0,)) 3221 self.running = True 2913 self.running = True 3222 self.thread.start() 2914 self.thread.start() 3223 def stop(self): 2915 def stop(self): 3224 self.running = False 2916 self.running = False 3225 2917 3226 # ----------------- FUNCTIONS --------------- 2918 # ----------------- FUNCTIONS -------------------- 3227 2919 3228 # Function: doesTraceLogHaveTraceEvents 2920 # Function: doesTraceLogHaveTraceEvents 3229 # Description: 2921 # Description: 3230 # Quickly determine if the ftrace log 2922 # Quickly determine if the ftrace log has all of the trace events, 3231 # markers, and/or kprobes required for 2923 # markers, and/or kprobes required for primary parsing. 3232 def doesTraceLogHaveTraceEvents(): 2924 def doesTraceLogHaveTraceEvents(): 3233 kpcheck = ['_cal: (', '_ret: ('] 2925 kpcheck = ['_cal: (', '_ret: ('] 3234 techeck = ['suspend_resume', 'device_ !! 2926 techeck = ['suspend_resume', 'device_pm_callback'] 3235 tmcheck = ['SUSPEND START', 'RESUME C 2927 tmcheck = ['SUSPEND START', 'RESUME COMPLETE'] 3236 sysvals.usekprobes = False 2928 sysvals.usekprobes = False 3237 fp = sysvals.openlog(sysvals.ftracefi 2929 fp = sysvals.openlog(sysvals.ftracefile, 'r') 3238 for line in fp: 2930 for line in fp: 3239 # check for kprobes 2931 # check for kprobes 3240 if not sysvals.usekprobes: 2932 if not sysvals.usekprobes: 3241 for i in kpcheck: 2933 for i in kpcheck: 3242 if i in line: 2934 if i in line: 3243 sysva 2935 sysvals.usekprobes = True 3244 # check for all necessary tra 2936 # check for all necessary trace events 3245 check = techeck[:] 2937 check = techeck[:] 3246 for i in techeck: 2938 for i in techeck: 3247 if i in line: 2939 if i in line: 3248 check.remove( 2940 check.remove(i) 3249 techeck = check 2941 techeck = check 3250 # check for all necessary tra 2942 # check for all necessary trace markers 3251 check = tmcheck[:] 2943 check = tmcheck[:] 3252 for i in tmcheck: 2944 for i in tmcheck: 3253 if i in line: 2945 if i in line: 3254 check.remove( 2946 check.remove(i) 3255 tmcheck = check 2947 tmcheck = check 3256 fp.close() 2948 fp.close() 3257 sysvals.usetraceevents = True if len( !! 2949 sysvals.usetraceevents = True if len(techeck) < 2 else False 3258 sysvals.usetracemarkers = True if len 2950 sysvals.usetracemarkers = True if len(tmcheck) == 0 else False 3259 2951 3260 # Function: appendIncompleteTraceLog 2952 # Function: appendIncompleteTraceLog 3261 # Description: 2953 # Description: >> 2954 # [deprecated for kernel 3.15 or newer] 3262 # Adds callgraph data which lacks trac 2955 # Adds callgraph data which lacks trace event data. This is only 3263 # for timelines generated from 3.15 or 2956 # for timelines generated from 3.15 or older 3264 # Arguments: 2957 # Arguments: 3265 # testruns: the array of Data objects 2958 # testruns: the array of Data objects obtained from parseKernelLog 3266 def appendIncompleteTraceLog(testruns): 2959 def appendIncompleteTraceLog(testruns): 3267 # create TestRun vessels for ftrace p 2960 # create TestRun vessels for ftrace parsing 3268 testcnt = len(testruns) 2961 testcnt = len(testruns) 3269 testidx = 0 2962 testidx = 0 3270 testrun = [] 2963 testrun = [] 3271 for data in testruns: 2964 for data in testruns: 3272 testrun.append(TestRun(data)) 2965 testrun.append(TestRun(data)) 3273 2966 3274 # extract the callgraph and traceeven 2967 # extract the callgraph and traceevent data 3275 sysvals.vprint('Analyzing the ftrace 2968 sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 3276 os.path.basename(sysvals.ftra 2969 os.path.basename(sysvals.ftracefile)) 3277 tp = TestProps() 2970 tp = TestProps() 3278 tf = sysvals.openlog(sysvals.ftracefi 2971 tf = sysvals.openlog(sysvals.ftracefile, 'r') 3279 data = 0 2972 data = 0 3280 for line in tf: 2973 for line in tf: 3281 # remove any latent carriage 2974 # remove any latent carriage returns 3282 line = line.replace('\r\n', ' 2975 line = line.replace('\r\n', '') 3283 if tp.stampInfo(line, sysvals !! 2976 if tp.stampInfo(line): >> 2977 continue >> 2978 # determine the trace data type (required for further parsing) >> 2979 m = re.match(tp.tracertypefmt, line) >> 2980 if(m): >> 2981 tp.setTracerType(m.group('t')) >> 2982 continue >> 2983 # device properties line >> 2984 if(re.match(tp.devpropfmt, line)): >> 2985 tp.parseDevprops(line, sysvals) >> 2986 continue >> 2987 # platform info line >> 2988 if(re.match(tp.pinfofmt, line)): >> 2989 tp.parsePlatformInfo(line, sysvals) 3284 continue 2990 continue 3285 # parse only valid lines, if 2991 # parse only valid lines, if this is not one move on 3286 m = re.match(tp.ftrace_line_f 2992 m = re.match(tp.ftrace_line_fmt, line) 3287 if(not m): 2993 if(not m): 3288 continue 2994 continue 3289 # gather the basic message da 2995 # gather the basic message data from the line 3290 m_time = m.group('time') 2996 m_time = m.group('time') 3291 m_pid = m.group('pid') 2997 m_pid = m.group('pid') 3292 m_msg = m.group('msg') 2998 m_msg = m.group('msg') 3293 if(tp.cgformat): 2999 if(tp.cgformat): 3294 m_param3 = m.group('d 3000 m_param3 = m.group('dur') 3295 else: 3001 else: 3296 m_param3 = 'traceeven 3002 m_param3 = 'traceevent' 3297 if(m_time and m_pid and m_msg 3003 if(m_time and m_pid and m_msg): 3298 t = FTraceLine(m_time 3004 t = FTraceLine(m_time, m_msg, m_param3) 3299 pid = int(m_pid) 3005 pid = int(m_pid) 3300 else: 3006 else: 3301 continue 3007 continue 3302 # the line should be a call, 3008 # the line should be a call, return, or event 3303 if(not t.fcall and not t.fret 3009 if(not t.fcall and not t.freturn and not t.fevent): 3304 continue 3010 continue 3305 # look for the suspend start 3011 # look for the suspend start marker 3306 if(t.startMarker()): 3012 if(t.startMarker()): 3307 data = testrun[testid 3013 data = testrun[testidx].data 3308 tp.parseStamp(data, s 3014 tp.parseStamp(data, sysvals) 3309 data.setStart(t.time, !! 3015 data.setStart(t.time) 3310 continue 3016 continue 3311 if(not data): 3017 if(not data): 3312 continue 3018 continue 3313 # find the end of resume 3019 # find the end of resume 3314 if(t.endMarker()): 3020 if(t.endMarker()): 3315 data.setEnd(t.time, t !! 3021 data.setEnd(t.time) 3316 testidx += 1 3022 testidx += 1 3317 if(testidx >= testcnt 3023 if(testidx >= testcnt): 3318 break 3024 break 3319 continue 3025 continue 3320 # trace event processing 3026 # trace event processing 3321 if(t.fevent): 3027 if(t.fevent): 3322 continue 3028 continue 3323 # call/return processing 3029 # call/return processing 3324 elif sysvals.usecallgraph: 3030 elif sysvals.usecallgraph: 3325 # create a callgraph 3031 # create a callgraph object for the data 3326 if(pid not in testrun 3032 if(pid not in testrun[testidx].ftemp): 3327 testrun[testi 3033 testrun[testidx].ftemp[pid] = [] 3328 testrun[testi 3034 testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 3329 # when the call is fi 3035 # when the call is finished, see which device matches it 3330 cg = testrun[testidx] 3036 cg = testrun[testidx].ftemp[pid][-1] 3331 res = cg.addLine(t) 3037 res = cg.addLine(t) 3332 if(res != 0): 3038 if(res != 0): 3333 testrun[testi 3039 testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 3334 if(res == -1): 3040 if(res == -1): 3335 testrun[testi 3041 testrun[testidx].ftemp[pid][-1].addLine(t) 3336 tf.close() 3042 tf.close() 3337 3043 3338 for test in testrun: 3044 for test in testrun: 3339 # add the callgraph data to t 3045 # add the callgraph data to the device hierarchy 3340 for pid in test.ftemp: 3046 for pid in test.ftemp: 3341 for cg in test.ftemp[ 3047 for cg in test.ftemp[pid]: 3342 if len(cg.lis 3048 if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 3343 conti 3049 continue 3344 if(not cg.pos 3050 if(not cg.postProcess()): 3345 id = 3051 id = 'task %s cpu %s' % (pid, m.group('cpu')) 3346 sysva 3052 sysvals.vprint('Sanity check failed for '+\ 3347 3053 id+', ignoring this callback') 3348 conti 3054 continue 3349 callstart = c 3055 callstart = cg.start 3350 callend = cg. 3056 callend = cg.end 3351 for p in test 3057 for p in test.data.sortedPhases(): 3352 if(te 3058 if(test.data.dmesg[p]['start'] <= callstart and 3353 3059 callstart <= test.data.dmesg[p]['end']): 3354 3060 list = test.data.dmesg[p]['list'] 3355 3061 for devname in list: 3356 3062 dev = list[devname] 3357 3063 if(pid == dev['pid'] and 3358 3064 callstart <= dev['start'] and 3359 3065 callend >= dev['end']): 3360 3066 dev['ftrace'] = cg 3361 3067 break 3362 3068 3363 # Function: loadTraceLog << 3364 # Description: << 3365 # load the ftrace file into memory and << 3366 # Output: << 3367 # TestProps instance and an array of l << 3368 def loadTraceLog(): << 3369 tp, data, lines, trace = TestProps(), << 3370 tf = sysvals.openlog(sysvals.ftracefi << 3371 for line in tf: << 3372 # remove any latent carriage << 3373 line = line.replace('\r\n', ' << 3374 if tp.stampInfo(line, sysvals << 3375 continue << 3376 # ignore all other commented << 3377 if line[0] == '#': << 3378 continue << 3379 # ftrace line: parse only val << 3380 m = re.match(tp.ftrace_line_f << 3381 if(not m): << 3382 continue << 3383 dur = m.group('dur') if tp.cg << 3384 info = (m.group('time'), m.gr << 3385 m.group('msg'), dur) << 3386 # group the data by timestamp << 3387 t = float(info[0]) << 3388 if t in data: << 3389 data[t].append(info) << 3390 else: << 3391 data[t] = [info] << 3392 # we only care about trace ev << 3393 if (info[3].startswith('suspe << 3394 info[3].startswith('t << 3395 trace.append( << 3396 tf.close() << 3397 for t in sorted(data): << 3398 first, last, blk = [], [], da << 3399 if len(blk) > 1 and t in trac << 3400 # move certain lines << 3401 for i in range(len(bl << 3402 if 'SUSPEND S << 3403 first << 3404 elif re.match << 3405 last. << 3406 elif re.match << 3407 first << 3408 elif 'RESUME << 3409 last. << 3410 if len(first) == 1 an << 3411 blk.insert(0, << 3412 elif len(last) == 1 a << 3413 blk.append(bl << 3414 for info in blk: << 3415 lines.append(info) << 3416 return (tp, lines) << 3417 << 3418 # Function: parseTraceLog 3069 # Function: parseTraceLog 3419 # Description: 3070 # Description: 3420 # Analyze an ftrace log output file ge 3071 # Analyze an ftrace log output file generated from this app during 3421 # the execution phase. Used when the f 3072 # the execution phase. Used when the ftrace log is the primary data source 3422 # and includes the suspend_resume and 3073 # and includes the suspend_resume and device_pm_callback trace events 3423 # The ftrace filename is taken from sy 3074 # The ftrace filename is taken from sysvals 3424 # Output: 3075 # Output: 3425 # An array of Data objects 3076 # An array of Data objects 3426 def parseTraceLog(live=False): 3077 def parseTraceLog(live=False): 3427 sysvals.vprint('Analyzing the ftrace 3078 sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 3428 os.path.basename(sysvals.ftra 3079 os.path.basename(sysvals.ftracefile)) 3429 if(os.path.exists(sysvals.ftracefile) 3080 if(os.path.exists(sysvals.ftracefile) == False): 3430 doError('%s does not exist' % 3081 doError('%s does not exist' % sysvals.ftracefile) 3431 if not live: 3082 if not live: 3432 sysvals.setupAllKprobes() 3083 sysvals.setupAllKprobes() 3433 ksuscalls = ['ksys_sync', 'pm_prepare !! 3084 ksuscalls = ['pm_prepare_console'] 3434 krescalls = ['pm_restore_console'] 3085 krescalls = ['pm_restore_console'] 3435 tracewatch = ['irq_wakeup'] 3086 tracewatch = ['irq_wakeup'] 3436 if sysvals.usekprobes: 3087 if sysvals.usekprobes: 3437 tracewatch += ['sync_filesyst 3088 tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend', 3438 'syscore_resume', 're 3089 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 3439 'CPU_OFF', 'acpi_susp !! 3090 'CPU_OFF', 'timekeeping_freeze', 'acpi_suspend'] 3440 3091 3441 # extract the callgraph and traceeven 3092 # extract the callgraph and traceevent data 3442 s2idle_enter = hwsus = False !! 3093 tp = TestProps() 3443 testruns, testdata = [], [] !! 3094 testruns = [] 3444 testrun, data, limbo = 0, 0, True !! 3095 testdata = [] >> 3096 testrun = 0 >> 3097 data = 0 >> 3098 tf = sysvals.openlog(sysvals.ftracefile, 'r') 3445 phase = 'suspend_prepare' 3099 phase = 'suspend_prepare' 3446 tp, tf = loadTraceLog() !! 3100 for line in tf: 3447 for m_time, m_proc, m_pid, m_msg, m_p !! 3101 # remove any latent carriage returns >> 3102 line = line.replace('\r\n', '') >> 3103 if tp.stampInfo(line): >> 3104 continue >> 3105 # tracer type line: determine the trace data type >> 3106 m = re.match(tp.tracertypefmt, line) >> 3107 if(m): >> 3108 tp.setTracerType(m.group('t')) >> 3109 continue >> 3110 # device properties line >> 3111 if(re.match(tp.devpropfmt, line)): >> 3112 tp.parseDevprops(line, sysvals) >> 3113 continue >> 3114 # platform info line >> 3115 if(re.match(tp.pinfofmt, line)): >> 3116 tp.parsePlatformInfo(line, sysvals) >> 3117 continue >> 3118 # ignore all other commented lines >> 3119 if line[0] == '#': >> 3120 continue >> 3121 # ftrace line: parse only valid lines >> 3122 m = re.match(tp.ftrace_line_fmt, line) >> 3123 if(not m): >> 3124 continue 3448 # gather the basic message da 3125 # gather the basic message data from the line >> 3126 m_time = m.group('time') >> 3127 m_proc = m.group('proc') >> 3128 m_pid = m.group('pid') >> 3129 m_msg = m.group('msg') >> 3130 if(tp.cgformat): >> 3131 m_param3 = m.group('dur') >> 3132 else: >> 3133 m_param3 = 'traceevent' 3449 if(m_time and m_pid and m_msg 3134 if(m_time and m_pid and m_msg): 3450 t = FTraceLine(m_time 3135 t = FTraceLine(m_time, m_msg, m_param3) 3451 pid = int(m_pid) 3136 pid = int(m_pid) 3452 else: 3137 else: 3453 continue 3138 continue 3454 # the line should be a call, 3139 # the line should be a call, return, or event 3455 if(not t.fcall and not t.fret 3140 if(not t.fcall and not t.freturn and not t.fevent): 3456 continue 3141 continue 3457 # find the start of suspend 3142 # find the start of suspend 3458 if(t.startMarker()): 3143 if(t.startMarker()): 3459 data, limbo = Data(le !! 3144 data = Data(len(testdata)) 3460 testdata.append(data) 3145 testdata.append(data) 3461 testrun = TestRun(dat 3146 testrun = TestRun(data) 3462 testruns.append(testr 3147 testruns.append(testrun) 3463 tp.parseStamp(data, s 3148 tp.parseStamp(data, sysvals) 3464 data.setStart(t.time, !! 3149 data.setStart(t.time) 3465 data.first_suspend_pr 3150 data.first_suspend_prepare = True 3466 phase = data.setPhase 3151 phase = data.setPhase('suspend_prepare', t.time, True) 3467 continue 3152 continue 3468 if(not data or limbo): !! 3153 if(not data): 3469 continue 3154 continue 3470 # process cpu exec line 3155 # process cpu exec line 3471 if t.type == 'tracing_mark_wr 3156 if t.type == 'tracing_mark_write': 3472 if t.name == 'CMD COM << 3473 data.tKernRes << 3474 m = re.match(tp.proce 3157 m = re.match(tp.procexecfmt, t.name) 3475 if(m): 3158 if(m): 3476 parts, msg = !! 3159 proclist = dict() 3477 m = re.match( !! 3160 for ps in m.group('ps').split(','): 3478 if(m): << 3479 parts << 3480 if tp << 3481 << 3482 << 3483 procl << 3484 tp.mu << 3485 else: << 3486 procl << 3487 tp.mu << 3488 for ps in msg << 3489 val = 3161 val = ps.split() 3490 if no !! 3162 if not val: 3491 3163 continue 3492 name 3164 name = val[0].replace('--', '-') 3493 procl 3165 proclist[name] = int(val[1]) 3494 if parts == 1 !! 3166 data.pstl[t.time] = proclist 3495 data. << 3496 elif parts == << 3497 data. << 3498 tp.mu << 3499 continue 3167 continue 3500 # find the end of resume 3168 # find the end of resume 3501 if(t.endMarker()): 3169 if(t.endMarker()): 3502 if data.tKernRes == 0 !! 3170 data.handleEndMarker(t.time) 3503 data.tKernRes << 3504 data.handleEndMarker( << 3505 if(not sysvals.usetra 3171 if(not sysvals.usetracemarkers): 3506 # no trace ma 3172 # no trace markers? then quit and be sure to finish recording 3507 # the event w 3173 # the event we used to trigger resume end 3508 if('thaw_proc 3174 if('thaw_processes' in testrun.ttemp and len(testrun.ttemp['thaw_processes']) > 0): 3509 # if 3175 # if an entry exists, assume this is its end 3510 testr 3176 testrun.ttemp['thaw_processes'][-1]['end'] = t.time 3511 limbo = True !! 3177 break 3512 continue 3178 continue 3513 # trace event processing 3179 # trace event processing 3514 if(t.fevent): 3180 if(t.fevent): 3515 if(t.type == 'suspend 3181 if(t.type == 'suspend_resume'): 3516 # suspend_res 3182 # suspend_resume trace events have two types, begin and end 3517 if(re.match(r !! 3183 if(re.match('(?P<name>.*) begin$', t.name)): 3518 isbeg 3184 isbegin = True 3519 elif(re.match !! 3185 elif(re.match('(?P<name>.*) end$', t.name)): 3520 isbeg 3186 isbegin = False 3521 else: 3187 else: 3522 conti 3188 continue 3523 if '[' in t.n 3189 if '[' in t.name: 3524 m = r !! 3190 m = re.match('(?P<name>.*)\[.*', t.name) 3525 else: 3191 else: 3526 m = r !! 3192 m = re.match('(?P<name>.*) .*', t.name) 3527 name = m.grou 3193 name = m.group('name') 3528 # ignore thes 3194 # ignore these events 3529 if(name.split 3195 if(name.split('[')[0] in tracewatch): 3530 conti 3196 continue 3531 # -- phase ch 3197 # -- phase changes -- 3532 # start of ke 3198 # start of kernel suspend 3533 if(re.match(r !! 3199 if(re.match('suspend_enter\[.*', t.name)): 3534 if(is !! 3200 if(isbegin): 3535 3201 data.tKernSus = t.time 3536 conti 3202 continue 3537 # suspend_pre 3203 # suspend_prepare start 3538 elif(re.match !! 3204 elif(re.match('dpm_prepare\[.*', t.name)): 3539 if is 3205 if isbegin and data.first_suspend_prepare: 3540 3206 data.first_suspend_prepare = False 3541 3207 if data.tKernSus == 0: 3542 3208 data.tKernSus = t.time 3543 3209 continue 3544 phase 3210 phase = data.setPhase('suspend_prepare', t.time, isbegin) 3545 conti 3211 continue 3546 # suspend sta 3212 # suspend start 3547 elif(re.match !! 3213 elif(re.match('dpm_suspend\[.*', t.name)): 3548 phase 3214 phase = data.setPhase('suspend', t.time, isbegin) 3549 conti 3215 continue 3550 # suspend_lat 3216 # suspend_late start 3551 elif(re.match !! 3217 elif(re.match('dpm_suspend_late\[.*', t.name)): 3552 phase 3218 phase = data.setPhase('suspend_late', t.time, isbegin) 3553 conti 3219 continue 3554 # suspend_noi 3220 # suspend_noirq start 3555 elif(re.match !! 3221 elif(re.match('dpm_suspend_noirq\[.*', t.name)): 3556 phase 3222 phase = data.setPhase('suspend_noirq', t.time, isbegin) 3557 conti 3223 continue 3558 # suspend_mac 3224 # suspend_machine/resume_machine 3559 elif(re.match !! 3225 elif(re.match('machine_suspend\[.*', t.name)): 3560 lp = << 3561 if(is 3226 if(isbegin): 3562 !! 3227 lp = data.lastPhase() 3563 !! 3228 if lp == 'resume_machine': 3564 !! 3229 data.dmesg[lp]['end'] = t.time 3565 << 3566 << 3567 << 3568 << 3569 << 3570 << 3571 << 3572 << 3573 << 3574 << 3575 3230 phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True) 3576 3231 data.setPhase(phase, t.time, False) 3577 3232 if data.tSuspended == 0: 3578 3233 data.tSuspended = t.time 3579 else: 3234 else: 3580 << 3581 << 3582 << 3583 3235 phase = data.setPhase('resume_machine', t.time, True) 3584 3236 if(sysvals.suspendmode in ['mem', 'disk']): 3585 3237 susp = phase.replace('resume', 'suspend') 3586 3238 if susp in data.dmesg: 3587 3239 data.dmesg[susp]['end'] = t.time 3588 3240 data.tSuspended = t.time 3589 3241 data.tResumed = t.time 3590 conti 3242 continue 3591 # resume_noir 3243 # resume_noirq start 3592 elif(re.match !! 3244 elif(re.match('dpm_resume_noirq\[.*', t.name)): 3593 phase 3245 phase = data.setPhase('resume_noirq', t.time, isbegin) 3594 conti 3246 continue 3595 # resume_earl 3247 # resume_early start 3596 elif(re.match !! 3248 elif(re.match('dpm_resume_early\[.*', t.name)): 3597 phase 3249 phase = data.setPhase('resume_early', t.time, isbegin) 3598 conti 3250 continue 3599 # resume star 3251 # resume start 3600 elif(re.match !! 3252 elif(re.match('dpm_resume\[.*', t.name)): 3601 phase 3253 phase = data.setPhase('resume', t.time, isbegin) 3602 conti 3254 continue 3603 # resume comp 3255 # resume complete start 3604 elif(re.match !! 3256 elif(re.match('dpm_complete\[.*', t.name)): 3605 phase 3257 phase = data.setPhase('resume_complete', t.time, isbegin) 3606 conti 3258 continue 3607 # skip trace 3259 # skip trace events inside devices calls 3608 if(not data.i 3260 if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)): 3609 conti 3261 continue 3610 # global even 3262 # global events (outside device calls) are graphed 3611 if(name not i 3263 if(name not in testrun.ttemp): 3612 testr 3264 testrun.ttemp[name] = [] 3613 # special han << 3614 if name == 'm << 3615 if hw << 3616 << 3617 elif << 3618 << 3619 << 3620 << 3621 elif << 3622 << 3623 << 3624 << 3625 conti << 3626 if(isbegin): 3265 if(isbegin): 3627 # cre 3266 # create a new list entry 3628 testr 3267 testrun.ttemp[name].append(\ 3629 3268 {'begin': t.time, 'end': t.time, 'pid': pid}) 3630 else: 3269 else: 3631 if(le 3270 if(len(testrun.ttemp[name]) > 0): 3632 3271 # if an entry exists, assume this is its end 3633 3272 testrun.ttemp[name][-1]['end'] = t.time 3634 # device callback sta 3273 # device callback start 3635 elif(t.type == 'devic 3274 elif(t.type == 'device_pm_callback_start'): 3636 if phase not 3275 if phase not in data.dmesg: 3637 conti 3276 continue 3638 m = re.match( !! 3277 m = re.match('(?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*',\ 3639 t.nam 3278 t.name); 3640 if(not m): 3279 if(not m): 3641 conti 3280 continue 3642 drv = m.group 3281 drv = m.group('drv') 3643 n = m.group(' 3282 n = m.group('d') 3644 p = m.group(' 3283 p = m.group('p') 3645 if(n and p): 3284 if(n and p): 3646 data. 3285 data.newAction(phase, n, pid, p, t.time, -1, drv) 3647 if pi 3286 if pid not in data.devpids: 3648 3287 data.devpids.append(pid) 3649 # device callback fin 3288 # device callback finish 3650 elif(t.type == 'devic 3289 elif(t.type == 'device_pm_callback_end'): 3651 if phase not 3290 if phase not in data.dmesg: 3652 conti 3291 continue 3653 m = re.match( !! 3292 m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name); 3654 if(not m): 3293 if(not m): 3655 conti 3294 continue 3656 n = m.group(' 3295 n = m.group('d') 3657 dev = data.fi !! 3296 list = data.dmesg[phase]['list'] 3658 if dev: !! 3297 if(n in list): >> 3298 dev = list[n] 3659 dev[' 3299 dev['length'] = t.time - dev['start'] 3660 dev[' 3300 dev['end'] = t.time 3661 # kprobe event processing 3301 # kprobe event processing 3662 elif(t.fkprobe): 3302 elif(t.fkprobe): 3663 kprobename = t.type 3303 kprobename = t.type 3664 kprobedata = t.name 3304 kprobedata = t.name 3665 key = (kprobename, pi 3305 key = (kprobename, pid) 3666 # displayname is gene 3306 # displayname is generated from kprobe data 3667 displayname = '' 3307 displayname = '' 3668 if(t.fcall): 3308 if(t.fcall): 3669 displayname = 3309 displayname = sysvals.kprobeDisplayName(kprobename, kprobedata) 3670 if not displa 3310 if not displayname: 3671 conti 3311 continue 3672 if(key not in 3312 if(key not in tp.ktemp): 3673 tp.kt 3313 tp.ktemp[key] = [] 3674 tp.ktemp[key] 3314 tp.ktemp[key].append({ 3675 'pid' 3315 'pid': pid, 3676 'begi 3316 'begin': t.time, 3677 'end' 3317 'end': -1, 3678 'name 3318 'name': displayname, 3679 'cdat 3319 'cdata': kprobedata, 3680 'proc 3320 'proc': m_proc, 3681 }) 3321 }) 3682 # start of ke 3322 # start of kernel resume 3683 if(data.tKern !! 3323 if(phase == 'suspend_prepare' and kprobename in ksuscalls): 3684 and k << 3685 data. 3324 data.tKernSus = t.time 3686 elif(t.freturn): 3325 elif(t.freturn): 3687 if(key not in 3326 if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1: 3688 conti 3327 continue 3689 e = next((x f 3328 e = next((x for x in reversed(tp.ktemp[key]) if x['end'] < 0), 0) 3690 if not e: 3329 if not e: 3691 conti 3330 continue 3692 if (t.time - << 3693 tp.kt << 3694 conti << 3695 e['end'] = t. 3331 e['end'] = t.time 3696 e['rdata'] = 3332 e['rdata'] = kprobedata 3697 # end of kern 3333 # end of kernel resume 3698 if(phase != ' 3334 if(phase != 'suspend_prepare' and kprobename in krescalls): 3699 if ph 3335 if phase in data.dmesg: 3700 3336 data.dmesg[phase]['end'] = t.time 3701 data. 3337 data.tKernRes = t.time 3702 3338 3703 # callgraph processing 3339 # callgraph processing 3704 elif sysvals.usecallgraph: 3340 elif sysvals.usecallgraph: 3705 # create a callgraph 3341 # create a callgraph object for the data 3706 key = (m_proc, pid) 3342 key = (m_proc, pid) 3707 if(key not in testrun 3343 if(key not in testrun.ftemp): 3708 testrun.ftemp 3344 testrun.ftemp[key] = [] 3709 testrun.ftemp 3345 testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 3710 # when the call is fi 3346 # when the call is finished, see which device matches it 3711 cg = testrun.ftemp[ke 3347 cg = testrun.ftemp[key][-1] 3712 res = cg.addLine(t) 3348 res = cg.addLine(t) 3713 if(res != 0): 3349 if(res != 0): 3714 testrun.ftemp 3350 testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 3715 if(res == -1): 3351 if(res == -1): 3716 testrun.ftemp 3352 testrun.ftemp[key][-1].addLine(t) >> 3353 tf.close() 3717 if len(testdata) < 1: 3354 if len(testdata) < 1: 3718 sysvals.vprint('WARNING: ftra 3355 sysvals.vprint('WARNING: ftrace start marker is missing') 3719 if data and not data.devicegroups: 3356 if data and not data.devicegroups: 3720 sysvals.vprint('WARNING: ftra 3357 sysvals.vprint('WARNING: ftrace end marker is missing') 3721 data.handleEndMarker(t.time, !! 3358 data.handleEndMarker(t.time) 3722 3359 3723 if sysvals.suspendmode == 'command': 3360 if sysvals.suspendmode == 'command': 3724 for test in testruns: 3361 for test in testruns: 3725 for p in test.data.so 3362 for p in test.data.sortedPhases(): 3726 if p == 'susp 3363 if p == 'suspend_prepare': 3727 test. 3364 test.data.dmesg[p]['start'] = test.data.start 3728 test. 3365 test.data.dmesg[p]['end'] = test.data.end 3729 else: 3366 else: 3730 test. 3367 test.data.dmesg[p]['start'] = test.data.end 3731 test. 3368 test.data.dmesg[p]['end'] = test.data.end 3732 test.data.tSuspended 3369 test.data.tSuspended = test.data.end 3733 test.data.tResumed = 3370 test.data.tResumed = test.data.end 3734 test.data.fwValid = F 3371 test.data.fwValid = False 3735 3372 3736 # dev source and procmon events can b 3373 # dev source and procmon events can be unreadable with mixed phase height 3737 if sysvals.usedevsrc or sysvals.usepr 3374 if sysvals.usedevsrc or sysvals.useprocmon: 3738 sysvals.mixedphaseheight = Fa 3375 sysvals.mixedphaseheight = False 3739 3376 3740 # expand phase boundaries so there ar 3377 # expand phase boundaries so there are no gaps 3741 for data in testdata: 3378 for data in testdata: 3742 lp = data.sortedPhases()[0] 3379 lp = data.sortedPhases()[0] 3743 for p in data.sortedPhases(): 3380 for p in data.sortedPhases(): 3744 if(p != lp and not (' 3381 if(p != lp and not ('machine' in p and 'machine' in lp)): 3745 data.dmesg[lp 3382 data.dmesg[lp]['end'] = data.dmesg[p]['start'] 3746 lp = p 3383 lp = p 3747 3384 3748 for i in range(len(testruns)): 3385 for i in range(len(testruns)): 3749 test = testruns[i] 3386 test = testruns[i] 3750 data = test.data 3387 data = test.data 3751 # find the total time range f 3388 # find the total time range for this test (begin, end) 3752 tlb, tle = data.start, data.e 3389 tlb, tle = data.start, data.end 3753 if i < len(testruns) - 1: 3390 if i < len(testruns) - 1: 3754 tle = testruns[i+1].d 3391 tle = testruns[i+1].data.start 3755 # add the process usage data 3392 # add the process usage data to the timeline 3756 if sysvals.useprocmon: 3393 if sysvals.useprocmon: 3757 data.createProcessUsa 3394 data.createProcessUsageEvents() 3758 # add the traceevent data to 3395 # add the traceevent data to the device hierarchy 3759 if(sysvals.usetraceevents): 3396 if(sysvals.usetraceevents): 3760 # add actual trace fu 3397 # add actual trace funcs 3761 for name in sorted(te 3398 for name in sorted(test.ttemp): 3762 for event in 3399 for event in test.ttemp[name]: 3763 if ev !! 3400 data.newActionGlobal(name, event['begin'], event['end'], event['pid']) 3764 << 3765 title << 3766 if na << 3767 << 3768 data. << 3769 # add the kprobe base 3401 # add the kprobe based virtual tracefuncs as actual devices 3770 for key in sorted(tp. 3402 for key in sorted(tp.ktemp): 3771 name, pid = k 3403 name, pid = key 3772 if name not i 3404 if name not in sysvals.tracefuncs: 3773 conti 3405 continue 3774 if pid not in 3406 if pid not in data.devpids: 3775 data. 3407 data.devpids.append(pid) 3776 for e in tp.k 3408 for e in tp.ktemp[key]: 3777 kb, k 3409 kb, ke = e['begin'], e['end'] 3778 if ke 3410 if ke - kb < 0.000001 or tlb > kb or tle <= kb: 3779 3411 continue 3780 color 3412 color = sysvals.kprobeColor(name) 3781 data. 3413 data.newActionGlobal(e['name'], kb, ke, pid, color) 3782 # add config base kpr 3414 # add config base kprobes and dev kprobes 3783 if sysvals.usedevsrc: 3415 if sysvals.usedevsrc: 3784 for key in so 3416 for key in sorted(tp.ktemp): 3785 name, 3417 name, pid = key 3786 if na 3418 if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs: 3787 3419 continue 3788 for e 3420 for e in tp.ktemp[key]: 3789 3421 kb, ke = e['begin'], e['end'] 3790 3422 if ke - kb < 0.000001 or tlb > kb or tle <= kb: 3791 3423 continue 3792 3424 data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb, 3793 3425 ke, e['cdata'], e['rdata']) 3794 if sysvals.usecallgraph: 3426 if sysvals.usecallgraph: 3795 # add the callgraph d 3427 # add the callgraph data to the device hierarchy 3796 sortlist = dict() 3428 sortlist = dict() 3797 for key in sorted(tes 3429 for key in sorted(test.ftemp): 3798 proc, pid = k 3430 proc, pid = key 3799 for cg in tes 3431 for cg in test.ftemp[key]: 3800 if le 3432 if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 3801 3433 continue 3802 if(no 3434 if(not cg.postProcess()): 3803 3435 id = 'task %s' % (pid) 3804 3436 sysvals.vprint('Sanity check failed for '+\ 3805 3437 id+', ignoring this callback') 3806 3438 continue 3807 # mat 3439 # match cg data to devices 3808 devna 3440 devname = '' 3809 if sy 3441 if sysvals.suspendmode != 'command': 3810 3442 devname = cg.deviceMatch(pid, data) 3811 if no 3443 if not devname: 3812 3444 sortkey = '%f%f%d' % (cg.start, cg.end, pid) 3813 3445 sortlist[sortkey] = cg 3814 elif 3446 elif len(cg.list) > 1000000 and cg.name != sysvals.ftopfunc: 3815 3447 sysvals.vprint('WARNING: the callgraph for %s is massive (%d lines)' %\ 3816 3448 (devname, len(cg.list))) 3817 # create blocks for o 3449 # create blocks for orphan cg data 3818 for sortkey in sorted 3450 for sortkey in sorted(sortlist): 3819 cg = sortlist 3451 cg = sortlist[sortkey] 3820 name = cg.nam 3452 name = cg.name 3821 if sysvals.is 3453 if sysvals.isCallgraphFunc(name): 3822 sysva 3454 sysvals.vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name)) 3823 cg.ne 3455 cg.newActionFromFunction(data) 3824 if sysvals.suspendmode == 'command': 3456 if sysvals.suspendmode == 'command': 3825 return (testdata, '') 3457 return (testdata, '') 3826 3458 3827 # fill in any missing phases 3459 # fill in any missing phases 3828 error = [] 3460 error = [] 3829 for data in testdata: 3461 for data in testdata: 3830 tn = '' if len(testdata) == 1 3462 tn = '' if len(testdata) == 1 else ('%d' % (data.testnumber + 1)) 3831 terr = '' 3463 terr = '' 3832 phasedef = data.phasedef 3464 phasedef = data.phasedef 3833 lp = 'suspend_prepare' 3465 lp = 'suspend_prepare' 3834 for p in sorted(phasedef, key 3466 for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 3835 if p not in data.dmes 3467 if p not in data.dmesg: 3836 if not terr: 3468 if not terr: 3837 ph = !! 3469 pprint('TEST%s FAILED: %s failed in %s phase' % (tn, sysvals.suspendmode, lp)) 3838 if p !! 3470 terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, lp) 3839 << 3840 << 3841 << 3842 << 3843 else: << 3844 << 3845 pprin << 3846 error 3471 error.append(terr) 3847 if da 3472 if data.tSuspended == 0: 3848 3473 data.tSuspended = data.dmesg[lp]['end'] 3849 if da 3474 if data.tResumed == 0: 3850 3475 data.tResumed = data.dmesg[lp]['end'] 3851 data. 3476 data.fwValid = False 3852 sysvals.vprin 3477 sysvals.vprint('WARNING: phase "%s" is missing!' % p) 3853 lp = p 3478 lp = p 3854 if not terr and 'dev' in data << 3855 terr = '%s%s failed i << 3856 (sysvals.susp << 3857 error.append(terr) << 3858 if not terr and data.enterfai 3479 if not terr and data.enterfail: 3859 pprint('test%s FAILED 3480 pprint('test%s FAILED: enter %s failed with %s' % (tn, sysvals.suspendmode, data.enterfail)) 3860 terr = 'test%s failed 3481 terr = 'test%s failed to enter %s mode' % (tn, sysvals.suspendmode) 3861 error.append(terr) 3482 error.append(terr) 3862 if data.tSuspended == 0: 3483 if data.tSuspended == 0: 3863 data.tSuspended = dat 3484 data.tSuspended = data.tKernRes 3864 if data.tResumed == 0: 3485 if data.tResumed == 0: 3865 data.tResumed = data. 3486 data.tResumed = data.tSuspended 3866 3487 3867 if(len(sysvals.devicefilter) 3488 if(len(sysvals.devicefilter) > 0): 3868 data.deviceFilter(sys 3489 data.deviceFilter(sysvals.devicefilter) 3869 data.fixupInitcallsThatDidntR 3490 data.fixupInitcallsThatDidntReturn() 3870 if sysvals.usedevsrc: 3491 if sysvals.usedevsrc: 3871 data.optimizeDevSrc() 3492 data.optimizeDevSrc() 3872 3493 3873 # x2: merge any overlapping devices b 3494 # x2: merge any overlapping devices between test runs 3874 if sysvals.usedevsrc and len(testdata 3495 if sysvals.usedevsrc and len(testdata) > 1: 3875 tc = len(testdata) 3496 tc = len(testdata) 3876 for i in range(tc - 1): 3497 for i in range(tc - 1): 3877 devlist = testdata[i] 3498 devlist = testdata[i].overflowDevices() 3878 for j in range(i + 1, 3499 for j in range(i + 1, tc): 3879 testdata[j].m 3500 testdata[j].mergeOverlapDevices(devlist) 3880 testdata[0].stitchTouchingThr 3501 testdata[0].stitchTouchingThreads(testdata[1:]) 3881 return (testdata, ', '.join(error)) 3502 return (testdata, ', '.join(error)) 3882 3503 3883 # Function: loadKernelLog 3504 # Function: loadKernelLog 3884 # Description: 3505 # Description: >> 3506 # [deprecated for kernel 3.15.0 or newer] 3885 # load the dmesg file into memory and 3507 # load the dmesg file into memory and fix up any ordering issues >> 3508 # The dmesg filename is taken from sysvals 3886 # Output: 3509 # Output: 3887 # An array of empty Data objects with 3510 # An array of empty Data objects with only their dmesgtext attributes set 3888 def loadKernelLog(): 3511 def loadKernelLog(): 3889 sysvals.vprint('Analyzing the dmesg d 3512 sysvals.vprint('Analyzing the dmesg data (%s)...' % \ 3890 os.path.basename(sysvals.dmes 3513 os.path.basename(sysvals.dmesgfile)) 3891 if(os.path.exists(sysvals.dmesgfile) 3514 if(os.path.exists(sysvals.dmesgfile) == False): 3892 doError('%s does not exist' % 3515 doError('%s does not exist' % sysvals.dmesgfile) 3893 3516 3894 # there can be multiple test runs in 3517 # there can be multiple test runs in a single file 3895 tp = TestProps() 3518 tp = TestProps() 3896 tp.stamp = datetime.now().strftime('# 3519 tp.stamp = datetime.now().strftime('# suspend-%m%d%y-%H%M%S localhost mem unknown') 3897 testruns = [] 3520 testruns = [] 3898 data = 0 3521 data = 0 3899 lf = sysvals.openlog(sysvals.dmesgfil 3522 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 3900 for line in lf: 3523 for line in lf: 3901 line = line.replace('\r\n', ' 3524 line = line.replace('\r\n', '') 3902 idx = line.find('[') 3525 idx = line.find('[') 3903 if idx > 1: 3526 if idx > 1: 3904 line = line[idx:] 3527 line = line[idx:] 3905 if tp.stampInfo(line, sysvals !! 3528 if tp.stampInfo(line): 3906 continue 3529 continue 3907 m = re.match(r'[ \t]*(\[ *)(? !! 3530 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 3908 if(not m): 3531 if(not m): 3909 continue 3532 continue 3910 msg = m.group("msg") 3533 msg = m.group("msg") 3911 if re.match(r'PM: Syncing fil !! 3534 if(re.match('PM: Syncing filesystems.*', msg)): 3912 re.match(r'PM: suspen << 3913 if(data): 3535 if(data): 3914 testruns.appe 3536 testruns.append(data) 3915 data = Data(len(testr 3537 data = Data(len(testruns)) 3916 tp.parseStamp(data, s 3538 tp.parseStamp(data, sysvals) 3917 if(not data): 3539 if(not data): 3918 continue 3540 continue 3919 m = re.match(r'.* *(?P<k>[0-9 !! 3541 m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg) 3920 if(m): 3542 if(m): 3921 sysvals.stamp['kernel 3543 sysvals.stamp['kernel'] = m.group('k') 3922 m = re.match(r'PM: Preparing !! 3544 m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg) 3923 if not m: !! 3545 if(m): 3924 m = re.match(r'PM: Pr << 3925 if m: << 3926 sysvals.stamp['mode'] 3546 sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m') 3927 data.dmesgtext.append(line) 3547 data.dmesgtext.append(line) 3928 lf.close() 3548 lf.close() 3929 3549 3930 if sysvals.suspendmode == 's2idle': << 3931 sysvals.suspendmode = 'freeze << 3932 elif sysvals.suspendmode == 'deep': << 3933 sysvals.suspendmode = 'mem' << 3934 if data: 3550 if data: 3935 testruns.append(data) 3551 testruns.append(data) 3936 if len(testruns) < 1: 3552 if len(testruns) < 1: 3937 doError('dmesg log has no sus 3553 doError('dmesg log has no suspend/resume data: %s' \ 3938 % sysvals.dmesgfile) 3554 % sysvals.dmesgfile) 3939 3555 3940 # fix lines with same timestamp/funct 3556 # fix lines with same timestamp/function with the call and return swapped 3941 for data in testruns: 3557 for data in testruns: 3942 last = '' 3558 last = '' 3943 for line in data.dmesgtext: 3559 for line in data.dmesgtext: 3944 ct, cf, n, p = data.i !! 3560 mc = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling '+\ 3945 rt, rf, l = data.init !! 3561 '(?P<f>.*)\+ @ .*, parent: .*', line) 3946 if ct and rt and ct = !! 3562 mr = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\ >> 3563 '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', last) >> 3564 if(mc and mr and (mc.group('t') == mr.group('t')) and >> 3565 (mc.group('f') == mr.group('f'))): 3947 i = data.dmes 3566 i = data.dmesgtext.index(last) 3948 j = data.dmes 3567 j = data.dmesgtext.index(line) 3949 data.dmesgtex 3568 data.dmesgtext[i] = line 3950 data.dmesgtex 3569 data.dmesgtext[j] = last 3951 last = line 3570 last = line 3952 return testruns 3571 return testruns 3953 3572 3954 # Function: parseKernelLog 3573 # Function: parseKernelLog 3955 # Description: 3574 # Description: >> 3575 # [deprecated for kernel 3.15.0 or newer] 3956 # Analyse a dmesg log output file gene 3576 # Analyse a dmesg log output file generated from this app during 3957 # the execution phase. Create a set of 3577 # the execution phase. Create a set of device structures in memory 3958 # for subsequent formatting in the htm 3578 # for subsequent formatting in the html output file 3959 # This call is only for legacy support 3579 # This call is only for legacy support on kernels where the ftrace 3960 # data lacks the suspend_resume or dev 3580 # data lacks the suspend_resume or device_pm_callbacks trace events. 3961 # Arguments: 3581 # Arguments: 3962 # data: an empty Data object (with dme 3582 # data: an empty Data object (with dmesgtext) obtained from loadKernelLog 3963 # Output: 3583 # Output: 3964 # The filled Data object 3584 # The filled Data object 3965 def parseKernelLog(data): 3585 def parseKernelLog(data): 3966 phase = 'suspend_runtime' 3586 phase = 'suspend_runtime' 3967 3587 3968 if(data.fwValid): 3588 if(data.fwValid): 3969 sysvals.vprint('Firmware Susp 3589 sysvals.vprint('Firmware Suspend = %u ns, Firmware Resume = %u ns' % \ 3970 (data.fwSuspend, data 3590 (data.fwSuspend, data.fwResume)) 3971 3591 3972 # dmesg phase match table 3592 # dmesg phase match table 3973 dm = { 3593 dm = { 3974 'suspend_prepare': ['PM: Sync !! 3594 'suspend_prepare': ['PM: Syncing filesystems.*'], 3975 'suspend': ['PM: Ente !! 3595 'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*'], 3976 'PM: Susp !! 3596 'suspend_late': ['PM: suspend of devices complete after.*'], 3977 'suspend_late': ['PM: susp !! 3597 'suspend_noirq': ['PM: late suspend of devices complete after.*'], 3978 !! 3598 'suspend_machine': ['PM: noirq suspend of devices complete after.*'], 3979 'suspend_noirq': ['PM: late !! 3599 'resume_machine': ['ACPI: Low-level resume complete.*'], 3980 !! 3600 'resume_noirq': ['ACPI: Waking up from system sleep state.*'], 3981 'suspend_machine': ['PM: susp !! 3601 'resume_early': ['PM: noirq resume of devices complete after.*'], 3982 !! 3602 'resume': ['PM: early resume of devices complete after.*'], 3983 !! 3603 'resume_complete': ['PM: resume of devices complete after.*'], 3984 'resume_machine': ['[PM: ]*T !! 3604 'post_resume': ['.*Restarting tasks \.\.\..*'], 3985 << 3986 << 3987 << 3988 'resume_noirq': ['PM: resu << 3989 << 3990 'resume_early': ['PM: noir << 3991 << 3992 'resume': ['PM: earl << 3993 << 3994 'resume_complete': ['PM: resu << 3995 << 3996 'post_resume': [r'.*Resta << 3997 } 3605 } >> 3606 if(sysvals.suspendmode == 'standby'): >> 3607 dm['resume_machine'] = ['PM: Restoring platform NVS memory'] >> 3608 elif(sysvals.suspendmode == 'disk'): >> 3609 dm['suspend_late'] = ['PM: freeze of devices complete after.*'] >> 3610 dm['suspend_noirq'] = ['PM: late freeze of devices complete after.*'] >> 3611 dm['suspend_machine'] = ['PM: noirq freeze of devices complete after.*'] >> 3612 dm['resume_machine'] = ['PM: Restoring platform NVS memory'] >> 3613 dm['resume_early'] = ['PM: noirq restore of devices complete after.*'] >> 3614 dm['resume'] = ['PM: early restore of devices complete after.*'] >> 3615 dm['resume_complete'] = ['PM: restore of devices complete after.*'] >> 3616 elif(sysvals.suspendmode == 'freeze'): >> 3617 dm['resume_machine'] = ['ACPI: resume from mwait'] 3998 3618 3999 # action table (expected events that 3619 # action table (expected events that occur and show up in dmesg) 4000 at = { 3620 at = { 4001 'sync_filesystems': { 3621 'sync_filesystems': { 4002 'smsg': '.*[Ff]+ilesy !! 3622 'smsg': 'PM: Syncing filesystems.*', 4003 'emsg': 'PM: Preparin !! 3623 'emsg': 'PM: Preparing system for mem sleep.*' }, 4004 'freeze_user_processes': { 3624 'freeze_user_processes': { 4005 'smsg': 'Freezing use !! 3625 'smsg': 'Freezing user space processes .*', 4006 'emsg': 'Freezing rem 3626 'emsg': 'Freezing remaining freezable tasks.*' }, 4007 'freeze_tasks': { 3627 'freeze_tasks': { 4008 'smsg': 'Freezing rem 3628 'smsg': 'Freezing remaining freezable tasks.*', 4009 'emsg': 'PM: Suspendi !! 3629 'emsg': 'PM: Entering (?P<mode>[a-z,A-Z]*) sleep.*' }, 4010 'ACPI prepare': { 3630 'ACPI prepare': { 4011 'smsg': 'ACPI: Prepar 3631 'smsg': 'ACPI: Preparing to enter system sleep state.*', 4012 'emsg': 'PM: Saving p 3632 'emsg': 'PM: Saving platform NVS memory.*' }, 4013 'PM vns': { 3633 'PM vns': { 4014 'smsg': 'PM: Saving p 3634 'smsg': 'PM: Saving platform NVS memory.*', 4015 'emsg': 'Disabling no 3635 'emsg': 'Disabling non-boot CPUs .*' }, 4016 } 3636 } 4017 3637 4018 t0 = -1.0 3638 t0 = -1.0 4019 cpu_start = -1.0 3639 cpu_start = -1.0 4020 prevktime = -1.0 3640 prevktime = -1.0 4021 actions = dict() 3641 actions = dict() 4022 for line in data.dmesgtext: 3642 for line in data.dmesgtext: 4023 # parse each dmesg line into 3643 # parse each dmesg line into the time and message 4024 m = re.match(r'[ \t]*(\[ *)(? !! 3644 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 4025 if(m): 3645 if(m): 4026 val = m.group('ktime' 3646 val = m.group('ktime') 4027 try: 3647 try: 4028 ktime = float 3648 ktime = float(val) 4029 except: 3649 except: 4030 continue 3650 continue 4031 msg = m.group('msg') 3651 msg = m.group('msg') 4032 # initialize data sta 3652 # initialize data start to first line time 4033 if t0 < 0: 3653 if t0 < 0: 4034 data.setStart 3654 data.setStart(ktime) 4035 t0 = ktime 3655 t0 = ktime 4036 else: 3656 else: 4037 continue 3657 continue 4038 3658 4039 # check for a phase change li 3659 # check for a phase change line 4040 phasechange = False 3660 phasechange = False 4041 for p in dm: 3661 for p in dm: 4042 for s in dm[p]: 3662 for s in dm[p]: 4043 if(re.match(s 3663 if(re.match(s, msg)): 4044 phase 3664 phasechange, phase = True, p 4045 dm[p] << 4046 break 3665 break 4047 3666 4048 # hack for determining resume 3667 # hack for determining resume_machine end for freeze 4049 if(not sysvals.usetraceevents 3668 if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \ 4050 and phase == 'resume_ 3669 and phase == 'resume_machine' and \ 4051 data.initcall_debug_c !! 3670 re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): 4052 data.setPhase(phase, 3671 data.setPhase(phase, ktime, False) 4053 phase = 'resume_noirq 3672 phase = 'resume_noirq' 4054 data.setPhase(phase, 3673 data.setPhase(phase, ktime, True) 4055 3674 4056 if phasechange: 3675 if phasechange: 4057 if phase == 'suspend_ 3676 if phase == 'suspend_prepare': 4058 data.setPhase 3677 data.setPhase(phase, ktime, True) 4059 data.setStart 3678 data.setStart(ktime) 4060 data.tKernSus 3679 data.tKernSus = ktime 4061 elif phase == 'suspen 3680 elif phase == 'suspend': 4062 lp = data.las 3681 lp = data.lastPhase() 4063 if lp: 3682 if lp: 4064 data. 3683 data.setPhase(lp, ktime, False) 4065 data.setPhase 3684 data.setPhase(phase, ktime, True) 4066 elif phase == 'suspen 3685 elif phase == 'suspend_late': 4067 lp = data.las 3686 lp = data.lastPhase() 4068 if lp: 3687 if lp: 4069 data. 3688 data.setPhase(lp, ktime, False) 4070 data.setPhase 3689 data.setPhase(phase, ktime, True) 4071 elif phase == 'suspen 3690 elif phase == 'suspend_noirq': 4072 lp = data.las 3691 lp = data.lastPhase() 4073 if lp: 3692 if lp: 4074 data. 3693 data.setPhase(lp, ktime, False) 4075 data.setPhase 3694 data.setPhase(phase, ktime, True) 4076 elif phase == 'suspen 3695 elif phase == 'suspend_machine': 4077 lp = data.las 3696 lp = data.lastPhase() 4078 if lp: 3697 if lp: 4079 data. 3698 data.setPhase(lp, ktime, False) 4080 data.setPhase 3699 data.setPhase(phase, ktime, True) 4081 elif phase == 'resume 3700 elif phase == 'resume_machine': 4082 lp = data.las 3701 lp = data.lastPhase() 4083 if(sysvals.su 3702 if(sysvals.suspendmode in ['freeze', 'standby']): 4084 data. 3703 data.tSuspended = prevktime 4085 if lp 3704 if lp: 4086 3705 data.setPhase(lp, prevktime, False) 4087 else: 3706 else: 4088 data. 3707 data.tSuspended = ktime 4089 if lp 3708 if lp: 4090 3709 data.setPhase(lp, prevktime, False) 4091 data.tResumed 3710 data.tResumed = ktime 4092 data.setPhase 3711 data.setPhase(phase, ktime, True) 4093 elif phase == 'resume 3712 elif phase == 'resume_noirq': 4094 lp = data.las 3713 lp = data.lastPhase() 4095 if lp: 3714 if lp: 4096 data. 3715 data.setPhase(lp, ktime, False) 4097 data.setPhase 3716 data.setPhase(phase, ktime, True) 4098 elif phase == 'resume 3717 elif phase == 'resume_early': 4099 lp = data.las 3718 lp = data.lastPhase() 4100 if lp: 3719 if lp: 4101 data. 3720 data.setPhase(lp, ktime, False) 4102 data.setPhase 3721 data.setPhase(phase, ktime, True) 4103 elif phase == 'resume 3722 elif phase == 'resume': 4104 lp = data.las 3723 lp = data.lastPhase() 4105 if lp: 3724 if lp: 4106 data. 3725 data.setPhase(lp, ktime, False) 4107 data.setPhase 3726 data.setPhase(phase, ktime, True) 4108 elif phase == 'resume 3727 elif phase == 'resume_complete': 4109 lp = data.las 3728 lp = data.lastPhase() 4110 if lp: 3729 if lp: 4111 data. 3730 data.setPhase(lp, ktime, False) 4112 data.setPhase 3731 data.setPhase(phase, ktime, True) 4113 elif phase == 'post_r 3732 elif phase == 'post_resume': 4114 lp = data.las 3733 lp = data.lastPhase() 4115 if lp: 3734 if lp: 4116 data. 3735 data.setPhase(lp, ktime, False) 4117 data.setEnd(k 3736 data.setEnd(ktime) 4118 data.tKernRes 3737 data.tKernRes = ktime 4119 break 3738 break 4120 3739 4121 # -- device callbacks -- 3740 # -- device callbacks -- 4122 if(phase in data.sortedPhases 3741 if(phase in data.sortedPhases()): 4123 # device init call 3742 # device init call 4124 t, f, n, p = data.ini !! 3743 if(re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): 4125 if t and f and n and !! 3744 sm = re.match('calling (?P<f>.*)\+ @ '+\ 4126 data.newActio !! 3745 '(?P<n>.*), parent: (?P<p>.*)', msg); 4127 else: !! 3746 f = sm.group('f') 4128 # device init !! 3747 n = sm.group('n') 4129 t, f, l = dat !! 3748 p = sm.group('p') 4130 if t and f an !! 3749 if(f and n and p): 4131 list !! 3750 data.newAction(phase, f, int(n), p, ktime, -1, '') 4132 if(f !! 3751 # device init return 4133 !! 3752 elif(re.match('call (?P<f>.*)\+ returned .* after '+\ 4134 !! 3753 '(?P<t>.*) usecs', msg)): 4135 !! 3754 sm = re.match('call (?P<f>.*)\+ returned .* after '+\ >> 3755 '(?P<t>.*) usecs(?P<a>.*)', msg); >> 3756 f = sm.group('f') >> 3757 t = sm.group('t') >> 3758 list = data.dmesg[phase]['list'] >> 3759 if(f in list): >> 3760 dev = list[f] >> 3761 dev['length'] = int(t) >> 3762 dev['end'] = ktime 4136 3763 4137 # if trace events are not ava 3764 # if trace events are not available, these are better than nothing 4138 if(not sysvals.usetraceevents 3765 if(not sysvals.usetraceevents): 4139 # look for known acti 3766 # look for known actions 4140 for a in sorted(at): 3767 for a in sorted(at): 4141 if(re.match(a 3768 if(re.match(at[a]['smsg'], msg)): 4142 if(a 3769 if(a not in actions): 4143 !! 3770 actions[a] = [] >> 3771 actions[a].append({'begin': ktime, 'end': ktime}) 4144 if(re.match(a 3772 if(re.match(at[a]['emsg'], msg)): 4145 if(a !! 3773 if(a in actions): 4146 3774 actions[a][-1]['end'] = ktime 4147 # now look for CPU on 3775 # now look for CPU on/off events 4148 if(re.match(r'Disabli !! 3776 if(re.match('Disabling non-boot CPUs .*', msg)): 4149 # start of fi 3777 # start of first cpu suspend 4150 cpu_start = k 3778 cpu_start = ktime 4151 elif(re.match(r'Enabl !! 3779 elif(re.match('Enabling non-boot CPUs .*', msg)): 4152 # start of fi 3780 # start of first cpu resume 4153 cpu_start = k 3781 cpu_start = ktime 4154 elif(re.match(r'smpbo !! 3782 elif(re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg)): 4155 or re.match(r << 4156 # end of a cp 3783 # end of a cpu suspend, start of the next 4157 m = re.match( !! 3784 m = re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg) 4158 if(not m): << 4159 m = r << 4160 cpu = 'CPU'+m 3785 cpu = 'CPU'+m.group('cpu') 4161 if(cpu not in 3786 if(cpu not in actions): 4162 actio 3787 actions[cpu] = [] 4163 actions[cpu]. 3788 actions[cpu].append({'begin': cpu_start, 'end': ktime}) 4164 cpu_start = k 3789 cpu_start = ktime 4165 elif(re.match(r'CPU(? !! 3790 elif(re.match('CPU(?P<cpu>[0-9]*) is up', msg)): 4166 # end of a cp 3791 # end of a cpu resume, start of the next 4167 m = re.match( !! 3792 m = re.match('CPU(?P<cpu>[0-9]*) is up', msg) 4168 cpu = 'CPU'+m 3793 cpu = 'CPU'+m.group('cpu') 4169 if(cpu not in 3794 if(cpu not in actions): 4170 actio 3795 actions[cpu] = [] 4171 actions[cpu]. 3796 actions[cpu].append({'begin': cpu_start, 'end': ktime}) 4172 cpu_start = k 3797 cpu_start = ktime 4173 prevktime = ktime 3798 prevktime = ktime 4174 data.initDevicegroups() 3799 data.initDevicegroups() 4175 3800 4176 # fill in any missing phases 3801 # fill in any missing phases 4177 phasedef = data.phasedef 3802 phasedef = data.phasedef 4178 terr, lp = '', 'suspend_prepare' 3803 terr, lp = '', 'suspend_prepare' 4179 if lp not in data.dmesg: << 4180 doError('dmesg log format has << 4181 for p in sorted(phasedef, key=lambda 3804 for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 4182 if p not in data.dmesg: 3805 if p not in data.dmesg: 4183 if not terr: 3806 if not terr: 4184 pprint('TEST 3807 pprint('TEST FAILED: %s failed in %s phase' % (sysvals.suspendmode, lp)) 4185 terr = '%s fa 3808 terr = '%s failed in %s phase' % (sysvals.suspendmode, lp) 4186 if data.tSusp 3809 if data.tSuspended == 0: 4187 data. 3810 data.tSuspended = data.dmesg[lp]['end'] 4188 if data.tResu 3811 if data.tResumed == 0: 4189 data. 3812 data.tResumed = data.dmesg[lp]['end'] 4190 sysvals.vprint('WARNI 3813 sysvals.vprint('WARNING: phase "%s" is missing!' % p) 4191 lp = p 3814 lp = p 4192 lp = data.sortedPhases()[0] 3815 lp = data.sortedPhases()[0] 4193 for p in data.sortedPhases(): 3816 for p in data.sortedPhases(): 4194 if(p != lp and not ('machine' 3817 if(p != lp and not ('machine' in p and 'machine' in lp)): 4195 data.dmesg[lp]['end'] 3818 data.dmesg[lp]['end'] = data.dmesg[p]['start'] 4196 lp = p 3819 lp = p 4197 if data.tSuspended == 0: 3820 if data.tSuspended == 0: 4198 data.tSuspended = data.tKernR 3821 data.tSuspended = data.tKernRes 4199 if data.tResumed == 0: 3822 if data.tResumed == 0: 4200 data.tResumed = data.tSuspend 3823 data.tResumed = data.tSuspended 4201 3824 4202 # fill in any actions we've found 3825 # fill in any actions we've found 4203 for name in sorted(actions): 3826 for name in sorted(actions): 4204 for event in actions[name]: 3827 for event in actions[name]: 4205 data.newActionGlobal( 3828 data.newActionGlobal(name, event['begin'], event['end']) 4206 3829 4207 if(len(sysvals.devicefilter) > 0): 3830 if(len(sysvals.devicefilter) > 0): 4208 data.deviceFilter(sysvals.dev 3831 data.deviceFilter(sysvals.devicefilter) 4209 data.fixupInitcallsThatDidntReturn() 3832 data.fixupInitcallsThatDidntReturn() 4210 return True 3833 return True 4211 3834 4212 def callgraphHTML(sv, hf, num, cg, title, col 3835 def callgraphHTML(sv, hf, num, cg, title, color, devid): 4213 html_func_top = '<article id="{0}" cl 3836 html_func_top = '<article id="{0}" class="atop" style="background:{1}">\n<input type="checkbox" class="pf" id="f{2}" checked/><label for="f{2}">{3} {4}</label>\n' 4214 html_func_start = '<article>\n<input 3837 html_func_start = '<article>\n<input type="checkbox" class="pf" id="f{0}" checked/><label for="f{0}">{1} {2}</label>\n' 4215 html_func_end = '</article>\n' 3838 html_func_end = '</article>\n' 4216 html_func_leaf = '<article>{0} {1}</a 3839 html_func_leaf = '<article>{0} {1}</article>\n' 4217 3840 4218 cgid = devid 3841 cgid = devid 4219 if cg.id: 3842 if cg.id: 4220 cgid += cg.id 3843 cgid += cg.id 4221 cglen = (cg.end - cg.start) * 1000 3844 cglen = (cg.end - cg.start) * 1000 4222 if cglen < sv.mincglen: 3845 if cglen < sv.mincglen: 4223 return num 3846 return num 4224 3847 4225 fmt = '<r>(%.3f ms @ '+sv.timeformat+' 3848 fmt = '<r>(%.3f ms @ '+sv.timeformat+' to '+sv.timeformat+')</r>' 4226 flen = fmt % (cglen, cg.start, cg.end 3849 flen = fmt % (cglen, cg.start, cg.end) 4227 hf.write(html_func_top.format(cgid, c 3850 hf.write(html_func_top.format(cgid, color, num, title, flen)) 4228 num += 1 3851 num += 1 4229 for line in cg.list: 3852 for line in cg.list: 4230 if(line.length < 0.000000001) 3853 if(line.length < 0.000000001): 4231 flen = '' 3854 flen = '' 4232 else: 3855 else: 4233 fmt = '<n>(%.3f ms @ ' 3856 fmt = '<n>(%.3f ms @ '+sv.timeformat+')</n>' 4234 flen = fmt % (line.le 3857 flen = fmt % (line.length*1000, line.time) 4235 if line.isLeaf(): 3858 if line.isLeaf(): 4236 if line.length * 1000 << 4237 continue << 4238 hf.write(html_func_le 3859 hf.write(html_func_leaf.format(line.name, flen)) 4239 elif line.freturn: 3860 elif line.freturn: 4240 hf.write(html_func_en 3861 hf.write(html_func_end) 4241 else: 3862 else: 4242 hf.write(html_func_st 3863 hf.write(html_func_start.format(num, line.name, flen)) 4243 num += 1 3864 num += 1 4244 hf.write(html_func_end) 3865 hf.write(html_func_end) 4245 return num 3866 return num 4246 3867 4247 def addCallgraphs(sv, hf, data): 3868 def addCallgraphs(sv, hf, data): 4248 hf.write('<section id="callgraphs" cl 3869 hf.write('<section id="callgraphs" class="callgraph">\n') 4249 # write out the ftrace data converted 3870 # write out the ftrace data converted to html 4250 num = 0 3871 num = 0 4251 for p in data.sortedPhases(): 3872 for p in data.sortedPhases(): 4252 if sv.cgphase and p != sv.cgp 3873 if sv.cgphase and p != sv.cgphase: 4253 continue 3874 continue 4254 list = data.dmesg[p]['list'] 3875 list = data.dmesg[p]['list'] 4255 for d in data.sortedDevices(p !! 3876 for devname in data.sortedDevices(p): 4256 if len(sv.cgfilter) > !! 3877 if len(sv.cgfilter) > 0 and devname not in sv.cgfilter: 4257 continue 3878 continue 4258 dev = list[d] !! 3879 dev = list[devname] 4259 color = 'white' 3880 color = 'white' 4260 if 'color' in data.dm 3881 if 'color' in data.dmesg[p]: 4261 color = data. 3882 color = data.dmesg[p]['color'] 4262 if 'color' in dev: 3883 if 'color' in dev: 4263 color = dev[' 3884 color = dev['color'] 4264 name = d if '[' not i !! 3885 name = devname 4265 if(d in sv.devprops): !! 3886 if(devname in sv.devprops): 4266 name = sv.dev !! 3887 name = sv.devprops[devname].altName(devname) 4267 if 'drv' in dev and d << 4268 name += ' {%s << 4269 if sv.suspendmode in 3888 if sv.suspendmode in suspendmodename: 4270 name += ' '+p 3889 name += ' '+p 4271 if('ftrace' in dev): 3890 if('ftrace' in dev): 4272 cg = dev['ftr 3891 cg = dev['ftrace'] 4273 if cg.name == 3892 if cg.name == sv.ftopfunc: 4274 name 3893 name = 'top level suspend/resume call' 4275 num = callgra 3894 num = callgraphHTML(sv, hf, num, cg, 4276 name, 3895 name, color, dev['id']) 4277 if('ftraces' in dev): 3896 if('ftraces' in dev): 4278 for cg in dev 3897 for cg in dev['ftraces']: 4279 num = 3898 num = callgraphHTML(sv, hf, num, cg, 4280 3899 name+' → '+cg.name, color, dev['id']) 4281 hf.write('\n\n </section>\n') 3900 hf.write('\n\n </section>\n') 4282 3901 4283 def summaryCSS(title, center=True): 3902 def summaryCSS(title, center=True): 4284 tdcenter = 'text-align:center;' if ce 3903 tdcenter = 'text-align:center;' if center else '' 4285 out = '<!DOCTYPE html>\n<html>\n<head 3904 out = '<!DOCTYPE html>\n<html>\n<head>\n\ 4286 <meta http-equiv="content-type" conte 3905 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 4287 <title>'+title+'</title>\n\ 3906 <title>'+title+'</title>\n\ 4288 <style type=\'text/css\'>\n\ 3907 <style type=\'text/css\'>\n\ 4289 .stamp {width: 100%;text-alig 3908 .stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\ 4290 table {width:100%;border-coll 3909 table {width:100%;border-collapse: collapse;border:1px solid;}\n\ 4291 th {border: 1px solid black;b 3910 th {border: 1px solid black;background:#222;color:white;}\n\ 4292 td {font: 14px "Times New Rom 3911 td {font: 14px "Times New Roman";'+tdcenter+'}\n\ 4293 tr.head td {border: 1px solid 3912 tr.head td {border: 1px solid black;background:#aaa;}\n\ 4294 tr.alt {background-color:#ddd 3913 tr.alt {background-color:#ddd;}\n\ 4295 tr.notice {color:red;}\n\ 3914 tr.notice {color:red;}\n\ 4296 .minval {background-color:#BB 3915 .minval {background-color:#BBFFBB;}\n\ 4297 .medval {background-color:#BB 3916 .medval {background-color:#BBBBFF;}\n\ 4298 .maxval {background-color:#FF 3917 .maxval {background-color:#FFBBBB;}\n\ 4299 .head a {color:#000;text-deco 3918 .head a {color:#000;text-decoration: none;}\n\ 4300 </style>\n</head>\n<body>\n' 3919 </style>\n</head>\n<body>\n' 4301 return out 3920 return out 4302 3921 4303 # Function: createHTMLSummarySimple 3922 # Function: createHTMLSummarySimple 4304 # Description: 3923 # Description: 4305 # Create summary html file for a serie 3924 # Create summary html file for a series of tests 4306 # Arguments: 3925 # Arguments: 4307 # testruns: array of Data objects from 3926 # testruns: array of Data objects from parseTraceLog 4308 def createHTMLSummarySimple(testruns, htmlfil 3927 def createHTMLSummarySimple(testruns, htmlfile, title): 4309 # write the html header first (html h 3928 # write the html header first (html head, css code, up to body start) 4310 html = summaryCSS('Summary - SleepGra 3929 html = summaryCSS('Summary - SleepGraph') 4311 3930 4312 # extract the test data into list 3931 # extract the test data into list 4313 list = dict() 3932 list = dict() 4314 tAvg, tMin, tMax, tMed = [0.0, 0.0], 3933 tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 4315 iMin, iMed, iMax = [0, 0], [0, 0], [0 3934 iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 4316 num = 0 3935 num = 0 4317 useturbo = usewifi = False !! 3936 useturbo = False 4318 lastmode = '' 3937 lastmode = '' 4319 cnt = dict() 3938 cnt = dict() 4320 for data in sorted(testruns, key=lamb 3939 for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])): 4321 mode = data['mode'] 3940 mode = data['mode'] 4322 if mode not in list: 3941 if mode not in list: 4323 list[mode] = {'data': 3942 list[mode] = {'data': [], 'avg': [0,0], 'min': [0,0], 'max': [0,0], 'med': [0,0]} 4324 if lastmode and lastmode != m 3943 if lastmode and lastmode != mode and num > 0: 4325 for i in range(2): 3944 for i in range(2): 4326 s = sorted(tM 3945 s = sorted(tMed[i]) 4327 list[lastmode 3946 list[lastmode]['med'][i] = s[int(len(s)//2)] 4328 iMed[i] = tMe 3947 iMed[i] = tMed[i][list[lastmode]['med'][i]] 4329 list[lastmode]['avg'] 3948 list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 4330 list[lastmode]['min'] 3949 list[lastmode]['min'] = tMin 4331 list[lastmode]['max'] 3950 list[lastmode]['max'] = tMax 4332 list[lastmode]['idx'] 3951 list[lastmode]['idx'] = (iMin, iMed, iMax) 4333 tAvg, tMin, tMax, tMe 3952 tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 4334 iMin, iMed, iMax = [0 3953 iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 4335 num = 0 3954 num = 0 4336 pkgpc10 = syslpi = wifi = '' !! 3955 pkgpc10 = syslpi = '' 4337 if 'pkgpc10' in data and 'sys 3956 if 'pkgpc10' in data and 'syslpi' in data: 4338 pkgpc10, syslpi, uset !! 3957 pkgpc10 = data['pkgpc10'] 4339 if 'wifi' in data: !! 3958 syslpi = data['syslpi'] 4340 wifi, usewifi = data[ !! 3959 useturbo = True 4341 res = data['result'] 3960 res = data['result'] 4342 tVal = [float(data['suspend'] 3961 tVal = [float(data['suspend']), float(data['resume'])] 4343 list[mode]['data'].append([da 3962 list[mode]['data'].append([data['host'], data['kernel'], 4344 data['time'], tVal[0] 3963 data['time'], tVal[0], tVal[1], data['url'], res, 4345 data['issues'], data[ 3964 data['issues'], data['sus_worst'], data['sus_worsttime'], 4346 data['res_worst'], da !! 3965 data['res_worst'], data['res_worsttime'], pkgpc10, syslpi]) 4347 (data['fullmode'] if << 4348 idx = len(list[mode]['data']) 3966 idx = len(list[mode]['data']) - 1 4349 if res.startswith('fail in'): 3967 if res.startswith('fail in'): 4350 res = 'fail' 3968 res = 'fail' 4351 if res not in cnt: 3969 if res not in cnt: 4352 cnt[res] = 1 3970 cnt[res] = 1 4353 else: 3971 else: 4354 cnt[res] += 1 3972 cnt[res] += 1 4355 if res == 'pass': 3973 if res == 'pass': 4356 for i in range(2): 3974 for i in range(2): 4357 tMed[i][tVal[ 3975 tMed[i][tVal[i]] = idx 4358 tAvg[i] += tV 3976 tAvg[i] += tVal[i] 4359 if tMin[i] == 3977 if tMin[i] == 0 or tVal[i] < tMin[i]: 4360 iMin[ 3978 iMin[i] = idx 4361 tMin[ 3979 tMin[i] = tVal[i] 4362 if tMax[i] == 3980 if tMax[i] == 0 or tVal[i] > tMax[i]: 4363 iMax[ 3981 iMax[i] = idx 4364 tMax[ 3982 tMax[i] = tVal[i] 4365 num += 1 3983 num += 1 4366 lastmode = mode 3984 lastmode = mode 4367 if lastmode and num > 0: 3985 if lastmode and num > 0: 4368 for i in range(2): 3986 for i in range(2): 4369 s = sorted(tMed[i]) 3987 s = sorted(tMed[i]) 4370 list[lastmode]['med'] 3988 list[lastmode]['med'][i] = s[int(len(s)//2)] 4371 iMed[i] = tMed[i][lis 3989 iMed[i] = tMed[i][list[lastmode]['med'][i]] 4372 list[lastmode]['avg'] = [tAvg 3990 list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 4373 list[lastmode]['min'] = tMin 3991 list[lastmode]['min'] = tMin 4374 list[lastmode]['max'] = tMax 3992 list[lastmode]['max'] = tMax 4375 list[lastmode]['idx'] = (iMin 3993 list[lastmode]['idx'] = (iMin, iMed, iMax) 4376 3994 4377 # group test header 3995 # group test header 4378 desc = [] 3996 desc = [] 4379 for ilk in sorted(cnt, reverse=True): 3997 for ilk in sorted(cnt, reverse=True): 4380 if cnt[ilk] > 0: 3998 if cnt[ilk] > 0: 4381 desc.append('%d %s' % 3999 desc.append('%d %s' % (cnt[ilk], ilk)) 4382 html += '<div class="stamp">%s (%d te 4000 html += '<div class="stamp">%s (%d tests: %s)</div>\n' % (title, len(testruns), ', '.join(desc)) 4383 th = '\t<th>{0}</th>\n' 4001 th = '\t<th>{0}</th>\n' 4384 td = '\t<td>{0}</td>\n' 4002 td = '\t<td>{0}</td>\n' 4385 tdh = '\t<td{1}>{0}</td>\n' 4003 tdh = '\t<td{1}>{0}</td>\n' 4386 tdlink = '\t<td><a href="{0}">html</a 4004 tdlink = '\t<td><a href="{0}">html</a></td>\n' 4387 cols = 12 !! 4005 colspan = '14' if useturbo else '12' 4388 if useturbo: << 4389 cols += 2 << 4390 if usewifi: << 4391 cols += 1 << 4392 colspan = '%d' % cols << 4393 4006 4394 # table header 4007 # table header 4395 html += '<table>\n<tr>\n' + th.format 4008 html += '<table>\n<tr>\n' + th.format('#') +\ 4396 th.format('Mode') + th.format 4009 th.format('Mode') + th.format('Host') + th.format('Kernel') +\ 4397 th.format('Test Time') + th.f 4010 th.format('Test Time') + th.format('Result') + th.format('Issues') +\ 4398 th.format('Suspend') + th.for 4011 th.format('Suspend') + th.format('Resume') +\ 4399 th.format('Worst Suspend Devi 4012 th.format('Worst Suspend Device') + th.format('SD Time') +\ 4400 th.format('Worst Resume Devic 4013 th.format('Worst Resume Device') + th.format('RD Time') 4401 if useturbo: 4014 if useturbo: 4402 html += th.format('PkgPC10') 4015 html += th.format('PkgPC10') + th.format('SysLPI') 4403 if usewifi: << 4404 html += th.format('Wifi') << 4405 html += th.format('Detail')+'</tr>\n' 4016 html += th.format('Detail')+'</tr>\n' 4406 # export list into html 4017 # export list into html 4407 head = '<tr class="head"><td>{0}</td> 4018 head = '<tr class="head"><td>{0}</td><td>{1}</td>'+\ 4408 '<td colspan='+colspan+' clas 4019 '<td colspan='+colspan+' class="sus">Suspend Avg={2} '+\ 4409 '<span class=minval><a href=" 4020 '<span class=minval><a href="#s{10}min">Min={3}</a></span> '+\ 4410 '<span class=medval><a href=" 4021 '<span class=medval><a href="#s{10}med">Med={4}</a></span> '+\ 4411 '<span class=maxval><a href=" 4022 '<span class=maxval><a href="#s{10}max">Max={5}</a></span> '+\ 4412 'Resume Avg={6} '+\ 4023 'Resume Avg={6} '+\ 4413 '<span class=minval><a href=" 4024 '<span class=minval><a href="#r{10}min">Min={7}</a></span> '+\ 4414 '<span class=medval><a href=" 4025 '<span class=medval><a href="#r{10}med">Med={8}</a></span> '+\ 4415 '<span class=maxval><a href=" 4026 '<span class=maxval><a href="#r{10}max">Max={9}</a></span></td>'+\ 4416 '</tr>\n' 4027 '</tr>\n' 4417 headnone = '<tr class="head"><td>{0}< 4028 headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan='+\ 4418 colspan+'></td></tr>\n' 4029 colspan+'></td></tr>\n' 4419 for mode in sorted(list): 4030 for mode in sorted(list): 4420 # header line for each suspen 4031 # header line for each suspend mode 4421 num = 0 4032 num = 0 4422 tAvg, tMin, tMax, tMed = list 4033 tAvg, tMin, tMax, tMed = list[mode]['avg'], list[mode]['min'],\ 4423 list[mode]['max'], li 4034 list[mode]['max'], list[mode]['med'] 4424 count = len(list[mode]['data' 4035 count = len(list[mode]['data']) 4425 if 'idx' in list[mode]: 4036 if 'idx' in list[mode]: 4426 iMin, iMed, iMax = li 4037 iMin, iMed, iMax = list[mode]['idx'] 4427 html += head.format(' 4038 html += head.format('%d' % count, mode.upper(), 4428 '%.3f' % tAvg 4039 '%.3f' % tAvg[0], '%.3f' % tMin[0], '%.3f' % tMed[0], '%.3f' % tMax[0], 4429 '%.3f' % tAvg 4040 '%.3f' % tAvg[1], '%.3f' % tMin[1], '%.3f' % tMed[1], '%.3f' % tMax[1], 4430 mode.lower() 4041 mode.lower() 4431 ) 4042 ) 4432 else: 4043 else: 4433 iMin = iMed = iMax = 4044 iMin = iMed = iMax = [-1, -1, -1] 4434 html += headnone.form 4045 html += headnone.format('%d' % count, mode.upper()) 4435 for d in list[mode]['data']: 4046 for d in list[mode]['data']: 4436 # row classes - alter 4047 # row classes - alternate row color 4437 rcls = ['alt'] if num 4048 rcls = ['alt'] if num % 2 == 1 else [] 4438 if d[6] != 'pass': 4049 if d[6] != 'pass': 4439 rcls.append(' 4050 rcls.append('notice') 4440 html += '<tr class="' 4051 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4441 # figure out if the l 4052 # figure out if the line has sus or res highlighted 4442 idx = list[mode]['dat 4053 idx = list[mode]['data'].index(d) 4443 tHigh = ['', ''] 4054 tHigh = ['', ''] 4444 for i in range(2): 4055 for i in range(2): 4445 tag = 's%s' % 4056 tag = 's%s' % mode if i == 0 else 'r%s' % mode 4446 if idx == iMi 4057 if idx == iMin[i]: 4447 tHigh 4058 tHigh[i] = ' id="%smin" class=minval title="Minimum"' % tag 4448 elif idx == i 4059 elif idx == iMax[i]: 4449 tHigh 4060 tHigh[i] = ' id="%smax" class=maxval title="Maximum"' % tag 4450 elif idx == i 4061 elif idx == iMed[i]: 4451 tHigh 4062 tHigh[i] = ' id="%smed" class=medval title="Median"' % tag 4452 html += td.format("%d 4063 html += td.format("%d" % (list[mode]['data'].index(d) + 1)) # row 4453 html += td.format(d[1 !! 4064 html += td.format(mode) # mode 4454 html += td.format(d[0 4065 html += td.format(d[0]) # host 4455 html += td.format(d[1 4066 html += td.format(d[1]) # kernel 4456 html += td.format(d[2 4067 html += td.format(d[2]) # time 4457 html += td.format(d[6 4068 html += td.format(d[6]) # result 4458 html += td.format(d[7 4069 html += td.format(d[7]) # issues 4459 html += tdh.format('% 4070 html += tdh.format('%.3f ms' % d[3], tHigh[0]) if d[3] else td.format('') # suspend 4460 html += tdh.format('% 4071 html += tdh.format('%.3f ms' % d[4], tHigh[1]) if d[4] else td.format('') # resume 4461 html += td.format(d[8 4072 html += td.format(d[8]) # sus_worst 4462 html += td.format('%. 4073 html += td.format('%.3f ms' % d[9]) if d[9] else td.format('') # sus_worst time 4463 html += td.format(d[1 4074 html += td.format(d[10]) # res_worst 4464 html += td.format('%. 4075 html += td.format('%.3f ms' % d[11]) if d[11] else td.format('') # res_worst time 4465 if useturbo: 4076 if useturbo: 4466 html += td.fo 4077 html += td.format(d[12]) # pkg_pc10 4467 html += td.fo 4078 html += td.format(d[13]) # syslpi 4468 if usewifi: << 4469 html += td.fo << 4470 html += tdlink.format 4079 html += tdlink.format(d[5]) if d[5] else td.format('') # url 4471 html += '</tr>\n' 4080 html += '</tr>\n' 4472 num += 1 4081 num += 1 4473 4082 4474 # flush the data to file 4083 # flush the data to file 4475 hf = open(htmlfile, 'w') 4084 hf = open(htmlfile, 'w') 4476 hf.write(html+'</table>\n</body>\n</h 4085 hf.write(html+'</table>\n</body>\n</html>\n') 4477 hf.close() 4086 hf.close() 4478 4087 4479 def createHTMLDeviceSummary(testruns, htmlfil 4088 def createHTMLDeviceSummary(testruns, htmlfile, title): 4480 html = summaryCSS('Device Summary - S 4089 html = summaryCSS('Device Summary - SleepGraph', False) 4481 4090 4482 # create global device list from all 4091 # create global device list from all tests 4483 devall = dict() 4092 devall = dict() 4484 for data in testruns: 4093 for data in testruns: 4485 host, url, devlist = data['ho 4094 host, url, devlist = data['host'], data['url'], data['devlist'] 4486 for type in devlist: 4095 for type in devlist: 4487 if type not in devall 4096 if type not in devall: 4488 devall[type] 4097 devall[type] = dict() 4489 mdevlist, devlist = d 4098 mdevlist, devlist = devall[type], data['devlist'][type] 4490 for name in devlist: 4099 for name in devlist: 4491 length = devl 4100 length = devlist[name] 4492 if name not i 4101 if name not in mdevlist: 4493 mdevl 4102 mdevlist[name] = {'name': name, 'host': host, 4494 4103 'worst': length, 'total': length, 'count': 1, 4495 4104 'url': url} 4496 else: 4105 else: 4497 if le 4106 if length > mdevlist[name]['worst']: 4498 4107 mdevlist[name]['worst'] = length 4499 4108 mdevlist[name]['url'] = url 4500 4109 mdevlist[name]['host'] = host 4501 mdevl 4110 mdevlist[name]['total'] += length 4502 mdevl 4111 mdevlist[name]['count'] += 1 4503 4112 4504 # generate the html 4113 # generate the html 4505 th = '\t<th>{0}</th>\n' 4114 th = '\t<th>{0}</th>\n' 4506 td = '\t<td align=center>{0}</td>\n' 4115 td = '\t<td align=center>{0}</td>\n' 4507 tdr = '\t<td align=right>{0}</td>\n' 4116 tdr = '\t<td align=right>{0}</td>\n' 4508 tdlink = '\t<td align=center><a href= 4117 tdlink = '\t<td align=center><a href="{0}">html</a></td>\n' 4509 limit = 1 4118 limit = 1 4510 for type in sorted(devall, reverse=Tr 4119 for type in sorted(devall, reverse=True): 4511 num = 0 4120 num = 0 4512 devlist = devall[type] 4121 devlist = devall[type] 4513 # table header 4122 # table header 4514 html += '<div class="stamp">% 4123 html += '<div class="stamp">%s (%s devices > %d ms)</div><table>\n' % \ 4515 (title, type.upper(), 4124 (title, type.upper(), limit) 4516 html += '<tr>\n' + '<th align 4125 html += '<tr>\n' + '<th align=right>Device Name</th>' +\ 4517 th.format('Average Ti 4126 th.format('Average Time') + th.format('Count') +\ 4518 th.format('Worst Time 4127 th.format('Worst Time') + th.format('Host (worst time)') +\ 4519 th.format('Link (wors 4128 th.format('Link (worst time)') + '</tr>\n' 4520 for name in sorted(devlist, k 4129 for name in sorted(devlist, key=lambda k:(devlist[k]['worst'], \ 4521 devlist[k]['total'], 4130 devlist[k]['total'], devlist[k]['name']), reverse=True): 4522 data = devall[type][n 4131 data = devall[type][name] 4523 data['average'] = dat 4132 data['average'] = data['total'] / data['count'] 4524 if data['average'] < 4133 if data['average'] < limit: 4525 continue 4134 continue 4526 # row classes - alter 4135 # row classes - alternate row color 4527 rcls = ['alt'] if num 4136 rcls = ['alt'] if num % 2 == 1 else [] 4528 html += '<tr class="' 4137 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4529 html += tdr.format(da 4138 html += tdr.format(data['name']) # name 4530 html += td.format('%. 4139 html += td.format('%.3f ms' % data['average']) # average 4531 html += td.format(dat 4140 html += td.format(data['count']) # count 4532 html += td.format('%. 4141 html += td.format('%.3f ms' % data['worst']) # worst 4533 html += td.format(dat 4142 html += td.format(data['host']) # host 4534 html += tdlink.format 4143 html += tdlink.format(data['url']) # url 4535 html += '</tr>\n' 4144 html += '</tr>\n' 4536 num += 1 4145 num += 1 4537 html += '</table>\n' 4146 html += '</table>\n' 4538 4147 4539 # flush the data to file 4148 # flush the data to file 4540 hf = open(htmlfile, 'w') 4149 hf = open(htmlfile, 'w') 4541 hf.write(html+'</body>\n</html>\n') 4150 hf.write(html+'</body>\n</html>\n') 4542 hf.close() 4151 hf.close() 4543 return devall 4152 return devall 4544 4153 4545 def createHTMLIssuesSummary(testruns, issues, 4154 def createHTMLIssuesSummary(testruns, issues, htmlfile, title, extra=''): 4546 multihost = len([e for e in issues if 4155 multihost = len([e for e in issues if len(e['urls']) > 1]) > 0 4547 html = summaryCSS('Issues Summary - S 4156 html = summaryCSS('Issues Summary - SleepGraph', False) 4548 total = len(testruns) 4157 total = len(testruns) 4549 4158 4550 # generate the html 4159 # generate the html 4551 th = '\t<th>{0}</th>\n' 4160 th = '\t<th>{0}</th>\n' 4552 td = '\t<td align={0}>{1}</td>\n' 4161 td = '\t<td align={0}>{1}</td>\n' 4553 tdlink = '<a href="{1}">{0}</a>' 4162 tdlink = '<a href="{1}">{0}</a>' 4554 subtitle = '%d issues' % len(issues) 4163 subtitle = '%d issues' % len(issues) if len(issues) > 0 else 'no issues' 4555 html += '<div class="stamp">%s (%s)</ 4164 html += '<div class="stamp">%s (%s)</div><table>\n' % (title, subtitle) 4556 html += '<tr>\n' + th.format('Issue') 4165 html += '<tr>\n' + th.format('Issue') + th.format('Count') 4557 if multihost: 4166 if multihost: 4558 html += th.format('Hosts') 4167 html += th.format('Hosts') 4559 html += th.format('Tests') + th.forma 4168 html += th.format('Tests') + th.format('Fail Rate') +\ 4560 th.format('First Instance') + 4169 th.format('First Instance') + '</tr>\n' 4561 4170 4562 num = 0 4171 num = 0 4563 for e in sorted(issues, key=lambda v: 4172 for e in sorted(issues, key=lambda v:v['count'], reverse=True): 4564 testtotal = 0 4173 testtotal = 0 4565 links = [] 4174 links = [] 4566 for host in sorted(e['urls']) 4175 for host in sorted(e['urls']): 4567 links.append(tdlink.f 4176 links.append(tdlink.format(host, e['urls'][host][0])) 4568 testtotal += len(e['u 4177 testtotal += len(e['urls'][host]) 4569 rate = '%d/%d (%.2f%%)' % (te 4178 rate = '%d/%d (%.2f%%)' % (testtotal, total, 100*float(testtotal)/float(total)) 4570 # row classes - alternate row 4179 # row classes - alternate row color 4571 rcls = ['alt'] if num % 2 == 4180 rcls = ['alt'] if num % 2 == 1 else [] 4572 html += '<tr class="'+(' '.jo 4181 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4573 html += td.format('left', e[' 4182 html += td.format('left', e['line']) # issue 4574 html += td.format('center', e 4183 html += td.format('center', e['count']) # count 4575 if multihost: 4184 if multihost: 4576 html += td.format('ce 4185 html += td.format('center', len(e['urls'])) # hosts 4577 html += td.format('center', t 4186 html += td.format('center', testtotal) # test count 4578 html += td.format('center', r 4187 html += td.format('center', rate) # test rate 4579 html += td.format('center now 4188 html += td.format('center nowrap', '<br>'.join(links)) # links 4580 html += '</tr>\n' 4189 html += '</tr>\n' 4581 num += 1 4190 num += 1 4582 4191 4583 # flush the data to file 4192 # flush the data to file 4584 hf = open(htmlfile, 'w') 4193 hf = open(htmlfile, 'w') 4585 hf.write(html+'</table>\n'+extra+'</b 4194 hf.write(html+'</table>\n'+extra+'</body>\n</html>\n') 4586 hf.close() 4195 hf.close() 4587 return issues 4196 return issues 4588 4197 4589 def ordinal(value): 4198 def ordinal(value): 4590 suffix = 'th' 4199 suffix = 'th' 4591 if value < 10 or value > 19: 4200 if value < 10 or value > 19: 4592 if value % 10 == 1: 4201 if value % 10 == 1: 4593 suffix = 'st' 4202 suffix = 'st' 4594 elif value % 10 == 2: 4203 elif value % 10 == 2: 4595 suffix = 'nd' 4204 suffix = 'nd' 4596 elif value % 10 == 3: 4205 elif value % 10 == 3: 4597 suffix = 'rd' 4206 suffix = 'rd' 4598 return '%d%s' % (value, suffix) 4207 return '%d%s' % (value, suffix) 4599 4208 4600 # Function: createHTML 4209 # Function: createHTML 4601 # Description: 4210 # Description: 4602 # Create the output html file from the 4211 # Create the output html file from the resident test data 4603 # Arguments: 4212 # Arguments: 4604 # testruns: array of Data objects from 4213 # testruns: array of Data objects from parseKernelLog or parseTraceLog 4605 # Output: 4214 # Output: 4606 # True if the html file was created, f 4215 # True if the html file was created, false if it failed 4607 def createHTML(testruns, testfail): 4216 def createHTML(testruns, testfail): 4608 if len(testruns) < 1: 4217 if len(testruns) < 1: 4609 pprint('ERROR: Not enough tes 4218 pprint('ERROR: Not enough test data to build a timeline') 4610 return 4219 return 4611 4220 4612 kerror = False 4221 kerror = False 4613 for data in testruns: 4222 for data in testruns: 4614 if data.kerror: 4223 if data.kerror: 4615 kerror = True 4224 kerror = True 4616 if(sysvals.suspendmode in ['f 4225 if(sysvals.suspendmode in ['freeze', 'standby']): 4617 data.trimFreezeTime(t 4226 data.trimFreezeTime(testruns[-1].tSuspended) 4618 else: << 4619 data.getMemTime() << 4620 4227 4621 # html function templates 4228 # html function templates 4622 html_error = '<div id="{1}" title="ke 4229 html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">{2}→</div>\n' 4623 html_traceevent = '<div title="{0}" c 4230 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' 4624 html_cpuexec = '<div class="jiffie" s 4231 html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n' 4625 html_timetotal = '<table class="time1 4232 html_timetotal = '<table class="time1">\n<tr>'\ 4626 '<td class="green" title="{3} 4233 '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ 4627 '<td class="yellow" title="{4 4234 '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ 4628 '</tr>\n</table>\n' 4235 '</tr>\n</table>\n' 4629 html_timetotal2 = '<table class="time 4236 html_timetotal2 = '<table class="time1">\n<tr>'\ 4630 '<td class="green" title="{4} 4237 '<td class="green" title="{4}">{3} Suspend Time: <b>{0} ms</b></td>'\ 4631 '<td class="gray" title="time 4238 '<td class="gray" title="time spent in low-power mode with clock running">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\ 4632 '<td class="yellow" title="{5 4239 '<td class="yellow" title="{5}">{3} Resume Time: <b>{2} ms</b></td>'\ 4633 '</tr>\n</table>\n' 4240 '</tr>\n</table>\n' 4634 html_timetotal3 = '<table class="time 4241 html_timetotal3 = '<table class="time1">\n<tr>'\ 4635 '<td class="green">Execution 4242 '<td class="green">Execution Time: <b>{0} ms</b></td>'\ 4636 '<td class="yellow">Command: 4243 '<td class="yellow">Command: <b>{1}</b></td>'\ 4637 '</tr>\n</table>\n' 4244 '</tr>\n</table>\n' >> 4245 html_timegroups = '<table class="time2">\n<tr>'\ >> 4246 '<td class="green" title="time from kernel enter_state({5}) to firmware mode [kernel time only]">{4}Kernel Suspend: {0} ms</td>'\ >> 4247 '<td class="purple">{4}Firmware Suspend: {1} ms</td>'\ >> 4248 '<td class="purple">{4}Firmware Resume: {2} ms</td>'\ >> 4249 '<td class="yellow" title="time from firmware mode to return from kernel enter_state({5}) [kernel time only]">{4}Kernel Resume: {3} ms</td>'\ >> 4250 '</tr>\n</table>\n' 4638 html_fail = '<table class="testfail"> 4251 html_fail = '<table class="testfail"><tr><td>{0}</td></tr></table>\n' 4639 html_kdesc = '<td class="{3}" title=" << 4640 html_fwdesc = '<td class="{3}" title= << 4641 html_wifdesc = '<td class="yellow" ti << 4642 4252 4643 # html format variables 4253 # html format variables 4644 scaleH = 20 4254 scaleH = 20 4645 if kerror: 4255 if kerror: 4646 scaleH = 40 4256 scaleH = 40 4647 4257 4648 # device timeline 4258 # device timeline 4649 devtl = Timeline(30, scaleH) 4259 devtl = Timeline(30, scaleH) 4650 4260 4651 # write the test title and general in 4261 # write the test title and general info header 4652 devtl.createHeader(sysvals, testruns[ 4262 devtl.createHeader(sysvals, testruns[0].stamp) 4653 4263 4654 # Generate the header for this timeli 4264 # Generate the header for this timeline 4655 for data in testruns: 4265 for data in testruns: 4656 tTotal = data.end - data.star 4266 tTotal = data.end - data.start >> 4267 sktime, rktime = data.getTimeValues() 4657 if(tTotal == 0): 4268 if(tTotal == 0): 4658 doError('No timeline 4269 doError('No timeline data') >> 4270 if(len(data.tLow) > 0): >> 4271 low_time = '+'.join(data.tLow) 4659 if sysvals.suspendmode == 'co 4272 if sysvals.suspendmode == 'command': 4660 run_time = '%.0f' % ( !! 4273 run_time = '%.0f'%((data.end-data.start)*1000) 4661 if sysvals.testcomman 4274 if sysvals.testcommand: 4662 testdesc = sy 4275 testdesc = sysvals.testcommand 4663 else: 4276 else: 4664 testdesc = 'u 4277 testdesc = 'unknown' 4665 if(len(testruns) > 1) 4278 if(len(testruns) > 1): 4666 testdesc = or 4279 testdesc = ordinal(data.testnumber+1)+' '+testdesc 4667 thtml = html_timetota 4280 thtml = html_timetotal3.format(run_time, testdesc) 4668 devtl.html += thtml 4281 devtl.html += thtml 4669 continue !! 4282 elif data.fwValid: 4670 # typical full suspend/resume !! 4283 suspend_time = '%.0f'%(sktime + (data.fwSuspend/1000000.0)) 4671 stot, rtot = sktime, rktime = !! 4284 resume_time = '%.0f'%(rktime + (data.fwResume/1000000.0)) 4672 ssrc, rsrc, testdesc, testdes !! 4285 testdesc1 = 'Total' 4673 if data.fwValid: !! 4286 testdesc2 = '' 4674 stot += (data.fwSuspe !! 4287 stitle = 'time from kernel enter_state(%s) to low-power mode [kernel & firmware time]' % sysvals.suspendmode 4675 rtot += (data.fwResum !! 4288 rtitle = 'time from low-power mode to return from kernel enter_state(%s) [firmware & kernel time]' % sysvals.suspendmode 4676 ssrc.append('firmware !! 4289 if(len(testruns) > 1): 4677 rsrc.append('firmware !! 4290 testdesc1 = testdesc2 = ordinal(data.testnumber+1) 4678 testdesc = 'Total' !! 4291 testdesc2 += ' ' 4679 if 'time' in data.wifi and da !! 4292 if(len(data.tLow) == 0): 4680 rtot += data.end - da !! 4293 thtml = html_timetotal.format(suspend_time, \ 4681 rsrc.append('wifi') !! 4294 resume_time, testdesc1, stitle, rtitle) 4682 testdesc = 'Total' !! 4295 else: 4683 suspend_time, resume_time = ' !! 4296 thtml = html_timetotal2.format(suspend_time, low_time, \ 4684 stitle = 'time from kernel su !! 4297 resume_time, testdesc1, stitle, rtitle) 4685 (sysvals.suspendmode, !! 4298 devtl.html += thtml 4686 rtitle = 'time from %s mode t << 4687 (sysvals.suspendmode, << 4688 if(len(testruns) > 1): << 4689 testdesc = testdesc2 << 4690 testdesc2 += ' ' << 4691 if(len(data.tLow) == 0): << 4692 thtml = html_timetota << 4693 resume_time, << 4694 else: << 4695 low_time = '+'.join(d << 4696 thtml = html_timetota << 4697 resume_time, << 4698 devtl.html += thtml << 4699 if not data.fwValid and 'dev' << 4700 continue << 4701 # extra detail when the times << 4702 thtml = '<table class="time2" << 4703 thtml += html_kdesc.format(te << 4704 if data.fwValid: << 4705 sftime = '%.3f'%(data 4299 sftime = '%.3f'%(data.fwSuspend / 1000000.0) 4706 rftime = '%.3f'%(data 4300 rftime = '%.3f'%(data.fwResume / 1000000.0) 4707 thtml += html_fwdesc. !! 4301 devtl.html += html_timegroups.format('%.3f'%sktime, \ 4708 thtml += html_fwdesc. !! 4302 sftime, rftime, '%.3f'%rktime, testdesc2, sysvals.suspendmode) 4709 thtml += html_kdesc.format(te !! 4303 else: 4710 if 'time' in data.wifi: !! 4304 suspend_time = '%.3f' % sktime 4711 if data.wifi['stat'] !! 4305 resume_time = '%.3f' % rktime 4712 wtime = '%.0f !! 4306 testdesc = 'Kernel' >> 4307 stitle = 'time from kernel enter_state(%s) to firmware mode [kernel time only]' % sysvals.suspendmode >> 4308 rtitle = 'time from firmware mode to return from kernel enter_state(%s) [kernel time only]' % sysvals.suspendmode >> 4309 if(len(testruns) > 1): >> 4310 testdesc = ordinal(data.testnumber+1)+' '+testdesc >> 4311 if(len(data.tLow) == 0): >> 4312 thtml = html_timetotal.format(suspend_time, \ >> 4313 resume_time, testdesc, stitle, rtitle) 4713 else: 4314 else: 4714 wtime = 'TIME !! 4315 thtml = html_timetotal2.format(suspend_time, low_time, \ 4715 thtml += html_wifdesc !! 4316 resume_time, testdesc, stitle, rtitle) 4716 thtml += '</tr>\n</table>\n' !! 4317 devtl.html += thtml 4717 devtl.html += thtml !! 4318 4718 if testfail: 4319 if testfail: 4719 devtl.html += html_fail.forma 4320 devtl.html += html_fail.format(testfail) 4720 4321 4721 # time scale for potentially multiple 4322 # time scale for potentially multiple datasets 4722 t0 = testruns[0].start 4323 t0 = testruns[0].start 4723 tMax = testruns[-1].end 4324 tMax = testruns[-1].end 4724 tTotal = tMax - t0 4325 tTotal = tMax - t0 4725 4326 4726 # determine the maximum number of row 4327 # determine the maximum number of rows we need to draw 4727 fulllist = [] 4328 fulllist = [] 4728 threadlist = [] 4329 threadlist = [] 4729 pscnt = 0 4330 pscnt = 0 4730 devcnt = 0 4331 devcnt = 0 4731 for data in testruns: 4332 for data in testruns: 4732 data.selectTimelineDevices('% 4333 data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen) 4733 for group in data.devicegroup 4334 for group in data.devicegroups: 4734 devlist = [] 4335 devlist = [] 4735 for phase in group: 4336 for phase in group: 4736 for devname i 4337 for devname in sorted(data.tdevlist[phase]): 4737 d = D 4338 d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname]) 4738 devli 4339 devlist.append(d) 4739 if d. 4340 if d.isa('kth'): 4740 4341 threadlist.append(d) 4741 else: 4342 else: 4742 4343 if d.isa('ps'): 4743 4344 pscnt += 1 4744 4345 else: 4745 4346 devcnt += 1 4746 4347 fulllist.append(d) 4747 if sysvals.mixedphase 4348 if sysvals.mixedphaseheight: 4748 devtl.getPhas 4349 devtl.getPhaseRows(devlist) 4749 if not sysvals.mixedphaseheight: 4350 if not sysvals.mixedphaseheight: 4750 if len(threadlist) > 0 and le 4351 if len(threadlist) > 0 and len(fulllist) > 0: 4751 if pscnt > 0 and devc 4352 if pscnt > 0 and devcnt > 0: 4752 msg = 'user p 4353 msg = 'user processes & device pm callbacks' 4753 elif pscnt > 0: 4354 elif pscnt > 0: 4754 msg = 'user p 4355 msg = 'user processes' 4755 else: 4356 else: 4756 msg = 'device 4357 msg = 'device pm callbacks' 4757 d = testruns[0].addHo 4358 d = testruns[0].addHorizontalDivider(msg, testruns[-1].end) 4758 fulllist.insert(0, d) 4359 fulllist.insert(0, d) 4759 devtl.getPhaseRows(fulllist) 4360 devtl.getPhaseRows(fulllist) 4760 if len(threadlist) > 0: 4361 if len(threadlist) > 0: 4761 d = testruns[0].addHo 4362 d = testruns[0].addHorizontalDivider('asynchronous kernel threads', testruns[-1].end) 4762 threadlist.insert(0, 4363 threadlist.insert(0, d) 4763 devtl.getPhaseRows(th 4364 devtl.getPhaseRows(threadlist, devtl.rows) 4764 devtl.calcTotalRows() 4365 devtl.calcTotalRows() 4765 4366 4766 # draw the full timeline 4367 # draw the full timeline 4767 devtl.createZoomBox(sysvals.suspendmo 4368 devtl.createZoomBox(sysvals.suspendmode, len(testruns)) 4768 for data in testruns: 4369 for data in testruns: 4769 # draw each test run and bloc 4370 # draw each test run and block chronologically 4770 phases = {'suspend':[],'resum 4371 phases = {'suspend':[],'resume':[]} 4771 for phase in data.sortedPhase 4372 for phase in data.sortedPhases(): 4772 if data.dmesg[phase][ 4373 if data.dmesg[phase]['start'] >= data.tSuspended: 4773 phases['resum 4374 phases['resume'].append(phase) 4774 else: 4375 else: 4775 phases['suspe 4376 phases['suspend'].append(phase) 4776 # now draw the actual timelin 4377 # now draw the actual timeline blocks 4777 for dir in phases: 4378 for dir in phases: 4778 # draw suspend and re 4379 # draw suspend and resume blocks separately 4779 bname = '%s%d' % (dir 4380 bname = '%s%d' % (dir[0], data.testnumber) 4780 if dir == 'suspend': 4381 if dir == 'suspend': 4781 m0 = data.sta 4382 m0 = data.start 4782 mMax = data.t 4383 mMax = data.tSuspended 4783 left = '%f' % 4384 left = '%f' % (((m0-t0)*100.0)/tTotal) 4784 else: 4385 else: 4785 m0 = data.tSu 4386 m0 = data.tSuspended 4786 mMax = data.e 4387 mMax = data.end 4787 # in an x2 ru 4388 # in an x2 run, remove any gap between blocks 4788 if len(testru 4389 if len(testruns) > 1 and data.testnumber == 0: 4789 mMax 4390 mMax = testruns[1].start 4790 left = '%f' % 4391 left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal) 4791 mTotal = mMax - m0 4392 mTotal = mMax - m0 4792 # if a timeline block 4393 # if a timeline block is 0 length, skip altogether 4793 if mTotal == 0: 4394 if mTotal == 0: 4794 continue 4395 continue 4795 width = '%f' % (((mTo 4396 width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal) 4796 devtl.html += devtl.h 4397 devtl.html += devtl.html_tblock.format(bname, left, width, devtl.scaleH) 4797 for b in phases[dir]: 4398 for b in phases[dir]: 4798 # draw the ph 4399 # draw the phase color background 4799 phase = data. 4400 phase = data.dmesg[b] 4800 length = phas 4401 length = phase['end']-phase['start'] 4801 left = '%f' % 4402 left = '%f' % (((phase['start']-m0)*100.0)/mTotal) 4802 width = '%f' 4403 width = '%f' % ((length*100.0)/mTotal) 4803 devtl.html += 4404 devtl.html += devtl.html_phase.format(left, width, \ 4804 '%.3f 4405 '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ 4805 data. 4406 data.dmesg[b]['color'], '') 4806 for e in data.errorin 4407 for e in data.errorinfo[dir]: 4807 # draw red li 4408 # draw red lines for any kernel errors found 4808 type, t, idx1 4409 type, t, idx1, idx2 = e 4809 id = '%d_%d' 4410 id = '%d_%d' % (idx1, idx2) 4810 right = '%f' 4411 right = '%f' % (((mMax-t)*100.0)/mTotal) 4811 devtl.html += 4412 devtl.html += html_error.format(right, id, type) 4812 for b in phases[dir]: 4413 for b in phases[dir]: 4813 # draw the de 4414 # draw the devices for this phase 4814 phaselist = d 4415 phaselist = data.dmesg[b]['list'] 4815 for d in sort 4416 for d in sorted(data.tdevlist[b]): 4816 dname !! 4417 name = d 4817 name, !! 4418 drv = '' 4818 drv = !! 4419 dev = phaselist[d] >> 4420 xtraclass = '' >> 4421 xtrainfo = '' >> 4422 xtrastyle = '' 4819 if 'h 4423 if 'htmlclass' in dev: 4820 4424 xtraclass = dev['htmlclass'] 4821 if 'c 4425 if 'color' in dev: 4822 4426 xtrastyle = 'background:%s;' % dev['color'] 4823 if(d 4427 if(d in sysvals.devprops): 4824 4428 name = sysvals.devprops[d].altName(d) 4825 4429 xtraclass = sysvals.devprops[d].xtraClass() 4826 4430 xtrainfo = sysvals.devprops[d].xtraInfo() 4827 elif 4431 elif xtraclass == ' kth': 4828 4432 xtrainfo = ' kernel_thread' 4829 if('d 4433 if('drv' in dev and dev['drv']): 4830 4434 drv = ' {%s}' % dev['drv'] 4831 rowhe 4435 rowheight = devtl.phaseRowHeight(data.testnumber, b, dev['row']) 4832 rowto 4436 rowtop = devtl.phaseRowTop(data.testnumber, b, dev['row']) 4833 top = 4437 top = '%.3f' % (rowtop + devtl.scaleH) 4834 left 4438 left = '%f' % (((dev['start']-m0)*100)/mTotal) 4835 width 4439 width = '%f' % (((dev['end']-dev['start'])*100)/mTotal) 4836 lengt 4440 length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) 4837 title 4441 title = name+drv+xtrainfo+length 4838 if sy 4442 if sysvals.suspendmode == 'command': 4839 4443 title += sysvals.testcommand 4840 elif 4444 elif xtraclass == ' ps': 4841 4445 if 'suspend' in b: 4842 4446 title += 'pre_suspend_process' 4843 4447 else: 4844 4448 title += 'post_resume_process' 4845 else: 4449 else: 4846 4450 title += b 4847 devtl 4451 devtl.html += devtl.html_device.format(dev['id'], \ 4848 4452 title, left, top, '%.3f'%rowheight, width, \ 4849 !! 4453 d+drv, xtraclass, xtrastyle) 4850 if('c 4454 if('cpuexec' in dev): 4851 4455 for t in sorted(dev['cpuexec']): 4852 4456 start, end = t >> 4457 j = float(dev['cpuexec'][t]) / 5 >> 4458 if j > 1.0: >> 4459 j = 1.0 4853 4460 height = '%.3f' % (rowheight/3) 4854 4461 top = '%.3f' % (rowtop + devtl.scaleH + 2*rowheight/3) 4855 4462 left = '%f' % (((start-m0)*100)/mTotal) 4856 4463 width = '%f' % ((end-start)*100/mTotal) 4857 !! 4464 color = 'rgba(255, 0, 0, %f)' % j 4858 4465 devtl.html += \ 4859 4466 html_cpuexec.format(left, top, height, width, color) 4860 if('s 4467 if('src' not in dev): 4861 4468 continue 4862 # dra 4469 # draw any trace events for this device 4863 for e 4470 for e in dev['src']: 4864 << 4865 << 4866 4471 height = '%.3f' % devtl.rowH 4867 4472 top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH)) 4868 4473 left = '%f' % (((e.time-m0)*100)/mTotal) 4869 4474 width = '%f' % (e.length*100/mTotal) 4870 4475 xtrastyle = '' 4871 4476 if e.color: 4872 4477 xtrastyle = 'background:%s;' % e.color 4873 4478 devtl.html += \ 4874 4479 html_traceevent.format(e.title(), \ 4875 4480 left, top, height, width, e.text(), '', xtrastyle) 4876 # draw the time scale 4481 # draw the time scale, try to make the number of labels readable 4877 devtl.createTimeScale 4482 devtl.createTimeScale(m0, mMax, tTotal, dir) 4878 devtl.html += '</div> 4483 devtl.html += '</div>\n' 4879 4484 4880 # timeline is finished 4485 # timeline is finished 4881 devtl.html += '</div>\n</div>\n' 4486 devtl.html += '</div>\n</div>\n' 4882 4487 4883 # draw a legend which describes the p 4488 # draw a legend which describes the phases by color 4884 if sysvals.suspendmode != 'command': 4489 if sysvals.suspendmode != 'command': 4885 phasedef = testruns[-1].phase 4490 phasedef = testruns[-1].phasedef 4886 devtl.html += '<div class="le 4491 devtl.html += '<div class="legend">\n' 4887 pdelta = 100.0/len(phasedef.k 4492 pdelta = 100.0/len(phasedef.keys()) 4888 pmargin = pdelta / 4.0 4493 pmargin = pdelta / 4.0 4889 for phase in sorted(phasedef, 4494 for phase in sorted(phasedef, key=lambda k:phasedef[k]['order']): 4890 id, p = '', phasedef[ 4495 id, p = '', phasedef[phase] 4891 for word in phase.spl 4496 for word in phase.split('_'): 4892 id += word[0] 4497 id += word[0] 4893 order = '%.2f' % ((p[ 4498 order = '%.2f' % ((p['order'] * pdelta) + pmargin) 4894 name = phase.replace( 4499 name = phase.replace('_', ' ') 4895 devtl.html += devtl.h 4500 devtl.html += devtl.html_legend.format(order, p['color'], name, id) 4896 devtl.html += '</div>\n' 4501 devtl.html += '</div>\n' 4897 4502 4898 hf = open(sysvals.htmlfile, 'w') 4503 hf = open(sysvals.htmlfile, 'w') 4899 addCSS(hf, sysvals, len(testruns), ke 4504 addCSS(hf, sysvals, len(testruns), kerror) 4900 4505 4901 # write the device timeline 4506 # write the device timeline 4902 hf.write(devtl.html) 4507 hf.write(devtl.html) 4903 hf.write('<div id="devicedetailtitle" 4508 hf.write('<div id="devicedetailtitle"></div>\n') 4904 hf.write('<div id="devicedetail" styl 4509 hf.write('<div id="devicedetail" style="display:none;">\n') 4905 # draw the colored boxes for the devi 4510 # draw the colored boxes for the device detail section 4906 for data in testruns: 4511 for data in testruns: 4907 hf.write('<div id="devicedeta 4512 hf.write('<div id="devicedetail%d">\n' % data.testnumber) 4908 pscolor = 'linear-gradient(to 4513 pscolor = 'linear-gradient(to top left, #ccc, #eee)' 4909 hf.write(devtl.html_phaselet. 4514 hf.write(devtl.html_phaselet.format('pre_suspend_process', \ 4910 '0', '0', pscolor)) 4515 '0', '0', pscolor)) 4911 for b in data.sortedPhases(): 4516 for b in data.sortedPhases(): 4912 phase = data.dmesg[b] 4517 phase = data.dmesg[b] 4913 length = phase['end'] 4518 length = phase['end']-phase['start'] 4914 left = '%.3f' % (((ph 4519 left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) 4915 width = '%.3f' % ((le 4520 width = '%.3f' % ((length*100.0)/tTotal) 4916 hf.write(devtl.html_p 4521 hf.write(devtl.html_phaselet.format(b, left, width, \ 4917 data.dmesg[b] 4522 data.dmesg[b]['color'])) 4918 hf.write(devtl.html_phaselet. 4523 hf.write(devtl.html_phaselet.format('post_resume_process', \ 4919 '0', '0', pscolor)) 4524 '0', '0', pscolor)) 4920 if sysvals.suspendmode == 'co 4525 if sysvals.suspendmode == 'command': 4921 hf.write(devtl.html_p 4526 hf.write(devtl.html_phaselet.format('cmdexec', '0', '0', pscolor)) 4922 hf.write('</div>\n') 4527 hf.write('</div>\n') 4923 hf.write('</div>\n') 4528 hf.write('</div>\n') 4924 4529 4925 # write the ftrace data (callgraph) 4530 # write the ftrace data (callgraph) 4926 if sysvals.cgtest >= 0 and len(testru 4531 if sysvals.cgtest >= 0 and len(testruns) > sysvals.cgtest: 4927 data = testruns[sysvals.cgtes 4532 data = testruns[sysvals.cgtest] 4928 else: 4533 else: 4929 data = testruns[-1] 4534 data = testruns[-1] 4930 if sysvals.usecallgraph: 4535 if sysvals.usecallgraph: 4931 addCallgraphs(sysvals, hf, da 4536 addCallgraphs(sysvals, hf, data) 4932 4537 4933 # add the test log as a hidden div 4538 # add the test log as a hidden div 4934 if sysvals.testlog and sysvals.logmsg 4539 if sysvals.testlog and sysvals.logmsg: 4935 hf.write('<div id="testlog" s 4540 hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') 4936 # add the dmesg log as a hidden div 4541 # add the dmesg log as a hidden div 4937 if sysvals.dmesglog and sysvals.dmesg 4542 if sysvals.dmesglog and sysvals.dmesgfile: 4938 hf.write('<div id="dmesglog" 4543 hf.write('<div id="dmesglog" style="display:none;">\n') 4939 lf = sysvals.openlog(sysvals. 4544 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 4940 for line in lf: 4545 for line in lf: 4941 line = line.replace(' 4546 line = line.replace('<', '<').replace('>', '>') 4942 hf.write(line) 4547 hf.write(line) 4943 lf.close() 4548 lf.close() 4944 hf.write('</div>\n') 4549 hf.write('</div>\n') 4945 # add the ftrace log as a hidden div 4550 # add the ftrace log as a hidden div 4946 if sysvals.ftracelog and sysvals.ftra 4551 if sysvals.ftracelog and sysvals.ftracefile: 4947 hf.write('<div id="ftracelog" 4552 hf.write('<div id="ftracelog" style="display:none;">\n') 4948 lf = sysvals.openlog(sysvals. 4553 lf = sysvals.openlog(sysvals.ftracefile, 'r') 4949 for line in lf: 4554 for line in lf: 4950 hf.write(line) 4555 hf.write(line) 4951 lf.close() 4556 lf.close() 4952 hf.write('</div>\n') 4557 hf.write('</div>\n') 4953 4558 4954 # write the footer and close 4559 # write the footer and close 4955 addScriptCode(hf, testruns) 4560 addScriptCode(hf, testruns) 4956 hf.write('</body>\n</html>\n') 4561 hf.write('</body>\n</html>\n') 4957 hf.close() 4562 hf.close() 4958 return True 4563 return True 4959 4564 4960 def addCSS(hf, sv, testcount=1, kerror=False, 4565 def addCSS(hf, sv, testcount=1, kerror=False, extra=''): 4961 kernel = sv.stamp['kernel'] 4566 kernel = sv.stamp['kernel'] 4962 host = sv.hostname[0].upper()+sv.host 4567 host = sv.hostname[0].upper()+sv.hostname[1:] 4963 mode = sv.suspendmode 4568 mode = sv.suspendmode 4964 if sv.suspendmode in suspendmodename: 4569 if sv.suspendmode in suspendmodename: 4965 mode = suspendmodename[sv.sus 4570 mode = suspendmodename[sv.suspendmode] 4966 title = host+' '+mode+' '+kernel 4571 title = host+' '+mode+' '+kernel 4967 4572 4968 # various format changes by flags 4573 # various format changes by flags 4969 cgchk = 'checked' 4574 cgchk = 'checked' 4970 cgnchk = 'not(:checked)' 4575 cgnchk = 'not(:checked)' 4971 if sv.cgexp: 4576 if sv.cgexp: 4972 cgchk = 'not(:checked)' 4577 cgchk = 'not(:checked)' 4973 cgnchk = 'checked' 4578 cgnchk = 'checked' 4974 4579 4975 hoverZ = 'z-index:8;' 4580 hoverZ = 'z-index:8;' 4976 if sv.usedevsrc: 4581 if sv.usedevsrc: 4977 hoverZ = '' 4582 hoverZ = '' 4978 4583 4979 devlistpos = 'absolute' 4584 devlistpos = 'absolute' 4980 if testcount > 1: 4585 if testcount > 1: 4981 devlistpos = 'relative' 4586 devlistpos = 'relative' 4982 4587 4983 scaleTH = 20 4588 scaleTH = 20 4984 if kerror: 4589 if kerror: 4985 scaleTH = 60 4590 scaleTH = 60 4986 4591 4987 # write the html header first (html h 4592 # write the html header first (html head, css code, up to body start) 4988 html_header = '<!DOCTYPE html>\n<html 4593 html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ 4989 <meta http-equiv="content-type" conte 4594 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 4990 <title>'+title+'</title>\n\ 4595 <title>'+title+'</title>\n\ 4991 <style type=\'text/css\'>\n\ 4596 <style type=\'text/css\'>\n\ 4992 body {overflow-y:scroll;}\n\ 4597 body {overflow-y:scroll;}\n\ 4993 .stamp {width:100%;text-align 4598 .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ 4994 .stamp.sysinfo {font:10px Ari 4599 .stamp.sysinfo {font:10px Arial;}\n\ 4995 .callgraph {margin-top:30px;b 4600 .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ 4996 .callgraph article * {padding 4601 .callgraph article * {padding-left:28px;}\n\ 4997 h1 {color:black;font:bold 30p 4602 h1 {color:black;font:bold 30px Times;}\n\ 4998 t0 {color:black;font:bold 30p 4603 t0 {color:black;font:bold 30px Times;}\n\ 4999 t1 {color:black;font:30px Tim 4604 t1 {color:black;font:30px Times;}\n\ 5000 t2 {color:black;font:25px Tim 4605 t2 {color:black;font:25px Times;}\n\ 5001 t3 {color:black;font:20px Tim 4606 t3 {color:black;font:20px Times;white-space:nowrap;}\n\ 5002 t4 {color:black;font:bold 30p 4607 t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ 5003 cS {font:bold 13px Times;}\n\ 4608 cS {font:bold 13px Times;}\n\ 5004 table {width:100%;}\n\ 4609 table {width:100%;}\n\ 5005 .gray {background:rgba(80,80, 4610 .gray {background:rgba(80,80,80,0.1);}\n\ 5006 .green {background:rgba(204,2 4611 .green {background:rgba(204,255,204,0.4);}\n\ 5007 .purple {background:rgba(128, 4612 .purple {background:rgba(128,0,128,0.2);}\n\ 5008 .yellow {background:rgba(255, 4613 .yellow {background:rgba(255,255,204,0.4);}\n\ 5009 .blue {background:rgba(169,20 4614 .blue {background:rgba(169,208,245,0.4);}\n\ 5010 .time1 {font:22px Arial;borde 4615 .time1 {font:22px Arial;border:1px solid;}\n\ 5011 .time2 {font:15px Arial;borde 4616 .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ 5012 .testfail {font:bold 22px Ari 4617 .testfail {font:bold 22px Arial;color:red;border:1px dashed;}\n\ 5013 td {text-align:center;}\n\ 4618 td {text-align:center;}\n\ 5014 r {color:#500000;font:15px Ta 4619 r {color:#500000;font:15px Tahoma;}\n\ 5015 n {color:#505050;font:15px Ta 4620 n {color:#505050;font:15px Tahoma;}\n\ 5016 .tdhl {color:red;}\n\ 4621 .tdhl {color:red;}\n\ 5017 .hide {display:none;}\n\ 4622 .hide {display:none;}\n\ 5018 .pf {display:none;}\n\ 4623 .pf {display:none;}\n\ 5019 .pf:'+cgchk+' + label {backgr 4624 .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\ 5020 .pf:'+cgnchk+' ~ label {backg 4625 .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\ 5021 .pf:'+cgchk+' ~ *:not(:nth-ch 4626 .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ 5022 .zoombox {position:relative;w 4627 .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ 5023 .timeline {position:relative; 4628 .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ 5024 .thread {position:absolute;he 4629 .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\ 5025 .thread.ps {border-radius:3px 4630 .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ 5026 .thread:hover {background:whi 4631 .thread:hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 5027 .thread.sec,.thread.sec:hover 4632 .thread.sec,.thread.sec:hover {background:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ 5028 .hover {background:white;bord 4633 .hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 5029 .hover.sync {background:white 4634 .hover.sync {background:white;}\n\ 5030 .hover.bg,.hover.kth,.hover.s 4635 .hover.bg,.hover.kth,.hover.sync,.hover.ps {background:white;}\n\ 5031 .jiffie {position:absolute;po 4636 .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ 5032 .traceevent {position:absolut 4637 .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\ 5033 .traceevent:hover {color:whit 4638 .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ 5034 .phase {position:absolute;ove 4639 .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ 5035 .phaselet {float:left;overflo 4640 .phaselet {float:left;overflow:hidden;border:0px;text-align:center;min-height:100px;font-size:24px;}\n\ 5036 .t {position:absolute;line-he 4641 .t {position:absolute;line-height:'+('%d'%scaleTH)+'px;pointer-events:none;top:0;height:100%;border-right:1px solid black;z-index:6;}\n\ 5037 .err {position:absolute;top:0 4642 .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\ 5038 .legend {position:relative; w 4643 .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ 5039 .legend .square {position:abs 4644 .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ 5040 button {height:40px;width:200 4645 button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ 5041 .btnfmt {position:relative;fl 4646 .btnfmt {position:relative;float:right;height:25px;width:auto;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ 5042 .devlist {position:'+devlistp 4647 .devlist {position:'+devlistpos+';width:190px;}\n\ 5043 a:link {color:white;text-deco 4648 a:link {color:white;text-decoration:none;}\n\ 5044 a:visited {color:white;}\n\ 4649 a:visited {color:white;}\n\ 5045 a:hover {color:white;}\n\ 4650 a:hover {color:white;}\n\ 5046 a:active {color:white;}\n\ 4651 a:active {color:white;}\n\ 5047 .version {position:relative;f 4652 .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ 5048 #devicedetail {min-height:100 4653 #devicedetail {min-height:100px;box-shadow:5px 5px 20px black;}\n\ 5049 .tblock {position:absolute;he 4654 .tblock {position:absolute;height:100%;background:#ddd;}\n\ 5050 .tback {position:absolute;wid 4655 .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ 5051 .bg {z-index:1;}\n\ 4656 .bg {z-index:1;}\n\ 5052 '+extra+'\ 4657 '+extra+'\ 5053 </style>\n</head>\n<body>\n' 4658 </style>\n</head>\n<body>\n' 5054 hf.write(html_header) 4659 hf.write(html_header) 5055 4660 5056 # Function: addScriptCode 4661 # Function: addScriptCode 5057 # Description: 4662 # Description: 5058 # Adds the javascript code to the outp 4663 # Adds the javascript code to the output html 5059 # Arguments: 4664 # Arguments: 5060 # hf: the open html file pointer 4665 # hf: the open html file pointer 5061 # testruns: array of Data objects from 4666 # testruns: array of Data objects from parseKernelLog or parseTraceLog 5062 def addScriptCode(hf, testruns): 4667 def addScriptCode(hf, testruns): 5063 t0 = testruns[0].start * 1000 4668 t0 = testruns[0].start * 1000 5064 tMax = testruns[-1].end * 1000 4669 tMax = testruns[-1].end * 1000 5065 hf.write('<script type="text/javascri << 5066 # create an array in javascript memor 4670 # create an array in javascript memory with the device details 5067 detail = ' var devtable = [];\n' 4671 detail = ' var devtable = [];\n' 5068 for data in testruns: 4672 for data in testruns: 5069 topo = data.deviceTopology() 4673 topo = data.deviceTopology() 5070 detail += ' devtable[%d] 4674 detail += ' devtable[%d] = "%s";\n' % (data.testnumber, topo) 5071 detail += ' var bounds = [%f,%f]; 4675 detail += ' var bounds = [%f,%f];\n' % (t0, tMax) 5072 # add the code which will manipulate 4676 # add the code which will manipulate the data in the browser 5073 hf.write(detail); !! 4677 script_code = \ 5074 script_code = r""" var resolutio !! 4678 '<script type="text/javascript">\n'+detail+\ 5075 var dragval = [0, 0]; !! 4679 ' var resolution = -1;\n'\ 5076 function redrawTimescale(t0, tMax, tS !! 4680 ' var dragval = [0, 0];\n'\ 5077 var rline = '<div class="t" s !! 4681 ' function redrawTimescale(t0, tMax, tS) {\n'\ 5078 var tTotal = tMax - t0; !! 4682 ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;">\';\n'\ 5079 var list = document.getElemen !! 4683 ' var tTotal = tMax - t0;\n'\ 5080 for (var i = 0; i < list.leng !! 4684 ' var list = document.getElementsByClassName("tblock");\n'\ 5081 var timescale = list[ !! 4685 ' for (var i = 0; i < list.length; i++) {\n'\ 5082 var m0 = t0 + (tTotal !! 4686 ' var timescale = list[i].getElementsByClassName("timescale")[0];\n'\ 5083 var mTotal = tTotal*p !! 4687 ' var m0 = t0 + (tTotal*parseFloat(list[i].style.left)/100);\n'\ 5084 var mMax = m0 + mTota !! 4688 ' var mTotal = tTotal*parseFloat(list[i].style.width)/100;\n'\ 5085 var html = ""; !! 4689 ' var mMax = m0 + mTotal;\n'\ 5086 var divTotal = Math.f !! 4690 ' var html = "";\n'\ 5087 if(divTotal > 1000) c !! 4691 ' var divTotal = Math.floor(mTotal/tS) + 1;\n'\ 5088 var divEdge = (mTotal !! 4692 ' if(divTotal > 1000) continue;\n'\ 5089 var pos = 0.0, val = !! 4693 ' var divEdge = (mTotal - tS*(divTotal-1))*100/mTotal;\n'\ 5090 for (var j = 0; j < d !! 4694 ' var pos = 0.0, val = 0.0;\n'\ 5091 var htmlline !! 4695 ' for (var j = 0; j < divTotal; j++) {\n'\ 5092 var mode = li !! 4696 ' var htmlline = "";\n'\ 5093 if(mode == "s !! 4697 ' var mode = list[i].id[5];\n'\ 5094 pos = !! 4698 ' if(mode == "s") {\n'\ 5095 val = !! 4699 ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\ 5096 if(j !! 4700 ' val = (j-divTotal+1)*tS;\n'\ 5097 !! 4701 ' if(j == divTotal - 1)\n'\ 5098 else !! 4702 ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S→</cS></div>\';\n'\ 5099 !! 4703 ' else\n'\ 5100 } else { !! 4704 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 5101 pos = !! 4705 ' } else {\n'\ 5102 val = !! 4706 ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ 5103 htmll !! 4707 ' val = (j)*tS;\n'\ 5104 if(j !! 4708 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 5105 !! 4709 ' if(j == 0)\n'\ 5106 !! 4710 ' if(mode == "r")\n'\ 5107 !! 4711 ' htmlline = rline+"<cS>←R</cS></div>";\n'\ 5108 !! 4712 ' else\n'\ 5109 } !! 4713 ' htmlline = rline+"<cS>0ms</div>";\n'\ 5110 html += htmll !! 4714 ' }\n'\ 5111 } !! 4715 ' html += htmlline;\n'\ 5112 timescale.innerHTML = !! 4716 ' }\n'\ 5113 } !! 4717 ' timescale.innerHTML = html;\n'\ 5114 } !! 4718 ' }\n'\ 5115 function zoomTimeline() { !! 4719 ' }\n'\ 5116 var dmesg = document.getEleme !! 4720 ' function zoomTimeline() {\n'\ 5117 var zoombox = document.getEle !! 4721 ' var dmesg = document.getElementById("dmesg");\n'\ 5118 var left = zoombox.scrollLeft !! 4722 ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 5119 var val = parseFloat(dmesg.st !! 4723 ' var left = zoombox.scrollLeft;\n'\ 5120 var newval = 100; !! 4724 ' var val = parseFloat(dmesg.style.width);\n'\ 5121 var sh = window.outerWidth / !! 4725 ' var newval = 100;\n'\ 5122 if(this.id == "zoomin") { !! 4726 ' var sh = window.outerWidth / 2;\n'\ 5123 newval = val * 1.2; !! 4727 ' if(this.id == "zoomin") {\n'\ 5124 if(newval > 910034) n !! 4728 ' newval = val * 1.2;\n'\ 5125 dmesg.style.width = n !! 4729 ' if(newval > 910034) newval = 910034;\n'\ 5126 zoombox.scrollLeft = !! 4730 ' dmesg.style.width = newval+"%";\n'\ 5127 } else if (this.id == "zoomou !! 4731 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 5128 newval = val / 1.2; !! 4732 ' } else if (this.id == "zoomout") {\n'\ 5129 if(newval < 100) newv !! 4733 ' newval = val / 1.2;\n'\ 5130 dmesg.style.width = n !! 4734 ' if(newval < 100) newval = 100;\n'\ 5131 zoombox.scrollLeft = !! 4735 ' dmesg.style.width = newval+"%";\n'\ 5132 } else { !! 4736 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 5133 zoombox.scrollLeft = !! 4737 ' } else {\n'\ 5134 dmesg.style.width = " !! 4738 ' zoombox.scrollLeft = 0;\n'\ 5135 } !! 4739 ' dmesg.style.width = "100%";\n'\ 5136 var tS = [10000, 5000, 2000, !! 4740 ' }\n'\ 5137 var t0 = bounds[0]; !! 4741 ' var tS = [10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1];\n'\ 5138 var tMax = bounds[1]; !! 4742 ' var t0 = bounds[0];\n'\ 5139 var tTotal = tMax - t0; !! 4743 ' var tMax = bounds[1];\n'\ 5140 var wTotal = tTotal * 100.0 / !! 4744 ' var tTotal = tMax - t0;\n'\ 5141 var idx = 7*window.innerWidth !! 4745 ' var wTotal = tTotal * 100.0 / newval;\n'\ 5142 for(var i = 0; (i < tS.length !! 4746 ' var idx = 7*window.innerWidth/1100;\n'\ 5143 if(i >= tS.length) i = tS.len !! 4747 ' for(var i = 0; (i < tS.length)&&((wTotal / tS[i]) < idx); i++);\n'\ 5144 if(tS[i] == resolution) retur !! 4748 ' if(i >= tS.length) i = tS.length - 1;\n'\ 5145 resolution = tS[i]; !! 4749 ' if(tS[i] == resolution) return;\n'\ 5146 redrawTimescale(t0, tMax, tS[ !! 4750 ' resolution = tS[i];\n'\ 5147 } !! 4751 ' redrawTimescale(t0, tMax, tS[i]);\n'\ 5148 function deviceName(title) { !! 4752 ' }\n'\ 5149 var name = title.slice(0, tit !! 4753 ' function deviceName(title) {\n'\ 5150 return name; !! 4754 ' var name = title.slice(0, title.indexOf(" ("));\n'\ 5151 } !! 4755 ' return name;\n'\ 5152 function deviceHover() { !! 4756 ' }\n'\ 5153 var name = deviceName(this.ti !! 4757 ' function deviceHover() {\n'\ 5154 var dmesg = document.getEleme !! 4758 ' var name = deviceName(this.title);\n'\ 5155 var dev = dmesg.getElementsBy !! 4759 ' var dmesg = document.getElementById("dmesg");\n'\ 5156 var cpu = -1; !! 4760 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5157 if(name.match("CPU_ON\[[0-9]* !! 4761 ' var cpu = -1;\n'\ 5158 cpu = parseInt(name.s !! 4762 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 5159 else if(name.match("CPU_OFF\[ !! 4763 ' cpu = parseInt(name.slice(7));\n'\ 5160 cpu = parseInt(name.s !! 4764 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 5161 for (var i = 0; i < dev.lengt !! 4765 ' cpu = parseInt(name.slice(8));\n'\ 5162 dname = deviceName(de !! 4766 ' for (var i = 0; i < dev.length; i++) {\n'\ 5163 var cname = dev[i].cl !! 4767 ' dname = deviceName(dev[i].title);\n'\ 5164 if((cpu >= 0 && dname !! 4768 ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 5165 (name == dnam !! 4769 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 5166 { !! 4770 ' (name == dname))\n'\ 5167 dev[i].classN !! 4771 ' {\n'\ 5168 } else { !! 4772 ' dev[i].className = "hover "+cname;\n'\ 5169 dev[i].classN !! 4773 ' } else {\n'\ 5170 } !! 4774 ' dev[i].className = cname;\n'\ 5171 } !! 4775 ' }\n'\ 5172 } !! 4776 ' }\n'\ 5173 function deviceUnhover() { !! 4777 ' }\n'\ 5174 var dmesg = document.getEleme !! 4778 ' function deviceUnhover() {\n'\ 5175 var dev = dmesg.getElementsBy !! 4779 ' var dmesg = document.getElementById("dmesg");\n'\ 5176 for (var i = 0; i < dev.lengt !! 4780 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5177 dev[i].className = de !! 4781 ' for (var i = 0; i < dev.length; i++) {\n'\ 5178 } !! 4782 ' dev[i].className = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 5179 } !! 4783 ' }\n'\ 5180 function deviceTitle(title, total, cp !! 4784 ' }\n'\ 5181 var prefix = "Total"; !! 4785 ' function deviceTitle(title, total, cpu) {\n'\ 5182 if(total.length > 3) { !! 4786 ' var prefix = "Total";\n'\ 5183 prefix = "Average"; !! 4787 ' if(total.length > 3) {\n'\ 5184 total[1] = (total[1]+ !! 4788 ' prefix = "Average";\n'\ 5185 total[2] = (total[2]+ !! 4789 ' total[1] = (total[1]+total[3])/2;\n'\ 5186 } !! 4790 ' total[2] = (total[2]+total[4])/2;\n'\ 5187 var devtitle = document.getEl !! 4791 ' }\n'\ 5188 var name = deviceName(title); !! 4792 ' var devtitle = document.getElementById("devicedetailtitle");\n'\ 5189 if(cpu >= 0) name = "CPU"+cpu !! 4793 ' var name = deviceName(title);\n'\ 5190 var driver = ""; !! 4794 ' if(cpu >= 0) name = "CPU"+cpu;\n'\ 5191 var tS = "<t2>(</t2>"; !! 4795 ' var driver = "";\n'\ 5192 var tR = "<t2>)</t2>"; !! 4796 ' var tS = "<t2>(</t2>";\n'\ 5193 if(total[1] > 0) !! 4797 ' var tR = "<t2>)</t2>";\n'\ 5194 tS = "<t2>("+prefix+" !! 4798 ' if(total[1] > 0)\n'\ 5195 if(total[2] > 0) !! 4799 ' tS = "<t2>("+prefix+" Suspend:</t2><t0> "+total[1].toFixed(3)+" ms</t0> ";\n'\ 5196 tR = " <t2>"+prefix+" !! 4800 ' if(total[2] > 0)\n'\ 5197 var s = title.indexOf("{"); !! 4801 ' tR = " <t2>"+prefix+" Resume:</t2><t0> "+total[2].toFixed(3)+" ms<t2>)</t2></t0>";\n'\ 5198 var e = title.indexOf("}"); !! 4802 ' var s = title.indexOf("{");\n'\ 5199 if((s >= 0) && (e >= 0)) !! 4803 ' var e = title.indexOf("}");\n'\ 5200 driver = title.slice(< !! 4804 ' if((s >= 0) && (e >= 0))\n'\ 5201 if(total[1] > 0 && total[2] > !! 4805 ' driver = title.slice(s+1, e) + " <t1>@</t1> ";\n'\ 5202 devtitle.innerHTML = !! 4806 ' if(total[1] > 0 && total[2] > 0)\n'\ 5203 else !! 4807 ' devtitle.innerHTML = "<t0>"+driver+name+"</t0> "+tS+tR;\n'\ 5204 devtitle.innerHTML = !! 4808 ' else\n'\ 5205 return name; !! 4809 ' devtitle.innerHTML = "<t0>"+title+"</t0>";\n'\ 5206 } !! 4810 ' return name;\n'\ 5207 function deviceDetail() { !! 4811 ' }\n'\ 5208 var devinfo = document.getEle !! 4812 ' function deviceDetail() {\n'\ 5209 devinfo.style.display = "bloc !! 4813 ' var devinfo = document.getElementById("devicedetail");\n'\ 5210 var name = deviceName(this.ti !! 4814 ' devinfo.style.display = "block";\n'\ 5211 var cpu = -1; !! 4815 ' var name = deviceName(this.title);\n'\ 5212 if(name.match("CPU_ON\[[0-9]* !! 4816 ' var cpu = -1;\n'\ 5213 cpu = parseInt(name.s !! 4817 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 5214 else if(name.match("CPU_OFF\[ !! 4818 ' cpu = parseInt(name.slice(7));\n'\ 5215 cpu = parseInt(name.s !! 4819 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 5216 var dmesg = document.getEleme !! 4820 ' cpu = parseInt(name.slice(8));\n'\ 5217 var dev = dmesg.getElementsBy !! 4821 ' var dmesg = document.getElementById("dmesg");\n'\ 5218 var idlist = []; !! 4822 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5219 var pdata = [[]]; !! 4823 ' var idlist = [];\n'\ 5220 if(document.getElementById("d !! 4824 ' var pdata = [[]];\n'\ 5221 pdata = [[], []]; !! 4825 ' if(document.getElementById("devicedetail1"))\n'\ 5222 var pd = pdata[0]; !! 4826 ' pdata = [[], []];\n'\ 5223 var total = [0.0, 0.0, 0.0]; !! 4827 ' var pd = pdata[0];\n'\ 5224 for (var i = 0; i < dev.lengt !! 4828 ' var total = [0.0, 0.0, 0.0];\n'\ 5225 dname = deviceName(de !! 4829 ' for (var i = 0; i < dev.length; i++) {\n'\ 5226 if((cpu >= 0 && dname !! 4830 ' dname = deviceName(dev[i].title);\n'\ 5227 (name == dnam !! 4831 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 5228 { !! 4832 ' (name == dname))\n'\ 5229 idlist[idlist !! 4833 ' {\n'\ 5230 var tidx = 1; !! 4834 ' idlist[idlist.length] = dev[i].id;\n'\ 5231 if(dev[i].id[ !! 4835 ' var tidx = 1;\n'\ 5232 pd = !! 4836 ' if(dev[i].id[0] == "a") {\n'\ 5233 } else { !! 4837 ' pd = pdata[0];\n'\ 5234 if(pd !! 4838 ' } else {\n'\ 5235 if(to !! 4839 ' if(pdata.length == 1) pdata[1] = [];\n'\ 5236 pd = !! 4840 ' if(total.length == 3) total[3]=total[4]=0.0;\n'\ 5237 tidx !! 4841 ' pd = pdata[1];\n'\ 5238 } !! 4842 ' tidx = 3;\n'\ 5239 var info = de !! 4843 ' }\n'\ 5240 var pname = i !! 4844 ' var info = dev[i].title.split(" ");\n'\ 5241 pd[pname] = p !! 4845 ' var pname = info[info.length-1];\n'\ 5242 total[0] += p !! 4846 ' pd[pname] = parseFloat(info[info.length-3].slice(1));\n'\ 5243 if(pname.inde !! 4847 ' total[0] += pd[pname];\n'\ 5244 total !! 4848 ' if(pname.indexOf("suspend") >= 0)\n'\ 5245 else !! 4849 ' total[tidx] += pd[pname];\n'\ 5246 total !! 4850 ' else\n'\ 5247 } !! 4851 ' total[tidx+1] += pd[pname];\n'\ 5248 } !! 4852 ' }\n'\ 5249 var devname = deviceTitle(thi !! 4853 ' }\n'\ 5250 var left = 0.0; !! 4854 ' var devname = deviceTitle(this.title, total, cpu);\n'\ 5251 for (var t = 0; t < pdata.len !! 4855 ' var left = 0.0;\n'\ 5252 pd = pdata[t]; !! 4856 ' for (var t = 0; t < pdata.length; t++) {\n'\ 5253 devinfo = document.ge !! 4857 ' pd = pdata[t];\n'\ 5254 var phases = devinfo. !! 4858 ' devinfo = document.getElementById("devicedetail"+t);\n'\ 5255 for (var i = 0; i < p !! 4859 ' var phases = devinfo.getElementsByClassName("phaselet");\n'\ 5256 if(phases[i]. !! 4860 ' for (var i = 0; i < phases.length; i++) {\n'\ 5257 var w !! 4861 ' if(phases[i].id in pd) {\n'\ 5258 var f !! 4862 ' var w = 100.0*pd[phases[i].id]/total[0];\n'\ 5259 if(w !! 4863 ' var fs = 32;\n'\ 5260 var f !! 4864 ' if(w < 8) fs = 4*w | 0;\n'\ 5261 phase !! 4865 ' var fs2 = fs*3/4;\n'\ 5262 phase !! 4866 ' phases[i].style.width = w+"%";\n'\ 5263 phase !! 4867 ' phases[i].style.left = left+"%";\n'\ 5264 left !! 4868 ' phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\ 5265 var t !! 4869 ' left += w;\n'\ 5266 var p !! 4870 ' var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\ 5267 phase !! 4871 ' var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";\n'\ 5268 } else { !! 4872 ' phases[i].innerHTML = time+pname;\n'\ 5269 phase !! 4873 ' } else {\n'\ 5270 phase !! 4874 ' phases[i].style.width = "0%";\n'\ 5271 } !! 4875 ' phases[i].style.left = left+"%";\n'\ 5272 } !! 4876 ' }\n'\ 5273 } !! 4877 ' }\n'\ 5274 if(typeof devstats !== 'undef !! 4878 ' }\n'\ 5275 callDetail(this.id, t !! 4879 ' if(typeof devstats !== \'undefined\')\n'\ 5276 var cglist = document.getElem !! 4880 ' callDetail(this.id, this.title);\n'\ 5277 if(!cglist) return; !! 4881 ' var cglist = document.getElementById("callgraphs");\n'\ 5278 var cg = cglist.getElementsBy !! 4882 ' if(!cglist) return;\n'\ 5279 if(cg.length < 10) return; !! 4883 ' var cg = cglist.getElementsByClassName("atop");\n'\ 5280 for (var i = 0; i < cg.length !! 4884 ' if(cg.length < 10) return;\n'\ 5281 cgid = cg[i].id.split !! 4885 ' for (var i = 0; i < cg.length; i++) {\n'\ 5282 if(idlist.indexOf(cgi !! 4886 ' cgid = cg[i].id.split("x")[0]\n'\ 5283 cg[i].style.d !! 4887 ' if(idlist.indexOf(cgid) >= 0) {\n'\ 5284 } else { !! 4888 ' cg[i].style.display = "block";\n'\ 5285 cg[i].style.d !! 4889 ' } else {\n'\ 5286 } !! 4890 ' cg[i].style.display = "none";\n'\ 5287 } !! 4891 ' }\n'\ 5288 } !! 4892 ' }\n'\ 5289 function callDetail(devid, devtitle) !! 4893 ' }\n'\ 5290 if(!(devid in devstats) || de !! 4894 ' function callDetail(devid, devtitle) {\n'\ 5291 return; !! 4895 ' if(!(devid in devstats) || devstats[devid].length < 1)\n'\ 5292 var list = devstats[devid]; !! 4896 ' return;\n'\ 5293 var tmp = devtitle.split(" ") !! 4897 ' var list = devstats[devid];\n'\ 5294 var name = tmp[0], phase = tm !! 4898 ' var tmp = devtitle.split(" ");\n'\ 5295 var dd = document.getElementB !! 4899 ' var name = tmp[0], phase = tmp[tmp.length-1];\n'\ 5296 var total = parseFloat(tmp[1] !! 4900 ' var dd = document.getElementById(phase);\n'\ 5297 var mlist = []; !! 4901 ' var total = parseFloat(tmp[1].slice(1));\n'\ 5298 var maxlen = 0; !! 4902 ' var mlist = [];\n'\ 5299 var info = [] !! 4903 ' var maxlen = 0;\n'\ 5300 for(var i in list) { !! 4904 ' var info = []\n'\ 5301 if(list[i][0] == "@") !! 4905 ' for(var i in list) {\n'\ 5302 info = list[i !! 4906 ' if(list[i][0] == "@") {\n'\ 5303 continue; !! 4907 ' info = list[i].split("|");\n'\ 5304 } !! 4908 ' continue;\n'\ 5305 var tmp = list[i].spl !! 4909 ' }\n'\ 5306 var t = parseFloat(tm !! 4910 ' var tmp = list[i].split("|");\n'\ 5307 var p = (t*100.0/tota !! 4911 ' var t = parseFloat(tmp[0]), f = tmp[1], c = parseInt(tmp[2]);\n'\ 5308 mlist[mlist.length] = !! 4912 ' var p = (t*100.0/total).toFixed(2);\n'\ 5309 if(f.length > maxlen) !! 4913 ' mlist[mlist.length] = [f, c, t.toFixed(2), p+"%"];\n'\ 5310 maxlen = f.le !! 4914 ' if(f.length > maxlen)\n'\ 5311 } !! 4915 ' maxlen = f.length;\n'\ 5312 var pad = 5; !! 4916 ' }\n'\ 5313 if(mlist.length == 0) pad = 3 !! 4917 ' var pad = 5;\n'\ 5314 var html = '<div style="paddi !! 4918 ' if(mlist.length == 0) pad = 30;\n'\ 5315 if(info.length > 2) !! 4919 ' var html = \'<div style="padding-top:\'+pad+\'px"><t3> <b>\'+name+\':</b>\';\n'\ 5316 html += " start=<b>"+ !! 4920 ' if(info.length > 2)\n'\ 5317 if(info.length > 3) !! 4921 ' html += " start=<b>"+info[1]+"</b>, end=<b>"+info[2]+"</b>";\n'\ 5318 html += ", length<i>( !! 4922 ' if(info.length > 3)\n'\ 5319 if(info.length > 4) !! 4923 ' html += ", length<i>(w/o overhead)</i>=<b>"+info[3]+" ms</b>";\n'\ 5320 html += ", return=<b> !! 4924 ' if(info.length > 4)\n'\ 5321 html += "</t3></div>"; !! 4925 ' html += ", return=<b>"+info[4]+"</b>";\n'\ 5322 if(mlist.length > 0) { !! 4926 ' html += "</t3></div>";\n'\ 5323 html += '<table class !! 4927 ' if(mlist.length > 0) {\n'\ 5324 for(var i in mlist) !! 4928 ' html += \'<table class=fstat style="padding-top:\'+(maxlen*5)+\'px;"><tr><th>Function</th>\';\n'\ 5325 html += "<td !! 4929 ' for(var i in mlist)\n'\ 5326 html += "</tr><tr><th !! 4930 ' html += "<td class=vt>"+mlist[i][0]+"</td>";\n'\ 5327 for(var i in mlist) !! 4931 ' html += "</tr><tr><th>Calls</th>";\n'\ 5328 html += "<td> !! 4932 ' for(var i in mlist)\n'\ 5329 html += "</tr><tr><th !! 4933 ' html += "<td>"+mlist[i][1]+"</td>";\n'\ 5330 for(var i in mlist) !! 4934 ' html += "</tr><tr><th>Time(ms)</th>";\n'\ 5331 html += "<td> !! 4935 ' for(var i in mlist)\n'\ 5332 html += "</tr><tr><th !! 4936 ' html += "<td>"+mlist[i][2]+"</td>";\n'\ 5333 for(var i in mlist) !! 4937 ' html += "</tr><tr><th>Percent</th>";\n'\ 5334 html += "<td> !! 4938 ' for(var i in mlist)\n'\ 5335 html += "</tr></table !! 4939 ' html += "<td>"+mlist[i][3]+"</td>";\n'\ 5336 } !! 4940 ' html += "</tr></table>";\n'\ 5337 dd.innerHTML = html; !! 4941 ' }\n'\ 5338 var height = (maxlen*5)+100; !! 4942 ' dd.innerHTML = html;\n'\ 5339 dd.style.height = height+"px" !! 4943 ' var height = (maxlen*5)+100;\n'\ 5340 document.getElementById("devi !! 4944 ' dd.style.height = height+"px";\n'\ 5341 } !! 4945 ' document.getElementById("devicedetail").style.height = height+"px";\n'\ 5342 function callSelect() { !! 4946 ' }\n'\ 5343 var cglist = document.getElem !! 4947 ' function callSelect() {\n'\ 5344 if(!cglist) return; !! 4948 ' var cglist = document.getElementById("callgraphs");\n'\ 5345 var cg = cglist.getElementsBy !! 4949 ' if(!cglist) return;\n'\ 5346 for (var i = 0; i < cg.length !! 4950 ' var cg = cglist.getElementsByClassName("atop");\n'\ 5347 if(this.id == cg[i].i !! 4951 ' for (var i = 0; i < cg.length; i++) {\n'\ 5348 cg[i].style.d !! 4952 ' if(this.id == cg[i].id) {\n'\ 5349 } else { !! 4953 ' cg[i].style.display = "block";\n'\ 5350 cg[i].style.d !! 4954 ' } else {\n'\ 5351 } !! 4955 ' cg[i].style.display = "none";\n'\ 5352 } !! 4956 ' }\n'\ 5353 } !! 4957 ' }\n'\ 5354 function devListWindow(e) { !! 4958 ' }\n'\ 5355 var win = window.open(); !! 4959 ' function devListWindow(e) {\n'\ 5356 var html = "<title>"+e.target !! 4960 ' var win = window.open();\n'\ 5357 "<style type=\"text/c !! 4961 ' var html = "<title>"+e.target.innerHTML+"</title>"+\n'\ 5358 " ul {list-style-ty !! 4962 ' "<style type=\\"text/css\\">"+\n'\ 5359 "</style>" !! 4963 ' " ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\ 5360 var dt = devtable[0]; !! 4964 ' "</style>"\n'\ 5361 if(e.target.id != "devlist1") !! 4965 ' var dt = devtable[0];\n'\ 5362 dt = devtable[1]; !! 4966 ' if(e.target.id != "devlist1")\n'\ 5363 win.document.write(html+dt); !! 4967 ' dt = devtable[1];\n'\ 5364 } !! 4968 ' win.document.write(html+dt);\n'\ 5365 function errWindow() { !! 4969 ' }\n'\ 5366 var range = this.id.split("_" !! 4970 ' function errWindow() {\n'\ 5367 var idx1 = parseInt(range[0]) !! 4971 ' var range = this.id.split("_");\n'\ 5368 var idx2 = parseInt(range[1]) !! 4972 ' var idx1 = parseInt(range[0]);\n'\ 5369 var win = window.open(); !! 4973 ' var idx2 = parseInt(range[1]);\n'\ 5370 var log = document.getElement !! 4974 ' var win = window.open();\n'\ 5371 var title = "<title>dmesg log !! 4975 ' var log = document.getElementById("dmesglog");\n'\ 5372 var text = log.innerHTML.spli !! 4976 ' var title = "<title>dmesg log</title>";\n'\ 5373 var html = ""; !! 4977 ' var text = log.innerHTML.split("\\n");\n'\ 5374 for(var i = 0; i < text.lengt !! 4978 ' var html = "";\n'\ 5375 if(i == idx1) { !! 4979 ' for(var i = 0; i < text.length; i++) {\n'\ 5376 html += "<e i !! 4980 ' if(i == idx1) {\n'\ 5377 } else if(i > idx1 && !! 4981 ' html += "<e id=target>"+text[i]+"</e>\\n";\n'\ 5378 html += "<e>" !! 4982 ' } else if(i > idx1 && i <= idx2) {\n'\ 5379 } else { !! 4983 ' html += "<e>"+text[i]+"</e>\\n";\n'\ 5380 html += text[ !! 4984 ' } else {\n'\ 5381 } !! 4985 ' html += text[i]+"\\n";\n'\ 5382 } !! 4986 ' }\n'\ 5383 win.document.write("<style>e{ !! 4987 ' }\n'\ 5384 win.location.hash = "#target" !! 4988 ' win.document.write("<style>e{color:red}</style>"+title+"<pre>"+html+"</pre>");\n'\ 5385 win.document.close(); !! 4989 ' win.location.hash = "#target";\n'\ 5386 } !! 4990 ' win.document.close();\n'\ 5387 function logWindow(e) { !! 4991 ' }\n'\ 5388 var name = e.target.id.slice( !! 4992 ' function logWindow(e) {\n'\ 5389 var win = window.open(); !! 4993 ' var name = e.target.id.slice(4);\n'\ 5390 var log = document.getElement !! 4994 ' var win = window.open();\n'\ 5391 var title = "<title>"+documen !! 4995 ' var log = document.getElementById(name+"log");\n'\ 5392 win.document.write(title+"<pr !! 4996 ' var title = "<title>"+document.title.split(" ")[0]+" "+name+" log</title>";\n'\ 5393 win.document.close(); !! 4997 ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ 5394 } !! 4998 ' win.document.close();\n'\ 5395 function onMouseDown(e) { !! 4999 ' }\n'\ 5396 dragval[0] = e.clientX; !! 5000 ' function onMouseDown(e) {\n'\ 5397 dragval[1] = document.getElem !! 5001 ' dragval[0] = e.clientX;\n'\ 5398 document.onmousemove = onMous !! 5002 ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ 5399 } !! 5003 ' document.onmousemove = onMouseMove;\n'\ 5400 function onMouseMove(e) { !! 5004 ' }\n'\ 5401 var zoombox = document.getEle !! 5005 ' function onMouseMove(e) {\n'\ 5402 zoombox.scrollLeft = dragval[ !! 5006 ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 5403 } !! 5007 ' zoombox.scrollLeft = dragval[1] + dragval[0] - e.clientX;\n'\ 5404 function onMouseUp(e) { !! 5008 ' }\n'\ 5405 document.onmousemove = null; !! 5009 ' function onMouseUp(e) {\n'\ 5406 } !! 5010 ' document.onmousemove = null;\n'\ 5407 function onKeyPress(e) { !! 5011 ' }\n'\ 5408 var c = e.charCode; !! 5012 ' function onKeyPress(e) {\n'\ 5409 if(c != 42 && c != 43 && c != !! 5013 ' var c = e.charCode;\n'\ 5410 var click = document.createEv !! 5014 ' if(c != 42 && c != 43 && c != 45) return;\n'\ 5411 click.initEvent("click", true !! 5015 ' var click = document.createEvent("Events");\n'\ 5412 if(c == 43) !! 5016 ' click.initEvent("click", true, false);\n'\ 5413 document.getElementBy !! 5017 ' if(c == 43) \n'\ 5414 else if(c == 45) !! 5018 ' document.getElementById("zoomin").dispatchEvent(click);\n'\ 5415 document.getElementBy !! 5019 ' else if(c == 45)\n'\ 5416 else if(c == 42) !! 5020 ' document.getElementById("zoomout").dispatchEvent(click);\n'\ 5417 document.getElementBy !! 5021 ' else if(c == 42)\n'\ 5418 } !! 5022 ' document.getElementById("zoomdef").dispatchEvent(click);\n'\ 5419 window.addEventListener("resize", fun !! 5023 ' }\n'\ 5420 window.addEventListener("load", funct !! 5024 ' window.addEventListener("resize", function () {zoomTimeline();});\n'\ 5421 var dmesg = document.getEleme !! 5025 ' window.addEventListener("load", function () {\n'\ 5422 dmesg.style.width = "100%" !! 5026 ' var dmesg = document.getElementById("dmesg");\n'\ 5423 dmesg.onmousedown = onMouseDo !! 5027 ' dmesg.style.width = "100%"\n'\ 5424 document.onmouseup = onMouseU !! 5028 ' dmesg.onmousedown = onMouseDown;\n'\ 5425 document.onkeypress = onKeyPr !! 5029 ' document.onmouseup = onMouseUp;\n'\ 5426 document.getElementById("zoom !! 5030 ' document.onkeypress = onKeyPress;\n'\ 5427 document.getElementById("zoom !! 5031 ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ 5428 document.getElementById("zoom !! 5032 ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ 5429 var list = document.getElemen !! 5033 ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ 5430 for (var i = 0; i < list.leng !! 5034 ' var list = document.getElementsByClassName("err");\n'\ 5431 list[i].onclick = err !! 5035 ' for (var i = 0; i < list.length; i++)\n'\ 5432 var list = document.getElemen !! 5036 ' list[i].onclick = errWindow;\n'\ 5433 for (var i = 0; i < list.leng !! 5037 ' var list = document.getElementsByClassName("logbtn");\n'\ 5434 list[i].onclick = log !! 5038 ' for (var i = 0; i < list.length; i++)\n'\ 5435 list = document.getElementsBy !! 5039 ' list[i].onclick = logWindow;\n'\ 5436 for (var i = 0; i < list.leng !! 5040 ' list = document.getElementsByClassName("devlist");\n'\ 5437 list[i].onclick = dev !! 5041 ' for (var i = 0; i < list.length; i++)\n'\ 5438 var dev = dmesg.getElementsBy !! 5042 ' list[i].onclick = devListWindow;\n'\ 5439 for (var i = 0; i < dev.lengt !! 5043 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5440 dev[i].onclick = devi !! 5044 ' for (var i = 0; i < dev.length; i++) {\n'\ 5441 dev[i].onmouseover = !! 5045 ' dev[i].onclick = deviceDetail;\n'\ 5442 dev[i].onmouseout = d !! 5046 ' dev[i].onmouseover = deviceHover;\n'\ 5443 } !! 5047 ' dev[i].onmouseout = deviceUnhover;\n'\ 5444 var dev = dmesg.getElementsBy !! 5048 ' }\n'\ 5445 for (var i = 0; i < dev.lengt !! 5049 ' var dev = dmesg.getElementsByClassName("srccall");\n'\ 5446 dev[i].onclick = call !! 5050 ' for (var i = 0; i < dev.length; i++)\n'\ 5447 zoomTimeline(); !! 5051 ' dev[i].onclick = callSelect;\n'\ 5448 }); !! 5052 ' zoomTimeline();\n'\ 5449 </script> """ !! 5053 ' });\n'\ >> 5054 '</script>\n' 5450 hf.write(script_code); 5055 hf.write(script_code); 5451 5056 >> 5057 def setRuntimeSuspend(before=True): >> 5058 global sysvals >> 5059 sv = sysvals >> 5060 if sv.rs == 0: >> 5061 return >> 5062 if before: >> 5063 # runtime suspend disable or enable >> 5064 if sv.rs > 0: >> 5065 sv.rstgt, sv.rsval, sv.rsdir = 'on', 'auto', 'enabled' >> 5066 else: >> 5067 sv.rstgt, sv.rsval, sv.rsdir = 'auto', 'on', 'disabled' >> 5068 pprint('CONFIGURING RUNTIME SUSPEND...') >> 5069 sv.rslist = deviceInfo(sv.rstgt) >> 5070 for i in sv.rslist: >> 5071 sv.setVal(sv.rsval, i) >> 5072 pprint('runtime suspend %s on all devices (%d changed)' % (sv.rsdir, len(sv.rslist))) >> 5073 pprint('waiting 5 seconds...') >> 5074 time.sleep(5) >> 5075 else: >> 5076 # runtime suspend re-enable or re-disable >> 5077 for i in sv.rslist: >> 5078 sv.setVal(sv.rstgt, i) >> 5079 pprint('runtime suspend settings restored on %d devices' % len(sv.rslist)) >> 5080 5452 # Function: executeSuspend 5081 # Function: executeSuspend 5453 # Description: 5082 # Description: 5454 # Execute system suspend through the s 5083 # Execute system suspend through the sysfs interface, then copy the output 5455 # dmesg and ftrace files to the test o 5084 # dmesg and ftrace files to the test output directory. 5456 def executeSuspend(quiet=False): !! 5085 def executeSuspend(): 5457 sv, tp, pm = sysvals, sysvals.tpath, !! 5086 pm = ProcessMonitor() 5458 if sv.wifi: !! 5087 tp = sysvals.tpath 5459 wifi = sv.checkWifi() !! 5088 wifi = sysvals.checkWifi() 5460 sv.dlog('wifi check, connecte << 5461 testdata = [] 5089 testdata = [] >> 5090 battery = True if getBattery() else False 5462 # run these commands to prepare the s 5091 # run these commands to prepare the system for suspend 5463 if sv.display: !! 5092 if sysvals.display: 5464 if not quiet: !! 5093 pprint('SET DISPLAY TO %s' % sysvals.display.upper()) 5465 pprint('SET DISPLAY T !! 5094 displayControl(sysvals.display) 5466 ret = sv.displayControl(sv.di << 5467 sv.dlog('xset display %s, ret << 5468 time.sleep(1) 5095 time.sleep(1) 5469 if sv.sync: !! 5096 if sysvals.sync: 5470 if not quiet: !! 5097 pprint('SYNCING FILESYSTEMS') 5471 pprint('SYNCING FILES << 5472 sv.dlog('syncing filesystems' << 5473 call('sync', shell=True) 5098 call('sync', shell=True) 5474 sv.dlog('read dmesg') !! 5099 # mark the start point in the kernel ring buffer just as we start 5475 sv.initdmesg() !! 5100 sysvals.initdmesg() 5476 sv.dlog('cmdinfo before') !! 5101 # start ftrace 5477 sv.cmdinfo(True) !! 5102 if(sysvals.usecallgraph or sysvals.usetraceevents): 5478 sv.start(pm) !! 5103 pprint('START TRACING') >> 5104 sysvals.fsetVal('1', 'tracing_on') >> 5105 if sysvals.useprocmon: >> 5106 pm.start() 5479 # execute however many s/r runs reque 5107 # execute however many s/r runs requested 5480 for count in range(1,sv.execcount+1): !! 5108 for count in range(1,sysvals.execcount+1): 5481 # x2delay in between test run 5109 # x2delay in between test runs 5482 if(count > 1 and sv.x2delay > !! 5110 if(count > 1 and sysvals.x2delay > 0): 5483 sv.fsetVal('WAIT %d' !! 5111 sysvals.fsetVal('WAIT %d' % sysvals.x2delay, 'trace_marker') 5484 time.sleep(sv.x2delay !! 5112 time.sleep(sysvals.x2delay/1000.0) 5485 sv.fsetVal('WAIT END' !! 5113 sysvals.fsetVal('WAIT END', 'trace_marker') 5486 # start message 5114 # start message 5487 if sv.testcommand != '': !! 5115 if sysvals.testcommand != '': 5488 pprint('COMMAND START 5116 pprint('COMMAND START') 5489 else: 5117 else: 5490 if(sv.rtcwake): !! 5118 if(sysvals.rtcwake): 5491 pprint('SUSPE 5119 pprint('SUSPEND START') 5492 else: 5120 else: 5493 pprint('SUSPE 5121 pprint('SUSPEND START (press a key to resume)') >> 5122 sysvals.mcelog(True) >> 5123 bat1 = getBattery() if battery else False 5494 # set rtcwake 5124 # set rtcwake 5495 if(sv.rtcwake): !! 5125 if(sysvals.rtcwake): 5496 if not quiet: !! 5126 pprint('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime) 5497 pprint('will !! 5127 sysvals.rtcWakeAlarmOn() 5498 sv.dlog('enable RTC w << 5499 sv.rtcWakeAlarmOn() << 5500 # start of suspend trace mark 5128 # start of suspend trace marker 5501 sv.fsetVal(datetime.now().str !! 5129 if(sysvals.usecallgraph or sysvals.usetraceevents): >> 5130 sysvals.fsetVal('SUSPEND START', 'trace_marker') 5502 # predelay delay 5131 # predelay delay 5503 if(count == 1 and sv.predelay !! 5132 if(count == 1 and sysvals.predelay > 0): 5504 sv.fsetVal('WAIT %d' !! 5133 sysvals.fsetVal('WAIT %d' % sysvals.predelay, 'trace_marker') 5505 time.sleep(sv.predela !! 5134 time.sleep(sysvals.predelay/1000.0) 5506 sv.fsetVal('WAIT END' !! 5135 sysvals.fsetVal('WAIT END', 'trace_marker') 5507 # initiate suspend or command 5136 # initiate suspend or command 5508 sv.dlog('system executing a s << 5509 tdata = {'error': ''} 5137 tdata = {'error': ''} 5510 if sv.testcommand != '': !! 5138 if sysvals.testcommand != '': 5511 res = call(sv.testcom !! 5139 res = call(sysvals.testcommand+' 2>&1', shell=True); 5512 if res != 0: 5140 if res != 0: 5513 tdata['error' 5141 tdata['error'] = 'cmd returned %d' % res 5514 else: 5142 else: 5515 s0ixready = sv.s0ixSu !! 5143 mode = sysvals.suspendmode 5516 mode = sv.suspendmode !! 5144 if sysvals.memmode and os.path.exists(sysvals.mempowerfile): 5517 if sv.memmode and os. << 5518 mode = 'mem' 5145 mode = 'mem' 5519 sv.testVal(sv !! 5146 pf = open(sysvals.mempowerfile, 'w') 5520 if sv.diskmode and os !! 5147 pf.write(sysvals.memmode) >> 5148 pf.close() >> 5149 if sysvals.diskmode and os.path.exists(sysvals.diskpowerfile): 5521 mode = 'disk' 5150 mode = 'disk' 5522 sv.testVal(sv !! 5151 pf = open(sysvals.diskpowerfile, 'w') 5523 if sv.acpidebug: !! 5152 pf.write(sysvals.diskmode) 5524 sv.testVal(sv !! 5153 pf.close() 5525 if ((mode == 'freeze' !! 5154 if mode == 'freeze' and sysvals.haveTurbostat(): 5526 and sv.haveTu << 5527 # execution w 5155 # execution will pause here 5528 retval, turbo !! 5156 turbo = sysvals.turbostat() 5529 if retval != << 5530 tdata << 5531 if turbo: 5157 if turbo: 5532 tdata 5158 tdata['turbo'] = turbo 5533 else: 5159 else: 5534 pf = open(sv. !! 5160 pf = open(sysvals.powerfile, 'w') 5535 pf.write(mode 5161 pf.write(mode) 5536 # execution w 5162 # execution will pause here 5537 try: 5163 try: 5538 pf.fl << 5539 pf.cl 5164 pf.close() 5540 except Except 5165 except Exception as e: 5541 tdata 5166 tdata['error'] = str(e) 5542 sv.fsetVal('CMD COMPLETE', 't !! 5167 if(sysvals.rtcwake): 5543 sv.dlog('system returned') !! 5168 sysvals.rtcWakeAlarmOff() 5544 # reset everything << 5545 sv.testVal('restoreall') << 5546 if(sv.rtcwake): << 5547 sv.dlog('disable RTC << 5548 sv.rtcWakeAlarmOff() << 5549 # postdelay delay 5169 # postdelay delay 5550 if(count == sv.execcount and !! 5170 if(count == sysvals.execcount and sysvals.postdelay > 0): 5551 sv.fsetVal('WAIT %d' !! 5171 sysvals.fsetVal('WAIT %d' % sysvals.postdelay, 'trace_marker') 5552 time.sleep(sv.postdel !! 5172 time.sleep(sysvals.postdelay/1000.0) 5553 sv.fsetVal('WAIT END' !! 5173 sysvals.fsetVal('WAIT END', 'trace_marker') 5554 # return from suspend 5174 # return from suspend 5555 pprint('RESUME COMPLETE') 5175 pprint('RESUME COMPLETE') 5556 if(count < sv.execcount): !! 5176 if(sysvals.usecallgraph or sysvals.usetraceevents): 5557 sv.fsetVal(datetime.n !! 5177 sysvals.fsetVal('RESUME COMPLETE', 'trace_marker') 5558 elif(not sv.wifitrace): !! 5178 if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'): 5559 sv.fsetVal(datetime.n << 5560 sv.stop(pm) << 5561 if sv.wifi and wifi: << 5562 tdata['wifi'] = sv.po << 5563 sv.dlog('wifi check, << 5564 if(count == sv.execcount and << 5565 sv.fsetVal(datetime.n << 5566 sv.stop(pm) << 5567 if sv.netfix: << 5568 tdata['netfix'] = sv. << 5569 sv.dlog('netfix, %s' << 5570 if(sv.suspendmode == 'mem' or << 5571 sv.dlog('read the ACP << 5572 tdata['fw'] = getFPDT 5179 tdata['fw'] = getFPDT(False) >> 5180 mcelog = sysvals.mcelog() >> 5181 if mcelog: >> 5182 tdata['mcelog'] = mcelog >> 5183 bat2 = getBattery() if battery else False >> 5184 if battery and bat1 and bat2: >> 5185 tdata['bat'] = (bat1, bat2) >> 5186 if 'device' in wifi and 'ip' in wifi: >> 5187 tdata['wifi'] = (wifi, sysvals.checkWifi()) 5573 testdata.append(tdata) 5188 testdata.append(tdata) 5574 sv.dlog('cmdinfo after') !! 5189 # stop ftrace 5575 cmdafter = sv.cmdinfo(False) !! 5190 if(sysvals.usecallgraph or sysvals.usetraceevents): >> 5191 if sysvals.useprocmon: >> 5192 pm.stop() >> 5193 sysvals.fsetVal('0', 'tracing_on') 5576 # grab a copy of the dmesg output 5194 # grab a copy of the dmesg output 5577 if not quiet: !! 5195 pprint('CAPTURING DMESG') 5578 pprint('CAPTURING DMESG') !! 5196 sysvals.getdmesg(testdata) 5579 sv.getdmesg(testdata) << 5580 # grab a copy of the ftrace output 5197 # grab a copy of the ftrace output 5581 if sv.useftrace: !! 5198 if(sysvals.usecallgraph or sysvals.usetraceevents): 5582 if not quiet: !! 5199 pprint('CAPTURING TRACE') 5583 pprint('CAPTURING TRA !! 5200 op = sysvals.writeDatafileHeader(sysvals.ftracefile, testdata) 5584 op = sv.writeDatafileHeader(s !! 5201 fp = open(tp+'trace', 'r') 5585 fp = open(tp+'trace', 'rb') !! 5202 for line in fp: 5586 op.write(ascii(fp.read())) !! 5203 op.write(line) 5587 op.close() 5204 op.close() 5588 sv.fsetVal('', 'trace') !! 5205 sysvals.fsetVal('', 'trace') 5589 sv.platforminfo(cmdafter) !! 5206 sysvals.platforminfo() >> 5207 return testdata 5590 5208 5591 def readFile(file): 5209 def readFile(file): 5592 if os.path.islink(file): 5210 if os.path.islink(file): 5593 return os.readlink(file).spli 5211 return os.readlink(file).split('/')[-1] 5594 else: 5212 else: 5595 return sysvals.getVal(file).s 5213 return sysvals.getVal(file).strip() 5596 5214 5597 # Function: ms2nice 5215 # Function: ms2nice 5598 # Description: 5216 # Description: 5599 # Print out a very concise time string 5217 # Print out a very concise time string in minutes and seconds 5600 # Output: 5218 # Output: 5601 # The time string, e.g. "1901m16s" 5219 # The time string, e.g. "1901m16s" 5602 def ms2nice(val): 5220 def ms2nice(val): 5603 val = int(val) 5221 val = int(val) 5604 h = val // 3600000 5222 h = val // 3600000 5605 m = (val // 60000) % 60 5223 m = (val // 60000) % 60 5606 s = (val // 1000) % 60 5224 s = (val // 1000) % 60 5607 if h > 0: 5225 if h > 0: 5608 return '%d:%02d:%02d' % (h, m 5226 return '%d:%02d:%02d' % (h, m, s) 5609 if m > 0: 5227 if m > 0: 5610 return '%02d:%02d' % (m, s) 5228 return '%02d:%02d' % (m, s) 5611 return '%ds' % s 5229 return '%ds' % s 5612 5230 5613 def yesno(val): 5231 def yesno(val): 5614 list = {'enabled':'A', 'disabled':'S' 5232 list = {'enabled':'A', 'disabled':'S', 'auto':'E', 'on':'D', 5615 'active':'A', 'suspended':'S' 5233 'active':'A', 'suspended':'S', 'suspending':'S'} 5616 if val not in list: 5234 if val not in list: 5617 return ' ' 5235 return ' ' 5618 return list[val] 5236 return list[val] 5619 5237 5620 # Function: deviceInfo 5238 # Function: deviceInfo 5621 # Description: 5239 # Description: 5622 # Detect all the USB hosts and devices 5240 # Detect all the USB hosts and devices currently connected and add 5623 # a list of USB device names to sysval 5241 # a list of USB device names to sysvals for better timeline readability 5624 def deviceInfo(output=''): 5242 def deviceInfo(output=''): 5625 if not output: 5243 if not output: 5626 pprint('LEGEND\n'\ 5244 pprint('LEGEND\n'\ 5627 '---------------------------- 5245 '---------------------------------------------------------------------------------------------\n'\ 5628 ' A = async/sync PM queue (A 5246 ' A = async/sync PM queue (A/S) C = runtime active children\n'\ 5629 ' R = runtime suspend enable 5247 ' R = runtime suspend enabled/disabled (E/D) rACTIVE = runtime active (min/sec)\n'\ 5630 ' S = runtime status active/ 5248 ' S = runtime status active/suspended (A/S) rSUSPEND = runtime suspend (min/sec)\n'\ 5631 ' U = runtime usage count\n' 5249 ' U = runtime usage count\n'\ 5632 '---------------------------- 5250 '---------------------------------------------------------------------------------------------\n'\ 5633 'DEVICE N 5251 'DEVICE NAME A R S U C rACTIVE rSUSPEND\n'\ 5634 '---------------------------- 5252 '---------------------------------------------------------------------------------------------') 5635 5253 5636 res = [] 5254 res = [] 5637 tgtval = 'runtime_status' 5255 tgtval = 'runtime_status' 5638 lines = dict() 5256 lines = dict() 5639 for dirname, dirnames, filenames in o 5257 for dirname, dirnames, filenames in os.walk('/sys/devices'): 5640 if(not re.match(r'.*/power', !! 5258 if(not re.match('.*/power', dirname) or 5641 'control' not in file 5259 'control' not in filenames or 5642 tgtval not in filenam 5260 tgtval not in filenames): 5643 continue 5261 continue 5644 name = '' 5262 name = '' 5645 dirname = dirname[:-6] 5263 dirname = dirname[:-6] 5646 device = dirname.split('/')[- 5264 device = dirname.split('/')[-1] 5647 power = dict() 5265 power = dict() 5648 power[tgtval] = readFile('%s/ 5266 power[tgtval] = readFile('%s/power/%s' % (dirname, tgtval)) 5649 # only list devices which sup 5267 # only list devices which support runtime suspend 5650 if power[tgtval] not in ['act 5268 if power[tgtval] not in ['active', 'suspended', 'suspending']: 5651 continue 5269 continue 5652 for i in ['product', 'driver' 5270 for i in ['product', 'driver', 'subsystem']: 5653 file = '%s/%s' % (dir 5271 file = '%s/%s' % (dirname, i) 5654 if os.path.exists(fil 5272 if os.path.exists(file): 5655 name = readFi 5273 name = readFile(file) 5656 break 5274 break 5657 for i in ['async', 'control', 5275 for i in ['async', 'control', 'runtime_status', 'runtime_usage', 5658 'runtime_active_kids' 5276 'runtime_active_kids', 'runtime_active_time', 5659 'runtime_suspended_ti 5277 'runtime_suspended_time']: 5660 if i in filenames: 5278 if i in filenames: 5661 power[i] = re 5279 power[i] = readFile('%s/power/%s' % (dirname, i)) 5662 if output: 5280 if output: 5663 if power['control'] = 5281 if power['control'] == output: 5664 res.append('% 5282 res.append('%s/power/control' % dirname) 5665 continue 5283 continue 5666 lines[dirname] = '%-26s %-26s 5284 lines[dirname] = '%-26s %-26s %1s %1s %1s %1s %1s %10s %10s' % \ 5667 (device[:26], name[:2 5285 (device[:26], name[:26], 5668 yesno(power['async']) 5286 yesno(power['async']), \ 5669 yesno(power['control' 5287 yesno(power['control']), \ 5670 yesno(power['runtime_ 5288 yesno(power['runtime_status']), \ 5671 power['runtime_usage' 5289 power['runtime_usage'], \ 5672 power['runtime_active 5290 power['runtime_active_kids'], \ 5673 ms2nice(power['runtim 5291 ms2nice(power['runtime_active_time']), \ 5674 ms2nice(power['runtim 5292 ms2nice(power['runtime_suspended_time'])) 5675 for i in sorted(lines): 5293 for i in sorted(lines): 5676 print(lines[i]) 5294 print(lines[i]) 5677 return res 5295 return res 5678 5296 5679 # Function: getModes 5297 # Function: getModes 5680 # Description: 5298 # Description: 5681 # Determine the supported power modes 5299 # Determine the supported power modes on this system 5682 # Output: 5300 # Output: 5683 # A string list of the available modes 5301 # A string list of the available modes 5684 def getModes(): 5302 def getModes(): 5685 modes = [] 5303 modes = [] 5686 if(os.path.exists(sysvals.powerfile)) 5304 if(os.path.exists(sysvals.powerfile)): 5687 fp = open(sysvals.powerfile, 5305 fp = open(sysvals.powerfile, 'r') 5688 modes = fp.read().split() 5306 modes = fp.read().split() 5689 fp.close() 5307 fp.close() 5690 if(os.path.exists(sysvals.mempowerfil 5308 if(os.path.exists(sysvals.mempowerfile)): 5691 deep = False 5309 deep = False 5692 fp = open(sysvals.mempowerfil 5310 fp = open(sysvals.mempowerfile, 'r') 5693 for m in fp.read().split(): 5311 for m in fp.read().split(): 5694 memmode = m.strip('[] 5312 memmode = m.strip('[]') 5695 if memmode == 'deep': 5313 if memmode == 'deep': 5696 deep = True 5314 deep = True 5697 else: 5315 else: 5698 modes.append( 5316 modes.append('mem-%s' % memmode) 5699 fp.close() 5317 fp.close() 5700 if 'mem' in modes and not dee 5318 if 'mem' in modes and not deep: 5701 modes.remove('mem') 5319 modes.remove('mem') 5702 if('disk' in modes and os.path.exists 5320 if('disk' in modes and os.path.exists(sysvals.diskpowerfile)): 5703 fp = open(sysvals.diskpowerfi 5321 fp = open(sysvals.diskpowerfile, 'r') 5704 for m in fp.read().split(): 5322 for m in fp.read().split(): 5705 modes.append('disk-%s 5323 modes.append('disk-%s' % m.strip('[]')) 5706 fp.close() 5324 fp.close() 5707 return modes 5325 return modes 5708 5326 5709 def dmidecode_backup(out, fatal=False): << 5710 cpath, spath, info = '/proc/cpuinfo', << 5711 'bios-vendor': 'bios_vendor', << 5712 'bios-version': 'bios_version << 5713 'bios-release-date': 'bios_da << 5714 'system-manufacturer': 'sys_v << 5715 'system-product-name': 'produ << 5716 'system-version': 'product_ve << 5717 'system-serial-number': 'prod << 5718 'baseboard-manufacturer': 'bo << 5719 'baseboard-product-name': 'bo << 5720 'baseboard-version': 'board_v << 5721 'baseboard-serial-number': 'b << 5722 'chassis-manufacturer': 'chas << 5723 'chassis-version': 'chassis_v << 5724 'chassis-serial-number': 'cha << 5725 } << 5726 for key in info: << 5727 if key not in out: << 5728 val = sysvals.getVal( << 5729 if val and val.lower( << 5730 out[key] = va << 5731 if 'processor-version' not in out and << 5732 with open(cpath, 'r') as fp: << 5733 for line in fp: << 5734 m = re.match( << 5735 if m: << 5736 out[' << 5737 break << 5738 if fatal and len(out) < 1: << 5739 doError('dmidecode failed to << 5740 (sysvals.mempath, spa << 5741 return out << 5742 << 5743 # Function: dmidecode 5327 # Function: dmidecode 5744 # Description: 5328 # Description: 5745 # Read the bios tables and pull out sy 5329 # Read the bios tables and pull out system info 5746 # Arguments: 5330 # Arguments: 5747 # mempath: /dev/mem or custom mem path 5331 # mempath: /dev/mem or custom mem path 5748 # fatal: True to exit on error, False 5332 # fatal: True to exit on error, False to return empty dict 5749 # Output: 5333 # Output: 5750 # A dict object with all available key 5334 # A dict object with all available key/values 5751 def dmidecode(mempath, fatal=False): 5335 def dmidecode(mempath, fatal=False): 5752 out = dict() 5336 out = dict() 5753 if(not (os.path.exists(mempath) and o << 5754 return dmidecode_backup(out, << 5755 5337 5756 # the list of values to retrieve, wit 5338 # the list of values to retrieve, with hardcoded (type, idx) 5757 info = { 5339 info = { 5758 'bios-vendor': (0, 4), 5340 'bios-vendor': (0, 4), 5759 'bios-version': (0, 5), 5341 'bios-version': (0, 5), 5760 'bios-release-date': (0, 8), 5342 'bios-release-date': (0, 8), 5761 'system-manufacturer': (1, 4) 5343 'system-manufacturer': (1, 4), 5762 'system-product-name': (1, 5) 5344 'system-product-name': (1, 5), 5763 'system-version': (1, 6), 5345 'system-version': (1, 6), 5764 'system-serial-number': (1, 7 5346 'system-serial-number': (1, 7), 5765 'baseboard-manufacturer': (2, 5347 'baseboard-manufacturer': (2, 4), 5766 'baseboard-product-name': (2, 5348 'baseboard-product-name': (2, 5), 5767 'baseboard-version': (2, 6), 5349 'baseboard-version': (2, 6), 5768 'baseboard-serial-number': (2 5350 'baseboard-serial-number': (2, 7), 5769 'chassis-manufacturer': (3, 4 5351 'chassis-manufacturer': (3, 4), >> 5352 'chassis-type': (3, 5), 5770 'chassis-version': (3, 6), 5353 'chassis-version': (3, 6), 5771 'chassis-serial-number': (3, 5354 'chassis-serial-number': (3, 7), 5772 'processor-manufacturer': (4, 5355 'processor-manufacturer': (4, 7), 5773 'processor-version': (4, 16), 5356 'processor-version': (4, 16), 5774 } 5357 } >> 5358 if(not os.path.exists(mempath)): >> 5359 if(fatal): >> 5360 doError('file does not exist: %s' % mempath) >> 5361 return out >> 5362 if(not os.access(mempath, os.R_OK)): >> 5363 if(fatal): >> 5364 doError('file is not readable: %s' % mempath) >> 5365 return out 5775 5366 5776 # by default use legacy scan, but try 5367 # by default use legacy scan, but try to use EFI first 5777 memaddr, memsize = 0xf0000, 0x10000 !! 5368 memaddr = 0xf0000 >> 5369 memsize = 0x10000 5778 for ep in ['/sys/firmware/efi/systab' 5370 for ep in ['/sys/firmware/efi/systab', '/proc/efi/systab']: 5779 if not os.path.exists(ep) or 5371 if not os.path.exists(ep) or not os.access(ep, os.R_OK): 5780 continue 5372 continue 5781 fp = open(ep, 'r') 5373 fp = open(ep, 'r') 5782 buf = fp.read() 5374 buf = fp.read() 5783 fp.close() 5375 fp.close() 5784 i = buf.find('SMBIOS=') 5376 i = buf.find('SMBIOS=') 5785 if i >= 0: 5377 if i >= 0: 5786 try: 5378 try: 5787 memaddr = int 5379 memaddr = int(buf[i+7:], 16) 5788 memsize = 0x2 5380 memsize = 0x20 5789 except: 5381 except: 5790 continue 5382 continue 5791 5383 5792 # read in the memory for scanning 5384 # read in the memory for scanning 5793 try: 5385 try: 5794 fp = open(mempath, 'rb') 5386 fp = open(mempath, 'rb') 5795 fp.seek(memaddr) 5387 fp.seek(memaddr) 5796 buf = fp.read(memsize) 5388 buf = fp.read(memsize) 5797 except: 5389 except: 5798 return dmidecode_backup(out, !! 5390 if(fatal): >> 5391 doError('DMI table is unreachable, sorry') >> 5392 else: >> 5393 pprint('WARNING: /dev/mem is not readable, ignoring DMI data') >> 5394 return out 5799 fp.close() 5395 fp.close() 5800 5396 5801 # search for either an SM table or DM 5397 # search for either an SM table or DMI table 5802 i = base = length = num = 0 5398 i = base = length = num = 0 5803 while(i < memsize): 5399 while(i < memsize): 5804 if buf[i:i+4] == b'_SM_' and 5400 if buf[i:i+4] == b'_SM_' and i < memsize - 16: 5805 length = struct.unpac 5401 length = struct.unpack('H', buf[i+22:i+24])[0] 5806 base, num = struct.un 5402 base, num = struct.unpack('IH', buf[i+24:i+30]) 5807 break 5403 break 5808 elif buf[i:i+5] == b'_DMI_': 5404 elif buf[i:i+5] == b'_DMI_': 5809 length = struct.unpac 5405 length = struct.unpack('H', buf[i+6:i+8])[0] 5810 base, num = struct.un 5406 base, num = struct.unpack('IH', buf[i+8:i+14]) 5811 break 5407 break 5812 i += 16 5408 i += 16 5813 if base == 0 and length == 0 and num 5409 if base == 0 and length == 0 and num == 0: 5814 return dmidecode_backup(out, !! 5410 if(fatal): >> 5411 doError('Neither SMBIOS nor DMI were found') >> 5412 else: >> 5413 return out 5815 5414 5816 # read in the SM or DMI table 5415 # read in the SM or DMI table 5817 try: 5416 try: 5818 fp = open(mempath, 'rb') 5417 fp = open(mempath, 'rb') 5819 fp.seek(base) 5418 fp.seek(base) 5820 buf = fp.read(length) 5419 buf = fp.read(length) 5821 except: 5420 except: 5822 return dmidecode_backup(out, !! 5421 if(fatal): >> 5422 doError('DMI table is unreachable, sorry') >> 5423 else: >> 5424 pprint('WARNING: /dev/mem is not readable, ignoring DMI data') >> 5425 return out 5823 fp.close() 5426 fp.close() 5824 5427 5825 # scan the table for the values we wa 5428 # scan the table for the values we want 5826 count = i = 0 5429 count = i = 0 5827 while(count < num and i <= len(buf) - 5430 while(count < num and i <= len(buf) - 4): 5828 type, size, handle = struct.u 5431 type, size, handle = struct.unpack('BBH', buf[i:i+4]) 5829 n = i + size 5432 n = i + size 5830 while n < len(buf) - 1: 5433 while n < len(buf) - 1: 5831 if 0 == struct.unpack 5434 if 0 == struct.unpack('H', buf[n:n+2])[0]: 5832 break 5435 break 5833 n += 1 5436 n += 1 5834 data = buf[i+size:n+2].split( 5437 data = buf[i+size:n+2].split(b'\0') 5835 for name in info: 5438 for name in info: 5836 itype, idxadr = info[ 5439 itype, idxadr = info[name] 5837 if itype == type: 5440 if itype == type: 5838 idx = struct. 5441 idx = struct.unpack('B', buf[i+idxadr:i+idxadr+1])[0] 5839 if idx > 0 an 5442 if idx > 0 and idx < len(data) - 1: 5840 s = d 5443 s = data[idx-1].decode('utf-8') 5841 if s. 5444 if s.strip() and s.strip().lower() != 'to be filled by o.e.m.': 5842 5445 out[name] = s 5843 i = n + 2 5446 i = n + 2 5844 count += 1 5447 count += 1 5845 return out 5448 return out 5846 5449 >> 5450 def getBattery(): >> 5451 p, charge, bat = '/sys/class/power_supply', 0, {} >> 5452 if not os.path.exists(p): >> 5453 return False >> 5454 for d in os.listdir(p): >> 5455 type = sysvals.getVal(os.path.join(p, d, 'type')).strip().lower() >> 5456 if type != 'battery': >> 5457 continue >> 5458 for v in ['status', 'energy_now', 'capacity_now']: >> 5459 bat[v] = sysvals.getVal(os.path.join(p, d, v)).strip().lower() >> 5460 break >> 5461 if 'status' not in bat: >> 5462 return False >> 5463 ac = False if 'discharging' in bat['status'] else True >> 5464 for v in ['energy_now', 'capacity_now']: >> 5465 if v in bat and bat[v]: >> 5466 charge = int(bat[v]) >> 5467 return (ac, charge) >> 5468 >> 5469 def displayControl(cmd): >> 5470 xset, ret = 'timeout 10 xset -d :0.0 {0}', 0 >> 5471 if sysvals.sudouser: >> 5472 xset = 'sudo -u %s %s' % (sysvals.sudouser, xset) >> 5473 if cmd == 'init': >> 5474 ret = call(xset.format('dpms 0 0 0'), shell=True) >> 5475 if not ret: >> 5476 ret = call(xset.format('s off'), shell=True) >> 5477 elif cmd == 'reset': >> 5478 ret = call(xset.format('s reset'), shell=True) >> 5479 elif cmd in ['on', 'off', 'standby', 'suspend']: >> 5480 b4 = displayControl('stat') >> 5481 ret = call(xset.format('dpms force %s' % cmd), shell=True) >> 5482 if not ret: >> 5483 curr = displayControl('stat') >> 5484 sysvals.vprint('Display Switched: %s -> %s' % (b4, curr)) >> 5485 if curr != cmd: >> 5486 sysvals.vprint('WARNING: Display failed to change to %s' % cmd) >> 5487 if ret: >> 5488 sysvals.vprint('WARNING: Display failed to change to %s with xset' % cmd) >> 5489 return ret >> 5490 elif cmd == 'stat': >> 5491 fp = Popen(xset.format('q').split(' '), stdout=PIPE).stdout >> 5492 ret = 'unknown' >> 5493 for line in fp: >> 5494 m = re.match('[\s]*Monitor is (?P<m>.*)', ascii(line)) >> 5495 if(m and len(m.group('m')) >= 2): >> 5496 out = m.group('m').lower() >> 5497 ret = out[3:] if out[0:2] == 'in' else out >> 5498 break >> 5499 fp.close() >> 5500 return ret >> 5501 5847 # Function: getFPDT 5502 # Function: getFPDT 5848 # Description: 5503 # Description: 5849 # Read the acpi bios tables and pull o 5504 # Read the acpi bios tables and pull out FPDT, the firmware data 5850 # Arguments: 5505 # Arguments: 5851 # output: True to output the info to s 5506 # output: True to output the info to stdout, False otherwise 5852 def getFPDT(output): 5507 def getFPDT(output): 5853 rectype = {} 5508 rectype = {} 5854 rectype[0] = 'Firmware Basic Boot Per 5509 rectype[0] = 'Firmware Basic Boot Performance Record' 5855 rectype[1] = 'S3 Performance Table Re 5510 rectype[1] = 'S3 Performance Table Record' 5856 prectype = {} 5511 prectype = {} 5857 prectype[0] = 'Basic S3 Resume Perfor 5512 prectype[0] = 'Basic S3 Resume Performance Record' 5858 prectype[1] = 'Basic S3 Suspend Perfo 5513 prectype[1] = 'Basic S3 Suspend Performance Record' 5859 5514 5860 sysvals.rootCheck(True) 5515 sysvals.rootCheck(True) 5861 if(not os.path.exists(sysvals.fpdtpat 5516 if(not os.path.exists(sysvals.fpdtpath)): 5862 if(output): 5517 if(output): 5863 doError('file does no 5518 doError('file does not exist: %s' % sysvals.fpdtpath) 5864 return False 5519 return False 5865 if(not os.access(sysvals.fpdtpath, os 5520 if(not os.access(sysvals.fpdtpath, os.R_OK)): 5866 if(output): 5521 if(output): 5867 doError('file is not 5522 doError('file is not readable: %s' % sysvals.fpdtpath) 5868 return False 5523 return False 5869 if(not os.path.exists(sysvals.mempath 5524 if(not os.path.exists(sysvals.mempath)): 5870 if(output): 5525 if(output): 5871 doError('file does no 5526 doError('file does not exist: %s' % sysvals.mempath) 5872 return False 5527 return False 5873 if(not os.access(sysvals.mempath, os. 5528 if(not os.access(sysvals.mempath, os.R_OK)): 5874 if(output): 5529 if(output): 5875 doError('file is not 5530 doError('file is not readable: %s' % sysvals.mempath) 5876 return False 5531 return False 5877 5532 5878 fp = open(sysvals.fpdtpath, 'rb') 5533 fp = open(sysvals.fpdtpath, 'rb') 5879 buf = fp.read() 5534 buf = fp.read() 5880 fp.close() 5535 fp.close() 5881 5536 5882 if(len(buf) < 36): 5537 if(len(buf) < 36): 5883 if(output): 5538 if(output): 5884 doError('Invalid FPDT 5539 doError('Invalid FPDT table data, should '+\ 5885 'be at least 5540 'be at least 36 bytes') 5886 return False 5541 return False 5887 5542 5888 table = struct.unpack('4sIBB6s8sI4sI' 5543 table = struct.unpack('4sIBB6s8sI4sI', buf[0:36]) 5889 if(output): 5544 if(output): 5890 pprint('\n'\ 5545 pprint('\n'\ 5891 'Firmware Performance Data Ta 5546 'Firmware Performance Data Table (%s)\n'\ 5892 ' Signature 5547 ' Signature : %s\n'\ 5893 ' Table Length 5548 ' Table Length : %u\n'\ 5894 ' Revision 5549 ' Revision : %u\n'\ 5895 ' Checksum 5550 ' Checksum : 0x%x\n'\ 5896 ' OEM ID 5551 ' OEM ID : %s\n'\ 5897 ' OEM Table ID 5552 ' OEM Table ID : %s\n'\ 5898 ' OEM Revision 5553 ' OEM Revision : %u\n'\ 5899 ' Creator ID 5554 ' Creator ID : %s\n'\ 5900 ' Creator Revision 5555 ' Creator Revision : 0x%x\n'\ 5901 '' % (ascii(table[0]), ascii( 5556 '' % (ascii(table[0]), ascii(table[0]), table[1], table[2], 5902 table[3], ascii(table 5557 table[3], ascii(table[4]), ascii(table[5]), table[6], 5903 ascii(table[7]), tabl 5558 ascii(table[7]), table[8])) 5904 5559 5905 if(table[0] != b'FPDT'): 5560 if(table[0] != b'FPDT'): 5906 if(output): 5561 if(output): 5907 doError('Invalid FPDT 5562 doError('Invalid FPDT table') 5908 return False 5563 return False 5909 if(len(buf) <= 36): 5564 if(len(buf) <= 36): 5910 return False 5565 return False 5911 i = 0 5566 i = 0 5912 fwData = [0, 0] 5567 fwData = [0, 0] 5913 records = buf[36:] 5568 records = buf[36:] 5914 try: 5569 try: 5915 fp = open(sysvals.mempath, 'r 5570 fp = open(sysvals.mempath, 'rb') 5916 except: 5571 except: 5917 pprint('WARNING: /dev/mem is 5572 pprint('WARNING: /dev/mem is not readable, ignoring the FPDT data') 5918 return False 5573 return False 5919 while(i < len(records)): 5574 while(i < len(records)): 5920 header = struct.unpack('HBB', 5575 header = struct.unpack('HBB', records[i:i+4]) 5921 if(header[0] not in rectype): 5576 if(header[0] not in rectype): 5922 i += header[1] 5577 i += header[1] 5923 continue 5578 continue 5924 if(header[1] != 16): 5579 if(header[1] != 16): 5925 i += header[1] 5580 i += header[1] 5926 continue 5581 continue 5927 addr = struct.unpack('Q', rec 5582 addr = struct.unpack('Q', records[i+8:i+16])[0] 5928 try: 5583 try: 5929 fp.seek(addr) 5584 fp.seek(addr) 5930 first = fp.read(8) 5585 first = fp.read(8) 5931 except: 5586 except: 5932 if(output): 5587 if(output): 5933 pprint('Bad a 5588 pprint('Bad address 0x%x in %s' % (addr, sysvals.mempath)) 5934 return [0, 0] 5589 return [0, 0] 5935 rechead = struct.unpack('4sI' 5590 rechead = struct.unpack('4sI', first) 5936 recdata = fp.read(rechead[1]- 5591 recdata = fp.read(rechead[1]-8) 5937 if(rechead[0] == b'FBPT'): 5592 if(rechead[0] == b'FBPT'): 5938 record = struct.unpac 5593 record = struct.unpack('HBBIQQQQQ', recdata[:48]) 5939 if(output): 5594 if(output): 5940 pprint('%s (% 5595 pprint('%s (%s)\n'\ 5941 ' 5596 ' Reset END : %u ns\n'\ 5942 ' OS Loader 5597 ' OS Loader LoadImage Start : %u ns\n'\ 5943 ' OS Loader S 5598 ' OS Loader StartImage Start : %u ns\n'\ 5944 ' ExitBoo 5599 ' ExitBootServices Entry : %u ns\n'\ 5945 ' ExitBo 5600 ' ExitBootServices Exit : %u ns'\ 5946 '' % (rectype 5601 '' % (rectype[header[0]], ascii(rechead[0]), record[4], record[5], 5947 recor 5602 record[6], record[7], record[8])) 5948 elif(rechead[0] == b'S3PT'): 5603 elif(rechead[0] == b'S3PT'): 5949 if(output): 5604 if(output): 5950 pprint('%s (% 5605 pprint('%s (%s)' % (rectype[header[0]], ascii(rechead[0]))) 5951 j = 0 5606 j = 0 5952 while(j < len(recdata 5607 while(j < len(recdata)): 5953 prechead = st 5608 prechead = struct.unpack('HBB', recdata[j:j+4]) 5954 if(prechead[0 5609 if(prechead[0] not in prectype): 5955 conti 5610 continue 5956 if(prechead[0 5611 if(prechead[0] == 0): 5957 recor 5612 record = struct.unpack('IIQQ', recdata[j:j+prechead[1]]) 5958 fwDat 5613 fwData[1] = record[2] 5959 if(ou 5614 if(output): 5960 5615 pprint(' %s\n'\ 5961 5616 ' Resume Count : %u\n'\ 5962 5617 ' FullResume : %u ns\n'\ 5963 5618 ' AverageResume : %u ns'\ 5964 5619 '' % (prectype[prechead[0]], record[1], 5965 5620 record[2], record[3])) 5966 elif(prechead 5621 elif(prechead[0] == 1): 5967 recor 5622 record = struct.unpack('QQ', recdata[j+4:j+prechead[1]]) 5968 fwDat 5623 fwData[0] = record[1] - record[0] 5969 if(ou 5624 if(output): 5970 5625 pprint(' %s\n'\ 5971 5626 ' SuspendStart : %u ns\n'\ 5972 5627 ' SuspendEnd : %u ns\n'\ 5973 5628 ' SuspendTime : %u ns'\ 5974 5629 '' % (prectype[prechead[0]], record[0], 5975 5630 record[1], fwData[0])) 5976 5631 5977 j += prechead 5632 j += prechead[1] 5978 if(output): 5633 if(output): 5979 pprint('') 5634 pprint('') 5980 i += header[1] 5635 i += header[1] 5981 fp.close() 5636 fp.close() 5982 return fwData 5637 return fwData 5983 5638 5984 # Function: statusCheck 5639 # Function: statusCheck 5985 # Description: 5640 # Description: 5986 # Verify that the requested command an 5641 # Verify that the requested command and options will work, and 5987 # print the results to the terminal 5642 # print the results to the terminal 5988 # Output: 5643 # Output: 5989 # True if the test will work, False if 5644 # True if the test will work, False if not 5990 def statusCheck(probecheck=False): 5645 def statusCheck(probecheck=False): 5991 status = '' 5646 status = '' 5992 5647 5993 pprint('Checking this system (%s)...' 5648 pprint('Checking this system (%s)...' % platform.node()) 5994 5649 5995 # check we have root access 5650 # check we have root access 5996 res = sysvals.colorText('NO (No featu 5651 res = sysvals.colorText('NO (No features of this tool will work!)') 5997 if(sysvals.rootCheck(False)): 5652 if(sysvals.rootCheck(False)): 5998 res = 'YES' 5653 res = 'YES' 5999 pprint(' have root access: %s' % r 5654 pprint(' have root access: %s' % res) 6000 if(res != 'YES'): 5655 if(res != 'YES'): 6001 pprint(' Try running this 5656 pprint(' Try running this script with sudo') 6002 return 'missing root access' 5657 return 'missing root access' 6003 5658 6004 # check sysfs is mounted 5659 # check sysfs is mounted 6005 res = sysvals.colorText('NO (No featu 5660 res = sysvals.colorText('NO (No features of this tool will work!)') 6006 if(os.path.exists(sysvals.powerfile)) 5661 if(os.path.exists(sysvals.powerfile)): 6007 res = 'YES' 5662 res = 'YES' 6008 pprint(' is sysfs mounted: %s' % r 5663 pprint(' is sysfs mounted: %s' % res) 6009 if(res != 'YES'): 5664 if(res != 'YES'): 6010 return 'sysfs is missing' 5665 return 'sysfs is missing' 6011 5666 6012 # check target mode is a valid mode 5667 # check target mode is a valid mode 6013 if sysvals.suspendmode != 'command': 5668 if sysvals.suspendmode != 'command': 6014 res = sysvals.colorText('NO') 5669 res = sysvals.colorText('NO') 6015 modes = getModes() 5670 modes = getModes() 6016 if(sysvals.suspendmode in mod 5671 if(sysvals.suspendmode in modes): 6017 res = 'YES' 5672 res = 'YES' 6018 else: 5673 else: 6019 status = '%s mode is 5674 status = '%s mode is not supported' % sysvals.suspendmode 6020 pprint(' is "%s" a valid p 5675 pprint(' is "%s" a valid power mode: %s' % (sysvals.suspendmode, res)) 6021 if(res == 'NO'): 5676 if(res == 'NO'): 6022 pprint(' valid p 5677 pprint(' valid power modes are: %s' % modes) 6023 pprint(' please 5678 pprint(' please choose one with -m') 6024 5679 6025 # check if ftrace is available 5680 # check if ftrace is available 6026 if sysvals.useftrace: !! 5681 res = sysvals.colorText('NO') 6027 res = sysvals.colorText('NO') !! 5682 ftgood = sysvals.verifyFtrace() 6028 sysvals.useftrace = sysvals.v !! 5683 if(ftgood): 6029 efmt = '"{0}" uses ftrace, an !! 5684 res = 'YES' 6030 if sysvals.useftrace: !! 5685 elif(sysvals.usecallgraph): 6031 res = 'YES' !! 5686 status = 'ftrace is not properly supported' 6032 elif sysvals.usecallgraph: !! 5687 pprint(' is ftrace supported: %s' % res) 6033 status = efmt.format( << 6034 elif sysvals.usedevsrc: << 6035 status = efmt.format( << 6036 elif sysvals.useprocmon: << 6037 status = efmt.format( << 6038 pprint(' is ftrace support << 6039 5688 6040 # check if kprobes are available 5689 # check if kprobes are available 6041 if sysvals.usekprobes: 5690 if sysvals.usekprobes: 6042 res = sysvals.colorText('NO') 5691 res = sysvals.colorText('NO') 6043 sysvals.usekprobes = sysvals. 5692 sysvals.usekprobes = sysvals.verifyKprobes() 6044 if(sysvals.usekprobes): 5693 if(sysvals.usekprobes): 6045 res = 'YES' 5694 res = 'YES' 6046 else: 5695 else: 6047 sysvals.usedevsrc = F 5696 sysvals.usedevsrc = False 6048 pprint(' are kprobes suppo 5697 pprint(' are kprobes supported: %s' % res) 6049 5698 6050 # what data source are we using 5699 # what data source are we using 6051 res = 'DMESG (very limited, ftrace is !! 5700 res = 'DMESG' 6052 if sysvals.useftrace: !! 5701 if(ftgood): 6053 sysvals.usetraceevents = True 5702 sysvals.usetraceevents = True 6054 for e in sysvals.traceevents: 5703 for e in sysvals.traceevents: 6055 if not os.path.exists 5704 if not os.path.exists(sysvals.epath+e): 6056 sysvals.usetr 5705 sysvals.usetraceevents = False 6057 if(sysvals.usetraceevents): 5706 if(sysvals.usetraceevents): 6058 res = 'FTRACE (all tr 5707 res = 'FTRACE (all trace events found)' 6059 pprint(' timeline data source: %s' 5708 pprint(' timeline data source: %s' % res) 6060 5709 6061 # check if rtcwake 5710 # check if rtcwake 6062 res = sysvals.colorText('NO') 5711 res = sysvals.colorText('NO') 6063 if(sysvals.rtcpath != ''): 5712 if(sysvals.rtcpath != ''): 6064 res = 'YES' 5713 res = 'YES' 6065 elif(sysvals.rtcwake): 5714 elif(sysvals.rtcwake): 6066 status = 'rtcwake is not prop 5715 status = 'rtcwake is not properly supported' 6067 pprint(' is rtcwake supported: %s' 5716 pprint(' is rtcwake supported: %s' % res) 6068 5717 6069 # check info commands << 6070 pprint(' optional commands this to << 6071 no = sysvals.colorText('MISSING') << 6072 yes = sysvals.colorText('FOUND', 32) << 6073 for c in ['turbostat', 'mcelog', 'lsp << 6074 if c == 'turbostat': << 6075 res = yes if sysvals. << 6076 else: << 6077 res = yes if sysvals. << 6078 pprint(' %s: %s' % (c, << 6079 << 6080 if not probecheck: 5718 if not probecheck: 6081 return status 5719 return status 6082 5720 6083 # verify kprobes 5721 # verify kprobes 6084 if sysvals.usekprobes: 5722 if sysvals.usekprobes: 6085 for name in sysvals.tracefunc 5723 for name in sysvals.tracefuncs: 6086 sysvals.defaultKprobe 5724 sysvals.defaultKprobe(name, sysvals.tracefuncs[name]) 6087 if sysvals.usedevsrc: 5725 if sysvals.usedevsrc: 6088 for name in sysvals.d 5726 for name in sysvals.dev_tracefuncs: 6089 sysvals.defau 5727 sysvals.defaultKprobe(name, sysvals.dev_tracefuncs[name]) 6090 sysvals.addKprobes(True) 5728 sysvals.addKprobes(True) 6091 5729 6092 return status 5730 return status 6093 5731 6094 # Function: doError 5732 # Function: doError 6095 # Description: 5733 # Description: 6096 # generic error function for catastrph 5734 # generic error function for catastrphic failures 6097 # Arguments: 5735 # Arguments: 6098 # msg: the error message to print 5736 # msg: the error message to print 6099 # help: True if printHelp should be ca 5737 # help: True if printHelp should be called after, False otherwise 6100 def doError(msg, help=False): 5738 def doError(msg, help=False): 6101 if(help == True): 5739 if(help == True): 6102 printHelp() 5740 printHelp() 6103 pprint('ERROR: %s\n' % msg) 5741 pprint('ERROR: %s\n' % msg) 6104 sysvals.outputResult({'error':msg}) 5742 sysvals.outputResult({'error':msg}) 6105 sys.exit(1) 5743 sys.exit(1) 6106 5744 6107 # Function: getArgInt 5745 # Function: getArgInt 6108 # Description: 5746 # Description: 6109 # pull out an integer argument from th 5747 # pull out an integer argument from the command line with checks 6110 def getArgInt(name, args, min, max, main=True 5748 def getArgInt(name, args, min, max, main=True): 6111 if main: 5749 if main: 6112 try: 5750 try: 6113 arg = next(args) 5751 arg = next(args) 6114 except: 5752 except: 6115 doError(name+': no ar 5753 doError(name+': no argument supplied', True) 6116 else: 5754 else: 6117 arg = args 5755 arg = args 6118 try: 5756 try: 6119 val = int(arg) 5757 val = int(arg) 6120 except: 5758 except: 6121 doError(name+': non-integer v 5759 doError(name+': non-integer value given', True) 6122 if(val < min or val > max): 5760 if(val < min or val > max): 6123 doError(name+': value should 5761 doError(name+': value should be between %d and %d' % (min, max), True) 6124 return val 5762 return val 6125 5763 6126 # Function: getArgFloat 5764 # Function: getArgFloat 6127 # Description: 5765 # Description: 6128 # pull out a float argument from the c 5766 # pull out a float argument from the command line with checks 6129 def getArgFloat(name, args, min, max, main=Tr 5767 def getArgFloat(name, args, min, max, main=True): 6130 if main: 5768 if main: 6131 try: 5769 try: 6132 arg = next(args) 5770 arg = next(args) 6133 except: 5771 except: 6134 doError(name+': no ar 5772 doError(name+': no argument supplied', True) 6135 else: 5773 else: 6136 arg = args 5774 arg = args 6137 try: 5775 try: 6138 val = float(arg) 5776 val = float(arg) 6139 except: 5777 except: 6140 doError(name+': non-numerical 5778 doError(name+': non-numerical value given', True) 6141 if(val < min or val > max): 5779 if(val < min or val > max): 6142 doError(name+': value should 5780 doError(name+': value should be between %f and %f' % (min, max), True) 6143 return val 5781 return val 6144 5782 6145 def processData(live=False, quiet=False): !! 5783 def processData(live=False): 6146 if not quiet: !! 5784 pprint('PROCESSING DATA') 6147 pprint('PROCESSING: %s' % sys << 6148 sysvals.vprint('usetraceevents=%s, us 5785 sysvals.vprint('usetraceevents=%s, usetracemarkers=%s, usekprobes=%s' % \ 6149 (sysvals.usetraceevents, sysv 5786 (sysvals.usetraceevents, sysvals.usetracemarkers, sysvals.usekprobes)) 6150 error = '' 5787 error = '' 6151 if(sysvals.usetraceevents): 5788 if(sysvals.usetraceevents): 6152 testruns, error = parseTraceL 5789 testruns, error = parseTraceLog(live) 6153 if sysvals.dmesgfile: 5790 if sysvals.dmesgfile: 6154 for data in testruns: 5791 for data in testruns: 6155 data.extractE 5792 data.extractErrorInfo() 6156 else: 5793 else: 6157 testruns = loadKernelLog() 5794 testruns = loadKernelLog() 6158 for data in testruns: 5795 for data in testruns: 6159 parseKernelLog(data) 5796 parseKernelLog(data) 6160 if(sysvals.ftracefile and (sy 5797 if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): 6161 appendIncompleteTrace 5798 appendIncompleteTraceLog(testruns) 6162 if not sysvals.stamp: !! 5799 shown = ['bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr', 6163 pprint('ERROR: data does not !! 5800 'memsz', 'mode', 'numcpu', 'plat', 'time'] 6164 return (testruns, {'error': ' << 6165 shown = ['os', 'bios', 'biosdate', 'c << 6166 'memsz', 'mode', 'num << 6167 sysvals.vprint('System Info:') 5801 sysvals.vprint('System Info:') 6168 for key in sorted(sysvals.stamp): 5802 for key in sorted(sysvals.stamp): 6169 if key in shown: 5803 if key in shown: 6170 sysvals.vprint(' % 5804 sysvals.vprint(' %-8s : %s' % (key.upper(), sysvals.stamp[key])) >> 5805 if sysvals.kparams: >> 5806 sysvals.vprint('Kparams:\n %s' % sysvals.kparams) 6171 sysvals.vprint('Command:\n %s' % s 5807 sysvals.vprint('Command:\n %s' % sysvals.cmdline) 6172 for data in testruns: 5808 for data in testruns: >> 5809 if data.mcelog: >> 5810 sysvals.vprint('MCELOG Data:') >> 5811 for line in data.mcelog.split('\n'): >> 5812 sysvals.vprint(' %s' % line) 6173 if data.turbostat: 5813 if data.turbostat: 6174 idx, s = 0, 'Turbosta 5814 idx, s = 0, 'Turbostat:\n ' 6175 for val in data.turbo 5815 for val in data.turbostat.split('|'): 6176 idx += len(va 5816 idx += len(val) + 1 6177 if idx >= 80: 5817 if idx >= 80: 6178 idx = 5818 idx = 0 6179 s += 5819 s += '\n ' 6180 s += val + ' 5820 s += val + ' ' 6181 sysvals.vprint(s) 5821 sysvals.vprint(s) >> 5822 if data.battery: >> 5823 a1, c1, a2, c2 = data.battery >> 5824 s = 'Battery:\n Before - AC: %s, Charge: %d\n After - AC: %s, Charge: %d' % \ >> 5825 (a1, int(c1), a2, int(c2)) >> 5826 sysvals.vprint(s) >> 5827 if data.wifi: >> 5828 w = data.wifi.replace('|', ' ').split(',') >> 5829 s = 'Wifi:\n Before %s\n After %s' % \ >> 5830 (w[0], w[1]) >> 5831 sysvals.vprint(s) 6182 data.printDetails() 5832 data.printDetails() 6183 if len(sysvals.platinfo) > 0: !! 5833 if len(sysvals.platinfo) > 0: 6184 sysvals.vprint('\nPlatform In !! 5834 sysvals.vprint('\nPlatform Info:') 6185 for info in sysvals.platinfo: !! 5835 for info in sysvals.platinfo: 6186 sysvals.vprint('[%s - !! 5836 sysvals.vprint(info[0]+' - '+info[1]) 6187 sysvals.vprint(info[2 !! 5837 sysvals.vprint(info[2]) 6188 sysvals.vprint('') !! 5838 sysvals.vprint('') 6189 if sysvals.cgdump: 5839 if sysvals.cgdump: 6190 for data in testruns: 5840 for data in testruns: 6191 data.debugPrint() 5841 data.debugPrint() 6192 sys.exit(0) 5842 sys.exit(0) 6193 if len(testruns) < 1: 5843 if len(testruns) < 1: 6194 pprint('ERROR: Not enough tes 5844 pprint('ERROR: Not enough test data to build a timeline') 6195 return (testruns, {'error': ' 5845 return (testruns, {'error': 'timeline generation failed'}) 6196 sysvals.vprint('Creating the html tim 5846 sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile) 6197 createHTML(testruns, error) 5847 createHTML(testruns, error) 6198 if not quiet: !! 5848 pprint('DONE') 6199 pprint('DONE: %s' % sys << 6200 data = testruns[0] 5849 data = testruns[0] 6201 stamp = data.stamp 5850 stamp = data.stamp 6202 stamp['suspend'], stamp['resume'] = d 5851 stamp['suspend'], stamp['resume'] = data.getTimeValues() 6203 if data.fwValid: 5852 if data.fwValid: 6204 stamp['fwsuspend'], stamp['fw 5853 stamp['fwsuspend'], stamp['fwresume'] = data.fwSuspend, data.fwResume 6205 if error: 5854 if error: 6206 stamp['error'] = error 5855 stamp['error'] = error 6207 return (testruns, stamp) 5856 return (testruns, stamp) 6208 5857 6209 # Function: rerunTest 5858 # Function: rerunTest 6210 # Description: 5859 # Description: 6211 # generate an output from an existing 5860 # generate an output from an existing set of ftrace/dmesg logs 6212 def rerunTest(htmlfile=''): 5861 def rerunTest(htmlfile=''): 6213 if sysvals.ftracefile: 5862 if sysvals.ftracefile: 6214 doesTraceLogHaveTraceEvents() 5863 doesTraceLogHaveTraceEvents() 6215 if not sysvals.dmesgfile and not sysv 5864 if not sysvals.dmesgfile and not sysvals.usetraceevents: 6216 doError('recreating this html 5865 doError('recreating this html output requires a dmesg file') 6217 if htmlfile: 5866 if htmlfile: 6218 sysvals.htmlfile = htmlfile 5867 sysvals.htmlfile = htmlfile 6219 else: 5868 else: 6220 sysvals.setOutputFile() 5869 sysvals.setOutputFile() 6221 if os.path.exists(sysvals.htmlfile): 5870 if os.path.exists(sysvals.htmlfile): 6222 if not os.path.isfile(sysvals 5871 if not os.path.isfile(sysvals.htmlfile): 6223 doError('a directory 5872 doError('a directory already exists with this name: %s' % sysvals.htmlfile) 6224 elif not os.access(sysvals.ht 5873 elif not os.access(sysvals.htmlfile, os.W_OK): 6225 doError('missing perm 5874 doError('missing permission to write to %s' % sysvals.htmlfile) 6226 testruns, stamp = processData() !! 5875 testruns, stamp = processData(False) 6227 sysvals.resetlog() !! 5876 sysvals.logmsg = '' 6228 return stamp 5877 return stamp 6229 5878 6230 # Function: runTest 5879 # Function: runTest 6231 # Description: 5880 # Description: 6232 # execute a suspend/resume, gather the 5881 # execute a suspend/resume, gather the logs, and generate the output 6233 def runTest(n=0, quiet=False): !! 5882 def runTest(n=0): 6234 # prepare for the test 5883 # prepare for the test >> 5884 sysvals.initFtrace() 6235 sysvals.initTestOutput('suspend') 5885 sysvals.initTestOutput('suspend') 6236 op = sysvals.writeDatafileHeader(sysv << 6237 op.write('# EXECUTION TRACE START\n') << 6238 op.close() << 6239 if n <= 1: << 6240 if sysvals.rs != 0: << 6241 sysvals.dlog('%sablin << 6242 sysvals.setRuntimeSus << 6243 if sysvals.display: << 6244 ret = sysvals.display << 6245 sysvals.dlog('xset di << 6246 sysvals.testVal(sysvals.pmdpath, 'bas << 6247 sysvals.testVal(sysvals.s0ixpath, 'ba << 6248 sysvals.dlog('initialize ftrace') << 6249 sysvals.initFtrace(quiet) << 6250 5886 6251 # execute the test 5887 # execute the test 6252 executeSuspend(quiet) !! 5888 testdata = executeSuspend() 6253 sysvals.cleanupFtrace() 5889 sysvals.cleanupFtrace() 6254 if sysvals.skiphtml: 5890 if sysvals.skiphtml: 6255 sysvals.outputResult({}, n) << 6256 sysvals.sudoUserchown(sysvals 5891 sysvals.sudoUserchown(sysvals.testdir) 6257 return 5892 return 6258 testruns, stamp = processData(True, q !! 5893 if not testdata[0]['error']: 6259 for data in testruns: !! 5894 testruns, stamp = processData(True) 6260 del data !! 5895 for data in testruns: >> 5896 del data >> 5897 else: >> 5898 stamp = testdata[0] >> 5899 6261 sysvals.sudoUserchown(sysvals.testdir 5900 sysvals.sudoUserchown(sysvals.testdir) 6262 sysvals.outputResult(stamp, n) 5901 sysvals.outputResult(stamp, n) 6263 if 'error' in stamp: 5902 if 'error' in stamp: 6264 return 2 5903 return 2 6265 return 0 5904 return 0 6266 5905 6267 def find_in_html(html, start, end, firstonly= 5906 def find_in_html(html, start, end, firstonly=True): 6268 cnt, out, list = len(html), [], [] !! 5907 n, out = 0, [] 6269 if firstonly: !! 5908 while n < len(html): 6270 m = re.search(start, html) !! 5909 m = re.search(start, html[n:]) 6271 if m: !! 5910 if not m: 6272 list.append(m) !! 5911 break 6273 else: !! 5912 i = m.end() 6274 list = re.finditer(start, htm !! 5913 m = re.search(end, html[n+i:]) 6275 for match in list: << 6276 s = match.end() << 6277 e = cnt if (len(out) < 1 or s << 6278 m = re.search(end, html[s:e]) << 6279 if not m: 5914 if not m: 6280 break 5915 break 6281 e = s + m.start() !! 5916 j = m.start() 6282 str = html[s:e] !! 5917 str = html[n+i:n+i+j] 6283 if end == 'ms': 5918 if end == 'ms': 6284 num = re.search(r'[-+ 5919 num = re.search(r'[-+]?\d*\.\d+|\d+', str) 6285 str = num.group() if 5920 str = num.group() if num else 'NaN' 6286 if firstonly: 5921 if firstonly: 6287 return str 5922 return str 6288 out.append(str) 5923 out.append(str) >> 5924 n += i+j 6289 if firstonly: 5925 if firstonly: 6290 return '' 5926 return '' 6291 return out 5927 return out 6292 5928 6293 def data_from_html(file, outpath, issues, ful 5929 def data_from_html(file, outpath, issues, fulldetail=False): 6294 try: !! 5930 html = open(file, 'r').read() 6295 html = open(file, 'r').read() << 6296 except: << 6297 html = ascii(open(file, 'rb') << 6298 sysvals.htmlfile = os.path.relpath(fi 5931 sysvals.htmlfile = os.path.relpath(file, outpath) 6299 # extract general info 5932 # extract general info 6300 suspend = find_in_html(html, 'Kernel 5933 suspend = find_in_html(html, 'Kernel Suspend', 'ms') 6301 resume = find_in_html(html, 'Kernel R 5934 resume = find_in_html(html, 'Kernel Resume', 'ms') 6302 sysinfo = find_in_html(html, '<div cl 5935 sysinfo = find_in_html(html, '<div class="stamp sysinfo">', '</div>') 6303 line = find_in_html(html, '<div class 5936 line = find_in_html(html, '<div class="stamp">', '</div>') 6304 stmp = line.split() 5937 stmp = line.split() 6305 if not suspend or not resume or len(s 5938 if not suspend or not resume or len(stmp) != 8: 6306 return False 5939 return False 6307 try: 5940 try: 6308 dt = datetime.strptime(' '.jo 5941 dt = datetime.strptime(' '.join(stmp[3:]), '%B %d %Y, %I:%M:%S %p') 6309 except: 5942 except: 6310 return False 5943 return False 6311 sysvals.hostname = stmp[0] 5944 sysvals.hostname = stmp[0] 6312 tstr = dt.strftime('%Y/%m/%d %H:%M:%S 5945 tstr = dt.strftime('%Y/%m/%d %H:%M:%S') 6313 error = find_in_html(html, '<table cl 5946 error = find_in_html(html, '<table class="testfail"><tr><td>', '</td>') 6314 if error: 5947 if error: 6315 m = re.match(r'[a-z0-9]* fail !! 5948 m = re.match('[a-z]* failed in (?P<p>[a-z0-9_]*) phase', error) 6316 if m: 5949 if m: 6317 result = 'fail in %s' 5950 result = 'fail in %s' % m.group('p') 6318 else: 5951 else: 6319 result = 'fail' 5952 result = 'fail' 6320 else: 5953 else: 6321 result = 'pass' 5954 result = 'pass' 6322 # extract error info 5955 # extract error info 6323 tp, ilist = False, [] !! 5956 ilist = [] 6324 extra = dict() 5957 extra = dict() 6325 log = find_in_html(html, '<div id="dm 5958 log = find_in_html(html, '<div id="dmesglog" style="display:none;">', 6326 '</div>').strip() 5959 '</div>').strip() 6327 if log: 5960 if log: 6328 d = Data(0) 5961 d = Data(0) 6329 d.end = 999999999 5962 d.end = 999999999 6330 d.dmesgtext = log.split('\n') 5963 d.dmesgtext = log.split('\n') 6331 tp = d.extractErrorInfo() !! 5964 msglist = d.extractErrorInfo() 6332 if len(issues) < 100: !! 5965 for msg in msglist: 6333 for msg in tp.msglist !! 5966 sysvals.errorSummary(issues, msg) 6334 sysvals.error << 6335 if stmp[2] == 'freeze': 5967 if stmp[2] == 'freeze': 6336 extra = d.turbostatIn 5968 extra = d.turbostatInfo() 6337 elist = dict() 5969 elist = dict() 6338 for dir in d.errorinfo: 5970 for dir in d.errorinfo: 6339 for err in d.errorinf 5971 for err in d.errorinfo[dir]: 6340 if err[0] not 5972 if err[0] not in elist: 6341 elist 5973 elist[err[0]] = 0 6342 elist[err[0]] 5974 elist[err[0]] += 1 6343 for i in elist: 5975 for i in elist: 6344 ilist.append('%sx%d' 5976 ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i) 6345 line = find_in_html(log, '# w << 6346 if line: << 6347 extra['wifi'] = line << 6348 line = find_in_html(log, '# n << 6349 if line: << 6350 extra['netfix'] = lin << 6351 line = find_in_html(log, '# c << 6352 if line: << 6353 m = re.match(r'.* -m << 6354 if m: << 6355 extra['fullmo << 6356 low = find_in_html(html, 'freeze time 5977 low = find_in_html(html, 'freeze time: <b>', ' ms</b>') 6357 for lowstr in ['waking', '+']: !! 5978 if low and '|' in low: 6358 if not low: !! 5979 issue = 'FREEZEx%d' % len(low.split('|')) 6359 break << 6360 if lowstr not in low: << 6361 continue << 6362 if lowstr == '+': << 6363 issue = 'S2LOOPx%d' % << 6364 else: << 6365 m = re.match(r'.*waki << 6366 issue = 'S2WAKEx%s' % << 6367 match = [i for i in issues if 5980 match = [i for i in issues if i['match'] == issue] 6368 if len(match) > 0: 5981 if len(match) > 0: 6369 match[0]['count'] += 5982 match[0]['count'] += 1 6370 if sysvals.hostname n 5983 if sysvals.hostname not in match[0]['urls']: 6371 match[0]['url 5984 match[0]['urls'][sysvals.hostname] = [sysvals.htmlfile] 6372 elif sysvals.htmlfile 5985 elif sysvals.htmlfile not in match[0]['urls'][sysvals.hostname]: 6373 match[0]['url 5986 match[0]['urls'][sysvals.hostname].append(sysvals.htmlfile) 6374 else: 5987 else: 6375 issues.append({ 5988 issues.append({ 6376 'match': issu 5989 'match': issue, 'count': 1, 'line': issue, 6377 'urls': {sysv 5990 'urls': {sysvals.hostname: [sysvals.htmlfile]}, 6378 }) 5991 }) 6379 ilist.append(issue) 5992 ilist.append(issue) 6380 # extract device info 5993 # extract device info 6381 devices = dict() 5994 devices = dict() 6382 for line in html.split('\n'): 5995 for line in html.split('\n'): 6383 m = re.match(r' *<div id=\"[a !! 5996 m = re.match(' *<div id=\"[a,0-9]*\" *title=\"(?P<title>.*)\" class=\"thread.*', line) 6384 if not m or 'thread kth' in l 5997 if not m or 'thread kth' in line or 'thread sec' in line: 6385 continue 5998 continue 6386 m = re.match(r'(?P<n>.*) \((? !! 5999 m = re.match('(?P<n>.*) \((?P<t>[0-9,\.]*) ms\) (?P<p>.*)', m.group('title')) 6387 if not m: 6000 if not m: 6388 continue 6001 continue 6389 name, time, phase = m.group(' 6002 name, time, phase = m.group('n'), m.group('t'), m.group('p') 6390 if name == 'async_synchronize << 6391 continue << 6392 if ' async' in name or ' sync 6003 if ' async' in name or ' sync' in name: 6393 name = ' '.join(name. 6004 name = ' '.join(name.split(' ')[:-1]) 6394 if phase.startswith('suspend' 6005 if phase.startswith('suspend'): 6395 d = 'suspend' 6006 d = 'suspend' 6396 elif phase.startswith('resume 6007 elif phase.startswith('resume'): 6397 d = 'resume' 6008 d = 'resume' 6398 else: 6009 else: 6399 continue 6010 continue 6400 if d not in devices: 6011 if d not in devices: 6401 devices[d] = dict() 6012 devices[d] = dict() 6402 if name not in devices[d]: 6013 if name not in devices[d]: 6403 devices[d][name] = 0. 6014 devices[d][name] = 0.0 6404 devices[d][name] += float(tim 6015 devices[d][name] += float(time) 6405 # create worst device info 6016 # create worst device info 6406 worst = dict() 6017 worst = dict() 6407 for d in ['suspend', 'resume']: 6018 for d in ['suspend', 'resume']: 6408 worst[d] = {'name':'', 'time' 6019 worst[d] = {'name':'', 'time': 0.0} 6409 dev = devices[d] if d in devi 6020 dev = devices[d] if d in devices else 0 6410 if dev and len(dev.keys()) > 6021 if dev and len(dev.keys()) > 0: 6411 n = sorted(dev, key=l 6022 n = sorted(dev, key=lambda k:(dev[k], k), reverse=True)[0] 6412 worst[d]['name'], wor 6023 worst[d]['name'], worst[d]['time'] = n, dev[n] 6413 data = { 6024 data = { 6414 'mode': stmp[2], 6025 'mode': stmp[2], 6415 'host': stmp[0], 6026 'host': stmp[0], 6416 'kernel': stmp[1], 6027 'kernel': stmp[1], 6417 'sysinfo': sysinfo, 6028 'sysinfo': sysinfo, 6418 'time': tstr, 6029 'time': tstr, 6419 'result': result, 6030 'result': result, 6420 'issues': ' '.join(ilist), 6031 'issues': ' '.join(ilist), 6421 'suspend': suspend, 6032 'suspend': suspend, 6422 'resume': resume, 6033 'resume': resume, 6423 'devlist': devices, 6034 'devlist': devices, 6424 'sus_worst': worst['suspend'] 6035 'sus_worst': worst['suspend']['name'], 6425 'sus_worsttime': worst['suspe 6036 'sus_worsttime': worst['suspend']['time'], 6426 'res_worst': worst['resume'][ 6037 'res_worst': worst['resume']['name'], 6427 'res_worsttime': worst['resum 6038 'res_worsttime': worst['resume']['time'], 6428 'url': sysvals.htmlfile, 6039 'url': sysvals.htmlfile, 6429 } 6040 } 6430 for key in extra: 6041 for key in extra: 6431 data[key] = extra[key] 6042 data[key] = extra[key] 6432 if fulldetail: 6043 if fulldetail: 6433 data['funclist'] = find_in_ht 6044 data['funclist'] = find_in_html(html, '<div title="', '" class="traceevent"', False) 6434 if tp: << 6435 for arg in ['-multi ', '-info << 6436 if arg in tp.cmdline: << 6437 data['target' << 6438 break << 6439 return data 6045 return data 6440 6046 6441 def genHtml(subdir, force=False): 6047 def genHtml(subdir, force=False): 6442 for dirname, dirnames, filenames in o 6048 for dirname, dirnames, filenames in os.walk(subdir): 6443 sysvals.dmesgfile = sysvals.f 6049 sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = '' 6444 for filename in filenames: 6050 for filename in filenames: 6445 file = os.path.join(d !! 6051 if(re.match('.*_dmesg.txt', filename)): 6446 if sysvals.usable(fil !! 6052 sysvals.dmesgfile = os.path.join(dirname, filename) 6447 if(re.match(r !! 6053 elif(re.match('.*_ftrace.txt', filename)): 6448 sysva !! 6054 sysvals.ftracefile = os.path.join(dirname, filename) 6449 elif(re.match << 6450 sysva << 6451 sysvals.setOutputFile() 6055 sysvals.setOutputFile() 6452 if (sysvals.dmesgfile or sysv !! 6056 if sysvals.ftracefile and sysvals.htmlfile and \ 6453 (force or not sysvals !! 6057 (force or not os.path.exists(sysvals.htmlfile)): 6454 pprint('FTRACE: %s' % 6058 pprint('FTRACE: %s' % sysvals.ftracefile) 6455 if sysvals.dmesgfile: 6059 if sysvals.dmesgfile: 6456 pprint('DMESG 6060 pprint('DMESG : %s' % sysvals.dmesgfile) 6457 rerunTest() 6061 rerunTest() 6458 6062 6459 # Function: runSummary 6063 # Function: runSummary 6460 # Description: 6064 # Description: 6461 # create a summary of tests in a sub-d 6065 # create a summary of tests in a sub-directory 6462 def runSummary(subdir, local=True, genhtml=Fa 6066 def runSummary(subdir, local=True, genhtml=False): 6463 inpath = os.path.abspath(subdir) 6067 inpath = os.path.abspath(subdir) 6464 outpath = os.path.abspath('.') if loc 6068 outpath = os.path.abspath('.') if local else inpath 6465 pprint('Generating a summary of folde 6069 pprint('Generating a summary of folder:\n %s' % inpath) 6466 if genhtml: 6070 if genhtml: 6467 genHtml(subdir) 6071 genHtml(subdir) 6468 target, issues, testruns = '', [], [] !! 6072 issues = [] >> 6073 testruns = [] 6469 desc = {'host':[],'mode':[],'kernel': 6074 desc = {'host':[],'mode':[],'kernel':[]} 6470 for dirname, dirnames, filenames in o 6075 for dirname, dirnames, filenames in os.walk(subdir): 6471 for filename in filenames: 6076 for filename in filenames: 6472 if(not re.match(r'.*. !! 6077 if(not re.match('.*.html', filename)): 6473 continue 6078 continue 6474 data = data_from_html 6079 data = data_from_html(os.path.join(dirname, filename), outpath, issues) 6475 if(not data): 6080 if(not data): 6476 continue 6081 continue 6477 if 'target' in data: << 6478 target = data << 6479 testruns.append(data) 6082 testruns.append(data) 6480 for key in desc: 6083 for key in desc: 6481 if data[key] 6084 if data[key] not in desc[key]: 6482 desc[ 6085 desc[key].append(data[key]) 6483 pprint('Summary files:') 6086 pprint('Summary files:') 6484 if len(desc['host']) == len(desc['mod 6087 if len(desc['host']) == len(desc['mode']) == len(desc['kernel']) == 1: 6485 title = '%s %s %s' % (desc['h 6088 title = '%s %s %s' % (desc['host'][0], desc['kernel'][0], desc['mode'][0]) 6486 if target: << 6487 title += ' %s' % targ << 6488 else: 6089 else: 6489 title = inpath 6090 title = inpath 6490 createHTMLSummarySimple(testruns, os. 6091 createHTMLSummarySimple(testruns, os.path.join(outpath, 'summary.html'), title) 6491 pprint(' summary.html - tab 6092 pprint(' summary.html - tabular list of test data found') 6492 createHTMLDeviceSummary(testruns, os. 6093 createHTMLDeviceSummary(testruns, os.path.join(outpath, 'summary-devices.html'), title) 6493 pprint(' summary-devices.html - ker 6094 pprint(' summary-devices.html - kernel device list sorted by total execution time') 6494 createHTMLIssuesSummary(testruns, iss 6095 createHTMLIssuesSummary(testruns, issues, os.path.join(outpath, 'summary-issues.html'), title) 6495 pprint(' summary-issues.html - ker 6096 pprint(' summary-issues.html - kernel issues found sorted by frequency') 6496 6097 6497 # Function: checkArgBool 6098 # Function: checkArgBool 6498 # Description: 6099 # Description: 6499 # check if a boolean string value is t 6100 # check if a boolean string value is true or false 6500 def checkArgBool(name, value): 6101 def checkArgBool(name, value): 6501 if value in switchvalues: 6102 if value in switchvalues: 6502 if value in switchoff: 6103 if value in switchoff: 6503 return False 6104 return False 6504 return True 6105 return True 6505 doError('invalid boolean --> (%s: %s) 6106 doError('invalid boolean --> (%s: %s), use "true/false" or "1/0"' % (name, value), True) 6506 return False 6107 return False 6507 6108 6508 # Function: configFromFile 6109 # Function: configFromFile 6509 # Description: 6110 # Description: 6510 # Configure the script via the info in 6111 # Configure the script via the info in a config file 6511 def configFromFile(file): 6112 def configFromFile(file): 6512 Config = configparser.ConfigParser() 6113 Config = configparser.ConfigParser() 6513 6114 6514 Config.read(file) 6115 Config.read(file) 6515 sections = Config.sections() 6116 sections = Config.sections() 6516 overridekprobes = False 6117 overridekprobes = False 6517 overridedevkprobes = False 6118 overridedevkprobes = False 6518 if 'Settings' in sections: 6119 if 'Settings' in sections: 6519 for opt in Config.options('Se 6120 for opt in Config.options('Settings'): 6520 value = Config.get('S 6121 value = Config.get('Settings', opt).lower() 6521 option = opt.lower() 6122 option = opt.lower() 6522 if(option == 'verbose 6123 if(option == 'verbose'): 6523 sysvals.verbo 6124 sysvals.verbose = checkArgBool(option, value) 6524 elif(option == 'addlo 6125 elif(option == 'addlogs'): 6525 sysvals.dmesg 6126 sysvals.dmesglog = sysvals.ftracelog = checkArgBool(option, value) 6526 elif(option == 'dev') 6127 elif(option == 'dev'): 6527 sysvals.usede 6128 sysvals.usedevsrc = checkArgBool(option, value) 6528 elif(option == 'proc' 6129 elif(option == 'proc'): 6529 sysvals.usepr 6130 sysvals.useprocmon = checkArgBool(option, value) 6530 elif(option == 'x2'): 6131 elif(option == 'x2'): 6531 if checkArgBo 6132 if checkArgBool(option, value): 6532 sysva 6133 sysvals.execcount = 2 6533 elif(option == 'callg 6134 elif(option == 'callgraph'): 6534 sysvals.useca 6135 sysvals.usecallgraph = checkArgBool(option, value) 6535 elif(option == 'overr 6136 elif(option == 'override-timeline-functions'): 6536 overridekprob 6137 overridekprobes = checkArgBool(option, value) 6537 elif(option == 'overr 6138 elif(option == 'override-dev-timeline-functions'): 6538 overridedevkp 6139 overridedevkprobes = checkArgBool(option, value) 6539 elif(option == 'skiph 6140 elif(option == 'skiphtml'): 6540 sysvals.skiph 6141 sysvals.skiphtml = checkArgBool(option, value) 6541 elif(option == 'sync' 6142 elif(option == 'sync'): 6542 sysvals.sync 6143 sysvals.sync = checkArgBool(option, value) 6543 elif(option == 'rs' o 6144 elif(option == 'rs' or option == 'runtimesuspend'): 6544 if value in s 6145 if value in switchvalues: 6545 if va 6146 if value in switchoff: 6546 6147 sysvals.rs = -1 6547 else: 6148 else: 6548 6149 sysvals.rs = 1 6549 else: 6150 else: 6550 doErr 6151 doError('invalid value --> (%s: %s), use "enable/disable"' % (option, value), True) 6551 elif(option == 'displ 6152 elif(option == 'display'): 6552 disopt = ['on 6153 disopt = ['on', 'off', 'standby', 'suspend'] 6553 if value not 6154 if value not in disopt: 6554 doErr 6155 doError('invalid value --> (%s: %s), use %s' % (option, value, disopt), True) 6555 sysvals.displ 6156 sysvals.display = value 6556 elif(option == 'gzip' 6157 elif(option == 'gzip'): 6557 sysvals.gzip 6158 sysvals.gzip = checkArgBool(option, value) 6558 elif(option == 'cgfil 6159 elif(option == 'cgfilter'): 6559 sysvals.setCa 6160 sysvals.setCallgraphFilter(value) 6560 elif(option == 'cgski 6161 elif(option == 'cgskip'): 6561 if value in s 6162 if value in switchoff: 6562 sysva 6163 sysvals.cgskip = '' 6563 else: 6164 else: 6564 sysva 6165 sysvals.cgskip = sysvals.configFile(val) 6565 if(no 6166 if(not sysvals.cgskip): 6566 6167 doError('%s does not exist' % sysvals.cgskip) 6567 elif(option == 'cgtes 6168 elif(option == 'cgtest'): 6568 sysvals.cgtes 6169 sysvals.cgtest = getArgInt('cgtest', value, 0, 1, False) 6569 elif(option == 'cgpha 6170 elif(option == 'cgphase'): 6570 d = Data(0) 6171 d = Data(0) 6571 if value not !! 6172 if value not in d.sortedPhases(): 6572 doErr 6173 doError('invalid phase --> (%s: %s), valid phases are %s'\ 6573 !! 6174 % (option, value, d.sortedPhases()), True) 6574 sysvals.cgpha 6175 sysvals.cgphase = value 6575 elif(option == 'fadd' 6176 elif(option == 'fadd'): 6576 file = sysval 6177 file = sysvals.configFile(value) 6577 if(not file): 6178 if(not file): 6578 doErr 6179 doError('%s does not exist' % value) 6579 sysvals.addFt 6180 sysvals.addFtraceFilterFunctions(file) 6580 elif(option == 'resul 6181 elif(option == 'result'): 6581 sysvals.resul 6182 sysvals.result = value 6582 elif(option == 'multi 6183 elif(option == 'multi'): 6583 nums = value. 6184 nums = value.split() 6584 if len(nums) 6185 if len(nums) != 2: 6585 doErr 6186 doError('multi requires 2 integers (exec_count and delay)', True) 6586 sysvals.multi !! 6187 sysvals.multitest['run'] = True >> 6188 sysvals.multitest['count'] = getArgInt('multi: n d (exec count)', nums[0], 2, 1000000, False) >> 6189 sysvals.multitest['delay'] = getArgInt('multi: n d (delay between tests)', nums[1], 0, 3600, False) 6587 elif(option == 'devic 6190 elif(option == 'devicefilter'): 6588 sysvals.setDe 6191 sysvals.setDeviceFilter(value) 6589 elif(option == 'expan 6192 elif(option == 'expandcg'): 6590 sysvals.cgexp 6193 sysvals.cgexp = checkArgBool(option, value) 6591 elif(option == 'srgap 6194 elif(option == 'srgap'): 6592 if checkArgBo 6195 if checkArgBool(option, value): 6593 sysva 6196 sysvals.srgap = 5 6594 elif(option == 'mode' 6197 elif(option == 'mode'): 6595 sysvals.suspe 6198 sysvals.suspendmode = value 6596 elif(option == 'comma 6199 elif(option == 'command' or option == 'cmd'): 6597 sysvals.testc 6200 sysvals.testcommand = value 6598 elif(option == 'x2del 6201 elif(option == 'x2delay'): 6599 sysvals.x2del 6202 sysvals.x2delay = getArgInt('x2delay', value, 0, 60000, False) 6600 elif(option == 'prede 6203 elif(option == 'predelay'): 6601 sysvals.prede 6204 sysvals.predelay = getArgInt('predelay', value, 0, 60000, False) 6602 elif(option == 'postd 6205 elif(option == 'postdelay'): 6603 sysvals.postd 6206 sysvals.postdelay = getArgInt('postdelay', value, 0, 60000, False) 6604 elif(option == 'maxde 6207 elif(option == 'maxdepth'): 6605 sysvals.max_g 6208 sysvals.max_graph_depth = getArgInt('maxdepth', value, 0, 1000, False) 6606 elif(option == 'rtcwa 6209 elif(option == 'rtcwake'): 6607 if value in s 6210 if value in switchoff: 6608 sysva 6211 sysvals.rtcwake = False 6609 else: 6212 else: 6610 sysva 6213 sysvals.rtcwake = True 6611 sysva 6214 sysvals.rtcwaketime = getArgInt('rtcwake', value, 0, 3600, False) 6612 elif(option == 'timep 6215 elif(option == 'timeprec'): 6613 sysvals.setPr 6216 sysvals.setPrecision(getArgInt('timeprec', value, 0, 6, False)) 6614 elif(option == 'minde 6217 elif(option == 'mindev'): 6615 sysvals.minde 6218 sysvals.mindevlen = getArgFloat('mindev', value, 0.0, 10000.0, False) 6616 elif(option == 'calll 6219 elif(option == 'callloop-maxgap'): 6617 sysvals.calll 6220 sysvals.callloopmaxgap = getArgFloat('callloop-maxgap', value, 0.0, 1.0, False) 6618 elif(option == 'calll 6221 elif(option == 'callloop-maxlen'): 6619 sysvals.calll 6222 sysvals.callloopmaxgap = getArgFloat('callloop-maxlen', value, 0.0, 1.0, False) 6620 elif(option == 'mincg 6223 elif(option == 'mincg'): 6621 sysvals.mincg 6224 sysvals.mincglen = getArgFloat('mincg', value, 0.0, 10000.0, False) 6622 elif(option == 'bufsi 6225 elif(option == 'bufsize'): 6623 sysvals.bufsi 6226 sysvals.bufsize = getArgInt('bufsize', value, 1, 1024*1024*8, False) 6624 elif(option == 'outpu 6227 elif(option == 'output-dir'): 6625 sysvals.outdi 6228 sysvals.outdir = sysvals.setOutputFolder(value) 6626 6229 6627 if sysvals.suspendmode == 'command' a 6230 if sysvals.suspendmode == 'command' and not sysvals.testcommand: 6628 doError('No command supplied 6231 doError('No command supplied for mode "command"') 6629 6232 6630 # compatibility errors 6233 # compatibility errors 6631 if sysvals.usedevsrc and sysvals.usec 6234 if sysvals.usedevsrc and sysvals.usecallgraph: 6632 doError('-dev is not compatib 6235 doError('-dev is not compatible with -f') 6633 if sysvals.usecallgraph and sysvals.u 6236 if sysvals.usecallgraph and sysvals.useprocmon: 6634 doError('-proc is not compati 6237 doError('-proc is not compatible with -f') 6635 6238 6636 if overridekprobes: 6239 if overridekprobes: 6637 sysvals.tracefuncs = dict() 6240 sysvals.tracefuncs = dict() 6638 if overridedevkprobes: 6241 if overridedevkprobes: 6639 sysvals.dev_tracefuncs = dict 6242 sysvals.dev_tracefuncs = dict() 6640 6243 6641 kprobes = dict() 6244 kprobes = dict() 6642 kprobesec = 'dev_timeline_functions_' 6245 kprobesec = 'dev_timeline_functions_'+platform.machine() 6643 if kprobesec in sections: 6246 if kprobesec in sections: 6644 for name in Config.options(kp 6247 for name in Config.options(kprobesec): 6645 text = Config.get(kpr 6248 text = Config.get(kprobesec, name) 6646 kprobes[name] = (text 6249 kprobes[name] = (text, True) 6647 kprobesec = 'timeline_functions_'+pla 6250 kprobesec = 'timeline_functions_'+platform.machine() 6648 if kprobesec in sections: 6251 if kprobesec in sections: 6649 for name in Config.options(kp 6252 for name in Config.options(kprobesec): 6650 if name in kprobes: 6253 if name in kprobes: 6651 doError('Dupl 6254 doError('Duplicate timeline function found "%s"' % (name)) 6652 text = Config.get(kpr 6255 text = Config.get(kprobesec, name) 6653 kprobes[name] = (text 6256 kprobes[name] = (text, False) 6654 6257 6655 for name in kprobes: 6258 for name in kprobes: 6656 function = name 6259 function = name 6657 format = name 6260 format = name 6658 color = '' 6261 color = '' 6659 args = dict() 6262 args = dict() 6660 text, dev = kprobes[name] 6263 text, dev = kprobes[name] 6661 data = text.split() 6264 data = text.split() 6662 i = 0 6265 i = 0 6663 for val in data: 6266 for val in data: 6664 # bracketted strings 6267 # bracketted strings are special formatting, read them separately 6665 if val[0] == '[' and 6268 if val[0] == '[' and val[-1] == ']': 6666 for prop in v 6269 for prop in val[1:-1].split(','): 6667 p = p 6270 p = prop.split('=') 6668 if p[ 6271 if p[0] == 'color': 6669 6272 try: 6670 6273 color = int(p[1], 16) 6671 6274 color = '#'+p[1] 6672 6275 except: 6673 6276 color = p[1] 6674 continue 6277 continue 6675 # first real arg shou 6278 # first real arg should be the format string 6676 if i == 0: 6279 if i == 0: 6677 format = val 6280 format = val 6678 # all other args are 6281 # all other args are actual function args 6679 else: 6282 else: 6680 d = val.split 6283 d = val.split('=') 6681 args[d[0]] = 6284 args[d[0]] = d[1] 6682 i += 1 6285 i += 1 6683 if not function or not format 6286 if not function or not format: 6684 doError('Invalid kpro 6287 doError('Invalid kprobe: %s' % name) 6685 for arg in re.findall('{(?P<n 6288 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format): 6686 if arg not in args: 6289 if arg not in args: 6687 doError('Kpro 6290 doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 6688 if (dev and name in sysvals.d 6291 if (dev and name in sysvals.dev_tracefuncs) or (not dev and name in sysvals.tracefuncs): 6689 doError('Duplicate ti 6292 doError('Duplicate timeline function found "%s"' % (name)) 6690 6293 6691 kp = { 6294 kp = { 6692 'name': name, 6295 'name': name, 6693 'func': function, 6296 'func': function, 6694 'format': format, 6297 'format': format, 6695 sysvals.archargs: arg 6298 sysvals.archargs: args 6696 } 6299 } 6697 if color: 6300 if color: 6698 kp['color'] = color 6301 kp['color'] = color 6699 if dev: 6302 if dev: 6700 sysvals.dev_tracefunc 6303 sysvals.dev_tracefuncs[name] = kp 6701 else: 6304 else: 6702 sysvals.tracefuncs[na 6305 sysvals.tracefuncs[name] = kp 6703 6306 6704 # Function: printHelp 6307 # Function: printHelp 6705 # Description: 6308 # Description: 6706 # print out the help text 6309 # print out the help text 6707 def printHelp(): 6310 def printHelp(): 6708 pprint('\n%s v%s\n'\ 6311 pprint('\n%s v%s\n'\ 6709 'Usage: sudo sleepgraph <options> <co 6312 'Usage: sudo sleepgraph <options> <commands>\n'\ 6710 '\n'\ 6313 '\n'\ 6711 'Description:\n'\ 6314 'Description:\n'\ 6712 ' This tool is designed to assist ke 6315 ' This tool is designed to assist kernel and OS developers in optimizing\n'\ 6713 ' their linux stack\'s suspend/resum 6316 ' their linux stack\'s suspend/resume time. Using a kernel image built\n'\ 6714 ' with a few extra options enabled, 6317 ' with a few extra options enabled, the tool will execute a suspend and\n'\ 6715 ' capture dmesg and ftrace data unti 6318 ' capture dmesg and ftrace data until resume is complete. This data is\n'\ 6716 ' transformed into a device timeline 6319 ' transformed into a device timeline and an optional callgraph to give\n'\ 6717 ' a detailed view of which devices/s 6320 ' a detailed view of which devices/subsystems are taking the most\n'\ 6718 ' time in suspend/resume.\n'\ 6321 ' time in suspend/resume.\n'\ 6719 '\n'\ 6322 '\n'\ 6720 ' If no specific command is given, t 6323 ' If no specific command is given, the default behavior is to initiate\n'\ 6721 ' a suspend/resume and capture the d 6324 ' a suspend/resume and capture the dmesg/ftrace output as an html timeline.\n'\ 6722 '\n'\ 6325 '\n'\ 6723 ' Generates output files in subdirec 6326 ' Generates output files in subdirectory: suspend-yymmdd-HHMMSS\n'\ 6724 ' HTML output: < 6327 ' HTML output: <hostname>_<mode>.html\n'\ 6725 ' raw dmesg output: < 6328 ' raw dmesg output: <hostname>_<mode>_dmesg.txt\n'\ 6726 ' raw ftrace output: < 6329 ' raw ftrace output: <hostname>_<mode>_ftrace.txt\n'\ 6727 '\n'\ 6330 '\n'\ 6728 'Options:\n'\ 6331 'Options:\n'\ 6729 ' -h Print this help text 6332 ' -h Print this help text\n'\ 6730 ' -v Print the current to 6333 ' -v Print the current tool version\n'\ 6731 ' -config fn Pull arguments and c 6334 ' -config fn Pull arguments and config options from file fn\n'\ 6732 ' -verbose Print extra informat 6335 ' -verbose Print extra information during execution and analysis\n'\ 6733 ' -m mode Mode to initiate for 6336 ' -m mode Mode to initiate for suspend (default: %s)\n'\ 6734 ' -o name Overrides the output 6337 ' -o name Overrides the output subdirectory name when running a new test\n'\ 6735 ' default: suspend-{da 6338 ' default: suspend-{date}-{time}\n'\ 6736 ' -rtcwake t Wakeup t seconds aft 6339 ' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)\n'\ 6737 ' -addlogs Add the dmesg and ft 6340 ' -addlogs Add the dmesg and ftrace logs to the html output\n'\ 6738 ' -noturbostat Dont use turbostat i 6341 ' -noturbostat Dont use turbostat in freeze mode (default: disabled)\n'\ 6739 ' -srgap Add a visible gap in 6342 ' -srgap Add a visible gap in the timeline between sus/res (default: disabled)\n'\ 6740 ' -skiphtml Run the test and cap 6343 ' -skiphtml Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\ 6741 ' -result fn Export a results tab 6344 ' -result fn Export a results table to a text file for parsing.\n'\ 6742 ' -wifi If a wifi connection << 6743 ' -wifitrace Trace kernel executi << 6744 ' -netfix Use netfix to reset << 6745 ' [testprep]\n'\ 6345 ' [testprep]\n'\ 6746 ' -sync Sync the filesystems 6346 ' -sync Sync the filesystems before starting the test\n'\ 6747 ' -rs on/off Enable/disable runti 6347 ' -rs on/off Enable/disable runtime suspend for all devices, restore all after test\n'\ 6748 ' -display m Change the display m 6348 ' -display m Change the display mode to m for the test (on/off/standby/suspend)\n'\ 6749 ' [advanced]\n'\ 6349 ' [advanced]\n'\ 6750 ' -gzip Gzip the trace and d 6350 ' -gzip Gzip the trace and dmesg logs to save space\n'\ 6751 ' -cmd {s} Run the timeline ove 6351 ' -cmd {s} Run the timeline over a custom command, e.g. "sync -d"\n'\ 6752 ' -proc Add usermode process 6352 ' -proc Add usermode process info into the timeline (default: disabled)\n'\ 6753 ' -dev Add kernel function 6353 ' -dev Add kernel function calls and threads to the timeline (default: disabled)\n'\ 6754 ' -x2 Run two suspend/resu 6354 ' -x2 Run two suspend/resumes back to back (default: disabled)\n'\ 6755 ' -x2delay t Include t ms delay b 6355 ' -x2delay t Include t ms delay between multiple test runs (default: 0 ms)\n'\ 6756 ' -predelay t Include t ms delay b 6356 ' -predelay t Include t ms delay before 1st suspend (default: 0 ms)\n'\ 6757 ' -postdelay t Include t ms delay a 6357 ' -postdelay t Include t ms delay after last resume (default: 0 ms)\n'\ 6758 ' -mindev ms Discard all device b 6358 ' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 6759 ' -multi n d Execute <n> consecut !! 6359 ' -multi n d Execute <n> consecutive tests at <d> seconds intervals. The outputs will\n'\ 6760 ' by a "d", "h", or "m !! 6360 ' be created in a new subdirectory with a summary page.\n'\ 6761 ' The outputs will be << 6762 ' -maxfail n Abort a -multi run a << 6763 ' [debug]\n'\ 6361 ' [debug]\n'\ 6764 ' -f Use ftrace to create 6362 ' -f Use ftrace to create device callgraphs (default: disabled)\n'\ 6765 ' -ftop Use ftrace on the to 6363 ' -ftop Use ftrace on the top level call: "%s" (default: disabled)\n'\ 6766 ' -maxdepth N limit the callgraph 6364 ' -maxdepth N limit the callgraph data to N call levels (default: 0=all)\n'\ 6767 ' -expandcg pre-expand the callg 6365 ' -expandcg pre-expand the callgraph data in the html output (default: disabled)\n'\ 6768 ' -fadd file Add functions to be 6366 ' -fadd file Add functions to be graphed in the timeline from a list in a text file\n'\ 6769 ' -filter "d1,d2,..." Filter out al 6367 ' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names\n'\ 6770 ' -mincg ms Discard all callgrap 6368 ' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 6771 ' -cgphase P Only show callgraph 6369 ' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)\n'\ 6772 ' -cgtest N Only show callgraph 6370 ' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)\n'\ 6773 ' -timeprec N Number of significan 6371 ' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)\n'\ 6774 ' -cgfilter S Filter the callgraph 6372 ' -cgfilter S Filter the callgraph output in the timeline\n'\ 6775 ' -cgskip file Callgraph functions 6373 ' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\ 6776 ' -bufsize N Set trace buffer siz 6374 ' -bufsize N Set trace buffer size to N kilo-bytes (default: all of free memory)\n'\ 6777 ' -devdump Print out all the ra 6375 ' -devdump Print out all the raw device data for each phase\n'\ 6778 ' -cgdump Print out all the ra 6376 ' -cgdump Print out all the raw callgraph data\n'\ 6779 '\n'\ 6377 '\n'\ 6780 'Other commands:\n'\ 6378 'Other commands:\n'\ 6781 ' -modes List available suspe 6379 ' -modes List available suspend modes\n'\ 6782 ' -status Test to see if the s 6380 ' -status Test to see if the system is enabled to run this tool\n'\ 6783 ' -fpdt Print out the conten 6381 ' -fpdt Print out the contents of the ACPI Firmware Performance Data Table\n'\ 6784 ' -wificheck Print out wifi conne !! 6382 ' -battery Print out battery info (if available)\n'\ >> 6383 ' -wifi Print out wifi connection info (if wireless-tools and device exists)\n'\ 6785 ' -x<mode> Test xset by togglin 6384 ' -x<mode> Test xset by toggling the given mode (on/off/standby/suspend)\n'\ 6786 ' -sysinfo Print out system inf 6385 ' -sysinfo Print out system info extracted from BIOS\n'\ 6787 ' -devinfo Print out the pm set 6386 ' -devinfo Print out the pm settings of all devices which support runtime suspend\n'\ 6788 ' -cmdinfo Print out all the pl << 6789 ' -flist Print the list of fu 6387 ' -flist Print the list of functions currently being captured in ftrace\n'\ 6790 ' -flistall Print all functions 6388 ' -flistall Print all functions capable of being captured in ftrace\n'\ 6791 ' -summary dir Create a summary of 6389 ' -summary dir Create a summary of tests in this dir [-genhtml builds missing html]\n'\ 6792 ' [redo]\n'\ 6390 ' [redo]\n'\ 6793 ' -ftrace ftracefile Create HTML o 6391 ' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)\n'\ 6794 ' -dmesg dmesgfile Create HTML o 6392 ' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)\n'\ 6795 '' % (sysvals.title, sysvals.version, 6393 '' % (sysvals.title, sysvals.version, sysvals.suspendmode, sysvals.ftopfunc)) 6796 return True 6394 return True 6797 6395 6798 # ----------------- MAIN -------------------- 6396 # ----------------- MAIN -------------------- 6799 # exec start (skipped if script is loaded as 6397 # exec start (skipped if script is loaded as library) 6800 if __name__ == '__main__': 6398 if __name__ == '__main__': 6801 genhtml = False 6399 genhtml = False 6802 cmd = '' 6400 cmd = '' 6803 simplecmds = ['-sysinfo', '-modes', ' 6401 simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall', 6804 '-devinfo', '-status', '-xon' !! 6402 '-devinfo', '-status', '-battery', '-xon', '-xoff', '-xstandby', 6805 '-xinit', '-xreset', '-xstat' !! 6403 '-xsuspend', '-xinit', '-xreset', '-xstat', '-wifi'] 6806 if '-f' in sys.argv: 6404 if '-f' in sys.argv: 6807 sysvals.cgskip = sysvals.conf 6405 sysvals.cgskip = sysvals.configFile('cgskip.txt') 6808 # loop through the command line argum 6406 # loop through the command line arguments 6809 args = iter(sys.argv[1:]) 6407 args = iter(sys.argv[1:]) 6810 for arg in args: 6408 for arg in args: 6811 if(arg == '-m'): 6409 if(arg == '-m'): 6812 try: 6410 try: 6813 val = next(ar 6411 val = next(args) 6814 except: 6412 except: 6815 doError('No m 6413 doError('No mode supplied', True) 6816 if val == 'command' a 6414 if val == 'command' and not sysvals.testcommand: 6817 doError('No c 6415 doError('No command supplied for mode "command"', True) 6818 sysvals.suspendmode = 6416 sysvals.suspendmode = val 6819 elif(arg in simplecmds): 6417 elif(arg in simplecmds): 6820 cmd = arg[1:] 6418 cmd = arg[1:] 6821 elif(arg == '-h'): 6419 elif(arg == '-h'): 6822 printHelp() 6420 printHelp() 6823 sys.exit(0) 6421 sys.exit(0) 6824 elif(arg == '-v'): 6422 elif(arg == '-v'): 6825 pprint("Version %s" % 6423 pprint("Version %s" % sysvals.version) 6826 sys.exit(0) 6424 sys.exit(0) 6827 elif(arg == '-debugtiming'): << 6828 debugtiming = True << 6829 elif(arg == '-x2'): 6425 elif(arg == '-x2'): 6830 sysvals.execcount = 2 6426 sysvals.execcount = 2 6831 elif(arg == '-x2delay'): 6427 elif(arg == '-x2delay'): 6832 sysvals.x2delay = get 6428 sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000) 6833 elif(arg == '-predelay'): 6429 elif(arg == '-predelay'): 6834 sysvals.predelay = ge 6430 sysvals.predelay = getArgInt('-predelay', args, 0, 60000) 6835 elif(arg == '-postdelay'): 6431 elif(arg == '-postdelay'): 6836 sysvals.postdelay = g 6432 sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000) 6837 elif(arg == '-f'): 6433 elif(arg == '-f'): 6838 sysvals.usecallgraph 6434 sysvals.usecallgraph = True 6839 elif(arg == '-ftop'): 6435 elif(arg == '-ftop'): 6840 sysvals.usecallgraph 6436 sysvals.usecallgraph = True 6841 sysvals.ftop = True 6437 sysvals.ftop = True 6842 sysvals.usekprobes = 6438 sysvals.usekprobes = False 6843 elif(arg == '-skiphtml'): 6439 elif(arg == '-skiphtml'): 6844 sysvals.skiphtml = Tr 6440 sysvals.skiphtml = True 6845 elif(arg == '-cgdump'): 6441 elif(arg == '-cgdump'): 6846 sysvals.cgdump = True 6442 sysvals.cgdump = True 6847 elif(arg == '-devdump'): 6443 elif(arg == '-devdump'): 6848 sysvals.devdump = Tru 6444 sysvals.devdump = True 6849 elif(arg == '-genhtml'): 6445 elif(arg == '-genhtml'): 6850 genhtml = True 6446 genhtml = True 6851 elif(arg == '-addlogs'): 6447 elif(arg == '-addlogs'): 6852 sysvals.dmesglog = sy 6448 sysvals.dmesglog = sysvals.ftracelog = True 6853 elif(arg == '-nologs'): 6449 elif(arg == '-nologs'): 6854 sysvals.dmesglog = sy 6450 sysvals.dmesglog = sysvals.ftracelog = False 6855 elif(arg == '-addlogdmesg'): 6451 elif(arg == '-addlogdmesg'): 6856 sysvals.dmesglog = Tr 6452 sysvals.dmesglog = True 6857 elif(arg == '-addlogftrace'): 6453 elif(arg == '-addlogftrace'): 6858 sysvals.ftracelog = T 6454 sysvals.ftracelog = True 6859 elif(arg == '-noturbostat'): 6455 elif(arg == '-noturbostat'): 6860 sysvals.tstat = False 6456 sysvals.tstat = False 6861 elif(arg == '-verbose'): 6457 elif(arg == '-verbose'): 6862 sysvals.verbose = Tru 6458 sysvals.verbose = True 6863 elif(arg == '-proc'): 6459 elif(arg == '-proc'): 6864 sysvals.useprocmon = 6460 sysvals.useprocmon = True 6865 elif(arg == '-dev'): 6461 elif(arg == '-dev'): 6866 sysvals.usedevsrc = T 6462 sysvals.usedevsrc = True 6867 elif(arg == '-sync'): 6463 elif(arg == '-sync'): 6868 sysvals.sync = True 6464 sysvals.sync = True 6869 elif(arg == '-wifi'): << 6870 sysvals.wifi = True << 6871 elif(arg == '-wifitrace'): << 6872 sysvals.wifitrace = T << 6873 elif(arg == '-netfix'): << 6874 sysvals.netfix = True << 6875 elif(arg == '-gzip'): 6465 elif(arg == '-gzip'): 6876 sysvals.gzip = True 6466 sysvals.gzip = True 6877 elif(arg == '-info'): << 6878 try: << 6879 val = next(ar << 6880 except: << 6881 doError('-inf << 6882 elif(arg == '-desc'): << 6883 try: << 6884 val = next(ar << 6885 except: << 6886 doError('-des << 6887 elif(arg == '-rs'): 6467 elif(arg == '-rs'): 6888 try: 6468 try: 6889 val = next(ar 6469 val = next(args) 6890 except: 6470 except: 6891 doError('-rs 6471 doError('-rs requires "enable" or "disable"', True) 6892 if val.lower() in swi 6472 if val.lower() in switchvalues: 6893 if val.lower( 6473 if val.lower() in switchoff: 6894 sysva 6474 sysvals.rs = -1 6895 else: 6475 else: 6896 sysva 6476 sysvals.rs = 1 6897 else: 6477 else: 6898 doError('inva 6478 doError('invalid option: %s, use "enable/disable" or "on/off"' % val, True) 6899 elif(arg == '-display'): 6479 elif(arg == '-display'): 6900 try: 6480 try: 6901 val = next(ar 6481 val = next(args) 6902 except: 6482 except: 6903 doError('-dis 6483 doError('-display requires an mode value', True) 6904 disopt = ['on', 'off' 6484 disopt = ['on', 'off', 'standby', 'suspend'] 6905 if val.lower() not in 6485 if val.lower() not in disopt: 6906 doError('vali 6486 doError('valid display mode values are %s' % disopt, True) 6907 sysvals.display = val 6487 sysvals.display = val.lower() 6908 elif(arg == '-maxdepth'): 6488 elif(arg == '-maxdepth'): 6909 sysvals.max_graph_dep 6489 sysvals.max_graph_depth = getArgInt('-maxdepth', args, 0, 1000) 6910 elif(arg == '-rtcwake'): 6490 elif(arg == '-rtcwake'): 6911 try: 6491 try: 6912 val = next(ar 6492 val = next(args) 6913 except: 6493 except: 6914 doError('No r 6494 doError('No rtcwake time supplied', True) 6915 if val.lower() in swi 6495 if val.lower() in switchoff: 6916 sysvals.rtcwa 6496 sysvals.rtcwake = False 6917 else: 6497 else: 6918 sysvals.rtcwa 6498 sysvals.rtcwake = True 6919 sysvals.rtcwa 6499 sysvals.rtcwaketime = getArgInt('-rtcwake', val, 0, 3600, False) 6920 elif(arg == '-timeprec'): 6500 elif(arg == '-timeprec'): 6921 sysvals.setPrecision( 6501 sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6)) 6922 elif(arg == '-mindev'): 6502 elif(arg == '-mindev'): 6923 sysvals.mindevlen = g 6503 sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0) 6924 elif(arg == '-mincg'): 6504 elif(arg == '-mincg'): 6925 sysvals.mincglen = ge 6505 sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0) 6926 elif(arg == '-bufsize'): 6506 elif(arg == '-bufsize'): 6927 sysvals.bufsize = get 6507 sysvals.bufsize = getArgInt('-bufsize', args, 1, 1024*1024*8) 6928 elif(arg == '-cgtest'): 6508 elif(arg == '-cgtest'): 6929 sysvals.cgtest = getA 6509 sysvals.cgtest = getArgInt('-cgtest', args, 0, 1) 6930 elif(arg == '-cgphase'): 6510 elif(arg == '-cgphase'): 6931 try: 6511 try: 6932 val = next(ar 6512 val = next(args) 6933 except: 6513 except: 6934 doError('No p 6514 doError('No phase name supplied', True) 6935 d = Data(0) 6515 d = Data(0) 6936 if val not in d.phase 6516 if val not in d.phasedef: 6937 doError('inva 6517 doError('invalid phase --> (%s: %s), valid phases are %s'\ 6938 % (ar 6518 % (arg, val, d.phasedef.keys()), True) 6939 sysvals.cgphase = val 6519 sysvals.cgphase = val 6940 elif(arg == '-cgfilter'): 6520 elif(arg == '-cgfilter'): 6941 try: 6521 try: 6942 val = next(ar 6522 val = next(args) 6943 except: 6523 except: 6944 doError('No c 6524 doError('No callgraph functions supplied', True) 6945 sysvals.setCallgraphF 6525 sysvals.setCallgraphFilter(val) 6946 elif(arg == '-skipkprobe'): 6526 elif(arg == '-skipkprobe'): 6947 try: 6527 try: 6948 val = next(ar 6528 val = next(args) 6949 except: 6529 except: 6950 doError('No k 6530 doError('No kprobe functions supplied', True) 6951 sysvals.skipKprobes(v 6531 sysvals.skipKprobes(val) 6952 elif(arg == '-cgskip'): 6532 elif(arg == '-cgskip'): 6953 try: 6533 try: 6954 val = next(ar 6534 val = next(args) 6955 except: 6535 except: 6956 doError('No f 6536 doError('No file supplied', True) 6957 if val.lower() in swi 6537 if val.lower() in switchoff: 6958 sysvals.cgski 6538 sysvals.cgskip = '' 6959 else: 6539 else: 6960 sysvals.cgski 6540 sysvals.cgskip = sysvals.configFile(val) 6961 if(not sysval 6541 if(not sysvals.cgskip): 6962 doErr 6542 doError('%s does not exist' % sysvals.cgskip) 6963 elif(arg == '-callloop-maxgap 6543 elif(arg == '-callloop-maxgap'): 6964 sysvals.callloopmaxga 6544 sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', args, 0.0, 1.0) 6965 elif(arg == '-callloop-maxlen 6545 elif(arg == '-callloop-maxlen'): 6966 sysvals.callloopmaxle 6546 sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0) 6967 elif(arg == '-cmd'): 6547 elif(arg == '-cmd'): 6968 try: 6548 try: 6969 val = next(ar 6549 val = next(args) 6970 except: 6550 except: 6971 doError('No c 6551 doError('No command string supplied', True) 6972 sysvals.testcommand = 6552 sysvals.testcommand = val 6973 sysvals.suspendmode = 6553 sysvals.suspendmode = 'command' 6974 elif(arg == '-expandcg'): 6554 elif(arg == '-expandcg'): 6975 sysvals.cgexp = True 6555 sysvals.cgexp = True 6976 elif(arg == '-srgap'): 6556 elif(arg == '-srgap'): 6977 sysvals.srgap = 5 6557 sysvals.srgap = 5 6978 elif(arg == '-maxfail'): << 6979 sysvals.maxfail = get << 6980 elif(arg == '-multi'): 6558 elif(arg == '-multi'): 6981 try: !! 6559 sysvals.multitest['run'] = True 6982 c, d = next(a !! 6560 sysvals.multitest['count'] = getArgInt('-multi n d (exec count)', args, 2, 1000000) 6983 except: !! 6561 sysvals.multitest['delay'] = getArgInt('-multi n d (delay between tests)', args, 0, 3600) 6984 doError('-mul << 6985 sysvals.multiinit(c, << 6986 elif(arg == '-o'): 6562 elif(arg == '-o'): 6987 try: 6563 try: 6988 val = next(ar 6564 val = next(args) 6989 except: 6565 except: 6990 doError('No s 6566 doError('No subdirectory name supplied', True) 6991 sysvals.outdir = sysv 6567 sysvals.outdir = sysvals.setOutputFolder(val) 6992 elif(arg == '-config'): 6568 elif(arg == '-config'): 6993 try: 6569 try: 6994 val = next(ar 6570 val = next(args) 6995 except: 6571 except: 6996 doError('No t 6572 doError('No text file supplied', True) 6997 file = sysvals.config 6573 file = sysvals.configFile(val) 6998 if(not file): 6574 if(not file): 6999 doError('%s d 6575 doError('%s does not exist' % val) 7000 configFromFile(file) 6576 configFromFile(file) 7001 elif(arg == '-fadd'): 6577 elif(arg == '-fadd'): 7002 try: 6578 try: 7003 val = next(ar 6579 val = next(args) 7004 except: 6580 except: 7005 doError('No t 6581 doError('No text file supplied', True) 7006 file = sysvals.config 6582 file = sysvals.configFile(val) 7007 if(not file): 6583 if(not file): 7008 doError('%s d 6584 doError('%s does not exist' % val) 7009 sysvals.addFtraceFilt 6585 sysvals.addFtraceFilterFunctions(file) 7010 elif(arg == '-dmesg'): 6586 elif(arg == '-dmesg'): 7011 try: 6587 try: 7012 val = next(ar 6588 val = next(args) 7013 except: 6589 except: 7014 doError('No d 6590 doError('No dmesg file supplied', True) 7015 sysvals.notestrun = T 6591 sysvals.notestrun = True 7016 sysvals.dmesgfile = v 6592 sysvals.dmesgfile = val 7017 if(os.path.exists(sys 6593 if(os.path.exists(sysvals.dmesgfile) == False): 7018 doError('%s d 6594 doError('%s does not exist' % sysvals.dmesgfile) 7019 elif(arg == '-ftrace'): 6595 elif(arg == '-ftrace'): 7020 try: 6596 try: 7021 val = next(ar 6597 val = next(args) 7022 except: 6598 except: 7023 doError('No f 6599 doError('No ftrace file supplied', True) 7024 sysvals.notestrun = T 6600 sysvals.notestrun = True 7025 sysvals.ftracefile = 6601 sysvals.ftracefile = val 7026 if(os.path.exists(sys 6602 if(os.path.exists(sysvals.ftracefile) == False): 7027 doError('%s d 6603 doError('%s does not exist' % sysvals.ftracefile) 7028 elif(arg == '-summary'): 6604 elif(arg == '-summary'): 7029 try: 6605 try: 7030 val = next(ar 6606 val = next(args) 7031 except: 6607 except: 7032 doError('No d 6608 doError('No directory supplied', True) 7033 cmd = 'summary' 6609 cmd = 'summary' 7034 sysvals.outdir = val 6610 sysvals.outdir = val 7035 sysvals.notestrun = T 6611 sysvals.notestrun = True 7036 if(os.path.isdir(val) 6612 if(os.path.isdir(val) == False): 7037 doError('%s i 6613 doError('%s is not accesible' % val) 7038 elif(arg == '-filter'): 6614 elif(arg == '-filter'): 7039 try: 6615 try: 7040 val = next(ar 6616 val = next(args) 7041 except: 6617 except: 7042 doError('No d 6618 doError('No devnames supplied', True) 7043 sysvals.setDeviceFilt 6619 sysvals.setDeviceFilter(val) 7044 elif(arg == '-result'): 6620 elif(arg == '-result'): 7045 try: 6621 try: 7046 val = next(ar 6622 val = next(args) 7047 except: 6623 except: 7048 doError('No r 6624 doError('No result file supplied', True) 7049 sysvals.result = val 6625 sysvals.result = val 7050 sysvals.signalHandler 6626 sysvals.signalHandlerInit() 7051 else: 6627 else: 7052 doError('Invalid argu 6628 doError('Invalid argument: '+arg, True) 7053 6629 7054 # compatibility errors 6630 # compatibility errors 7055 if(sysvals.usecallgraph and sysvals.u 6631 if(sysvals.usecallgraph and sysvals.usedevsrc): 7056 doError('-dev is not compatib 6632 doError('-dev is not compatible with -f') 7057 if(sysvals.usecallgraph and sysvals.u 6633 if(sysvals.usecallgraph and sysvals.useprocmon): 7058 doError('-proc is not compati 6634 doError('-proc is not compatible with -f') 7059 6635 7060 if sysvals.usecallgraph and sysvals.c 6636 if sysvals.usecallgraph and sysvals.cgskip: 7061 sysvals.vprint('Using cgskip 6637 sysvals.vprint('Using cgskip file: %s' % sysvals.cgskip) 7062 sysvals.setCallgraphBlacklist 6638 sysvals.setCallgraphBlacklist(sysvals.cgskip) 7063 6639 7064 # callgraph size cannot exceed device 6640 # callgraph size cannot exceed device size 7065 if sysvals.mincglen < sysvals.mindevl 6641 if sysvals.mincglen < sysvals.mindevlen: 7066 sysvals.mincglen = sysvals.mi 6642 sysvals.mincglen = sysvals.mindevlen 7067 6643 7068 # remove existing buffers before calc 6644 # remove existing buffers before calculating memory 7069 if(sysvals.usecallgraph or sysvals.us 6645 if(sysvals.usecallgraph or sysvals.usedevsrc): 7070 sysvals.fsetVal('16', 'buffer 6646 sysvals.fsetVal('16', 'buffer_size_kb') 7071 sysvals.cpuInfo() 6647 sysvals.cpuInfo() 7072 6648 7073 # just run a utility command and exit 6649 # just run a utility command and exit 7074 if(cmd != ''): 6650 if(cmd != ''): 7075 ret = 0 6651 ret = 0 7076 if(cmd == 'status'): 6652 if(cmd == 'status'): 7077 if not statusCheck(Tr 6653 if not statusCheck(True): 7078 ret = 1 6654 ret = 1 7079 elif(cmd == 'fpdt'): 6655 elif(cmd == 'fpdt'): 7080 if not getFPDT(True): 6656 if not getFPDT(True): 7081 ret = 1 6657 ret = 1 >> 6658 elif(cmd == 'battery'): >> 6659 out = getBattery() >> 6660 if out: >> 6661 pprint('AC Connect : %s\nBattery Charge: %d' % out) >> 6662 else: >> 6663 pprint('no battery found') >> 6664 ret = 1 7082 elif(cmd == 'sysinfo'): 6665 elif(cmd == 'sysinfo'): 7083 sysvals.printSystemIn 6666 sysvals.printSystemInfo(True) 7084 elif(cmd == 'devinfo'): 6667 elif(cmd == 'devinfo'): 7085 deviceInfo() 6668 deviceInfo() 7086 elif(cmd == 'modes'): 6669 elif(cmd == 'modes'): 7087 pprint(getModes()) 6670 pprint(getModes()) 7088 elif(cmd == 'flist'): 6671 elif(cmd == 'flist'): 7089 sysvals.getFtraceFilt 6672 sysvals.getFtraceFilterFunctions(True) 7090 elif(cmd == 'flistall'): 6673 elif(cmd == 'flistall'): 7091 sysvals.getFtraceFilt 6674 sysvals.getFtraceFilterFunctions(False) 7092 elif(cmd == 'summary'): 6675 elif(cmd == 'summary'): 7093 runSummary(sysvals.ou 6676 runSummary(sysvals.outdir, True, genhtml) 7094 elif(cmd in ['xon', 'xoff', ' 6677 elif(cmd in ['xon', 'xoff', 'xstandby', 'xsuspend', 'xinit', 'xreset']): 7095 sysvals.verbose = Tru 6678 sysvals.verbose = True 7096 ret = sysvals.display !! 6679 ret = displayControl(cmd[1:]) 7097 elif(cmd == 'xstat'): 6680 elif(cmd == 'xstat'): 7098 pprint('Display Statu !! 6681 pprint('Display Status: %s' % displayControl('stat').upper()) 7099 elif(cmd == 'wificheck'): !! 6682 elif(cmd == 'wifi'): 7100 dev = sysvals.checkWi !! 6683 out = sysvals.checkWifi() 7101 if dev: !! 6684 if 'device' not in out: 7102 print('%s is !! 6685 pprint('WIFI interface not found') 7103 else: 6686 else: 7104 print('No wif !! 6687 for key in sorted(out): 7105 elif(cmd == 'cmdinfo'): !! 6688 pprint('%6s: %s' % (key.upper(), out[key])) 7106 for out in sysvals.cm << 7107 print('[%s - << 7108 sys.exit(ret) 6689 sys.exit(ret) 7109 6690 7110 # if instructed, re-analyze existing 6691 # if instructed, re-analyze existing data files 7111 if(sysvals.notestrun): 6692 if(sysvals.notestrun): 7112 stamp = rerunTest(sysvals.out 6693 stamp = rerunTest(sysvals.outdir) 7113 sysvals.outputResult(stamp) 6694 sysvals.outputResult(stamp) 7114 sys.exit(0) 6695 sys.exit(0) 7115 6696 7116 # verify that we can run a test 6697 # verify that we can run a test 7117 error = statusCheck() 6698 error = statusCheck() 7118 if(error): 6699 if(error): 7119 doError(error) 6700 doError(error) 7120 6701 7121 # extract mem/disk extra modes and co 6702 # extract mem/disk extra modes and convert 7122 mode = sysvals.suspendmode 6703 mode = sysvals.suspendmode 7123 if mode.startswith('mem'): 6704 if mode.startswith('mem'): 7124 memmode = mode.split('-', 1)[ 6705 memmode = mode.split('-', 1)[-1] if '-' in mode else 'deep' 7125 if memmode == 'shallow': 6706 if memmode == 'shallow': 7126 mode = 'standby' 6707 mode = 'standby' 7127 elif memmode == 's2idle': 6708 elif memmode == 's2idle': 7128 mode = 'freeze' 6709 mode = 'freeze' 7129 else: 6710 else: 7130 mode = 'mem' 6711 mode = 'mem' 7131 sysvals.memmode = memmode 6712 sysvals.memmode = memmode 7132 sysvals.suspendmode = mode 6713 sysvals.suspendmode = mode 7133 if mode.startswith('disk-'): 6714 if mode.startswith('disk-'): 7134 sysvals.diskmode = mode.split 6715 sysvals.diskmode = mode.split('-', 1)[-1] 7135 sysvals.suspendmode = 'disk' 6716 sysvals.suspendmode = 'disk' >> 6717 7136 sysvals.systemInfo(dmidecode(sysvals. 6718 sysvals.systemInfo(dmidecode(sysvals.mempath)) 7137 6719 7138 failcnt, ret = 0, 0 !! 6720 setRuntimeSuspend(True) >> 6721 if sysvals.display: >> 6722 displayControl('init') >> 6723 ret = 0 7139 if sysvals.multitest['run']: 6724 if sysvals.multitest['run']: 7140 # run multiple tests in a sep 6725 # run multiple tests in a separate subdirectory 7141 if not sysvals.outdir: 6726 if not sysvals.outdir: 7142 if 'time' in sysvals. !! 6727 s = 'suspend-x%d' % sysvals.multitest['count'] 7143 s = '-%dm' % !! 6728 sysvals.outdir = datetime.now().strftime(s+'-%y%m%d-%H%M%S') 7144 else: << 7145 s = '-x%d' % << 7146 sysvals.outdir = date << 7147 if not os.path.isdir(sysvals. 6729 if not os.path.isdir(sysvals.outdir): 7148 os.makedirs(sysvals.o 6730 os.makedirs(sysvals.outdir) 7149 sysvals.sudoUserchown(sysvals << 7150 finish = datetime.now() << 7151 if 'time' in sysvals.multites << 7152 finish += timedelta(m << 7153 for i in range(sysvals.multit 6731 for i in range(sysvals.multitest['count']): 7154 sysvals.multistat(Tru !! 6732 if(i != 0): 7155 if i != 0 and sysvals << 7156 pprint('Waiti 6733 pprint('Waiting %d seconds...' % (sysvals.multitest['delay'])) 7157 time.sleep(sy 6734 time.sleep(sysvals.multitest['delay']) >> 6735 pprint('TEST (%d/%d) START' % (i+1, sysvals.multitest['count'])) 7158 fmt = 'suspend-%y%m%d 6736 fmt = 'suspend-%y%m%d-%H%M%S' 7159 sysvals.testdir = os. 6737 sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt)) 7160 ret = runTest(i+1, no !! 6738 ret = runTest(i+1) 7161 failcnt = 0 if not re !! 6739 pprint('TEST (%d/%d) COMPLETE' % (i+1, sysvals.multitest['count'])) 7162 if sysvals.maxfail > !! 6740 sysvals.logmsg = '' 7163 pprint('Maxim << 7164 break << 7165 sysvals.resetlog() << 7166 sysvals.multistat(Fal << 7167 if 'time' in sysvals. << 7168 break << 7169 if not sysvals.skiphtml: 6741 if not sysvals.skiphtml: 7170 runSummary(sysvals.ou 6742 runSummary(sysvals.outdir, False, False) 7171 sysvals.sudoUserchown(sysvals 6743 sysvals.sudoUserchown(sysvals.outdir) 7172 else: 6744 else: 7173 if sysvals.outdir: 6745 if sysvals.outdir: 7174 sysvals.testdir = sys 6746 sysvals.testdir = sysvals.outdir 7175 # run the test in the current 6747 # run the test in the current directory 7176 ret = runTest() 6748 ret = runTest() 7177 << 7178 # reset to default values after testi << 7179 if sysvals.display: 6749 if sysvals.display: 7180 sysvals.displayControl('reset !! 6750 displayControl('reset') 7181 if sysvals.rs != 0: !! 6751 setRuntimeSuspend(False) 7182 sysvals.setRuntimeSuspend(Fal << 7183 sys.exit(ret) 6752 sys.exit(ret)
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.