1 #!/usr/bin/env python3 1 #!/usr/bin/env python3 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, timedelta 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.7' 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 90 wifi = False 96 netfix = False << 97 verbose = False 91 verbose = False 98 testlog = True 92 testlog = True 99 dmesglog = True 93 dmesglog = True 100 ftracelog = False 94 ftracelog = False 101 acpidebug = True << 102 tstat = True 95 tstat = True 103 wifitrace = False !! 96 mindevlen = 0.0 104 mindevlen = 0.0001 << 105 mincglen = 0.0 97 mincglen = 0.0 106 cgphase = '' 98 cgphase = '' 107 cgtest = -1 99 cgtest = -1 108 cgskip = '' 100 cgskip = '' 109 maxfail = 0 101 maxfail = 0 110 multitest = {'run': False, 'count': 10 102 multitest = {'run': False, 'count': 1000000, 'delay': 0} 111 max_graph_depth = 0 103 max_graph_depth = 0 112 callloopmaxgap = 0.0001 104 callloopmaxgap = 0.0001 113 callloopmaxlen = 0.005 105 callloopmaxlen = 0.005 114 bufsize = 0 106 bufsize = 0 115 cpucount = 0 107 cpucount = 0 116 memtotal = 204800 108 memtotal = 204800 117 memfree = 204800 109 memfree = 204800 118 osversion = '' << 119 srgap = 0 110 srgap = 0 120 cgexp = False 111 cgexp = False 121 testdir = '' 112 testdir = '' 122 outdir = '' 113 outdir = '' 123 tpath = '/sys/kernel/tracing/' !! 114 tpath = '/sys/kernel/debug/tracing/' 124 fpdtpath = '/sys/firmware/acpi/tables/ 115 fpdtpath = '/sys/firmware/acpi/tables/FPDT' 125 epath = '/sys/kernel/tracing/events/po !! 116 epath = '/sys/kernel/debug/tracing/events/power/' 126 pmdpath = '/sys/power/pm_debug_message 117 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 = [ 118 traceevents = [ 131 'suspend_resume', 119 'suspend_resume', 132 'wakeup_source_activate', 120 'wakeup_source_activate', 133 'wakeup_source_deactivate', 121 'wakeup_source_deactivate', 134 'device_pm_callback_end', 122 'device_pm_callback_end', 135 'device_pm_callback_start' 123 'device_pm_callback_start' 136 ] 124 ] 137 logmsg = '' 125 logmsg = '' 138 testcommand = '' 126 testcommand = '' 139 mempath = '/dev/mem' 127 mempath = '/dev/mem' 140 powerfile = '/sys/power/state' 128 powerfile = '/sys/power/state' 141 mempowerfile = '/sys/power/mem_sleep' 129 mempowerfile = '/sys/power/mem_sleep' 142 diskpowerfile = '/sys/power/disk' 130 diskpowerfile = '/sys/power/disk' 143 suspendmode = 'mem' 131 suspendmode = 'mem' 144 memmode = '' 132 memmode = '' 145 diskmode = '' 133 diskmode = '' 146 hostname = 'localhost' 134 hostname = 'localhost' 147 prefix = 'test' 135 prefix = 'test' 148 teststamp = '' 136 teststamp = '' 149 sysstamp = '' 137 sysstamp = '' 150 dmesgstart = 0.0 138 dmesgstart = 0.0 151 dmesgfile = '' 139 dmesgfile = '' 152 ftracefile = '' 140 ftracefile = '' 153 htmlfile = 'output.html' 141 htmlfile = 'output.html' 154 result = '' 142 result = '' 155 rtcwake = True 143 rtcwake = True 156 rtcwaketime = 15 144 rtcwaketime = 15 157 rtcpath = '' 145 rtcpath = '' 158 devicefilter = [] 146 devicefilter = [] 159 cgfilter = [] 147 cgfilter = [] 160 stamp = 0 148 stamp = 0 161 execcount = 1 149 execcount = 1 162 x2delay = 0 150 x2delay = 0 163 skiphtml = False 151 skiphtml = False 164 usecallgraph = False 152 usecallgraph = False 165 ftopfunc = 'pm_suspend' 153 ftopfunc = 'pm_suspend' 166 ftop = False 154 ftop = False 167 usetraceevents = False 155 usetraceevents = False 168 usetracemarkers = True 156 usetracemarkers = True 169 useftrace = True << 170 usekprobes = True 157 usekprobes = True 171 usedevsrc = False 158 usedevsrc = False 172 useprocmon = False 159 useprocmon = False 173 notestrun = False 160 notestrun = False 174 cgdump = False 161 cgdump = False 175 devdump = False 162 devdump = False 176 mixedphaseheight = True 163 mixedphaseheight = True 177 devprops = dict() 164 devprops = dict() 178 cfgdef = dict() << 179 platinfo = [] 165 platinfo = [] 180 predelay = 0 166 predelay = 0 181 postdelay = 0 167 postdelay = 0 >> 168 pmdebug = '' 182 tmstart = 'SUSPEND START %Y%m%d-%H:%M: 169 tmstart = 'SUSPEND START %Y%m%d-%H:%M:%S.%f' 183 tmend = 'RESUME COMPLETE %Y%m%d-%H:%M: 170 tmend = 'RESUME COMPLETE %Y%m%d-%H:%M:%S.%f' 184 tracefuncs = { 171 tracefuncs = { 185 'async_synchronize_full': {}, << 186 'sys_sync': {}, 172 'sys_sync': {}, 187 'ksys_sync': {}, 173 'ksys_sync': {}, 188 '__pm_notifier_call_chain': {} !! 174 'pm_notifier_call_chain_robust': {}, 189 'pm_prepare_console': {}, 175 'pm_prepare_console': {}, 190 'pm_notifier_call_chain': {}, 176 'pm_notifier_call_chain': {}, 191 'freeze_processes': {}, 177 'freeze_processes': {}, 192 'freeze_kernel_threads': {}, 178 'freeze_kernel_threads': {}, 193 'pm_restrict_gfp_mask': {}, 179 'pm_restrict_gfp_mask': {}, 194 'acpi_suspend_begin': {}, 180 'acpi_suspend_begin': {}, 195 'acpi_hibernation_begin': {}, 181 'acpi_hibernation_begin': {}, 196 'acpi_hibernation_enter': {}, 182 'acpi_hibernation_enter': {}, 197 'acpi_hibernation_leave': {}, 183 'acpi_hibernation_leave': {}, 198 'acpi_pm_freeze': {}, 184 'acpi_pm_freeze': {}, 199 'acpi_pm_thaw': {}, 185 'acpi_pm_thaw': {}, 200 'acpi_s2idle_end': {}, 186 'acpi_s2idle_end': {}, 201 'acpi_s2idle_sync': {}, 187 'acpi_s2idle_sync': {}, 202 'acpi_s2idle_begin': {}, 188 'acpi_s2idle_begin': {}, 203 'acpi_s2idle_prepare': {}, 189 'acpi_s2idle_prepare': {}, 204 'acpi_s2idle_prepare_late': {} 190 'acpi_s2idle_prepare_late': {}, 205 'acpi_s2idle_wake': {}, 191 'acpi_s2idle_wake': {}, 206 'acpi_s2idle_wakeup': {}, 192 'acpi_s2idle_wakeup': {}, 207 'acpi_s2idle_restore': {}, 193 'acpi_s2idle_restore': {}, 208 'acpi_s2idle_restore_early': { 194 'acpi_s2idle_restore_early': {}, 209 'hibernate_preallocate_memory' 195 'hibernate_preallocate_memory': {}, 210 'create_basic_memory_bitmaps': 196 'create_basic_memory_bitmaps': {}, 211 'swsusp_write': {}, 197 'swsusp_write': {}, 212 'suspend_console': {}, 198 'suspend_console': {}, 213 'acpi_pm_prepare': {}, 199 'acpi_pm_prepare': {}, 214 'syscore_suspend': {}, 200 'syscore_suspend': {}, 215 'arch_enable_nonboot_cpus_end' 201 'arch_enable_nonboot_cpus_end': {}, 216 'syscore_resume': {}, 202 'syscore_resume': {}, 217 'acpi_pm_finish': {}, 203 'acpi_pm_finish': {}, 218 'resume_console': {}, 204 'resume_console': {}, 219 'acpi_pm_end': {}, 205 'acpi_pm_end': {}, 220 'pm_restore_gfp_mask': {}, 206 'pm_restore_gfp_mask': {}, 221 'thaw_processes': {}, 207 'thaw_processes': {}, 222 'pm_restore_console': {}, 208 'pm_restore_console': {}, 223 'CPU_OFF': { 209 'CPU_OFF': { 224 'func':'_cpu_down', 210 'func':'_cpu_down', 225 'args_x86_64': {'cpu': 211 'args_x86_64': {'cpu':'%di:s32'}, 226 'format': 'CPU_OFF[{cp 212 'format': 'CPU_OFF[{cpu}]' 227 }, 213 }, 228 'CPU_ON': { 214 'CPU_ON': { 229 'func':'_cpu_up', 215 'func':'_cpu_up', 230 'args_x86_64': {'cpu': 216 'args_x86_64': {'cpu':'%di:s32'}, 231 'format': 'CPU_ON[{cpu 217 'format': 'CPU_ON[{cpu}]' 232 }, 218 }, 233 } 219 } 234 dev_tracefuncs = { 220 dev_tracefuncs = { 235 # general wait/delay/sleep 221 # general wait/delay/sleep 236 'msleep': { 'args_x86_64': {'t 222 'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 }, 237 'schedule_timeout': { 'args_x8 223 'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 }, 238 'udelay': { 'func':'__const_ud 224 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 }, 239 'usleep_range': { 'args_x86_64 225 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 }, 240 'mutex_lock_slowpath': { 'func 226 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 }, 241 'acpi_os_stall': {'ub': 1}, 227 'acpi_os_stall': {'ub': 1}, 242 'rt_mutex_slowlock': {'ub': 1} 228 'rt_mutex_slowlock': {'ub': 1}, 243 # ACPI 229 # ACPI 244 'acpi_resume_power_resources': 230 'acpi_resume_power_resources': {}, 245 'acpi_ps_execute_method': { 'a 231 'acpi_ps_execute_method': { 'args_x86_64': { 246 'fullpath':'+0(+40(%di 232 'fullpath':'+0(+40(%di)):string', 247 }}, 233 }}, 248 # mei_me 234 # mei_me 249 'mei_reset': {}, 235 'mei_reset': {}, 250 # filesystem 236 # filesystem 251 'ext4_sync_fs': {}, 237 'ext4_sync_fs': {}, 252 # 80211 238 # 80211 253 'ath10k_bmi_read_memory': { 'a 239 'ath10k_bmi_read_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 254 'ath10k_bmi_write_memory': { ' 240 'ath10k_bmi_write_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 255 'ath10k_bmi_fast_download': { 241 'ath10k_bmi_fast_download': { 'args_x86_64': {'length':'%cx:s32'} }, 256 'iwlagn_mac_start': {}, 242 'iwlagn_mac_start': {}, 257 'iwlagn_alloc_bcast_station': 243 'iwlagn_alloc_bcast_station': {}, 258 'iwl_trans_pcie_start_hw': {}, 244 'iwl_trans_pcie_start_hw': {}, 259 'iwl_trans_pcie_start_fw': {}, 245 'iwl_trans_pcie_start_fw': {}, 260 'iwl_run_init_ucode': {}, 246 'iwl_run_init_ucode': {}, 261 'iwl_load_ucode_wait_alive': { 247 'iwl_load_ucode_wait_alive': {}, 262 'iwl_alive_start': {}, 248 'iwl_alive_start': {}, 263 'iwlagn_mac_stop': {}, 249 'iwlagn_mac_stop': {}, 264 'iwlagn_mac_suspend': {}, 250 'iwlagn_mac_suspend': {}, 265 'iwlagn_mac_resume': {}, 251 'iwlagn_mac_resume': {}, 266 'iwlagn_mac_add_interface': {} 252 'iwlagn_mac_add_interface': {}, 267 'iwlagn_mac_remove_interface': 253 'iwlagn_mac_remove_interface': {}, 268 'iwlagn_mac_change_interface': 254 'iwlagn_mac_change_interface': {}, 269 'iwlagn_mac_config': {}, 255 'iwlagn_mac_config': {}, 270 'iwlagn_configure_filter': {}, 256 'iwlagn_configure_filter': {}, 271 'iwlagn_mac_hw_scan': {}, 257 'iwlagn_mac_hw_scan': {}, 272 'iwlagn_bss_info_changed': {}, 258 'iwlagn_bss_info_changed': {}, 273 'iwlagn_mac_channel_switch': { 259 'iwlagn_mac_channel_switch': {}, 274 'iwlagn_mac_flush': {}, 260 'iwlagn_mac_flush': {}, 275 # ATA 261 # ATA 276 'ata_eh_recover': { 'args_x86_ 262 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} }, 277 # i915 263 # i915 278 'i915_gem_resume': {}, 264 'i915_gem_resume': {}, 279 'i915_restore_state': {}, 265 'i915_restore_state': {}, 280 'intel_opregion_setup': {}, 266 'intel_opregion_setup': {}, 281 'g4x_pre_enable_dp': {}, 267 'g4x_pre_enable_dp': {}, 282 'vlv_pre_enable_dp': {}, 268 'vlv_pre_enable_dp': {}, 283 'chv_pre_enable_dp': {}, 269 'chv_pre_enable_dp': {}, 284 'g4x_enable_dp': {}, 270 'g4x_enable_dp': {}, 285 'vlv_enable_dp': {}, 271 'vlv_enable_dp': {}, 286 'intel_hpd_init': {}, 272 'intel_hpd_init': {}, 287 'intel_opregion_register': {}, 273 'intel_opregion_register': {}, 288 'intel_dp_detect': {}, 274 'intel_dp_detect': {}, 289 'intel_hdmi_detect': {}, 275 'intel_hdmi_detect': {}, 290 'intel_opregion_init': {}, 276 'intel_opregion_init': {}, 291 'intel_fbdev_set_suspend': {}, 277 'intel_fbdev_set_suspend': {}, 292 } 278 } 293 infocmds = [ 279 infocmds = [ 294 [0, 'sysinfo', 'uname', '-a'], << 295 [0, 'cpuinfo', 'head', '-7', ' << 296 [0, 'kparams', 'cat', '/proc/c 280 [0, 'kparams', 'cat', '/proc/cmdline'], 297 [0, 'mcelog', 'mcelog'], 281 [0, 'mcelog', 'mcelog'], 298 [0, 'pcidevices', 'lspci', '-t 282 [0, 'pcidevices', 'lspci', '-tv'], 299 [0, 'usbdevices', 'lsusb', '-t !! 283 [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 284 [1, 'interrupts', 'cat', '/proc/interrupts'], 306 [1, 'wakeups', 'cat', '/sys/ke 285 [1, 'wakeups', 'cat', '/sys/kernel/debug/wakeup_sources'], 307 [2, 'gpecounts', 'sh', '-c', ' 286 [2, 'gpecounts', 'sh', '-c', 'grep -v invalid /sys/firmware/acpi/interrupts/*'], 308 [2, 'suspendstats', 'sh', '-c' 287 [2, 'suspendstats', 'sh', '-c', 'grep -v invalid /sys/power/suspend_stats/*'], 309 [2, 'cpuidle', 'sh', '-c', 'gr 288 [2, 'cpuidle', 'sh', '-c', 'grep -v invalid /sys/devices/system/cpu/cpu*/cpuidle/state*/s2idle/*'], 310 [2, 'battery', 'sh', '-c', 'gr 289 [2, 'battery', 'sh', '-c', 'grep -v invalid /sys/class/power_supply/*/*'], 311 [2, 'thermal', 'sh', '-c', 'gr << 312 ] 290 ] 313 cgblacklist = [] 291 cgblacklist = [] 314 kprobes = dict() 292 kprobes = dict() 315 timeformat = '%.3f' 293 timeformat = '%.3f' 316 cmdline = '%s %s' % \ 294 cmdline = '%s %s' % \ 317 (os.path.basename(sys. 295 (os.path.basename(sys.argv[0]), ' '.join(sys.argv[1:])) 318 sudouser = '' 296 sudouser = '' 319 def __init__(self): 297 def __init__(self): 320 self.archargs = 'args_'+platfo 298 self.archargs = 'args_'+platform.machine() 321 self.hostname = platform.node( 299 self.hostname = platform.node() 322 if(self.hostname == ''): 300 if(self.hostname == ''): 323 self.hostname = 'local 301 self.hostname = 'localhost' 324 rtc = "rtc0" 302 rtc = "rtc0" 325 if os.path.exists('/dev/rtc'): 303 if os.path.exists('/dev/rtc'): 326 rtc = os.readlink('/de 304 rtc = os.readlink('/dev/rtc') 327 rtc = '/sys/class/rtc/'+rtc 305 rtc = '/sys/class/rtc/'+rtc 328 if os.path.exists(rtc) and os. 306 if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \ 329 os.path.exists(rtc+'/t 307 os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'): 330 self.rtcpath = rtc 308 self.rtcpath = rtc 331 if (hasattr(sys.stdout, 'isatt 309 if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): 332 self.ansi = True 310 self.ansi = True 333 self.testdir = datetime.now(). 311 self.testdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S') 334 if os.getuid() == 0 and 'SUDO_ 312 if os.getuid() == 0 and 'SUDO_USER' in os.environ and \ 335 os.environ['SUDO_USER' 313 os.environ['SUDO_USER']: 336 self.sudouser = os.env 314 self.sudouser = os.environ['SUDO_USER'] 337 def resetlog(self): 315 def resetlog(self): 338 self.logmsg = '' 316 self.logmsg = '' 339 self.platinfo = [] 317 self.platinfo = [] 340 def vprint(self, msg): 318 def vprint(self, msg): 341 self.logmsg += msg+'\n' 319 self.logmsg += msg+'\n' 342 if self.verbose or msg.startsw 320 if self.verbose or msg.startswith('WARNING:'): 343 pprint(msg) 321 pprint(msg) 344 def signalHandler(self, signum, frame) 322 def signalHandler(self, signum, frame): 345 if not self.result: 323 if not self.result: 346 return 324 return 347 signame = self.signames[signum 325 signame = self.signames[signum] if signum in self.signames else 'UNKNOWN' 348 msg = 'Signal %s caused a tool 326 msg = 'Signal %s caused a tool exit, line %d' % (signame, frame.f_lineno) 349 self.outputResult({'error':msg 327 self.outputResult({'error':msg}) 350 sys.exit(3) 328 sys.exit(3) 351 def signalHandlerInit(self): 329 def signalHandlerInit(self): 352 capture = ['BUS', 'SYS', 'XCPU 330 capture = ['BUS', 'SYS', 'XCPU', 'XFSZ', 'PWR', 'HUP', 'INT', 'QUIT', 353 'ILL', 'ABRT', 'FPE', 331 'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM'] 354 self.signames = dict() 332 self.signames = dict() 355 for i in capture: 333 for i in capture: 356 s = 'SIG'+i 334 s = 'SIG'+i 357 try: 335 try: 358 signum = getat 336 signum = getattr(signal, s) 359 signal.signal( 337 signal.signal(signum, self.signalHandler) 360 except: 338 except: 361 continue 339 continue 362 self.signames[signum] 340 self.signames[signum] = s 363 def rootCheck(self, fatal=True): 341 def rootCheck(self, fatal=True): 364 if(os.access(self.powerfile, o 342 if(os.access(self.powerfile, os.W_OK)): 365 return True 343 return True 366 if fatal: 344 if fatal: 367 msg = 'This command re 345 msg = 'This command requires sysfs mount and root access' 368 pprint('ERROR: %s\n' % 346 pprint('ERROR: %s\n' % msg) 369 self.outputResult({'er 347 self.outputResult({'error':msg}) 370 sys.exit(1) 348 sys.exit(1) 371 return False 349 return False 372 def rootUser(self, fatal=False): 350 def rootUser(self, fatal=False): 373 if 'USER' in os.environ and os 351 if 'USER' in os.environ and os.environ['USER'] == 'root': 374 return True 352 return True 375 if fatal: 353 if fatal: 376 msg = 'This command mu 354 msg = 'This command must be run as root' 377 pprint('ERROR: %s\n' % 355 pprint('ERROR: %s\n' % msg) 378 self.outputResult({'er 356 self.outputResult({'error':msg}) 379 sys.exit(1) 357 sys.exit(1) 380 return False 358 return False 381 def usable(self, file, ishtml=False): !! 359 def usable(self, file): 382 if not os.path.exists(file) or !! 360 return (os.path.exists(file) and os.path.getsize(file) > 0) 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): 361 def getExec(self, cmd): 395 try: 362 try: 396 fp = Popen(['which', c 363 fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout 397 out = ascii(fp.read()) 364 out = ascii(fp.read()).strip() 398 fp.close() 365 fp.close() 399 except: 366 except: 400 out = '' 367 out = '' 401 if out: 368 if out: 402 return out 369 return out 403 for path in ['/sbin', '/bin', 370 for path in ['/sbin', '/bin', '/usr/sbin', '/usr/bin', 404 '/usr/local/sbin', '/u 371 '/usr/local/sbin', '/usr/local/bin']: 405 cmdfull = os.path.join 372 cmdfull = os.path.join(path, cmd) 406 if os.path.exists(cmdf 373 if os.path.exists(cmdfull): 407 return cmdfull 374 return cmdfull 408 return out 375 return out 409 def setPrecision(self, num): 376 def setPrecision(self, num): 410 if num < 0 or num > 6: 377 if num < 0 or num > 6: 411 return 378 return 412 self.timeformat = '%.{0}f'.for 379 self.timeformat = '%.{0}f'.format(num) 413 def setOutputFolder(self, value): 380 def setOutputFolder(self, value): 414 args = dict() 381 args = dict() 415 n = datetime.now() 382 n = datetime.now() 416 args['date'] = n.strftime('%y% 383 args['date'] = n.strftime('%y%m%d') 417 args['time'] = n.strftime('%H% 384 args['time'] = n.strftime('%H%M%S') 418 args['hostname'] = args['host' 385 args['hostname'] = args['host'] = self.hostname 419 args['mode'] = self.suspendmod 386 args['mode'] = self.suspendmode 420 return value.format(**args) 387 return value.format(**args) 421 def setOutputFile(self): 388 def setOutputFile(self): 422 if self.dmesgfile != '': 389 if self.dmesgfile != '': 423 m = re.match(r'(?P<nam !! 390 m = re.match('(?P<name>.*)_dmesg\.txt.*', self.dmesgfile) 424 if(m): 391 if(m): 425 self.htmlfile 392 self.htmlfile = m.group('name')+'.html' 426 if self.ftracefile != '': 393 if self.ftracefile != '': 427 m = re.match(r'(?P<nam !! 394 m = re.match('(?P<name>.*)_ftrace\.txt.*', self.ftracefile) 428 if(m): 395 if(m): 429 self.htmlfile 396 self.htmlfile = m.group('name')+'.html' 430 def systemInfo(self, info): 397 def systemInfo(self, info): 431 p = m = '' 398 p = m = '' 432 if 'baseboard-manufacturer' in 399 if 'baseboard-manufacturer' in info: 433 m = info['baseboard-ma 400 m = info['baseboard-manufacturer'] 434 elif 'system-manufacturer' in 401 elif 'system-manufacturer' in info: 435 m = info['system-manuf 402 m = info['system-manufacturer'] 436 if 'system-product-name' in in 403 if 'system-product-name' in info: 437 p = info['system-produ 404 p = info['system-product-name'] 438 elif 'baseboard-product-name' 405 elif 'baseboard-product-name' in info: 439 p = info['baseboard-pr 406 p = info['baseboard-product-name'] 440 if m[:5].lower() == 'intel' an 407 if m[:5].lower() == 'intel' and 'baseboard-product-name' in info: 441 p = info['baseboard-pr 408 p = info['baseboard-product-name'] 442 c = info['processor-version'] 409 c = info['processor-version'] if 'processor-version' in info else '' 443 b = info['bios-version'] if 'b 410 b = info['bios-version'] if 'bios-version' in info else '' 444 r = info['bios-release-date'] 411 r = info['bios-release-date'] if 'bios-release-date' in info else '' 445 self.sysstamp = '# sysinfo | m 412 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 413 (m, p, c, b, r, self.cpucount, self.memtotal, self.memfree) 447 if self.osversion: << 448 self.sysstamp += ' | o << 449 def printSystemInfo(self, fatal=False) 414 def printSystemInfo(self, fatal=False): 450 self.rootCheck(True) 415 self.rootCheck(True) 451 out = dmidecode(self.mempath, 416 out = dmidecode(self.mempath, fatal) 452 if len(out) < 1: 417 if len(out) < 1: 453 return 418 return 454 fmt = '%-24s: %s' 419 fmt = '%-24s: %s' 455 if self.osversion: << 456 print(fmt % ('os-versi << 457 for name in sorted(out): 420 for name in sorted(out): 458 print(fmt % (name, out 421 print(fmt % (name, out[name])) 459 print(fmt % ('cpucount', ('%d' 422 print(fmt % ('cpucount', ('%d' % self.cpucount))) 460 print(fmt % ('memtotal', ('%d 423 print(fmt % ('memtotal', ('%d kB' % self.memtotal))) 461 print(fmt % ('memfree', ('%d k 424 print(fmt % ('memfree', ('%d kB' % self.memfree))) 462 def cpuInfo(self): 425 def cpuInfo(self): 463 self.cpucount = 0 426 self.cpucount = 0 464 if os.path.exists('/proc/cpuin !! 427 fp = open('/proc/cpuinfo', 'r') 465 with open('/proc/cpuin !! 428 for line in fp: 466 for line in fp !! 429 if re.match('^processor[ \t]*:[ \t]*[0-9]*', line): 467 if re. !! 430 self.cpucount += 1 468 !! 431 fp.close() 469 if os.path.exists('/proc/memin !! 432 fp = open('/proc/meminfo', 'r') 470 with open('/proc/memin !! 433 for line in fp: 471 for line in fp !! 434 m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line) 472 m = re !! 435 if m: 473 if m: !! 436 self.memtotal = int(m.group('sz')) 474 !! 437 m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line) 475 m = re !! 438 if m: 476 if m: !! 439 self.memfree = int(m.group('sz')) 477 !! 440 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): 441 def initTestOutput(self, name): 484 self.prefix = self.hostname 442 self.prefix = self.hostname 485 v = open('/proc/version', 'r') 443 v = open('/proc/version', 'r').read().strip() 486 kver = v.split()[2] 444 kver = v.split()[2] 487 fmt = name+'-%m%d%y-%H%M%S' 445 fmt = name+'-%m%d%y-%H%M%S' 488 testtime = datetime.now().strf 446 testtime = datetime.now().strftime(fmt) 489 self.teststamp = \ 447 self.teststamp = \ 490 '# '+testtime+' '+self 448 '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver 491 ext = '' 449 ext = '' 492 if self.gzip: 450 if self.gzip: 493 ext = '.gz' 451 ext = '.gz' 494 self.dmesgfile = \ 452 self.dmesgfile = \ 495 self.testdir+'/'+self. 453 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt'+ext 496 self.ftracefile = \ 454 self.ftracefile = \ 497 self.testdir+'/'+self. 455 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt'+ext 498 self.htmlfile = \ 456 self.htmlfile = \ 499 self.testdir+'/'+self. 457 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' 500 if not os.path.isdir(self.test 458 if not os.path.isdir(self.testdir): 501 os.makedirs(self.testd 459 os.makedirs(self.testdir) 502 self.sudoUserchown(self.testdi 460 self.sudoUserchown(self.testdir) 503 def getValueList(self, value): 461 def getValueList(self, value): 504 out = [] 462 out = [] 505 for i in value.split(','): 463 for i in value.split(','): 506 if i.strip(): 464 if i.strip(): 507 out.append(i.s 465 out.append(i.strip()) 508 return out 466 return out 509 def setDeviceFilter(self, value): 467 def setDeviceFilter(self, value): 510 self.devicefilter = self.getVa 468 self.devicefilter = self.getValueList(value) 511 def setCallgraphFilter(self, value): 469 def setCallgraphFilter(self, value): 512 self.cgfilter = self.getValueL 470 self.cgfilter = self.getValueList(value) 513 def skipKprobes(self, value): 471 def skipKprobes(self, value): 514 for k in self.getValueList(val 472 for k in self.getValueList(value): 515 if k in self.tracefunc 473 if k in self.tracefuncs: 516 del self.trace 474 del self.tracefuncs[k] 517 if k in self.dev_trace 475 if k in self.dev_tracefuncs: 518 del self.dev_t 476 del self.dev_tracefuncs[k] 519 def setCallgraphBlacklist(self, file): 477 def setCallgraphBlacklist(self, file): 520 self.cgblacklist = self.listFr 478 self.cgblacklist = self.listFromFile(file) 521 def rtcWakeAlarmOn(self): 479 def rtcWakeAlarmOn(self): 522 call('echo 0 > '+self.rtcpath+ 480 call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True) 523 nowtime = open(self.rtcpath+'/ 481 nowtime = open(self.rtcpath+'/since_epoch', 'r').read().strip() 524 if nowtime: 482 if nowtime: 525 nowtime = int(nowtime) 483 nowtime = int(nowtime) 526 else: 484 else: 527 # if hardware time fai 485 # if hardware time fails, use the software time 528 nowtime = int(datetime 486 nowtime = int(datetime.now().strftime('%s')) 529 alarm = nowtime + self.rtcwake 487 alarm = nowtime + self.rtcwaketime 530 call('echo %d > %s/wakealarm' 488 call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True) 531 def rtcWakeAlarmOff(self): 489 def rtcWakeAlarmOff(self): 532 call('echo 0 > %s/wakealarm' % 490 call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True) 533 def initdmesg(self): 491 def initdmesg(self): 534 # get the latest time stamp fr 492 # get the latest time stamp from the dmesg log 535 lines = Popen('dmesg', stdout= !! 493 fp = Popen('dmesg', stdout=PIPE).stdout 536 ktime = '0' 494 ktime = '0' 537 for line in reversed(lines): !! 495 for line in fp: 538 line = ascii(line).rep 496 line = ascii(line).replace('\r\n', '') 539 idx = line.find('[') 497 idx = line.find('[') 540 if idx > 1: 498 if idx > 1: 541 line = line[id 499 line = line[idx:] 542 m = re.match(r'[ \t]*( !! 500 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 543 if(m): 501 if(m): 544 ktime = m.grou 502 ktime = m.group('ktime') 545 break !! 503 fp.close() 546 self.dmesgstart = float(ktime) 504 self.dmesgstart = float(ktime) 547 def getdmesg(self, testdata): 505 def getdmesg(self, testdata): 548 op = self.writeDatafileHeader( 506 op = self.writeDatafileHeader(self.dmesgfile, testdata) 549 # store all new dmesg lines si 507 # store all new dmesg lines since initdmesg was called 550 fp = Popen('dmesg', stdout=PIP 508 fp = Popen('dmesg', stdout=PIPE).stdout 551 for line in fp: 509 for line in fp: 552 line = ascii(line).rep 510 line = ascii(line).replace('\r\n', '') 553 idx = line.find('[') 511 idx = line.find('[') 554 if idx > 1: 512 if idx > 1: 555 line = line[id 513 line = line[idx:] 556 m = re.match(r'[ \t]*( !! 514 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 557 if(not m): 515 if(not m): 558 continue 516 continue 559 ktime = float(m.group( 517 ktime = float(m.group('ktime')) 560 if ktime > self.dmesgs 518 if ktime > self.dmesgstart: 561 op.write(line) 519 op.write(line) 562 fp.close() 520 fp.close() 563 op.close() 521 op.close() 564 def listFromFile(self, file): 522 def listFromFile(self, file): 565 list = [] 523 list = [] 566 fp = open(file) 524 fp = open(file) 567 for i in fp.read().split('\n') 525 for i in fp.read().split('\n'): 568 i = i.strip() 526 i = i.strip() 569 if i and i[0] != '#': 527 if i and i[0] != '#': 570 list.append(i) 528 list.append(i) 571 fp.close() 529 fp.close() 572 return list 530 return list 573 def addFtraceFilterFunctions(self, fil 531 def addFtraceFilterFunctions(self, file): 574 for i in self.listFromFile(fil 532 for i in self.listFromFile(file): 575 if len(i) < 2: 533 if len(i) < 2: 576 continue 534 continue 577 self.tracefuncs[i] = d 535 self.tracefuncs[i] = dict() 578 def getFtraceFilterFunctions(self, cur 536 def getFtraceFilterFunctions(self, current): 579 self.rootCheck(True) 537 self.rootCheck(True) 580 if not current: 538 if not current: 581 call('cat '+self.tpath 539 call('cat '+self.tpath+'available_filter_functions', shell=True) 582 return 540 return 583 master = self.listFromFile(sel 541 master = self.listFromFile(self.tpath+'available_filter_functions') 584 for i in sorted(self.tracefunc 542 for i in sorted(self.tracefuncs): 585 if 'func' in self.trac 543 if 'func' in self.tracefuncs[i]: 586 i = self.trace 544 i = self.tracefuncs[i]['func'] 587 if i in master: 545 if i in master: 588 print(i) 546 print(i) 589 else: 547 else: 590 print(self.col 548 print(self.colorText(i)) 591 def setFtraceFilterFunctions(self, lis 549 def setFtraceFilterFunctions(self, list): 592 master = self.listFromFile(sel 550 master = self.listFromFile(self.tpath+'available_filter_functions') 593 flist = '' 551 flist = '' 594 for i in list: 552 for i in list: 595 if i not in master: 553 if i not in master: 596 continue 554 continue 597 if ' [' in i: 555 if ' [' in i: 598 flist += i.spl 556 flist += i.split(' ')[0]+'\n' 599 else: 557 else: 600 flist += i+'\n 558 flist += i+'\n' 601 fp = open(self.tpath+'set_grap 559 fp = open(self.tpath+'set_graph_function', 'w') 602 fp.write(flist) 560 fp.write(flist) 603 fp.close() 561 fp.close() 604 def basicKprobe(self, name): 562 def basicKprobe(self, name): 605 self.kprobes[name] = {'name': 563 self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name} 606 def defaultKprobe(self, name, kdata): 564 def defaultKprobe(self, name, kdata): 607 k = kdata 565 k = kdata 608 for field in ['name', 'format' 566 for field in ['name', 'format', 'func']: 609 if field not in k: 567 if field not in k: 610 k[field] = nam 568 k[field] = name 611 if self.archargs in k: 569 if self.archargs in k: 612 k['args'] = k[self.arc 570 k['args'] = k[self.archargs] 613 else: 571 else: 614 k['args'] = dict() 572 k['args'] = dict() 615 k['format'] = name 573 k['format'] = name 616 self.kprobes[name] = k 574 self.kprobes[name] = k 617 def kprobeColor(self, name): 575 def kprobeColor(self, name): 618 if name not in self.kprobes or 576 if name not in self.kprobes or 'color' not in self.kprobes[name]: 619 return '' 577 return '' 620 return self.kprobes[name]['col 578 return self.kprobes[name]['color'] 621 def kprobeDisplayName(self, name, data 579 def kprobeDisplayName(self, name, dataraw): 622 if name not in self.kprobes: 580 if name not in self.kprobes: 623 self.basicKprobe(name) 581 self.basicKprobe(name) 624 data = '' 582 data = '' 625 quote=0 583 quote=0 626 # first remvoe any spaces insi 584 # first remvoe any spaces inside quotes, and the quotes 627 for c in dataraw: 585 for c in dataraw: 628 if c == '"': 586 if c == '"': 629 quote = (quote 587 quote = (quote + 1) % 2 630 if quote and c == ' ': 588 if quote and c == ' ': 631 data += '_' 589 data += '_' 632 elif c != '"': 590 elif c != '"': 633 data += c 591 data += c 634 fmt, args = self.kprobes[name] 592 fmt, args = self.kprobes[name]['format'], self.kprobes[name]['args'] 635 arglist = dict() 593 arglist = dict() 636 # now process the args 594 # now process the args 637 for arg in sorted(args): 595 for arg in sorted(args): 638 arglist[arg] = '' 596 arglist[arg] = '' 639 m = re.match(r'.* '+ar !! 597 m = re.match('.* '+arg+'=(?P<arg>.*) ', data); 640 if m: 598 if m: 641 arglist[arg] = 599 arglist[arg] = m.group('arg') 642 else: 600 else: 643 m = re.match(r !! 601 m = re.match('.* '+arg+'=(?P<arg>.*)', data); 644 if m: 602 if m: 645 arglis 603 arglist[arg] = m.group('arg') 646 out = fmt.format(**arglist) 604 out = fmt.format(**arglist) 647 out = out.replace(' ', '_').re 605 out = out.replace(' ', '_').replace('"', '') 648 return out 606 return out 649 def kprobeText(self, kname, kprobe): 607 def kprobeText(self, kname, kprobe): 650 name = fmt = func = kname 608 name = fmt = func = kname 651 args = dict() 609 args = dict() 652 if 'name' in kprobe: 610 if 'name' in kprobe: 653 name = kprobe['name'] 611 name = kprobe['name'] 654 if 'format' in kprobe: 612 if 'format' in kprobe: 655 fmt = kprobe['format'] 613 fmt = kprobe['format'] 656 if 'func' in kprobe: 614 if 'func' in kprobe: 657 func = kprobe['func'] 615 func = kprobe['func'] 658 if self.archargs in kprobe: 616 if self.archargs in kprobe: 659 args = kprobe[self.arc 617 args = kprobe[self.archargs] 660 if 'args' in kprobe: 618 if 'args' in kprobe: 661 args = kprobe['args'] 619 args = kprobe['args'] 662 if re.findall('{(?P<n>[a-z,A-Z 620 if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func): 663 doError('Kprobe "%s" h 621 doError('Kprobe "%s" has format info in the function name "%s"' % (name, func)) 664 for arg in re.findall('{(?P<n> 622 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt): 665 if arg not in args: 623 if arg not in args: 666 doError('Kprob 624 doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 667 val = 'p:%s_cal %s' % (name, f 625 val = 'p:%s_cal %s' % (name, func) 668 for i in sorted(args): 626 for i in sorted(args): 669 val += ' %s=%s' % (i, 627 val += ' %s=%s' % (i, args[i]) 670 val += '\nr:%s_ret %s $retval\ 628 val += '\nr:%s_ret %s $retval\n' % (name, func) 671 return val 629 return val 672 def addKprobes(self, output=False): 630 def addKprobes(self, output=False): 673 if len(self.kprobes) < 1: 631 if len(self.kprobes) < 1: 674 return 632 return 675 if output: 633 if output: 676 pprint(' kprobe fun 634 pprint(' kprobe functions in this kernel:') 677 # first test each kprobe 635 # first test each kprobe 678 rejects = [] 636 rejects = [] 679 # sort kprobes: trace, ub-dev, 637 # sort kprobes: trace, ub-dev, custom, dev 680 kpl = [[], [], [], []] 638 kpl = [[], [], [], []] 681 linesout = len(self.kprobes) 639 linesout = len(self.kprobes) 682 for name in sorted(self.kprobe 640 for name in sorted(self.kprobes): 683 res = self.colorText(' 641 res = self.colorText('YES', 32) 684 if not self.testKprobe 642 if not self.testKprobe(name, self.kprobes[name]): 685 res = self.col 643 res = self.colorText('NO') 686 rejects.append 644 rejects.append(name) 687 else: 645 else: 688 if name in sel 646 if name in self.tracefuncs: 689 kpl[0] 647 kpl[0].append(name) 690 elif name in s 648 elif name in self.dev_tracefuncs: 691 if 'ub 649 if 'ub' in self.dev_tracefuncs[name]: 692 650 kpl[1].append(name) 693 else: 651 else: 694 652 kpl[3].append(name) 695 else: 653 else: 696 kpl[2] 654 kpl[2].append(name) 697 if output: 655 if output: 698 pprint(' 656 pprint(' %s: %s' % (name, res)) 699 kplist = kpl[0] + kpl[1] + kpl 657 kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3] 700 # remove all failed ones from 658 # remove all failed ones from the list 701 for name in rejects: 659 for name in rejects: 702 self.kprobes.pop(name) 660 self.kprobes.pop(name) 703 # set the kprobes all at once 661 # set the kprobes all at once 704 self.fsetVal('', 'kprobe_event 662 self.fsetVal('', 'kprobe_events') 705 kprobeevents = '' 663 kprobeevents = '' 706 for kp in kplist: 664 for kp in kplist: 707 kprobeevents += self.k 665 kprobeevents += self.kprobeText(kp, self.kprobes[kp]) 708 self.fsetVal(kprobeevents, 'kp 666 self.fsetVal(kprobeevents, 'kprobe_events') 709 if output: 667 if output: 710 check = self.fgetVal(' 668 check = self.fgetVal('kprobe_events') 711 linesack = (len(check. 669 linesack = (len(check.split('\n')) - 1) // 2 712 pprint(' kprobe fun 670 pprint(' kprobe functions enabled: %d/%d' % (linesack, linesout)) 713 self.fsetVal('1', 'events/kpro 671 self.fsetVal('1', 'events/kprobes/enable') 714 def testKprobe(self, kname, kprobe): 672 def testKprobe(self, kname, kprobe): 715 self.fsetVal('0', 'events/kpro 673 self.fsetVal('0', 'events/kprobes/enable') 716 kprobeevents = self.kprobeText 674 kprobeevents = self.kprobeText(kname, kprobe) 717 if not kprobeevents: 675 if not kprobeevents: 718 return False 676 return False 719 try: 677 try: 720 self.fsetVal(kprobeeve 678 self.fsetVal(kprobeevents, 'kprobe_events') 721 check = self.fgetVal(' 679 check = self.fgetVal('kprobe_events') 722 except: 680 except: 723 return False 681 return False 724 linesout = len(kprobeevents.sp 682 linesout = len(kprobeevents.split('\n')) 725 linesack = len(check.split('\n 683 linesack = len(check.split('\n')) 726 if linesack < linesout: 684 if linesack < linesout: 727 return False 685 return False 728 return True 686 return True 729 def setVal(self, val, file): 687 def setVal(self, val, file): 730 if not os.path.exists(file): 688 if not os.path.exists(file): 731 return False 689 return False 732 try: 690 try: 733 fp = open(file, 'wb', 691 fp = open(file, 'wb', 0) 734 fp.write(val.encode()) 692 fp.write(val.encode()) 735 fp.flush() 693 fp.flush() 736 fp.close() 694 fp.close() 737 except: 695 except: 738 return False 696 return False 739 return True 697 return True 740 def fsetVal(self, val, path): 698 def fsetVal(self, val, path): 741 if not self.useftrace: << 742 return False << 743 return self.setVal(val, self.t 699 return self.setVal(val, self.tpath+path) 744 def getVal(self, file): 700 def getVal(self, file): 745 res = '' 701 res = '' 746 if not os.path.exists(file): 702 if not os.path.exists(file): 747 return res 703 return res 748 try: 704 try: 749 fp = open(file, 'r') 705 fp = open(file, 'r') 750 res = fp.read() 706 res = fp.read() 751 fp.close() 707 fp.close() 752 except: 708 except: 753 pass 709 pass 754 return res 710 return res 755 def fgetVal(self, path): 711 def fgetVal(self, path): 756 if not self.useftrace: << 757 return '' << 758 return self.getVal(self.tpath+ 712 return self.getVal(self.tpath+path) 759 def cleanupFtrace(self): 713 def cleanupFtrace(self): 760 if self.useftrace: !! 714 if(self.usecallgraph or self.usetraceevents or self.usedevsrc): 761 self.fsetVal('0', 'eve 715 self.fsetVal('0', 'events/kprobes/enable') 762 self.fsetVal('', 'kpro 716 self.fsetVal('', 'kprobe_events') 763 self.fsetVal('1024', ' 717 self.fsetVal('1024', 'buffer_size_kb') >> 718 if self.pmdebug: >> 719 self.setVal(self.pmdebug, self.pmdpath) 764 def setupAllKprobes(self): 720 def setupAllKprobes(self): 765 for name in self.tracefuncs: 721 for name in self.tracefuncs: 766 self.defaultKprobe(nam 722 self.defaultKprobe(name, self.tracefuncs[name]) 767 for name in self.dev_tracefunc 723 for name in self.dev_tracefuncs: 768 self.defaultKprobe(nam 724 self.defaultKprobe(name, self.dev_tracefuncs[name]) 769 def isCallgraphFunc(self, name): 725 def isCallgraphFunc(self, name): 770 if len(self.tracefuncs) < 1 an 726 if len(self.tracefuncs) < 1 and self.suspendmode == 'command': 771 return True 727 return True 772 for i in self.tracefuncs: 728 for i in self.tracefuncs: 773 if 'func' in self.trac 729 if 'func' in self.tracefuncs[i]: 774 f = self.trace 730 f = self.tracefuncs[i]['func'] 775 else: 731 else: 776 f = i 732 f = i 777 if name == f: 733 if name == f: 778 return True 734 return True 779 return False 735 return False 780 def initFtrace(self, quiet=False): 736 def initFtrace(self, quiet=False): 781 if not self.useftrace: << 782 return << 783 if not quiet: 737 if not quiet: 784 sysvals.printSystemInf 738 sysvals.printSystemInfo(False) 785 pprint('INITIALIZING F !! 739 pprint('INITIALIZING FTRACE...') 786 # turn trace off 740 # turn trace off 787 self.fsetVal('0', 'tracing_on' 741 self.fsetVal('0', 'tracing_on') 788 self.cleanupFtrace() 742 self.cleanupFtrace() >> 743 # pm debug messages >> 744 pv = self.getVal(self.pmdpath) >> 745 if pv != '1': >> 746 self.setVal('1', self.pmdpath) >> 747 self.pmdebug = pv 789 # set the trace clock to globa 748 # set the trace clock to global 790 self.fsetVal('global', 'trace_ 749 self.fsetVal('global', 'trace_clock') 791 self.fsetVal('nop', 'current_t 750 self.fsetVal('nop', 'current_tracer') 792 # set trace buffer to an appro 751 # set trace buffer to an appropriate value 793 cpus = max(1, self.cpucount) 752 cpus = max(1, self.cpucount) 794 if self.bufsize > 0: 753 if self.bufsize > 0: 795 tgtsize = self.bufsize 754 tgtsize = self.bufsize 796 elif self.usecallgraph or self 755 elif self.usecallgraph or self.usedevsrc: 797 bmax = (1*1024*1024) i 756 bmax = (1*1024*1024) if self.suspendmode in ['disk', 'command'] \ 798 else (3*1024*1 757 else (3*1024*1024) 799 tgtsize = min(self.mem 758 tgtsize = min(self.memfree, bmax) 800 else: 759 else: 801 tgtsize = 65536 760 tgtsize = 65536 802 while not self.fsetVal('%d' % 761 while not self.fsetVal('%d' % (tgtsize // cpus), 'buffer_size_kb'): 803 # if the size failed t 762 # if the size failed to set, lower it and keep trying 804 tgtsize -= 65536 763 tgtsize -= 65536 805 if tgtsize < 65536: 764 if tgtsize < 65536: 806 tgtsize = int( 765 tgtsize = int(self.fgetVal('buffer_size_kb')) * cpus 807 break 766 break 808 self.vprint('Setting trace buf 767 self.vprint('Setting trace buffers to %d kB (%d kB per cpu)' % (tgtsize, tgtsize/cpus)) 809 # initialize the callgraph tra 768 # initialize the callgraph trace 810 if(self.usecallgraph): 769 if(self.usecallgraph): 811 # set trace type 770 # set trace type 812 self.fsetVal('function 771 self.fsetVal('function_graph', 'current_tracer') 813 self.fsetVal('', 'set_ 772 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 773 # set trace format options 819 self.fsetVal('print-pa 774 self.fsetVal('print-parent', 'trace_options') 820 self.fsetVal('funcgrap 775 self.fsetVal('funcgraph-abstime', 'trace_options') 821 self.fsetVal('funcgrap 776 self.fsetVal('funcgraph-cpu', 'trace_options') 822 self.fsetVal('funcgrap 777 self.fsetVal('funcgraph-duration', 'trace_options') 823 self.fsetVal('funcgrap 778 self.fsetVal('funcgraph-proc', 'trace_options') 824 self.fsetVal('funcgrap 779 self.fsetVal('funcgraph-tail', 'trace_options') 825 self.fsetVal('nofuncgr 780 self.fsetVal('nofuncgraph-overhead', 'trace_options') 826 self.fsetVal('context- 781 self.fsetVal('context-info', 'trace_options') 827 self.fsetVal('graph-ti 782 self.fsetVal('graph-time', 'trace_options') 828 self.fsetVal('%d' % se 783 self.fsetVal('%d' % self.max_graph_depth, 'max_graph_depth') 829 cf = ['dpm_run_callbac 784 cf = ['dpm_run_callback'] 830 if(self.usetraceevents 785 if(self.usetraceevents): 831 cf += ['dpm_pr 786 cf += ['dpm_prepare', 'dpm_complete'] 832 for fn in self.tracefu 787 for fn in self.tracefuncs: 833 if 'func' in s 788 if 'func' in self.tracefuncs[fn]: 834 cf.app 789 cf.append(self.tracefuncs[fn]['func']) 835 else: 790 else: 836 cf.app 791 cf.append(fn) 837 if self.ftop: 792 if self.ftop: 838 self.setFtrace 793 self.setFtraceFilterFunctions([self.ftopfunc]) 839 else: 794 else: 840 self.setFtrace 795 self.setFtraceFilterFunctions(cf) 841 # initialize the kprobe trace 796 # initialize the kprobe trace 842 elif self.usekprobes: 797 elif self.usekprobes: 843 for name in self.trace 798 for name in self.tracefuncs: 844 self.defaultKp 799 self.defaultKprobe(name, self.tracefuncs[name]) 845 if self.usedevsrc: 800 if self.usedevsrc: 846 for name in se 801 for name in self.dev_tracefuncs: 847 self.d 802 self.defaultKprobe(name, self.dev_tracefuncs[name]) 848 if not quiet: 803 if not quiet: 849 pprint('INITIA !! 804 pprint('INITIALIZING KPROBES...') 850 self.addKprobes(self.v 805 self.addKprobes(self.verbose) 851 if(self.usetraceevents): 806 if(self.usetraceevents): 852 # turn trace events on 807 # turn trace events on 853 events = iter(self.tra 808 events = iter(self.traceevents) 854 for e in events: 809 for e in events: 855 self.fsetVal(' 810 self.fsetVal('1', 'events/power/'+e+'/enable') 856 # clear the trace buffer 811 # clear the trace buffer 857 self.fsetVal('', 'trace') 812 self.fsetVal('', 'trace') 858 def verifyFtrace(self): 813 def verifyFtrace(self): 859 # files needed for any trace d 814 # files needed for any trace data 860 files = ['buffer_size_kb', 'cu 815 files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock', 861 'trace_marker 816 'trace_marker', 'trace_options', 'tracing_on'] 862 # files needed for callgraph t 817 # files needed for callgraph trace data 863 tp = self.tpath 818 tp = self.tpath 864 if(self.usecallgraph): 819 if(self.usecallgraph): 865 files += [ 820 files += [ 866 'available_fil 821 'available_filter_functions', 867 'set_ftrace_fi 822 'set_ftrace_filter', 868 'set_graph_fun 823 'set_graph_function' 869 ] 824 ] 870 for f in files: 825 for f in files: 871 if(os.path.exists(tp+f 826 if(os.path.exists(tp+f) == False): 872 return False 827 return False 873 return True 828 return True 874 def verifyKprobes(self): 829 def verifyKprobes(self): 875 # files needed for kprobes to 830 # files needed for kprobes to work 876 files = ['kprobe_events', 'eve 831 files = ['kprobe_events', 'events'] 877 tp = self.tpath 832 tp = self.tpath 878 for f in files: 833 for f in files: 879 if(os.path.exists(tp+f 834 if(os.path.exists(tp+f) == False): 880 return False 835 return False 881 return True 836 return True 882 def colorText(self, str, color=31): 837 def colorText(self, str, color=31): 883 if not self.ansi: 838 if not self.ansi: 884 return str 839 return str 885 return '\x1B[%d;40m%s\x1B[m' % 840 return '\x1B[%d;40m%s\x1B[m' % (color, str) 886 def writeDatafileHeader(self, filename 841 def writeDatafileHeader(self, filename, testdata): 887 fp = self.openlog(filename, 'w 842 fp = self.openlog(filename, 'w') 888 fp.write('%s\n%s\n# command | 843 fp.write('%s\n%s\n# command | %s\n' % (self.teststamp, self.sysstamp, self.cmdline)) 889 for test in testdata: 844 for test in testdata: 890 if 'fw' in test: 845 if 'fw' in test: 891 fw = test['fw' 846 fw = test['fw'] 892 if(fw): 847 if(fw): 893 fp.wri 848 fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) 894 if 'turbo' in test: 849 if 'turbo' in test: 895 fp.write('# tu 850 fp.write('# turbostat %s\n' % test['turbo']) 896 if 'wifi' in test: 851 if 'wifi' in test: 897 fp.write('# wi 852 fp.write('# wifi %s\n' % test['wifi']) 898 if 'netfix' in test: << 899 fp.write('# ne << 900 if test['error'] or le 853 if test['error'] or len(testdata) > 1: 901 fp.write('# en 854 fp.write('# enter_sleep_error %s\n' % test['error']) 902 return fp 855 return fp 903 def sudoUserchown(self, dir): 856 def sudoUserchown(self, dir): 904 if os.path.exists(dir) and sel 857 if os.path.exists(dir) and self.sudouser: 905 cmd = 'chown -R {0}:{0 858 cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' 906 call(cmd.format(self.s 859 call(cmd.format(self.sudouser, dir), shell=True) 907 def outputResult(self, testdata, num=0 860 def outputResult(self, testdata, num=0): 908 if not self.result: 861 if not self.result: 909 return 862 return 910 n = '' 863 n = '' 911 if num > 0: 864 if num > 0: 912 n = '%d' % num 865 n = '%d' % num 913 fp = open(self.result, 'a') 866 fp = open(self.result, 'a') 914 if 'error' in testdata: 867 if 'error' in testdata: 915 fp.write('result%s: fa 868 fp.write('result%s: fail\n' % n) 916 fp.write('error%s: %s\ 869 fp.write('error%s: %s\n' % (n, testdata['error'])) 917 else: 870 else: 918 fp.write('result%s: pa 871 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', 872 for v in ['suspend', 'resume', 'boot', 'lastinit']: 922 if v in testdata: 873 if v in testdata: 923 fp.write('%s%s 874 fp.write('%s%s: %.3f\n' % (v, n, testdata[v])) 924 for v in ['fwsuspend', 'fwresu 875 for v in ['fwsuspend', 'fwresume']: 925 if v in testdata: 876 if v in testdata: 926 fp.write('%s%s 877 fp.write('%s%s: %.3f\n' % (v, n, testdata[v] / 1000000.0)) 927 if 'bugurl' in testdata: 878 if 'bugurl' in testdata: 928 fp.write('url%s: %s\n' 879 fp.write('url%s: %s\n' % (n, testdata['bugurl'])) 929 fp.close() 880 fp.close() 930 self.sudoUserchown(self.result 881 self.sudoUserchown(self.result) 931 def configFile(self, file): 882 def configFile(self, file): 932 dir = os.path.dirname(os.path. 883 dir = os.path.dirname(os.path.realpath(__file__)) 933 if os.path.exists(file): 884 if os.path.exists(file): 934 return file 885 return file 935 elif os.path.exists(dir+'/'+fi 886 elif os.path.exists(dir+'/'+file): 936 return dir+'/'+file 887 return dir+'/'+file 937 elif os.path.exists(dir+'/conf 888 elif os.path.exists(dir+'/config/'+file): 938 return dir+'/config/'+ 889 return dir+'/config/'+file 939 return '' 890 return '' 940 def openlog(self, filename, mode): 891 def openlog(self, filename, mode): 941 isgz = self.gzip 892 isgz = self.gzip 942 if mode == 'r': 893 if mode == 'r': 943 try: 894 try: 944 with gzip.open 895 with gzip.open(filename, mode+'t') as fp: 945 test = 896 test = fp.read(64) 946 isgz = True 897 isgz = True 947 except: 898 except: 948 isgz = False 899 isgz = False 949 if isgz: 900 if isgz: 950 return gzip.open(filen 901 return gzip.open(filename, mode+'t') 951 return open(filename, mode) 902 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): 903 def b64unzip(self, data): 963 try: 904 try: 964 out = codecs.decode(ba 905 out = codecs.decode(base64.b64decode(data), 'zlib').decode() 965 except: 906 except: 966 out = data 907 out = data 967 return out 908 return out 968 def b64zip(self, data): 909 def b64zip(self, data): 969 out = base64.b64encode(codecs. 910 out = base64.b64encode(codecs.encode(data.encode(), 'zlib')).decode() 970 return out 911 return out 971 def platforminfo(self, cmdafter): 912 def platforminfo(self, cmdafter): 972 # add platform info on to a co 913 # add platform info on to a completed ftrace file 973 if not os.path.exists(self.ftr 914 if not os.path.exists(self.ftracefile): 974 return False 915 return False 975 footer = '#\n' 916 footer = '#\n' 976 917 977 # add test command string line 918 # add test command string line if need be 978 if self.suspendmode == 'comman 919 if self.suspendmode == 'command' and self.testcommand: 979 footer += '# platform- 920 footer += '# platform-testcmd: %s\n' % (self.testcommand) 980 921 981 # get a list of target devices 922 # get a list of target devices from the ftrace file 982 props = dict() 923 props = dict() 983 tp = TestProps() 924 tp = TestProps() 984 tf = self.openlog(self.ftracef 925 tf = self.openlog(self.ftracefile, 'r') 985 for line in tf: 926 for line in tf: 986 if tp.stampInfo(line, 927 if tp.stampInfo(line, self): 987 continue 928 continue 988 # parse only valid lin 929 # parse only valid lines, if this is not one move on 989 m = re.match(tp.ftrace 930 m = re.match(tp.ftrace_line_fmt, line) 990 if(not m or 'device_pm 931 if(not m or 'device_pm_callback_start' not in line): 991 continue 932 continue 992 m = re.match(r'.*: (?P !! 933 m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg')); 993 if(not m): 934 if(not m): 994 continue 935 continue 995 dev = m.group('d') 936 dev = m.group('d') 996 if dev not in props: 937 if dev not in props: 997 props[dev] = D 938 props[dev] = DevProps() 998 tf.close() 939 tf.close() 999 940 1000 # now get the syspath for eac 941 # now get the syspath for each target device 1001 for dirname, dirnames, filena 942 for dirname, dirnames, filenames in os.walk('/sys/devices'): 1002 if(re.match(r'.*/powe !! 943 if(re.match('.*/power', dirname) and 'async' in filenames): 1003 dev = dirname 944 dev = dirname.split('/')[-2] 1004 if dev in pro 945 if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)): 1005 props 946 props[dev].syspath = dirname[:-6] 1006 947 1007 # now fill in the properties 948 # now fill in the properties for our target devices 1008 for dev in sorted(props): 949 for dev in sorted(props): 1009 dirname = props[dev]. 950 dirname = props[dev].syspath 1010 if not dirname or not 951 if not dirname or not os.path.exists(dirname): 1011 continue 952 continue 1012 props[dev].isasync = !! 953 with open(dirname+'/power/async') as fp: 1013 if os.path.exists(dir !! 954 text = fp.read() 1014 fp = open(dir !! 955 props[dev].isasync = False 1015 if 'enabled' !! 956 if 'enabled' in text: 1016 props 957 props[dev].isasync = True 1017 fp.close() << 1018 fields = os.listdir(d 958 fields = os.listdir(dirname) 1019 for file in ['product !! 959 if 'product' in fields: 1020 if file not i !! 960 with open(dirname+'/product', 'rb') as fp: 1021 conti !! 961 props[dev].altname = ascii(fp.read()) 1022 try: !! 962 elif 'name' in fields: 1023 with !! 963 with open(dirname+'/name', 'rb') as fp: 1024 !! 964 props[dev].altname = ascii(fp.read()) 1025 except: !! 965 elif 'model' in fields: 1026 conti !! 966 with open(dirname+'/model', 'rb') as fp: 1027 if file == 'i !! 967 props[dev].altname = ascii(fp.read()) 1028 idv, !! 968 elif 'description' in fields: 1029 try: !! 969 with open(dirname+'/description', 'rb') as fp: 1030 !! 970 props[dev].altname = ascii(fp.read()) 1031 !! 971 elif 'id' in fields: 1032 excep !! 972 with open(dirname+'/id', 'rb') as fp: 1033 !! 973 props[dev].altname = ascii(fp.read()) 1034 !! 974 elif 'idVendor' in fields and 'idProduct' in fields: 1035 props !! 975 idv, idp = '', '' 1036 break !! 976 with open(dirname+'/idVendor', 'rb') as fp: >> 977 idv = ascii(fp.read()).strip() >> 978 with open(dirname+'/idProduct', 'rb') as fp: >> 979 idp = ascii(fp.read()).strip() >> 980 props[dev].altname = '%s:%s' % (idv, idp) 1037 if props[dev].altname 981 if props[dev].altname: 1038 out = props[d 982 out = props[dev].altname.strip().replace('\n', ' ')\ 1039 .repl 983 .replace(',', ' ').replace(';', ' ') 1040 props[dev].al 984 props[dev].altname = out 1041 985 1042 # add a devinfo line to the b 986 # add a devinfo line to the bottom of ftrace 1043 out = '' 987 out = '' 1044 for dev in sorted(props): 988 for dev in sorted(props): 1045 out += props[dev].out 989 out += props[dev].out(dev) 1046 footer += '# platform-devinfo 990 footer += '# platform-devinfo: %s\n' % self.b64zip(out) 1047 991 1048 # add a line for each of thes 992 # add a line for each of these commands with their outputs 1049 for name, cmdline, info in cm 993 for name, cmdline, info in cmdafter: 1050 footer += '# platform 994 footer += '# platform-%s: %s | %s\n' % (name, cmdline, self.b64zip(info)) 1051 self.flog(footer) !! 995 >> 996 with self.openlog(self.ftracefile, 'a') as fp: >> 997 fp.write(footer) 1052 return True 998 return True 1053 def commonPrefix(self, list): 999 def commonPrefix(self, list): 1054 if len(list) < 2: 1000 if len(list) < 2: 1055 return '' 1001 return '' 1056 prefix = list[0] 1002 prefix = list[0] 1057 for s in list[1:]: 1003 for s in list[1:]: 1058 while s[:len(prefix)] 1004 while s[:len(prefix)] != prefix and prefix: 1059 prefix = pref 1005 prefix = prefix[:len(prefix)-1] 1060 if not prefix: 1006 if not prefix: 1061 break 1007 break 1062 if '/' in prefix and prefix[- 1008 if '/' in prefix and prefix[-1] != '/': 1063 prefix = prefix[0:pre 1009 prefix = prefix[0:prefix.rfind('/')+1] 1064 return prefix 1010 return prefix 1065 def dictify(self, text, format): 1011 def dictify(self, text, format): 1066 out = dict() 1012 out = dict() 1067 header = True if format == 1 1013 header = True if format == 1 else False 1068 delim = ' ' if format == 1 el 1014 delim = ' ' if format == 1 else ':' 1069 for line in text.split('\n'): 1015 for line in text.split('\n'): 1070 if header: 1016 if header: 1071 header, out[' 1017 header, out['@'] = False, line 1072 continue 1018 continue 1073 line = line.strip() 1019 line = line.strip() 1074 if delim in line: 1020 if delim in line: 1075 data = line.s 1021 data = line.split(delim, 1) 1076 num = re.sear 1022 num = re.search(r'[\d]+', data[1]) 1077 if format == 1023 if format == 2 and num: 1078 out[d 1024 out[data[0].strip()] = num.group() 1079 else: 1025 else: 1080 out[d 1026 out[data[0].strip()] = data[1] 1081 return out 1027 return out 1082 def cmdinfovar(self, arg): << 1083 if arg == 'ethdev': << 1084 try: << 1085 cmd = [self.g << 1086 fp = Popen(cm << 1087 info = ascii( << 1088 fp.close() << 1089 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) 1028 def cmdinfo(self, begin, debug=False): 1097 out = [] 1029 out = [] 1098 if begin: 1030 if begin: 1099 self.cmd1 = dict() 1031 self.cmd1 = dict() 1100 for cargs in self.infocmds: 1032 for cargs in self.infocmds: 1101 delta, name, args = c !! 1033 delta, name = cargs[0], cargs[1] 1102 for i in range(len(ar !! 1034 cmdline, cmdpath = ' '.join(cargs[2:]), self.getExec(cargs[2]) 1103 if args[i][0] << 1104 args[ << 1105 cmdline, cmdpath = ' << 1106 if not cmdpath or (be 1035 if not cmdpath or (begin and not delta): 1107 continue 1036 continue 1108 self.dlog('[%s]' % cm << 1109 try: 1037 try: 1110 fp = Popen([c !! 1038 fp = Popen([cmdpath]+cargs[3:], stdout=PIPE, stderr=PIPE).stdout 1111 info = ascii( 1039 info = ascii(fp.read()).strip() 1112 fp.close() 1040 fp.close() 1113 except: 1041 except: 1114 continue 1042 continue 1115 if not debug and begi 1043 if not debug and begin: 1116 self.cmd1[nam 1044 self.cmd1[name] = self.dictify(info, delta) 1117 elif not debug and de 1045 elif not debug and delta and name in self.cmd1: 1118 before, after 1046 before, after = self.cmd1[name], self.dictify(info, delta) 1119 dinfo = ('\t% !! 1047 dinfo = ('\t%s\n' % before['@']) if '@' in before else '' 1120 prefix = self 1048 prefix = self.commonPrefix(list(before.keys())) 1121 for key in so 1049 for key in sorted(before): 1122 if ke 1050 if key in after and before[key] != after[key]: 1123 1051 title = key.replace(prefix, '') 1124 1052 if delta == 2: 1125 1053 dinfo += '\t%s : %s -> %s\n' % \ 1126 1054 (title, before[key].strip(), after[key].strip()) 1127 1055 else: 1128 1056 dinfo += '%10s (start) : %s\n%10s (after) : %s\n' % \ 1129 1057 (title, before[key], title, after[key]) 1130 dinfo = '\tno 1058 dinfo = '\tnothing changed' if not dinfo else dinfo.rstrip() 1131 out.append((n 1059 out.append((name, cmdline, dinfo)) 1132 else: 1060 else: 1133 out.append((n 1061 out.append((name, cmdline, '\tnothing' if not info else info)) 1134 return out 1062 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): 1063 def haveTurbostat(self): 1168 if not self.tstat: 1064 if not self.tstat: 1169 return False 1065 return False 1170 cmd = self.getExec('turbostat 1066 cmd = self.getExec('turbostat') 1171 if not cmd: 1067 if not cmd: 1172 return False 1068 return False 1173 fp = Popen([cmd, '-v'], stdou 1069 fp = Popen([cmd, '-v'], stdout=PIPE, stderr=PIPE).stderr 1174 out = ascii(fp.read()).strip( 1070 out = ascii(fp.read()).strip() 1175 fp.close() 1071 fp.close() 1176 if re.match(r'turbostat versi !! 1072 if re.match('turbostat version .*', out): 1177 self.vprint(out) 1073 self.vprint(out) 1178 return True 1074 return True 1179 return False 1075 return False 1180 def turbostat(self, s0ixready): !! 1076 def turbostat(self): 1181 cmd = self.getExec('turbostat 1077 cmd = self.getExec('turbostat') 1182 rawout = keyline = valline = 1078 rawout = keyline = valline = '' 1183 fullcmd = '%s -q -S echo free 1079 fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile) 1184 fp = Popen(['sh', '-c', fullc !! 1080 fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE).stderr 1185 for line in fp.stderr: !! 1081 for line in fp: 1186 line = ascii(line) 1082 line = ascii(line) 1187 rawout += line 1083 rawout += line 1188 if keyline and vallin 1084 if keyline and valline: 1189 continue 1085 continue 1190 if re.match(r'(?i)Avg !! 1086 if re.match('(?i)Avg_MHz.*', line): 1191 keyline = lin 1087 keyline = line.strip().split() 1192 elif keyline: 1088 elif keyline: 1193 valline = lin 1089 valline = line.strip().split() 1194 fp.wait() !! 1090 fp.close() 1195 if not keyline or not valline 1091 if not keyline or not valline or len(keyline) != len(valline): 1196 errmsg = 'unrecognize 1092 errmsg = 'unrecognized turbostat output:\n'+rawout.strip() 1197 self.vprint(errmsg) 1093 self.vprint(errmsg) 1198 if not self.verbose: 1094 if not self.verbose: 1199 pprint(errmsg 1095 pprint(errmsg) 1200 return (fp.returncode !! 1096 return '' 1201 if self.verbose: 1097 if self.verbose: 1202 pprint(rawout.strip() 1098 pprint(rawout.strip()) 1203 out = [] 1099 out = [] 1204 for key in keyline: 1100 for key in keyline: 1205 idx = keyline.index(k 1101 idx = keyline.index(key) 1206 val = valline[idx] 1102 val = valline[idx] 1207 if key == 'SYS%LPI' a << 1208 continue << 1209 out.append('%s=%s' % 1103 out.append('%s=%s' % (key, val)) 1210 return (fp.returncode, '|'.jo !! 1104 return '|'.join(out) 1211 def netfixon(self, net='both'): << 1212 cmd = self.getExec('netfix') << 1213 if not cmd: << 1214 return '' << 1215 fp = Popen([cmd, '-s', net, ' << 1216 out = ascii(fp.read()).strip( << 1217 fp.close() << 1218 return out << 1219 def wifiDetails(self, dev): 1105 def wifiDetails(self, dev): 1220 try: 1106 try: 1221 info = open('/sys/cla 1107 info = open('/sys/class/net/%s/device/uevent' % dev, 'r').read().strip() 1222 except: 1108 except: 1223 return dev 1109 return dev 1224 vals = [dev] 1110 vals = [dev] 1225 for prop in info.split('\n'): 1111 for prop in info.split('\n'): 1226 if prop.startswith('D 1112 if prop.startswith('DRIVER=') or prop.startswith('PCI_ID='): 1227 vals.append(p 1113 vals.append(prop.split('=')[-1]) 1228 return ':'.join(vals) 1114 return ':'.join(vals) 1229 def checkWifi(self, dev=''): 1115 def checkWifi(self, dev=''): 1230 try: 1116 try: 1231 w = open('/proc/net/w 1117 w = open('/proc/net/wireless', 'r').read().strip() 1232 except: 1118 except: 1233 return '' 1119 return '' 1234 for line in reversed(w.split( 1120 for line in reversed(w.split('\n')): 1235 m = re.match(r' *(?P< !! 1121 m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', w.split('\n')[-1]) 1236 if not m or (dev and 1122 if not m or (dev and dev != m.group('dev')): 1237 continue 1123 continue 1238 return m.group('dev') 1124 return m.group('dev') 1239 return '' 1125 return '' 1240 def pollWifi(self, dev, timeout=10): !! 1126 def pollWifi(self, dev, timeout=60): 1241 start = time.time() 1127 start = time.time() 1242 while (time.time() - start) < 1128 while (time.time() - start) < timeout: 1243 w = self.checkWifi(de 1129 w = self.checkWifi(dev) 1244 if w: 1130 if w: 1245 return '%s re 1131 return '%s reconnected %.2f' % \ 1246 (self 1132 (self.wifiDetails(dev), max(0, time.time() - start)) 1247 time.sleep(0.01) 1133 time.sleep(0.01) 1248 return '%s timeout %d' % (sel 1134 return '%s timeout %d' % (self.wifiDetails(dev), timeout) 1249 def errorSummary(self, errinfo, msg): 1135 def errorSummary(self, errinfo, msg): 1250 found = False 1136 found = False 1251 for entry in errinfo: 1137 for entry in errinfo: 1252 if re.match(entry['ma 1138 if re.match(entry['match'], msg): 1253 entry['count' 1139 entry['count'] += 1 1254 if self.hostn 1140 if self.hostname not in entry['urls']: 1255 entry 1141 entry['urls'][self.hostname] = [self.htmlfile] 1256 elif self.htm 1142 elif self.htmlfile not in entry['urls'][self.hostname]: 1257 entry 1143 entry['urls'][self.hostname].append(self.htmlfile) 1258 found = True 1144 found = True 1259 break 1145 break 1260 if found: 1146 if found: 1261 return 1147 return 1262 arr = msg.split() 1148 arr = msg.split() 1263 for j in range(len(arr)): 1149 for j in range(len(arr)): 1264 if re.match(r'^[0-9,\ !! 1150 if re.match('^[0-9,\-\.]*$', arr[j]): 1265 arr[j] = r'[0 !! 1151 arr[j] = '[0-9,\-\.]*' 1266 else: 1152 else: 1267 arr[j] = arr[ 1153 arr[j] = arr[j]\ 1268 .repl !! 1154 .replace('\\', '\\\\').replace(']', '\]').replace('[', '\[')\ 1269 .repl !! 1155 .replace('.', '\.').replace('+', '\+').replace('*', '\*')\ 1270 .repl !! 1156 .replace('(', '\(').replace(')', '\)').replace('}', '\}')\ 1271 .repl !! 1157 .replace('{', '\{') 1272 mstr = ' *'.join(arr) 1158 mstr = ' *'.join(arr) 1273 entry = { 1159 entry = { 1274 'line': msg, 1160 'line': msg, 1275 'match': mstr, 1161 'match': mstr, 1276 'count': 1, 1162 'count': 1, 1277 'urls': {self.hostnam 1163 'urls': {self.hostname: [self.htmlfile]} 1278 } 1164 } 1279 errinfo.append(entry) 1165 errinfo.append(entry) 1280 def multistat(self, start, idx, finis 1166 def multistat(self, start, idx, finish): 1281 if 'time' in self.multitest: 1167 if 'time' in self.multitest: 1282 id = '%d Duration=%dm 1168 id = '%d Duration=%dmin' % (idx+1, self.multitest['time']) 1283 else: 1169 else: 1284 id = '%d/%d' % (idx+1 1170 id = '%d/%d' % (idx+1, self.multitest['count']) 1285 t = time.time() 1171 t = time.time() 1286 if 'start' not in self.multit 1172 if 'start' not in self.multitest: 1287 self.multitest['start 1173 self.multitest['start'] = self.multitest['last'] = t 1288 self.multitest['total 1174 self.multitest['total'] = 0.0 1289 pprint('TEST (%s) STA 1175 pprint('TEST (%s) START' % id) 1290 return 1176 return 1291 dt = t - self.multitest['last 1177 dt = t - self.multitest['last'] 1292 if not start: 1178 if not start: 1293 if idx == 0 and self. 1179 if idx == 0 and self.multitest['delay'] > 0: 1294 self.multites 1180 self.multitest['total'] += self.multitest['delay'] 1295 pprint('TEST (%s) COM 1181 pprint('TEST (%s) COMPLETE -- Duration %.1fs' % (id, dt)) 1296 return 1182 return 1297 self.multitest['total'] += dt 1183 self.multitest['total'] += dt 1298 self.multitest['last'] = t 1184 self.multitest['last'] = t 1299 avg = self.multitest['total'] 1185 avg = self.multitest['total'] / idx 1300 if 'time' in self.multitest: 1186 if 'time' in self.multitest: 1301 left = finish - datet 1187 left = finish - datetime.now() 1302 left -= timedelta(mic 1188 left -= timedelta(microseconds=left.microseconds) 1303 else: 1189 else: 1304 left = timedelta(seco 1190 left = timedelta(seconds=((self.multitest['count'] - idx) * int(avg))) 1305 pprint('TEST (%s) START - Avg 1191 pprint('TEST (%s) START - Avg Duration %.1fs, Time left %s' % \ 1306 (id, avg, str(left))) 1192 (id, avg, str(left))) 1307 def multiinit(self, c, d): 1193 def multiinit(self, c, d): 1308 sz, unit = 'count', 'm' 1194 sz, unit = 'count', 'm' 1309 if c.endswith('d') or c.endsw 1195 if c.endswith('d') or c.endswith('h') or c.endswith('m'): 1310 sz, unit, c = 'time', 1196 sz, unit, c = 'time', c[-1], c[:-1] 1311 self.multitest['run'] = True 1197 self.multitest['run'] = True 1312 self.multitest[sz] = getArgIn 1198 self.multitest[sz] = getArgInt('multi: n d (exec count)', c, 1, 1000000, False) 1313 self.multitest['delay'] = get 1199 self.multitest['delay'] = getArgInt('multi: n d (delay between tests)', d, 0, 3600, False) 1314 if unit == 'd': 1200 if unit == 'd': 1315 self.multitest[sz] *= 1201 self.multitest[sz] *= 1440 1316 elif unit == 'h': 1202 elif unit == 'h': 1317 self.multitest[sz] *= 1203 self.multitest[sz] *= 60 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 1204 1384 sysvals = SystemValues() 1205 sysvals = SystemValues() 1385 switchvalues = ['enable', 'disable', 'on', 'o 1206 switchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0'] 1386 switchoff = ['disable', 'off', 'false', '0'] 1207 switchoff = ['disable', 'off', 'false', '0'] 1387 suspendmodename = { 1208 suspendmodename = { 1388 'standby': 'standby (S1)', !! 1209 'freeze': 'Freeze (S0)', 1389 'freeze': 'freeze (S2idle)', !! 1210 'standby': 'Standby (S1)', 1390 'mem': 'suspend (S3)', !! 1211 'mem': 'Suspend (S3)', 1391 'disk': 'hibernate (S4)' !! 1212 'disk': 'Hibernate (S4)' 1392 } 1213 } 1393 1214 1394 # Class: DevProps 1215 # Class: DevProps 1395 # Description: 1216 # Description: 1396 # Simple class which holds property va 1217 # Simple class which holds property values collected 1397 # for all the devices used in the time 1218 # for all the devices used in the timeline. 1398 class DevProps: 1219 class DevProps: 1399 def __init__(self): 1220 def __init__(self): 1400 self.syspath = '' 1221 self.syspath = '' 1401 self.altname = '' 1222 self.altname = '' 1402 self.isasync = True 1223 self.isasync = True 1403 self.xtraclass = '' 1224 self.xtraclass = '' 1404 self.xtrainfo = '' 1225 self.xtrainfo = '' 1405 def out(self, dev): 1226 def out(self, dev): 1406 return '%s,%s,%d;' % (dev, se 1227 return '%s,%s,%d;' % (dev, self.altname, self.isasync) 1407 def debug(self, dev): 1228 def debug(self, dev): 1408 pprint('%s:\n\taltname = %s\n 1229 pprint('%s:\n\taltname = %s\n\t async = %s' % (dev, self.altname, self.isasync)) 1409 def altName(self, dev): 1230 def altName(self, dev): 1410 if not self.altname or self.a 1231 if not self.altname or self.altname == dev: 1411 return dev 1232 return dev 1412 return '%s [%s]' % (self.altn 1233 return '%s [%s]' % (self.altname, dev) 1413 def xtraClass(self): 1234 def xtraClass(self): 1414 if self.xtraclass: 1235 if self.xtraclass: 1415 return ' '+self.xtrac 1236 return ' '+self.xtraclass 1416 if not self.isasync: 1237 if not self.isasync: 1417 return ' sync' 1238 return ' sync' 1418 return '' 1239 return '' 1419 def xtraInfo(self): 1240 def xtraInfo(self): 1420 if self.xtraclass: 1241 if self.xtraclass: 1421 return ' '+self.xtrac 1242 return ' '+self.xtraclass 1422 if self.isasync: 1243 if self.isasync: 1423 return ' (async)' 1244 return ' (async)' 1424 return ' (sync)' 1245 return ' (sync)' 1425 1246 1426 # Class: DeviceNode 1247 # Class: DeviceNode 1427 # Description: 1248 # Description: 1428 # A container used to create a device 1249 # A container used to create a device hierachy, with a single root node 1429 # and a tree of child nodes. Used by D 1250 # and a tree of child nodes. Used by Data.deviceTopology() 1430 class DeviceNode: 1251 class DeviceNode: 1431 def __init__(self, nodename, nodedept 1252 def __init__(self, nodename, nodedepth): 1432 self.name = nodename 1253 self.name = nodename 1433 self.children = [] 1254 self.children = [] 1434 self.depth = nodedepth 1255 self.depth = nodedepth 1435 1256 1436 # Class: Data 1257 # Class: Data 1437 # Description: 1258 # Description: 1438 # The primary container for suspend/re 1259 # The primary container for suspend/resume test data. There is one for 1439 # each test run. The data is organized 1260 # each test run. The data is organized into a cronological hierarchy: 1440 # Data.dmesg { 1261 # Data.dmesg { 1441 # phases { 1262 # phases { 1442 # 10 sequential, non-ov 1263 # 10 sequential, non-overlapping phases of S/R 1443 # contents: times for p 1264 # contents: times for phase start/end, order/color data for html 1444 # devlist { 1265 # devlist { 1445 # device callba 1266 # device callback or action list for this phase 1446 # device { 1267 # device { 1447 # a sin 1268 # a single device callback or generic action 1448 # conte 1269 # contents: start/stop times, pid/cpu/driver info 1449 # 1270 # parents/children, html id for timeline/callgraph 1450 # 1271 # optionally includes an ftrace callgraph 1451 # 1272 # optionally includes dev/ps data 1452 # } 1273 # } 1453 # } 1274 # } 1454 # } 1275 # } 1455 # } 1276 # } 1456 # 1277 # 1457 class Data: 1278 class Data: 1458 phasedef = { 1279 phasedef = { 1459 'suspend_prepare': {'order': 1280 'suspend_prepare': {'order': 0, 'color': '#CCFFCC'}, 1460 'suspend': {'order': 1281 'suspend': {'order': 1, 'color': '#88FF88'}, 1461 'suspend_late': {'order': 1282 'suspend_late': {'order': 2, 'color': '#00AA00'}, 1462 'suspend_noirq': {'order': 1283 'suspend_noirq': {'order': 3, 'color': '#008888'}, 1463 'suspend_machine': {'order': 1284 'suspend_machine': {'order': 4, 'color': '#0000FF'}, 1464 'resume_machine': {'order': 1285 'resume_machine': {'order': 5, 'color': '#FF0000'}, 1465 'resume_noirq': {'order': 1286 'resume_noirq': {'order': 6, 'color': '#FF9900'}, 1466 'resume_early': {'order': 1287 'resume_early': {'order': 7, 'color': '#FFCC00'}, 1467 'resume': {'order': 1288 'resume': {'order': 8, 'color': '#FFFF88'}, 1468 'resume_complete': {'order': 1289 'resume_complete': {'order': 9, 'color': '#FFFFCC'}, 1469 } 1290 } 1470 errlist = { 1291 errlist = { 1471 'HWERROR' : r'.*\[ *Hardware 1292 'HWERROR' : r'.*\[ *Hardware Error *\].*', 1472 'FWBUG' : r'.*\[ *Firmware 1293 'FWBUG' : r'.*\[ *Firmware Bug *\].*', 1473 'TASKFAIL': r'.*Freezing .*af << 1474 'BUG' : r'(?i).*\bBUG\b.* 1294 'BUG' : r'(?i).*\bBUG\b.*', 1475 'ERROR' : r'(?i).*\bERROR\b 1295 'ERROR' : r'(?i).*\bERROR\b.*', 1476 'WARNING' : r'(?i).*\bWARNING 1296 'WARNING' : r'(?i).*\bWARNING\b.*', 1477 'FAULT' : r'(?i).*\bFAULT\b 1297 'FAULT' : r'(?i).*\bFAULT\b.*', 1478 'FAIL' : r'(?i).*\bFAILED\ 1298 'FAIL' : r'(?i).*\bFAILED\b.*', 1479 'INVALID' : r'(?i).*\bINVALID 1299 'INVALID' : r'(?i).*\bINVALID\b.*', 1480 'CRASH' : r'(?i).*\bCRASHED 1300 'CRASH' : r'(?i).*\bCRASHED\b.*', 1481 'TIMEOUT' : r'(?i).*\bTIMEOUT 1301 'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*', 1482 'ABORT' : r'(?i).*\bABORT\b << 1483 'IRQ' : r'.*\bgenirq: .*' 1302 'IRQ' : r'.*\bgenirq: .*', >> 1303 'TASKFAIL': r'.*Freezing of tasks *.*', 1484 'ACPI' : r'.*\bACPI *(?P<b 1304 'ACPI' : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*', 1485 'DISKFULL': r'.*\bNo space le 1305 'DISKFULL': r'.*\bNo space left on device.*', 1486 'USBERR' : r'.*usb .*device 1306 'USBERR' : r'.*usb .*device .*, error [0-9-]*', 1487 'ATAERR' : r' *ata[0-9\.]*: 1307 'ATAERR' : r' *ata[0-9\.]*: .*failed.*', 1488 'MEIERR' : r' *mei.*: .*fail 1308 'MEIERR' : r' *mei.*: .*failed.*', 1489 'TPMERR' : r'(?i) *tpm *tpm[ 1309 'TPMERR' : r'(?i) *tpm *tpm[0-9]*: .*error.*', 1490 } 1310 } 1491 def __init__(self, num): 1311 def __init__(self, num): 1492 idchar = 'abcdefghij' 1312 idchar = 'abcdefghij' 1493 self.start = 0.0 # test start 1313 self.start = 0.0 # test start 1494 self.end = 0.0 # test end 1314 self.end = 0.0 # test end 1495 self.hwstart = 0 # rtc test s 1315 self.hwstart = 0 # rtc test start 1496 self.hwend = 0 # rtc test e 1316 self.hwend = 0 # rtc test end 1497 self.tSuspended = 0.0 # low-l 1317 self.tSuspended = 0.0 # low-level suspend start 1498 self.tResumed = 0.0 # low-l 1318 self.tResumed = 0.0 # low-level resume start 1499 self.tKernSus = 0.0 # kerne 1319 self.tKernSus = 0.0 # kernel level suspend start 1500 self.tKernRes = 0.0 # kerne 1320 self.tKernRes = 0.0 # kernel level resume end 1501 self.fwValid = False # is fi 1321 self.fwValid = False # is firmware data available 1502 self.fwSuspend = 0 # time 1322 self.fwSuspend = 0 # time spent in firmware suspend 1503 self.fwResume = 0 # time 1323 self.fwResume = 0 # time spent in firmware resume 1504 self.html_device_id = 0 1324 self.html_device_id = 0 1505 self.stamp = 0 1325 self.stamp = 0 1506 self.outfile = '' 1326 self.outfile = '' 1507 self.kerror = False 1327 self.kerror = False 1508 self.wifi = dict() 1328 self.wifi = dict() 1509 self.turbostat = 0 1329 self.turbostat = 0 1510 self.enterfail = '' 1330 self.enterfail = '' 1511 self.currphase = '' 1331 self.currphase = '' 1512 self.pstl = dict() # proce 1332 self.pstl = dict() # process timeline 1513 self.testnumber = num 1333 self.testnumber = num 1514 self.idstr = idchar[num] 1334 self.idstr = idchar[num] 1515 self.dmesgtext = [] # dmesg 1335 self.dmesgtext = [] # dmesg text file in memory 1516 self.dmesg = dict() # root 1336 self.dmesg = dict() # root data structure 1517 self.errorinfo = {'suspend':[ 1337 self.errorinfo = {'suspend':[],'resume':[]} 1518 self.tLow = [] # time 1338 self.tLow = [] # time spent in low-level suspends (standby/freeze) 1519 self.devpids = [] 1339 self.devpids = [] 1520 self.devicegroups = 0 1340 self.devicegroups = 0 1521 def sortedPhases(self): 1341 def sortedPhases(self): 1522 return sorted(self.dmesg, key 1342 return sorted(self.dmesg, key=lambda k:self.dmesg[k]['order']) 1523 def initDevicegroups(self): 1343 def initDevicegroups(self): 1524 # called when phases are all 1344 # called when phases are all finished being added 1525 for phase in sorted(self.dmes 1345 for phase in sorted(self.dmesg.keys()): 1526 if '*' in phase: 1346 if '*' in phase: 1527 p = phase.spl 1347 p = phase.split('*') 1528 pnew = '%s%d' 1348 pnew = '%s%d' % (p[0], len(p)) 1529 self.dmesg[pn 1349 self.dmesg[pnew] = self.dmesg.pop(phase) 1530 self.devicegroups = [] 1350 self.devicegroups = [] 1531 for phase in self.sortedPhase 1351 for phase in self.sortedPhases(): 1532 self.devicegroups.app 1352 self.devicegroups.append([phase]) 1533 def nextPhase(self, phase, offset): 1353 def nextPhase(self, phase, offset): 1534 order = self.dmesg[phase]['or 1354 order = self.dmesg[phase]['order'] + offset 1535 for p in self.dmesg: 1355 for p in self.dmesg: 1536 if self.dmesg[p]['ord 1356 if self.dmesg[p]['order'] == order: 1537 return p 1357 return p 1538 return '' 1358 return '' 1539 def lastPhase(self, depth=1): 1359 def lastPhase(self, depth=1): 1540 plist = self.sortedPhases() 1360 plist = self.sortedPhases() 1541 if len(plist) < depth: 1361 if len(plist) < depth: 1542 return '' 1362 return '' 1543 return plist[-1*depth] 1363 return plist[-1*depth] 1544 def turbostatInfo(self): 1364 def turbostatInfo(self): 1545 tp = TestProps() 1365 tp = TestProps() 1546 out = {'syslpi':'N/A','pkgpc1 1366 out = {'syslpi':'N/A','pkgpc10':'N/A'} 1547 for line in self.dmesgtext: 1367 for line in self.dmesgtext: 1548 m = re.match(tp.tstat 1368 m = re.match(tp.tstatfmt, line) 1549 if not m: 1369 if not m: 1550 continue 1370 continue 1551 for i in m.group('t') 1371 for i in m.group('t').split('|'): 1552 if 'SYS%LPI' 1372 if 'SYS%LPI' in i: 1553 out[' 1373 out['syslpi'] = i.split('=')[-1]+'%' 1554 elif 'pc10' i 1374 elif 'pc10' in i: 1555 out[' 1375 out['pkgpc10'] = i.split('=')[-1]+'%' 1556 break 1376 break 1557 return out 1377 return out 1558 def extractErrorInfo(self): 1378 def extractErrorInfo(self): 1559 lf = self.dmesgtext 1379 lf = self.dmesgtext 1560 if len(self.dmesgtext) < 1 an 1380 if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 1561 lf = sysvals.openlog( 1381 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 1562 i = 0 1382 i = 0 1563 tp = TestProps() 1383 tp = TestProps() 1564 list = [] 1384 list = [] 1565 for line in lf: 1385 for line in lf: 1566 i += 1 1386 i += 1 1567 if tp.stampInfo(line, 1387 if tp.stampInfo(line, sysvals): 1568 continue 1388 continue 1569 m = re.match(r'[ \t]* !! 1389 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 1570 if not m: 1390 if not m: 1571 continue 1391 continue 1572 t = float(m.group('kt 1392 t = float(m.group('ktime')) 1573 if t < self.start or 1393 if t < self.start or t > self.end: 1574 continue 1394 continue 1575 dir = 'suspend' if t 1395 dir = 'suspend' if t < self.tSuspended else 'resume' 1576 msg = m.group('msg') 1396 msg = m.group('msg') 1577 if re.match(r'capabil !! 1397 if re.match('capability: warning: .*', msg): 1578 continue 1398 continue 1579 for err in self.errli 1399 for err in self.errlist: 1580 if re.match(s 1400 if re.match(self.errlist[err], msg): 1581 list. 1401 list.append((msg, err, dir, t, i, i)) 1582 self. 1402 self.kerror = True 1583 break 1403 break 1584 tp.msglist = [] 1404 tp.msglist = [] 1585 for msg, type, dir, t, idx1, 1405 for msg, type, dir, t, idx1, idx2 in list: 1586 tp.msglist.append(msg 1406 tp.msglist.append(msg) 1587 self.errorinfo[dir].a 1407 self.errorinfo[dir].append((type, t, idx1, idx2)) 1588 if self.kerror: 1408 if self.kerror: 1589 sysvals.dmesglog = Tr 1409 sysvals.dmesglog = True 1590 if len(self.dmesgtext) < 1 an 1410 if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 1591 lf.close() 1411 lf.close() 1592 return tp 1412 return tp 1593 def setStart(self, time, msg=''): 1413 def setStart(self, time, msg=''): 1594 self.start = time 1414 self.start = time 1595 if msg: 1415 if msg: 1596 try: 1416 try: 1597 self.hwstart 1417 self.hwstart = datetime.strptime(msg, sysvals.tmstart) 1598 except: 1418 except: 1599 self.hwstart 1419 self.hwstart = 0 1600 def setEnd(self, time, msg=''): 1420 def setEnd(self, time, msg=''): 1601 self.end = time 1421 self.end = time 1602 if msg: 1422 if msg: 1603 try: 1423 try: 1604 self.hwend = 1424 self.hwend = datetime.strptime(msg, sysvals.tmend) 1605 except: 1425 except: 1606 self.hwend = 1426 self.hwend = 0 1607 def isTraceEventOutsideDeviceCalls(se 1427 def isTraceEventOutsideDeviceCalls(self, pid, time): 1608 for phase in self.sortedPhase 1428 for phase in self.sortedPhases(): 1609 list = self.dmesg[pha 1429 list = self.dmesg[phase]['list'] 1610 for dev in list: 1430 for dev in list: 1611 d = list[dev] 1431 d = list[dev] 1612 if(d['pid'] = 1432 if(d['pid'] == pid and time >= d['start'] and 1613 time 1433 time < d['end']): 1614 retur 1434 return False 1615 return True 1435 return True 1616 def sourcePhase(self, start): 1436 def sourcePhase(self, start): 1617 for phase in self.sortedPhase 1437 for phase in self.sortedPhases(): 1618 if 'machine' in phase 1438 if 'machine' in phase: 1619 continue 1439 continue 1620 pend = self.dmesg[pha 1440 pend = self.dmesg[phase]['end'] 1621 if start <= pend: 1441 if start <= pend: 1622 return phase 1442 return phase 1623 return 'resume_complete' if ' !! 1443 return 'resume_complete' 1624 def sourceDevice(self, phaselist, sta 1444 def sourceDevice(self, phaselist, start, end, pid, type): 1625 tgtdev = '' 1445 tgtdev = '' 1626 for phase in phaselist: 1446 for phase in phaselist: 1627 list = self.dmesg[pha 1447 list = self.dmesg[phase]['list'] 1628 for devname in list: 1448 for devname in list: 1629 dev = list[de 1449 dev = list[devname] 1630 # pid must ma 1450 # pid must match 1631 if dev['pid'] 1451 if dev['pid'] != pid: 1632 conti 1452 continue 1633 devS = dev['s 1453 devS = dev['start'] 1634 devE = dev['e 1454 devE = dev['end'] 1635 if type == 'd 1455 if type == 'device': 1636 # dev 1456 # device target event is entirely inside the source boundary 1637 if(st 1457 if(start < devS or start >= devE or end <= devS or end > devE): 1638 1458 continue 1639 elif type == 1459 elif type == 'thread': 1640 # thr 1460 # thread target event will expand the source boundary 1641 if st 1461 if start < devS: 1642 1462 dev['start'] = start 1643 if en 1463 if end > devE: 1644 1464 dev['end'] = end 1645 tgtdev = dev 1465 tgtdev = dev 1646 break 1466 break 1647 return tgtdev 1467 return tgtdev 1648 def addDeviceFunctionCall(self, displ 1468 def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata): 1649 # try to place the call in a 1469 # try to place the call in a device 1650 phases = self.sortedPhases() 1470 phases = self.sortedPhases() 1651 tgtdev = self.sourceDevice(ph 1471 tgtdev = self.sourceDevice(phases, start, end, pid, 'device') 1652 # calls with device pids that 1472 # calls with device pids that occur outside device bounds are dropped 1653 # TODO: include these somehow 1473 # TODO: include these somehow 1654 if not tgtdev and pid in self 1474 if not tgtdev and pid in self.devpids: 1655 return False 1475 return False 1656 # try to place the call in a 1476 # try to place the call in a thread 1657 if not tgtdev: 1477 if not tgtdev: 1658 tgtdev = self.sourceD 1478 tgtdev = self.sourceDevice(phases, start, end, pid, 'thread') 1659 # create new thread blocks, e 1479 # create new thread blocks, expand as new calls are found 1660 if not tgtdev: 1480 if not tgtdev: 1661 if proc == '<...>': 1481 if proc == '<...>': 1662 threadname = 1482 threadname = 'kthread-%d' % (pid) 1663 else: 1483 else: 1664 threadname = 1484 threadname = '%s-%d' % (proc, pid) 1665 tgtphase = self.sourc 1485 tgtphase = self.sourcePhase(start) 1666 if not tgtphase: << 1667 return False << 1668 self.newAction(tgtpha 1486 self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '') 1669 return self.addDevice 1487 return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata) 1670 # this should not happen 1488 # this should not happen 1671 if not tgtdev: 1489 if not tgtdev: 1672 sysvals.vprint('[%f - 1490 sysvals.vprint('[%f - %f] %s-%d %s %s %s' % \ 1673 (start, end, 1491 (start, end, proc, pid, kprobename, cdata, rdata)) 1674 return False 1492 return False 1675 # place the call data inside 1493 # place the call data inside the src element of the tgtdev 1676 if('src' not in tgtdev): 1494 if('src' not in tgtdev): 1677 tgtdev['src'] = [] 1495 tgtdev['src'] = [] 1678 dtf = sysvals.dev_tracefuncs 1496 dtf = sysvals.dev_tracefuncs 1679 ubiquitous = False 1497 ubiquitous = False 1680 if kprobename in dtf and 'ub' 1498 if kprobename in dtf and 'ub' in dtf[kprobename]: 1681 ubiquitous = True 1499 ubiquitous = True 1682 mc = re.match(r'\(.*\) *(?P<a !! 1500 title = cdata+' '+rdata 1683 mr = re.match(r'\((?P<caller> !! 1501 mstr = '\(.*\) *(?P<args>.*) *\((?P<caller>.*)\+.* arg1=(?P<ret>.*)' 1684 if mc and mr: !! 1502 m = re.match(mstr, title) 1685 c = mr.group('caller' !! 1503 if m: 1686 a = mc.group('args'). !! 1504 c = m.group('caller') 1687 r = mr.group('ret') !! 1505 a = m.group('args').strip() >> 1506 r = m.group('ret') 1688 if len(r) > 6: 1507 if len(r) > 6: 1689 r = '' 1508 r = '' 1690 else: 1509 else: 1691 r = 'ret=%s ' 1510 r = 'ret=%s ' % r 1692 if ubiquitous and c i 1511 if ubiquitous and c in dtf and 'ub' in dtf[c]: 1693 return False 1512 return False 1694 else: << 1695 return False << 1696 color = sysvals.kprobeColor(k 1513 color = sysvals.kprobeColor(kprobename) 1697 e = DevFunction(displayname, 1514 e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color) 1698 tgtdev['src'].append(e) 1515 tgtdev['src'].append(e) 1699 return True 1516 return True 1700 def overflowDevices(self): 1517 def overflowDevices(self): 1701 # get a list of devices that 1518 # get a list of devices that extend beyond the end of this test run 1702 devlist = [] 1519 devlist = [] 1703 for phase in self.sortedPhase 1520 for phase in self.sortedPhases(): 1704 list = self.dmesg[pha 1521 list = self.dmesg[phase]['list'] 1705 for devname in list: 1522 for devname in list: 1706 dev = list[de 1523 dev = list[devname] 1707 if dev['end'] 1524 if dev['end'] > self.end: 1708 devli 1525 devlist.append(dev) 1709 return devlist 1526 return devlist 1710 def mergeOverlapDevices(self, devlist 1527 def mergeOverlapDevices(self, devlist): 1711 # merge any devices that over 1528 # merge any devices that overlap devlist 1712 for dev in devlist: 1529 for dev in devlist: 1713 devname = dev['name'] 1530 devname = dev['name'] 1714 for phase in self.sor 1531 for phase in self.sortedPhases(): 1715 list = self.d 1532 list = self.dmesg[phase]['list'] 1716 if devname no 1533 if devname not in list: 1717 conti 1534 continue 1718 tdev = list[d 1535 tdev = list[devname] 1719 o = min(dev[' 1536 o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start']) 1720 if o <= 0: 1537 if o <= 0: 1721 conti 1538 continue 1722 dev['end'] = 1539 dev['end'] = tdev['end'] 1723 if 'src' not 1540 if 'src' not in dev or 'src' not in tdev: 1724 conti 1541 continue 1725 dev['src'] += 1542 dev['src'] += tdev['src'] 1726 del list[devn 1543 del list[devname] 1727 def usurpTouchingThread(self, name, d 1544 def usurpTouchingThread(self, name, dev): 1728 # the caller test has priorit 1545 # the caller test has priority of this thread, give it to him 1729 for phase in self.sortedPhase 1546 for phase in self.sortedPhases(): 1730 list = self.dmesg[pha 1547 list = self.dmesg[phase]['list'] 1731 if name in list: 1548 if name in list: 1732 tdev = list[n 1549 tdev = list[name] 1733 if tdev['star 1550 if tdev['start'] - dev['end'] < 0.1: 1734 dev[' 1551 dev['end'] = tdev['end'] 1735 if 's 1552 if 'src' not in dev: 1736 1553 dev['src'] = [] 1737 if 's 1554 if 'src' in tdev: 1738 1555 dev['src'] += tdev['src'] 1739 del l 1556 del list[name] 1740 break 1557 break 1741 def stitchTouchingThreads(self, testl 1558 def stitchTouchingThreads(self, testlist): 1742 # merge any threads between t 1559 # merge any threads between tests that touch 1743 for phase in self.sortedPhase 1560 for phase in self.sortedPhases(): 1744 list = self.dmesg[pha 1561 list = self.dmesg[phase]['list'] 1745 for devname in list: 1562 for devname in list: 1746 dev = list[de 1563 dev = list[devname] 1747 if 'htmlclass 1564 if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']: 1748 conti 1565 continue 1749 for data in t 1566 for data in testlist: 1750 data. 1567 data.usurpTouchingThread(devname, dev) 1751 def optimizeDevSrc(self): 1568 def optimizeDevSrc(self): 1752 # merge any src call loops to 1569 # merge any src call loops to reduce timeline size 1753 for phase in self.sortedPhase 1570 for phase in self.sortedPhases(): 1754 list = self.dmesg[pha 1571 list = self.dmesg[phase]['list'] 1755 for dev in list: 1572 for dev in list: 1756 if 'src' not 1573 if 'src' not in list[dev]: 1757 conti 1574 continue 1758 src = list[de 1575 src = list[dev]['src'] 1759 p = 0 1576 p = 0 1760 for e in sort 1577 for e in sorted(src, key=lambda event: event.time): 1761 if no 1578 if not p or not e.repeat(p): 1762 1579 p = e 1763 1580 continue 1764 # e i 1581 # e is another iteration of p, move it into p 1765 p.end 1582 p.end = e.end 1766 p.len 1583 p.length = p.end - p.time 1767 p.cou 1584 p.count += 1 1768 src.r 1585 src.remove(e) 1769 def trimTimeVal(self, t, t0, dT, left 1586 def trimTimeVal(self, t, t0, dT, left): 1770 if left: 1587 if left: 1771 if(t > t0): 1588 if(t > t0): 1772 if(t - dT < t 1589 if(t - dT < t0): 1773 retur 1590 return t0 1774 return t - dT 1591 return t - dT 1775 else: 1592 else: 1776 return t 1593 return t 1777 else: 1594 else: 1778 if(t < t0 + dT): 1595 if(t < t0 + dT): 1779 if(t > t0): 1596 if(t > t0): 1780 retur 1597 return t0 + dT 1781 return t + dT 1598 return t + dT 1782 else: 1599 else: 1783 return t 1600 return t 1784 def trimTime(self, t0, dT, left): 1601 def trimTime(self, t0, dT, left): 1785 self.tSuspended = self.trimTi 1602 self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left) 1786 self.tResumed = self.trimTime 1603 self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left) 1787 self.start = self.trimTimeVal 1604 self.start = self.trimTimeVal(self.start, t0, dT, left) 1788 self.tKernSus = self.trimTime 1605 self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left) 1789 self.tKernRes = self.trimTime 1606 self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left) 1790 self.end = self.trimTimeVal(s 1607 self.end = self.trimTimeVal(self.end, t0, dT, left) 1791 for phase in self.sortedPhase 1608 for phase in self.sortedPhases(): 1792 p = self.dmesg[phase] 1609 p = self.dmesg[phase] 1793 p['start'] = self.tri 1610 p['start'] = self.trimTimeVal(p['start'], t0, dT, left) 1794 p['end'] = self.trimT 1611 p['end'] = self.trimTimeVal(p['end'], t0, dT, left) 1795 list = p['list'] 1612 list = p['list'] 1796 for name in list: 1613 for name in list: 1797 d = list[name 1614 d = list[name] 1798 d['start'] = 1615 d['start'] = self.trimTimeVal(d['start'], t0, dT, left) 1799 d['end'] = se 1616 d['end'] = self.trimTimeVal(d['end'], t0, dT, left) 1800 d['length'] = 1617 d['length'] = d['end'] - d['start'] 1801 if('ftrace' i 1618 if('ftrace' in d): 1802 cg = 1619 cg = d['ftrace'] 1803 cg.st 1620 cg.start = self.trimTimeVal(cg.start, t0, dT, left) 1804 cg.en 1621 cg.end = self.trimTimeVal(cg.end, t0, dT, left) 1805 for l 1622 for line in cg.list: 1806 1623 line.time = self.trimTimeVal(line.time, t0, dT, left) 1807 if('src' in d 1624 if('src' in d): 1808 for e 1625 for e in d['src']: 1809 1626 e.time = self.trimTimeVal(e.time, t0, dT, left) 1810 1627 e.end = self.trimTimeVal(e.end, t0, dT, left) 1811 1628 e.length = e.end - e.time 1812 if('cpuexec' << 1813 cpuex << 1814 for e << 1815 << 1816 << 1817 << 1818 << 1819 d['cp << 1820 for dir in ['suspend', 'resum 1629 for dir in ['suspend', 'resume']: 1821 list = [] 1630 list = [] 1822 for e in self.errorin 1631 for e in self.errorinfo[dir]: 1823 type, tm, idx 1632 type, tm, idx1, idx2 = e 1824 tm = self.tri 1633 tm = self.trimTimeVal(tm, t0, dT, left) 1825 list.append(( 1634 list.append((type, tm, idx1, idx2)) 1826 self.errorinfo[dir] = 1635 self.errorinfo[dir] = list 1827 def trimFreezeTime(self, tZero): 1636 def trimFreezeTime(self, tZero): 1828 # trim out any standby or fre 1637 # trim out any standby or freeze clock time 1829 lp = '' 1638 lp = '' 1830 for phase in self.sortedPhase 1639 for phase in self.sortedPhases(): 1831 if 'resume_machine' i 1640 if 'resume_machine' in phase and 'suspend_machine' in lp: 1832 tS, tR = self 1641 tS, tR = self.dmesg[lp]['end'], self.dmesg[phase]['start'] 1833 tL = tR - tS 1642 tL = tR - tS 1834 if tL <= 0: !! 1643 if tL > 0: 1835 conti !! 1644 left = True if tR > tZero else False 1836 left = True i !! 1645 self.trimTime(tS, tL, left) 1837 self.trimTime !! 1646 if 'trying' in self.dmesg[lp] and self.dmesg[lp]['trying'] >= 0.001: 1838 if 'waking' i !! 1647 tTry = round(self.dmesg[lp]['trying'] * 1000) 1839 tCnt !! 1648 text = '%.0f (-%.0f waking)' % (tL * 1000, tTry) 1840 if se << 1841 << 1842 else: 1649 else: 1843 !! 1650 text = '%.0f' % (tL * 1000) 1844 text !! 1651 self.tLow.append(text) 1845 else: << 1846 text << 1847 self.tLow.app << 1848 lp = phase 1652 lp = phase 1849 def getMemTime(self): 1653 def getMemTime(self): 1850 if not self.hwstart or not se 1654 if not self.hwstart or not self.hwend: 1851 return 1655 return 1852 stime = (self.tSuspended - se 1656 stime = (self.tSuspended - self.start) * 1000000 1853 rtime = (self.end - self.tRes 1657 rtime = (self.end - self.tResumed) * 1000000 1854 hws = self.hwstart + timedelt 1658 hws = self.hwstart + timedelta(microseconds=stime) 1855 hwr = self.hwend - timedelta( 1659 hwr = self.hwend - timedelta(microseconds=rtime) 1856 self.tLow.append('%.0f'%((hwr 1660 self.tLow.append('%.0f'%((hwr - hws).total_seconds() * 1000)) 1857 def getTimeValues(self): 1661 def getTimeValues(self): 1858 s = (self.tSuspended - self.t !! 1662 sktime = (self.tSuspended - self.tKernSus) * 1000 1859 r = (self.tKernRes - self.tRe !! 1663 rktime = (self.tKernRes - self.tResumed) * 1000 1860 return (max(s, 0), max(r, 0)) !! 1664 return (sktime, rktime) 1861 def setPhase(self, phase, ktime, isbe 1665 def setPhase(self, phase, ktime, isbegin, order=-1): 1862 if(isbegin): 1666 if(isbegin): 1863 # phase start over cu 1667 # phase start over current phase 1864 if self.currphase: 1668 if self.currphase: 1865 if 'resume_ma 1669 if 'resume_machine' not in self.currphase: 1866 sysva 1670 sysvals.vprint('WARNING: phase %s failed to end' % self.currphase) 1867 self.dmesg[se 1671 self.dmesg[self.currphase]['end'] = ktime 1868 phases = self.dmesg.k 1672 phases = self.dmesg.keys() 1869 color = self.phasedef 1673 color = self.phasedef[phase]['color'] 1870 count = len(phases) i 1674 count = len(phases) if order < 0 else order 1871 # create unique name 1675 # create unique name for every new phase 1872 while phase in phases 1676 while phase in phases: 1873 phase += '*' 1677 phase += '*' 1874 self.dmesg[phase] = { 1678 self.dmesg[phase] = {'list': dict(), 'start': -1.0, 'end': -1.0, 1875 'row': 0, 'co 1679 'row': 0, 'color': color, 'order': count} 1876 self.dmesg[phase]['st 1680 self.dmesg[phase]['start'] = ktime 1877 self.currphase = phas 1681 self.currphase = phase 1878 else: 1682 else: 1879 # phase end without a 1683 # phase end without a start 1880 if phase not in self. 1684 if phase not in self.currphase: 1881 if self.currp 1685 if self.currphase: 1882 sysva 1686 sysvals.vprint('WARNING: %s ended instead of %s, ftrace corruption?' % (phase, self.currphase)) 1883 else: 1687 else: 1884 sysva 1688 sysvals.vprint('WARNING: %s ended without a start, ftrace corruption?' % phase) 1885 retur 1689 return phase 1886 phase = self.currphas 1690 phase = self.currphase 1887 self.dmesg[phase]['en 1691 self.dmesg[phase]['end'] = ktime 1888 self.currphase = '' 1692 self.currphase = '' 1889 return phase 1693 return phase 1890 def sortedDevices(self, phase): 1694 def sortedDevices(self, phase): 1891 list = self.dmesg[phase]['lis 1695 list = self.dmesg[phase]['list'] 1892 return sorted(list, key=lambd 1696 return sorted(list, key=lambda k:list[k]['start']) 1893 def fixupInitcalls(self, phase): 1697 def fixupInitcalls(self, phase): 1894 # if any calls never returned 1698 # if any calls never returned, clip them at system resume end 1895 phaselist = self.dmesg[phase] 1699 phaselist = self.dmesg[phase]['list'] 1896 for devname in phaselist: 1700 for devname in phaselist: 1897 dev = phaselist[devna 1701 dev = phaselist[devname] 1898 if(dev['end'] < 0): 1702 if(dev['end'] < 0): 1899 for p in self 1703 for p in self.sortedPhases(): 1900 if se 1704 if self.dmesg[p]['end'] > dev['start']: 1901 1705 dev['end'] = self.dmesg[p]['end'] 1902 1706 break 1903 sysvals.vprin 1707 sysvals.vprint('%s (%s): callback didnt return' % (devname, phase)) 1904 def deviceFilter(self, devicefilter): 1708 def deviceFilter(self, devicefilter): 1905 for phase in self.sortedPhase 1709 for phase in self.sortedPhases(): 1906 list = self.dmesg[pha 1710 list = self.dmesg[phase]['list'] 1907 rmlist = [] 1711 rmlist = [] 1908 for name in list: 1712 for name in list: 1909 keep = False 1713 keep = False 1910 for filter in 1714 for filter in devicefilter: 1911 if fi 1715 if filter in name or \ 1912 1716 ('drv' in list[name] and filter in list[name]['drv']): 1913 1717 keep = True 1914 if not keep: 1718 if not keep: 1915 rmlis 1719 rmlist.append(name) 1916 for name in rmlist: 1720 for name in rmlist: 1917 del list[name 1721 del list[name] 1918 def fixupInitcallsThatDidntReturn(sel 1722 def fixupInitcallsThatDidntReturn(self): 1919 # if any calls never returned 1723 # if any calls never returned, clip them at system resume end 1920 for phase in self.sortedPhase 1724 for phase in self.sortedPhases(): 1921 self.fixupInitcalls(p 1725 self.fixupInitcalls(phase) 1922 def phaseOverlap(self, phases): 1726 def phaseOverlap(self, phases): 1923 rmgroups = [] 1727 rmgroups = [] 1924 newgroup = [] 1728 newgroup = [] 1925 for group in self.devicegroup 1729 for group in self.devicegroups: 1926 for phase in phases: 1730 for phase in phases: 1927 if phase not 1731 if phase not in group: 1928 conti 1732 continue 1929 for p in grou 1733 for p in group: 1930 if p 1734 if p not in newgroup: 1931 1735 newgroup.append(p) 1932 if group not 1736 if group not in rmgroups: 1933 rmgro 1737 rmgroups.append(group) 1934 for group in rmgroups: 1738 for group in rmgroups: 1935 self.devicegroups.rem 1739 self.devicegroups.remove(group) 1936 self.devicegroups.append(newg 1740 self.devicegroups.append(newgroup) 1937 def newActionGlobal(self, name, start 1741 def newActionGlobal(self, name, start, end, pid=-1, color=''): 1938 # which phase is this device 1742 # which phase is this device callback or action in 1939 phases = self.sortedPhases() 1743 phases = self.sortedPhases() 1940 targetphase = 'none' 1744 targetphase = 'none' 1941 htmlclass = '' 1745 htmlclass = '' 1942 overlap = 0.0 1746 overlap = 0.0 1943 myphases = [] 1747 myphases = [] 1944 for phase in phases: 1748 for phase in phases: 1945 pstart = self.dmesg[p 1749 pstart = self.dmesg[phase]['start'] 1946 pend = self.dmesg[pha 1750 pend = self.dmesg[phase]['end'] 1947 # see if the action o 1751 # see if the action overlaps this phase 1948 o = max(0, min(end, p 1752 o = max(0, min(end, pend) - max(start, pstart)) 1949 if o > 0: 1753 if o > 0: 1950 myphases.appe 1754 myphases.append(phase) 1951 # set the target phas 1755 # set the target phase to the one that overlaps most 1952 if o > overlap: 1756 if o > overlap: 1953 if overlap > 1757 if overlap > 0 and phase == 'post_resume': 1954 conti 1758 continue 1955 targetphase = 1759 targetphase = phase 1956 overlap = o 1760 overlap = o 1957 # if no target phase was foun 1761 # if no target phase was found, pin it to the edge 1958 if targetphase == 'none': 1762 if targetphase == 'none': 1959 p0start = self.dmesg[ 1763 p0start = self.dmesg[phases[0]]['start'] 1960 if start <= p0start: 1764 if start <= p0start: 1961 targetphase = 1765 targetphase = phases[0] 1962 else: 1766 else: 1963 targetphase = 1767 targetphase = phases[-1] 1964 if pid == -2: 1768 if pid == -2: 1965 htmlclass = ' bg' 1769 htmlclass = ' bg' 1966 elif pid == -3: 1770 elif pid == -3: 1967 htmlclass = ' ps' 1771 htmlclass = ' ps' 1968 if len(myphases) > 1: 1772 if len(myphases) > 1: 1969 htmlclass = ' bg' 1773 htmlclass = ' bg' 1970 self.phaseOverlap(myp 1774 self.phaseOverlap(myphases) 1971 if targetphase in phases: 1775 if targetphase in phases: 1972 newname = self.newAct 1776 newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color) 1973 return (targetphase, 1777 return (targetphase, newname) 1974 return False 1778 return False 1975 def newAction(self, phase, name, pid, 1779 def newAction(self, phase, name, pid, parent, start, end, drv, htmlclass='', color=''): 1976 # new device callback for a s 1780 # new device callback for a specific phase 1977 self.html_device_id += 1 1781 self.html_device_id += 1 1978 devid = '%s%d' % (self.idstr, 1782 devid = '%s%d' % (self.idstr, self.html_device_id) 1979 list = self.dmesg[phase]['lis 1783 list = self.dmesg[phase]['list'] 1980 length = -1.0 1784 length = -1.0 1981 if(start >= 0 and end >= 0): 1785 if(start >= 0 and end >= 0): 1982 length = end - start 1786 length = end - start 1983 if pid == -2 or name not in s 1787 if pid == -2 or name not in sysvals.tracefuncs.keys(): 1984 i = 2 1788 i = 2 1985 origname = name 1789 origname = name 1986 while(name in list): 1790 while(name in list): 1987 name = '%s[%d 1791 name = '%s[%d]' % (origname, i) 1988 i += 1 1792 i += 1 1989 list[name] = {'name': name, ' 1793 list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid, 1990 'par': parent, 'lengt 1794 'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv } 1991 if htmlclass: 1795 if htmlclass: 1992 list[name]['htmlclass 1796 list[name]['htmlclass'] = htmlclass 1993 if color: 1797 if color: 1994 list[name]['color'] = 1798 list[name]['color'] = color 1995 return name 1799 return name 1996 def findDevice(self, phase, name): 1800 def findDevice(self, phase, name): 1997 list = self.dmesg[phase]['lis 1801 list = self.dmesg[phase]['list'] 1998 mydev = '' 1802 mydev = '' 1999 for devname in sorted(list): 1803 for devname in sorted(list): 2000 if name == devname or !! 1804 if name == devname or re.match('^%s\[(?P<num>[0-9]*)\]$' % name, devname): 2001 mydev = devna 1805 mydev = devname 2002 if mydev: 1806 if mydev: 2003 return list[mydev] 1807 return list[mydev] 2004 return False 1808 return False 2005 def deviceChildren(self, devname, pha 1809 def deviceChildren(self, devname, phase): 2006 devlist = [] 1810 devlist = [] 2007 list = self.dmesg[phase]['lis 1811 list = self.dmesg[phase]['list'] 2008 for child in list: 1812 for child in list: 2009 if(list[child]['par'] 1813 if(list[child]['par'] == devname): 2010 devlist.appen 1814 devlist.append(child) 2011 return devlist 1815 return devlist 2012 def maxDeviceNameSize(self, phase): 1816 def maxDeviceNameSize(self, phase): 2013 size = 0 1817 size = 0 2014 for name in self.dmesg[phase] 1818 for name in self.dmesg[phase]['list']: 2015 if len(name) > size: 1819 if len(name) > size: 2016 size = len(na 1820 size = len(name) 2017 return size 1821 return size 2018 def printDetails(self): 1822 def printDetails(self): 2019 sysvals.vprint('Timeline Deta 1823 sysvals.vprint('Timeline Details:') 2020 sysvals.vprint(' tes 1824 sysvals.vprint(' test start: %f' % self.start) 2021 sysvals.vprint('kernel suspen 1825 sysvals.vprint('kernel suspend start: %f' % self.tKernSus) 2022 tS = tR = False 1826 tS = tR = False 2023 for phase in self.sortedPhase 1827 for phase in self.sortedPhases(): 2024 devlist = self.dmesg[ 1828 devlist = self.dmesg[phase]['list'] 2025 dc, ps, pe = len(devl 1829 dc, ps, pe = len(devlist), self.dmesg[phase]['start'], self.dmesg[phase]['end'] 2026 if not tS and ps >= s 1830 if not tS and ps >= self.tSuspended: 2027 sysvals.vprin 1831 sysvals.vprint(' machine suspended: %f' % self.tSuspended) 2028 tS = True 1832 tS = True 2029 if not tR and ps >= s 1833 if not tR and ps >= self.tResumed: 2030 sysvals.vprin 1834 sysvals.vprint(' machine resumed: %f' % self.tResumed) 2031 tR = True 1835 tR = True 2032 sysvals.vprint('%20s: 1836 sysvals.vprint('%20s: %f - %f (%d devices)' % (phase, ps, pe, dc)) 2033 if sysvals.devdump: 1837 if sysvals.devdump: 2034 sysvals.vprin 1838 sysvals.vprint(''.join('-' for i in range(80))) 2035 maxname = '%d 1839 maxname = '%d' % self.maxDeviceNameSize(phase) 2036 fmt = '%3d) % 1840 fmt = '%3d) %'+maxname+'s - %f - %f' 2037 c = 1 1841 c = 1 2038 for name in s 1842 for name in sorted(devlist): 2039 s = d 1843 s = devlist[name]['start'] 2040 e = d 1844 e = devlist[name]['end'] 2041 sysva 1845 sysvals.vprint(fmt % (c, name, s, e)) 2042 c += 1846 c += 1 2043 sysvals.vprin 1847 sysvals.vprint(''.join('-' for i in range(80))) 2044 sysvals.vprint(' kernel res 1848 sysvals.vprint(' kernel resume end: %f' % self.tKernRes) 2045 sysvals.vprint(' t 1849 sysvals.vprint(' test end: %f' % self.end) 2046 def deviceChildrenAllPhases(self, dev 1850 def deviceChildrenAllPhases(self, devname): 2047 devlist = [] 1851 devlist = [] 2048 for phase in self.sortedPhase 1852 for phase in self.sortedPhases(): 2049 list = self.deviceChi 1853 list = self.deviceChildren(devname, phase) 2050 for dev in sorted(lis 1854 for dev in sorted(list): 2051 if dev not in 1855 if dev not in devlist: 2052 devli 1856 devlist.append(dev) 2053 return devlist 1857 return devlist 2054 def masterTopology(self, name, list, 1858 def masterTopology(self, name, list, depth): 2055 node = DeviceNode(name, depth 1859 node = DeviceNode(name, depth) 2056 for cname in list: 1860 for cname in list: 2057 # avoid recursions 1861 # avoid recursions 2058 if name == cname: 1862 if name == cname: 2059 continue 1863 continue 2060 clist = self.deviceCh 1864 clist = self.deviceChildrenAllPhases(cname) 2061 cnode = self.masterTo 1865 cnode = self.masterTopology(cname, clist, depth+1) 2062 node.children.append( 1866 node.children.append(cnode) 2063 return node 1867 return node 2064 def printTopology(self, node): 1868 def printTopology(self, node): 2065 html = '' 1869 html = '' 2066 if node.name: 1870 if node.name: 2067 info = '' 1871 info = '' 2068 drv = '' 1872 drv = '' 2069 for phase in self.sor 1873 for phase in self.sortedPhases(): 2070 list = self.d 1874 list = self.dmesg[phase]['list'] 2071 if node.name 1875 if node.name in list: 2072 s = l 1876 s = list[node.name]['start'] 2073 e = l 1877 e = list[node.name]['end'] 2074 if li 1878 if list[node.name]['drv']: 2075 1879 drv = ' {'+list[node.name]['drv']+'}' 2076 info 1880 info += ('<li>%s: %.3fms</li>' % (phase, (e-s)*1000)) 2077 html += '<li><b>'+nod 1881 html += '<li><b>'+node.name+drv+'</b>' 2078 if info: 1882 if info: 2079 html += '<ul> 1883 html += '<ul>'+info+'</ul>' 2080 html += '</li>' 1884 html += '</li>' 2081 if len(node.children) > 0: 1885 if len(node.children) > 0: 2082 html += '<ul>' 1886 html += '<ul>' 2083 for cnode in node.chi 1887 for cnode in node.children: 2084 html += self. 1888 html += self.printTopology(cnode) 2085 html += '</ul>' 1889 html += '</ul>' 2086 return html 1890 return html 2087 def rootDeviceList(self): 1891 def rootDeviceList(self): 2088 # list of devices graphed 1892 # list of devices graphed 2089 real = [] 1893 real = [] 2090 for phase in self.sortedPhase 1894 for phase in self.sortedPhases(): 2091 list = self.dmesg[pha 1895 list = self.dmesg[phase]['list'] 2092 for dev in sorted(lis 1896 for dev in sorted(list): 2093 if list[dev][ 1897 if list[dev]['pid'] >= 0 and dev not in real: 2094 real. 1898 real.append(dev) 2095 # list of top-most root devic 1899 # list of top-most root devices 2096 rootlist = [] 1900 rootlist = [] 2097 for phase in self.sortedPhase 1901 for phase in self.sortedPhases(): 2098 list = self.dmesg[pha 1902 list = self.dmesg[phase]['list'] 2099 for dev in sorted(lis 1903 for dev in sorted(list): 2100 pdev = list[d 1904 pdev = list[dev]['par'] 2101 pid = list[de 1905 pid = list[dev]['pid'] 2102 if(pid < 0 or !! 1906 if(pid < 0 or re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)): 2103 conti 1907 continue 2104 if pdev and p 1908 if pdev and pdev not in real and pdev not in rootlist: 2105 rootl 1909 rootlist.append(pdev) 2106 return rootlist 1910 return rootlist 2107 def deviceTopology(self): 1911 def deviceTopology(self): 2108 rootlist = self.rootDeviceLis 1912 rootlist = self.rootDeviceList() 2109 master = self.masterTopology( 1913 master = self.masterTopology('', rootlist, 0) 2110 return self.printTopology(mas 1914 return self.printTopology(master) 2111 def selectTimelineDevices(self, widfm 1915 def selectTimelineDevices(self, widfmt, tTotal, mindevlen): 2112 # only select devices that wi 1916 # only select devices that will actually show up in html 2113 self.tdevlist = dict() 1917 self.tdevlist = dict() 2114 for phase in self.dmesg: 1918 for phase in self.dmesg: 2115 devlist = [] 1919 devlist = [] 2116 list = self.dmesg[pha 1920 list = self.dmesg[phase]['list'] 2117 for dev in list: 1921 for dev in list: 2118 length = (lis 1922 length = (list[dev]['end'] - list[dev]['start']) * 1000 2119 width = widfm 1923 width = widfmt % (((list[dev]['end']-list[dev]['start'])*100)/tTotal) 2120 if length >= !! 1924 if width != '0.000000' and length >= mindevlen: 2121 devli 1925 devlist.append(dev) 2122 self.tdevlist[phase] 1926 self.tdevlist[phase] = devlist 2123 def addHorizontalDivider(self, devnam 1927 def addHorizontalDivider(self, devname, devend): 2124 phase = 'suspend_prepare' 1928 phase = 'suspend_prepare' 2125 self.newAction(phase, devname 1929 self.newAction(phase, devname, -2, '', \ 2126 self.start, devend, ' 1930 self.start, devend, '', ' sec', '') 2127 if phase not in self.tdevlist 1931 if phase not in self.tdevlist: 2128 self.tdevlist[phase] 1932 self.tdevlist[phase] = [] 2129 self.tdevlist[phase].append(d 1933 self.tdevlist[phase].append(devname) 2130 d = DevItem(0, phase, self.dm 1934 d = DevItem(0, phase, self.dmesg[phase]['list'][devname]) 2131 return d 1935 return d 2132 def addProcessUsageEvent(self, name, 1936 def addProcessUsageEvent(self, name, times): 2133 # get the start and end times 1937 # get the start and end times for this process 2134 cpuexec = dict() !! 1938 maxC = 0 2135 tlast = start = end = -1 !! 1939 tlast = 0 >> 1940 start = -1 >> 1941 end = -1 2136 for t in sorted(times): 1942 for t in sorted(times): 2137 if tlast < 0: !! 1943 if tlast == 0: 2138 tlast = t 1944 tlast = t 2139 continue 1945 continue 2140 if name in self.pstl[ !! 1946 if name in self.pstl[t]: 2141 if start < 0: !! 1947 if start == -1 or tlast < start: 2142 start 1948 start = tlast 2143 end, key = t, !! 1949 if end == -1 or t > end: 2144 maxj = (t - t !! 1950 end = t 2145 cpuexec[key] << 2146 tlast = t 1951 tlast = t 2147 if start < 0 or end < 0: !! 1952 if start == -1 or end == -1: 2148 return !! 1953 return 0 2149 # add a new action for this p 1954 # add a new action for this process and get the object 2150 out = self.newActionGlobal(na 1955 out = self.newActionGlobal(name, start, end, -3) 2151 if out: !! 1956 if not out: 2152 phase, devname = out !! 1957 return 0 2153 dev = self.dmesg[phas !! 1958 phase, devname = out 2154 dev['cpuexec'] = cpue !! 1959 dev = self.dmesg[phase]['list'][devname] >> 1960 # get the cpu exec data >> 1961 tlast = 0 >> 1962 clast = 0 >> 1963 cpuexec = dict() >> 1964 for t in sorted(times): >> 1965 if tlast == 0 or t <= start or t > end: >> 1966 tlast = t >> 1967 continue >> 1968 list = self.pstl[t] >> 1969 c = 0 >> 1970 if name in list: >> 1971 c = list[name] >> 1972 if c > maxC: >> 1973 maxC = c >> 1974 if c != clast: >> 1975 key = (tlast, t) >> 1976 cpuexec[key] = c >> 1977 tlast = t >> 1978 clast = c >> 1979 dev['cpuexec'] = cpuexec >> 1980 return maxC 2155 def createProcessUsageEvents(self): 1981 def createProcessUsageEvents(self): 2156 # get an array of process nam !! 1982 # get an array of process names 2157 proclist = {'sus': dict(), 'r !! 1983 proclist = [] 2158 tdata = {'sus': [], 'res': [] << 2159 for t in sorted(self.pstl): 1984 for t in sorted(self.pstl): 2160 dir = 'sus' if t < se !! 1985 pslist = self.pstl[t] 2161 for ps in sorted(self !! 1986 for ps in sorted(pslist): 2162 if ps not in !! 1987 if ps not in proclist: 2163 procl !! 1988 proclist.append(ps) 2164 tdata[dir].append(t) !! 1989 # get a list of data points for suspend and resume >> 1990 tsus = [] >> 1991 tres = [] >> 1992 for t in sorted(self.pstl): >> 1993 if t < self.tSuspended: >> 1994 tsus.append(t) >> 1995 else: >> 1996 tres.append(t) 2165 # process the events for susp 1997 # process the events for suspend and resume 2166 if len(proclist['sus']) > 0 o !! 1998 if len(proclist) > 0: 2167 sysvals.vprint('Proce 1999 sysvals.vprint('Process Execution:') 2168 for dir in ['sus', 'res']: !! 2000 for ps in proclist: 2169 for ps in sorted(proc !! 2001 c = self.addProcessUsageEvent(ps, tsus) 2170 self.addProce !! 2002 if c > 0: >> 2003 sysvals.vprint('%25s (sus): %d' % (ps, c)) >> 2004 c = self.addProcessUsageEvent(ps, tres) >> 2005 if c > 0: >> 2006 sysvals.vprint('%25s (res): %d' % (ps, c)) 2171 def handleEndMarker(self, time, msg=' 2007 def handleEndMarker(self, time, msg=''): 2172 dm = self.dmesg 2008 dm = self.dmesg 2173 self.setEnd(time, msg) 2009 self.setEnd(time, msg) 2174 self.initDevicegroups() 2010 self.initDevicegroups() 2175 # give suspend_prepare an end 2011 # give suspend_prepare an end if needed 2176 if 'suspend_prepare' in dm an 2012 if 'suspend_prepare' in dm and dm['suspend_prepare']['end'] < 0: 2177 dm['suspend_prepare'] 2013 dm['suspend_prepare']['end'] = time 2178 # assume resume machine ends 2014 # assume resume machine ends at next phase start 2179 if 'resume_machine' in dm and 2015 if 'resume_machine' in dm and dm['resume_machine']['end'] < 0: 2180 np = self.nextPhase(' 2016 np = self.nextPhase('resume_machine', 1) 2181 if np: 2017 if np: 2182 dm['resume_ma 2018 dm['resume_machine']['end'] = dm[np]['start'] 2183 # if kernel resume end not fo 2019 # if kernel resume end not found, assume its the end marker 2184 if self.tKernRes == 0.0: 2020 if self.tKernRes == 0.0: 2185 self.tKernRes = time 2021 self.tKernRes = time 2186 # if kernel suspend start not 2022 # if kernel suspend start not found, assume its the end marker 2187 if self.tKernSus == 0.0: 2023 if self.tKernSus == 0.0: 2188 self.tKernSus = time 2024 self.tKernSus = time 2189 # set resume complete to end 2025 # set resume complete to end at end marker 2190 if 'resume_complete' in dm: 2026 if 'resume_complete' in dm: 2191 dm['resume_complete'] 2027 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): 2028 def debugPrint(self): 2217 for p in self.sortedPhases(): 2029 for p in self.sortedPhases(): 2218 list = self.dmesg[p][ 2030 list = self.dmesg[p]['list'] 2219 for devname in sorted 2031 for devname in sorted(list): 2220 dev = list[de 2032 dev = list[devname] 2221 if 'ftrace' i 2033 if 'ftrace' in dev: 2222 dev[' 2034 dev['ftrace'].debugPrint(' [%s]' % devname) 2223 2035 2224 # Class: DevFunction 2036 # Class: DevFunction 2225 # Description: 2037 # Description: 2226 # A container for kprobe function data 2038 # A container for kprobe function data we want in the dev timeline 2227 class DevFunction: 2039 class DevFunction: 2228 def __init__(self, name, args, caller 2040 def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color): 2229 self.row = 0 2041 self.row = 0 2230 self.count = 1 2042 self.count = 1 2231 self.name = name 2043 self.name = name 2232 self.args = args 2044 self.args = args 2233 self.caller = caller 2045 self.caller = caller 2234 self.ret = ret 2046 self.ret = ret 2235 self.time = start 2047 self.time = start 2236 self.length = end - start 2048 self.length = end - start 2237 self.end = end 2049 self.end = end 2238 self.ubiquitous = u 2050 self.ubiquitous = u 2239 self.proc = proc 2051 self.proc = proc 2240 self.pid = pid 2052 self.pid = pid 2241 self.color = color 2053 self.color = color 2242 def title(self): 2054 def title(self): 2243 cnt = '' 2055 cnt = '' 2244 if self.count > 1: 2056 if self.count > 1: 2245 cnt = '(x%d)' % self. 2057 cnt = '(x%d)' % self.count 2246 l = '%0.3fms' % (self.length 2058 l = '%0.3fms' % (self.length * 1000) 2247 if self.ubiquitous: 2059 if self.ubiquitous: 2248 title = '%s(%s)%s <- 2060 title = '%s(%s)%s <- %s, %s(%s)' % \ 2249 (self.name, s 2061 (self.name, self.args, cnt, self.caller, self.ret, l) 2250 else: 2062 else: 2251 title = '%s(%s) %s%s( 2063 title = '%s(%s) %s%s(%s)' % (self.name, self.args, self.ret, cnt, l) 2252 return title.replace('"', '') 2064 return title.replace('"', '') 2253 def text(self): 2065 def text(self): 2254 if self.count > 1: 2066 if self.count > 1: 2255 text = '%s(x%d)' % (s 2067 text = '%s(x%d)' % (self.name, self.count) 2256 else: 2068 else: 2257 text = self.name 2069 text = self.name 2258 return text 2070 return text 2259 def repeat(self, tgt): 2071 def repeat(self, tgt): 2260 # is the tgt call just a repe 2072 # is the tgt call just a repeat of this call (e.g. are we in a loop) 2261 dt = self.time - tgt.end 2073 dt = self.time - tgt.end 2262 # only combine calls if -all- 2074 # only combine calls if -all- attributes are identical 2263 if tgt.caller == self.caller 2075 if tgt.caller == self.caller and \ 2264 tgt.name == self.name 2076 tgt.name == self.name and tgt.args == self.args and \ 2265 tgt.proc == self.proc 2077 tgt.proc == self.proc and tgt.pid == self.pid and \ 2266 tgt.ret == self.ret a 2078 tgt.ret == self.ret and dt >= 0 and \ 2267 dt <= sysvals.callloo 2079 dt <= sysvals.callloopmaxgap and \ 2268 self.length < sysvals 2080 self.length < sysvals.callloopmaxlen: 2269 return True 2081 return True 2270 return False 2082 return False 2271 2083 2272 # Class: FTraceLine 2084 # Class: FTraceLine 2273 # Description: 2085 # Description: 2274 # A container for a single line of ftr 2086 # A container for a single line of ftrace data. There are six basic types: 2275 # callgraph line: 2087 # callgraph line: 2276 # call: " dpm_run_ca 2088 # call: " dpm_run_callback() {" 2277 # return: " }" 2089 # return: " }" 2278 # leaf: " dpm_run_cal 2090 # leaf: " dpm_run_callback();" 2279 # trace event: 2091 # trace event: 2280 # tracing_mark_write: 2092 # tracing_mark_write: SUSPEND START or RESUME COMPLETE 2281 # suspend_resume: phas 2093 # suspend_resume: phase or custom exec block data 2282 # device_pm_callback: 2094 # device_pm_callback: device callback info 2283 class FTraceLine: 2095 class FTraceLine: 2284 def __init__(self, t, m='', d=''): 2096 def __init__(self, t, m='', d=''): 2285 self.length = 0.0 2097 self.length = 0.0 2286 self.fcall = False 2098 self.fcall = False 2287 self.freturn = False 2099 self.freturn = False 2288 self.fevent = False 2100 self.fevent = False 2289 self.fkprobe = False 2101 self.fkprobe = False 2290 self.depth = 0 2102 self.depth = 0 2291 self.name = '' 2103 self.name = '' 2292 self.type = '' 2104 self.type = '' 2293 self.time = float(t) 2105 self.time = float(t) 2294 if not m and not d: 2106 if not m and not d: 2295 return 2107 return 2296 # is this a trace event 2108 # is this a trace event 2297 if(d == 'traceevent' or re.ma !! 2109 if(d == 'traceevent' or re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m)): 2298 if(d == 'traceevent') 2110 if(d == 'traceevent'): 2299 # nop format 2111 # nop format trace event 2300 msg = m 2112 msg = m 2301 else: 2113 else: 2302 # function_gr 2114 # function_graph format trace event 2303 em = re.match !! 2115 em = re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m) 2304 msg = em.grou 2116 msg = em.group('msg') 2305 2117 2306 emm = re.match(r'^(?P !! 2118 emm = re.match('^(?P<call>.*?): (?P<msg>.*)', msg) 2307 if(emm): 2119 if(emm): 2308 self.name = e 2120 self.name = emm.group('msg') 2309 self.type = e 2121 self.type = emm.group('call') 2310 else: 2122 else: 2311 self.name = m 2123 self.name = msg 2312 km = re.match(r'^(?P< !! 2124 km = re.match('^(?P<n>.*)_cal$', self.type) 2313 if km: 2125 if km: 2314 self.fcall = 2126 self.fcall = True 2315 self.fkprobe 2127 self.fkprobe = True 2316 self.type = k 2128 self.type = km.group('n') 2317 return 2129 return 2318 km = re.match(r'^(?P< !! 2130 km = re.match('^(?P<n>.*)_ret$', self.type) 2319 if km: 2131 if km: 2320 self.freturn 2132 self.freturn = True 2321 self.fkprobe 2133 self.fkprobe = True 2322 self.type = k 2134 self.type = km.group('n') 2323 return 2135 return 2324 self.fevent = True 2136 self.fevent = True 2325 return 2137 return 2326 # convert the duration to sec 2138 # convert the duration to seconds 2327 if(d): 2139 if(d): 2328 self.length = float(d 2140 self.length = float(d)/1000000 2329 # the indentation determines 2141 # the indentation determines the depth 2330 match = re.match(r'^(?P<d> *) !! 2142 match = re.match('^(?P<d> *)(?P<o>.*)$', m) 2331 if(not match): 2143 if(not match): 2332 return 2144 return 2333 self.depth = self.getDepth(ma 2145 self.depth = self.getDepth(match.group('d')) 2334 m = match.group('o') 2146 m = match.group('o') 2335 # function return 2147 # function return 2336 if(m[0] == '}'): 2148 if(m[0] == '}'): 2337 self.freturn = True 2149 self.freturn = True 2338 if(len(m) > 1): 2150 if(len(m) > 1): 2339 # includes co 2151 # includes comment with function name 2340 match = re.ma !! 2152 match = re.match('^} *\/\* *(?P<n>.*) *\*\/$', m) 2341 if(match): 2153 if(match): 2342 self. 2154 self.name = match.group('n').strip() 2343 # function call 2155 # function call 2344 else: 2156 else: 2345 self.fcall = True 2157 self.fcall = True 2346 # function call with 2158 # function call with children 2347 if(m[-1] == '{'): 2159 if(m[-1] == '{'): 2348 match = re.ma !! 2160 match = re.match('^(?P<n>.*) *\(.*', m) 2349 if(match): 2161 if(match): 2350 self. 2162 self.name = match.group('n').strip() 2351 # function call with 2163 # function call with no children (leaf) 2352 elif(m[-1] == ';'): 2164 elif(m[-1] == ';'): 2353 self.freturn 2165 self.freturn = True 2354 match = re.ma !! 2166 match = re.match('^(?P<n>.*) *\(.*', m) 2355 if(match): 2167 if(match): 2356 self. 2168 self.name = match.group('n').strip() 2357 # something else (pos 2169 # something else (possibly a trace marker) 2358 else: 2170 else: 2359 self.name = m 2171 self.name = m 2360 def isCall(self): 2172 def isCall(self): 2361 return self.fcall and not sel 2173 return self.fcall and not self.freturn 2362 def isReturn(self): 2174 def isReturn(self): 2363 return self.freturn and not s 2175 return self.freturn and not self.fcall 2364 def isLeaf(self): 2176 def isLeaf(self): 2365 return self.fcall and self.fr 2177 return self.fcall and self.freturn 2366 def getDepth(self, str): 2178 def getDepth(self, str): 2367 return len(str)/2 2179 return len(str)/2 2368 def debugPrint(self, info=''): 2180 def debugPrint(self, info=''): 2369 if self.isLeaf(): 2181 if self.isLeaf(): 2370 pprint(' -- %12.6f (d 2182 pprint(' -- %12.6f (depth=%02d): %s(); (%.3f us) %s' % (self.time, \ 2371 self.depth, s 2183 self.depth, self.name, self.length*1000000, info)) 2372 elif self.freturn: 2184 elif self.freturn: 2373 pprint(' -- %12.6f (d 2185 pprint(' -- %12.6f (depth=%02d): %s} (%.3f us) %s' % (self.time, \ 2374 self.depth, s 2186 self.depth, self.name, self.length*1000000, info)) 2375 else: 2187 else: 2376 pprint(' -- %12.6f (d 2188 pprint(' -- %12.6f (depth=%02d): %s() { (%.3f us) %s' % (self.time, \ 2377 self.depth, s 2189 self.depth, self.name, self.length*1000000, info)) 2378 def startMarker(self): 2190 def startMarker(self): 2379 # Is this the starting line o 2191 # Is this the starting line of a suspend? 2380 if not self.fevent: 2192 if not self.fevent: 2381 return False 2193 return False 2382 if sysvals.usetracemarkers: 2194 if sysvals.usetracemarkers: 2383 if(self.name.startswi 2195 if(self.name.startswith('SUSPEND START')): 2384 return True 2196 return True 2385 return False 2197 return False 2386 else: 2198 else: 2387 if(self.type == 'susp 2199 if(self.type == 'suspend_resume' and 2388 re.match(r'su !! 2200 re.match('suspend_enter\[.*\] begin', self.name)): 2389 return True 2201 return True 2390 return False 2202 return False 2391 def endMarker(self): 2203 def endMarker(self): 2392 # Is this the ending line of 2204 # Is this the ending line of a resume? 2393 if not self.fevent: 2205 if not self.fevent: 2394 return False 2206 return False 2395 if sysvals.usetracemarkers: 2207 if sysvals.usetracemarkers: 2396 if(self.name.startswi 2208 if(self.name.startswith('RESUME COMPLETE')): 2397 return True 2209 return True 2398 return False 2210 return False 2399 else: 2211 else: 2400 if(self.type == 'susp 2212 if(self.type == 'suspend_resume' and 2401 re.match(r'th !! 2213 re.match('thaw_processes\[.*\] end', self.name)): 2402 return True 2214 return True 2403 return False 2215 return False 2404 2216 2405 # Class: FTraceCallGraph 2217 # Class: FTraceCallGraph 2406 # Description: 2218 # Description: 2407 # A container for the ftrace callgraph 2219 # A container for the ftrace callgraph of a single recursive function. 2408 # This can be a dpm_run_callback, dpm_ 2220 # This can be a dpm_run_callback, dpm_prepare, or dpm_complete callgraph 2409 # Each instance is tied to a single de 2221 # Each instance is tied to a single device in a single phase, and is 2410 # comprised of an ordered list of FTra 2222 # comprised of an ordered list of FTraceLine objects 2411 class FTraceCallGraph: 2223 class FTraceCallGraph: 2412 vfname = 'missing_function_name' 2224 vfname = 'missing_function_name' 2413 def __init__(self, pid, sv): 2225 def __init__(self, pid, sv): 2414 self.id = '' 2226 self.id = '' 2415 self.invalid = False 2227 self.invalid = False 2416 self.name = '' 2228 self.name = '' 2417 self.partial = False 2229 self.partial = False 2418 self.ignore = False 2230 self.ignore = False 2419 self.start = -1.0 2231 self.start = -1.0 2420 self.end = -1.0 2232 self.end = -1.0 2421 self.list = [] 2233 self.list = [] 2422 self.depth = 0 2234 self.depth = 0 2423 self.pid = pid 2235 self.pid = pid 2424 self.sv = sv 2236 self.sv = sv 2425 def addLine(self, line): 2237 def addLine(self, line): 2426 # if this is already invalid, 2238 # if this is already invalid, just leave 2427 if(self.invalid): 2239 if(self.invalid): 2428 if(line.depth == 0 an 2240 if(line.depth == 0 and line.freturn): 2429 return 1 2241 return 1 2430 return 0 2242 return 0 2431 # invalidate on bad depth 2243 # invalidate on bad depth 2432 if(self.depth < 0): 2244 if(self.depth < 0): 2433 self.invalidate(line) 2245 self.invalidate(line) 2434 return 0 2246 return 0 2435 # ignore data til we return t 2247 # ignore data til we return to the current depth 2436 if self.ignore: 2248 if self.ignore: 2437 if line.depth > self. 2249 if line.depth > self.depth: 2438 return 0 2250 return 0 2439 else: 2251 else: 2440 self.list[-1] 2252 self.list[-1].freturn = True 2441 self.list[-1] 2253 self.list[-1].length = line.time - self.list[-1].time 2442 self.ignore = 2254 self.ignore = False 2443 # if this is 2255 # if this is a return at self.depth, no more work is needed 2444 if line.depth 2256 if line.depth == self.depth and line.isReturn(): 2445 if li 2257 if line.depth == 0: 2446 2258 self.end = line.time 2447 2259 return 1 2448 retur 2260 return 0 2449 # compare current depth with 2261 # compare current depth with this lines pre-call depth 2450 prelinedep = line.depth 2262 prelinedep = line.depth 2451 if line.isReturn(): 2263 if line.isReturn(): 2452 prelinedep += 1 2264 prelinedep += 1 2453 last = 0 2265 last = 0 2454 lasttime = line.time 2266 lasttime = line.time 2455 if len(self.list) > 0: 2267 if len(self.list) > 0: 2456 last = self.list[-1] 2268 last = self.list[-1] 2457 lasttime = last.time 2269 lasttime = last.time 2458 if last.isLeaf(): 2270 if last.isLeaf(): 2459 lasttime += l 2271 lasttime += last.length 2460 # handle low misalignments by 2272 # handle low misalignments by inserting returns 2461 mismatch = prelinedep - self. 2273 mismatch = prelinedep - self.depth 2462 warning = self.sv.verbose and 2274 warning = self.sv.verbose and abs(mismatch) > 1 2463 info = [] 2275 info = [] 2464 if mismatch < 0: 2276 if mismatch < 0: 2465 idx = 0 2277 idx = 0 2466 # add return calls to 2278 # add return calls to get the depth down 2467 while prelinedep < se 2279 while prelinedep < self.depth: 2468 self.depth -= 2280 self.depth -= 1 2469 if idx == 0 a 2281 if idx == 0 and last and last.isCall(): 2470 # spe 2282 # special case, turn last call into a leaf 2471 last. 2283 last.depth = self.depth 2472 last. 2284 last.freturn = True 2473 last. 2285 last.length = line.time - last.time 2474 if wa 2286 if warning: 2475 2287 info.append(('[make leaf]', last)) 2476 else: 2288 else: 2477 vline 2289 vline = FTraceLine(lasttime) 2478 vline 2290 vline.depth = self.depth 2479 vline 2291 vline.name = self.vfname 2480 vline 2292 vline.freturn = True 2481 self. 2293 self.list.append(vline) 2482 if wa 2294 if warning: 2483 2295 if idx == 0: 2484 2296 info.append(('', last)) 2485 2297 info.append(('[add return]', vline)) 2486 idx += 1 2298 idx += 1 2487 if warning: 2299 if warning: 2488 info.append(( 2300 info.append(('', line)) 2489 # handle high misalignments b 2301 # handle high misalignments by inserting calls 2490 elif mismatch > 0: 2302 elif mismatch > 0: 2491 idx = 0 2303 idx = 0 2492 if warning: 2304 if warning: 2493 info.append(( 2305 info.append(('', last)) 2494 # add calls to get th 2306 # add calls to get the depth up 2495 while prelinedep > se 2307 while prelinedep > self.depth: 2496 if idx == 0 a 2308 if idx == 0 and line.isReturn(): 2497 # spe 2309 # special case, turn this return into a leaf 2498 line. 2310 line.fcall = True 2499 preli 2311 prelinedep -= 1 2500 if wa 2312 if warning: 2501 2313 info.append(('[make leaf]', line)) 2502 else: 2314 else: 2503 vline 2315 vline = FTraceLine(lasttime) 2504 vline 2316 vline.depth = self.depth 2505 vline 2317 vline.name = self.vfname 2506 vline 2318 vline.fcall = True 2507 self. 2319 self.list.append(vline) 2508 self. 2320 self.depth += 1 2509 if no 2321 if not last: 2510 2322 self.start = vline.time 2511 if wa 2323 if warning: 2512 2324 info.append(('[add call]', vline)) 2513 idx += 1 2325 idx += 1 2514 if warning and ('[mak 2326 if warning and ('[make leaf]', line) not in info: 2515 info.append(( 2327 info.append(('', line)) 2516 if warning: 2328 if warning: 2517 pprint('WARNING: ftra 2329 pprint('WARNING: ftrace data missing, corrections made:') 2518 for i in info: 2330 for i in info: 2519 t, obj = i 2331 t, obj = i 2520 if obj: 2332 if obj: 2521 obj.d 2333 obj.debugPrint(t) 2522 # process the call and set th 2334 # process the call and set the new depth 2523 skipadd = False 2335 skipadd = False 2524 md = self.sv.max_graph_depth 2336 md = self.sv.max_graph_depth 2525 if line.isCall(): 2337 if line.isCall(): 2526 # ignore blacklisted/ 2338 # ignore blacklisted/overdepth funcs 2527 if (md and self.depth 2339 if (md and self.depth >= md - 1) or (line.name in self.sv.cgblacklist): 2528 self.ignore = 2340 self.ignore = True 2529 else: 2341 else: 2530 self.depth += 2342 self.depth += 1 2531 elif line.isReturn(): 2343 elif line.isReturn(): 2532 self.depth -= 1 2344 self.depth -= 1 2533 # remove blacklisted/ 2345 # remove blacklisted/overdepth/empty funcs that slipped through 2534 if (last and last.isC 2346 if (last and last.isCall() and last.depth == line.depth) or \ 2535 (md and last 2347 (md and last and last.depth >= md) or \ 2536 (line.name in 2348 (line.name in self.sv.cgblacklist): 2537 while len(sel 2349 while len(self.list) > 0 and self.list[-1].depth > line.depth: 2538 self. 2350 self.list.pop(-1) 2539 if len(self.l 2351 if len(self.list) == 0: 2540 self. 2352 self.invalid = True 2541 retur 2353 return 1 2542 self.list[-1] 2354 self.list[-1].freturn = True 2543 self.list[-1] 2355 self.list[-1].length = line.time - self.list[-1].time 2544 self.list[-1] 2356 self.list[-1].name = line.name 2545 skipadd = Tru 2357 skipadd = True 2546 if len(self.list) < 1: 2358 if len(self.list) < 1: 2547 self.start = line.tim 2359 self.start = line.time 2548 # check for a mismatch that r 2360 # check for a mismatch that returned all the way to callgraph end 2549 res = 1 2361 res = 1 2550 if mismatch < 0 and self.list 2362 if mismatch < 0 and self.list[-1].depth == 0 and self.list[-1].freturn: 2551 line = self.list[-1] 2363 line = self.list[-1] 2552 skipadd = True 2364 skipadd = True 2553 res = -1 2365 res = -1 2554 if not skipadd: 2366 if not skipadd: 2555 self.list.append(line 2367 self.list.append(line) 2556 if(line.depth == 0 and line.f 2368 if(line.depth == 0 and line.freturn): 2557 if(self.start < 0): 2369 if(self.start < 0): 2558 self.start = 2370 self.start = line.time 2559 self.end = line.time 2371 self.end = line.time 2560 if line.fcall: 2372 if line.fcall: 2561 self.end += l 2373 self.end += line.length 2562 if self.list[0].name 2374 if self.list[0].name == self.vfname: 2563 self.invalid 2375 self.invalid = True 2564 if res == -1: 2376 if res == -1: 2565 self.partial 2377 self.partial = True 2566 return res 2378 return res 2567 return 0 2379 return 0 2568 def invalidate(self, line): 2380 def invalidate(self, line): 2569 if(len(self.list) > 0): 2381 if(len(self.list) > 0): 2570 first = self.list[0] 2382 first = self.list[0] 2571 self.list = [] 2383 self.list = [] 2572 self.list.append(firs 2384 self.list.append(first) 2573 self.invalid = True 2385 self.invalid = True 2574 id = 'task %s' % (self.pid) 2386 id = 'task %s' % (self.pid) 2575 window = '(%f - %f)' % (self. 2387 window = '(%f - %f)' % (self.start, line.time) 2576 if(self.depth < 0): 2388 if(self.depth < 0): 2577 pprint('Data misalign 2389 pprint('Data misalignment for '+id+\ 2578 ' (buffer ove 2390 ' (buffer overflow), ignoring this callback') 2579 else: 2391 else: 2580 pprint('Too much data 2392 pprint('Too much data for '+id+\ 2581 ' '+window+', 2393 ' '+window+', ignoring this callback') 2582 def slice(self, dev): 2394 def slice(self, dev): 2583 minicg = FTraceCallGraph(dev[ 2395 minicg = FTraceCallGraph(dev['pid'], self.sv) 2584 minicg.name = self.name 2396 minicg.name = self.name 2585 mydepth = -1 2397 mydepth = -1 2586 good = False 2398 good = False 2587 for l in self.list: 2399 for l in self.list: 2588 if(l.time < dev['star 2400 if(l.time < dev['start'] or l.time > dev['end']): 2589 continue 2401 continue 2590 if mydepth < 0: 2402 if mydepth < 0: 2591 if l.name == 2403 if l.name == 'mutex_lock' and l.freturn: 2592 mydep 2404 mydepth = l.depth 2593 continue 2405 continue 2594 elif l.depth == mydep 2406 elif l.depth == mydepth and l.name == 'mutex_unlock' and l.fcall: 2595 good = True 2407 good = True 2596 break 2408 break 2597 l.depth -= mydepth 2409 l.depth -= mydepth 2598 minicg.addLine(l) 2410 minicg.addLine(l) 2599 if not good or len(minicg.lis 2411 if not good or len(minicg.list) < 1: 2600 return 0 2412 return 0 2601 return minicg 2413 return minicg 2602 def repair(self, enddepth): 2414 def repair(self, enddepth): 2603 # bring the depth back to 0 w 2415 # bring the depth back to 0 with additional returns 2604 fixed = False 2416 fixed = False 2605 last = self.list[-1] 2417 last = self.list[-1] 2606 for i in reversed(range(endde 2418 for i in reversed(range(enddepth)): 2607 t = FTraceLine(last.t 2419 t = FTraceLine(last.time) 2608 t.depth = i 2420 t.depth = i 2609 t.freturn = True 2421 t.freturn = True 2610 fixed = self.addLine( 2422 fixed = self.addLine(t) 2611 if fixed != 0: 2423 if fixed != 0: 2612 self.end = la 2424 self.end = last.time 2613 return True 2425 return True 2614 return False 2426 return False 2615 def postProcess(self): 2427 def postProcess(self): 2616 if len(self.list) > 0: 2428 if len(self.list) > 0: 2617 self.name = self.list 2429 self.name = self.list[0].name 2618 stack = dict() 2430 stack = dict() 2619 cnt = 0 2431 cnt = 0 2620 last = 0 2432 last = 0 2621 for l in self.list: 2433 for l in self.list: 2622 # ftrace bug: reporte 2434 # ftrace bug: reported duration is not reliable 2623 # check each leaf and 2435 # check each leaf and clip it at max possible length 2624 if last and last.isLe 2436 if last and last.isLeaf(): 2625 if last.lengt 2437 if last.length > l.time - last.time: 2626 last. 2438 last.length = l.time - last.time 2627 if l.isCall(): 2439 if l.isCall(): 2628 stack[l.depth 2440 stack[l.depth] = l 2629 cnt += 1 2441 cnt += 1 2630 elif l.isReturn(): 2442 elif l.isReturn(): 2631 if(l.depth no 2443 if(l.depth not in stack): 2632 if se 2444 if self.sv.verbose: 2633 2445 pprint('Post Process Error: Depth missing') 2634 2446 l.debugPrint() 2635 retur 2447 return False 2636 # calculate c 2448 # calculate call length from call/return lines 2637 cl = stack[l. 2449 cl = stack[l.depth] 2638 cl.length = l 2450 cl.length = l.time - cl.time 2639 if cl.name == 2451 if cl.name == self.vfname: 2640 cl.na 2452 cl.name = l.name 2641 stack.pop(l.d 2453 stack.pop(l.depth) 2642 l.length = 0 2454 l.length = 0 2643 cnt -= 1 2455 cnt -= 1 2644 last = l 2456 last = l 2645 if(cnt == 0): 2457 if(cnt == 0): 2646 # trace caught the wh 2458 # trace caught the whole call tree 2647 return True 2459 return True 2648 elif(cnt < 0): 2460 elif(cnt < 0): 2649 if self.sv.verbose: 2461 if self.sv.verbose: 2650 pprint('Post 2462 pprint('Post Process Error: Depth is less than 0') 2651 return False 2463 return False 2652 # trace ended before call tre 2464 # trace ended before call tree finished 2653 return self.repair(cnt) 2465 return self.repair(cnt) 2654 def deviceMatch(self, pid, data): 2466 def deviceMatch(self, pid, data): 2655 found = '' 2467 found = '' 2656 # add the callgraph data to t 2468 # add the callgraph data to the device hierarchy 2657 borderphase = { 2469 borderphase = { 2658 'dpm_prepare': 'suspe 2470 'dpm_prepare': 'suspend_prepare', 2659 'dpm_complete': 'resu 2471 'dpm_complete': 'resume_complete' 2660 } 2472 } 2661 if(self.name in borderphase): 2473 if(self.name in borderphase): 2662 p = borderphase[self. 2474 p = borderphase[self.name] 2663 list = data.dmesg[p][ 2475 list = data.dmesg[p]['list'] 2664 for devname in list: 2476 for devname in list: 2665 dev = list[de 2477 dev = list[devname] 2666 if(pid == dev 2478 if(pid == dev['pid'] and 2667 self. 2479 self.start <= dev['start'] and 2668 self. 2480 self.end >= dev['end']): 2669 cg = 2481 cg = self.slice(dev) 2670 if cg 2482 if cg: 2671 2483 dev['ftrace'] = cg 2672 found 2484 found = devname 2673 return found 2485 return found 2674 for p in data.sortedPhases(): 2486 for p in data.sortedPhases(): 2675 if(data.dmesg[p]['sta 2487 if(data.dmesg[p]['start'] <= self.start and 2676 self.start <= 2488 self.start <= data.dmesg[p]['end']): 2677 list = data.d 2489 list = data.dmesg[p]['list'] 2678 for devname i 2490 for devname in sorted(list, key=lambda k:list[k]['start']): 2679 dev = 2491 dev = list[devname] 2680 if(pi 2492 if(pid == dev['pid'] and 2681 2493 self.start <= dev['start'] and 2682 2494 self.end >= dev['end']): 2683 2495 dev['ftrace'] = self 2684 2496 found = devname 2685 2497 break 2686 break 2498 break 2687 return found 2499 return found 2688 def newActionFromFunction(self, data) 2500 def newActionFromFunction(self, data): 2689 name = self.name 2501 name = self.name 2690 if name in ['dpm_run_callback 2502 if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']: 2691 return 2503 return 2692 fs = self.start 2504 fs = self.start 2693 fe = self.end 2505 fe = self.end 2694 if fs < data.start or fe > da 2506 if fs < data.start or fe > data.end: 2695 return 2507 return 2696 phase = '' 2508 phase = '' 2697 for p in data.sortedPhases(): 2509 for p in data.sortedPhases(): 2698 if(data.dmesg[p]['sta 2510 if(data.dmesg[p]['start'] <= self.start and 2699 self.start < 2511 self.start < data.dmesg[p]['end']): 2700 phase = p 2512 phase = p 2701 break 2513 break 2702 if not phase: 2514 if not phase: 2703 return 2515 return 2704 out = data.newActionGlobal(na 2516 out = data.newActionGlobal(name, fs, fe, -2) 2705 if out: 2517 if out: 2706 phase, myname = out 2518 phase, myname = out 2707 data.dmesg[phase]['li 2519 data.dmesg[phase]['list'][myname]['ftrace'] = self 2708 def debugPrint(self, info=''): 2520 def debugPrint(self, info=''): 2709 pprint('%s pid=%d [%f - %f] % 2521 pprint('%s pid=%d [%f - %f] %.3f us' % \ 2710 (self.name, self.pid, 2522 (self.name, self.pid, self.start, self.end, 2711 (self.end - self.star 2523 (self.end - self.start)*1000000)) 2712 for l in self.list: 2524 for l in self.list: 2713 if l.isLeaf(): 2525 if l.isLeaf(): 2714 pprint('%f (% 2526 pprint('%f (%02d): %s(); (%.3f us)%s' % (l.time, \ 2715 l.dep 2527 l.depth, l.name, l.length*1000000, info)) 2716 elif l.freturn: 2528 elif l.freturn: 2717 pprint('%f (% 2529 pprint('%f (%02d): %s} (%.3f us)%s' % (l.time, \ 2718 l.dep 2530 l.depth, l.name, l.length*1000000, info)) 2719 else: 2531 else: 2720 pprint('%f (% 2532 pprint('%f (%02d): %s() { (%.3f us)%s' % (l.time, \ 2721 l.dep 2533 l.depth, l.name, l.length*1000000, info)) 2722 pprint(' ') 2534 pprint(' ') 2723 2535 2724 class DevItem: 2536 class DevItem: 2725 def __init__(self, test, phase, dev): 2537 def __init__(self, test, phase, dev): 2726 self.test = test 2538 self.test = test 2727 self.phase = phase 2539 self.phase = phase 2728 self.dev = dev 2540 self.dev = dev 2729 def isa(self, cls): 2541 def isa(self, cls): 2730 if 'htmlclass' in self.dev an 2542 if 'htmlclass' in self.dev and cls in self.dev['htmlclass']: 2731 return True 2543 return True 2732 return False 2544 return False 2733 2545 2734 # Class: Timeline 2546 # Class: Timeline 2735 # Description: 2547 # Description: 2736 # A container for a device timeline wh 2548 # A container for a device timeline which calculates 2737 # all the html properties to display i 2549 # all the html properties to display it correctly 2738 class Timeline: 2550 class Timeline: 2739 html_tblock = '<div id="block{0}" cla 2551 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="{ 2552 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 2553 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= 2554 html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' 2743 html_legend = '<div id="p{3}" class=" 2555 html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' 2744 def __init__(self, rowheight, scalehe 2556 def __init__(self, rowheight, scaleheight): 2745 self.html = '' 2557 self.html = '' 2746 self.height = 0 # total time 2558 self.height = 0 # total timeline height 2747 self.scaleH = scaleheight # t 2559 self.scaleH = scaleheight # timescale (top) row height 2748 self.rowH = rowheight # d 2560 self.rowH = rowheight # device row height 2749 self.bodyH = 0 # body heigh 2561 self.bodyH = 0 # body height 2750 self.rows = 0 # total time 2562 self.rows = 0 # total timeline rows 2751 self.rowlines = dict() 2563 self.rowlines = dict() 2752 self.rowheight = dict() 2564 self.rowheight = dict() 2753 def createHeader(self, sv, stamp): 2565 def createHeader(self, sv, stamp): 2754 if(not stamp['time']): 2566 if(not stamp['time']): 2755 return 2567 return 2756 self.html += '<div class="ver 2568 self.html += '<div class="version"><a href="https://01.org/pm-graph">%s v%s</a></div>' \ 2757 % (sv.title, sv.versi 2569 % (sv.title, sv.version) 2758 if sv.logmsg and sv.testlog: 2570 if sv.logmsg and sv.testlog: 2759 self.html += '<button 2571 self.html += '<button id="showtest" class="logbtn btnfmt">log</button>' 2760 if sv.dmesglog: 2572 if sv.dmesglog: 2761 self.html += '<button 2573 self.html += '<button id="showdmesg" class="logbtn btnfmt">dmesg</button>' 2762 if sv.ftracelog: 2574 if sv.ftracelog: 2763 self.html += '<button 2575 self.html += '<button id="showftrace" class="logbtn btnfmt">ftrace</button>' 2764 headline_stamp = '<div class= 2576 headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' 2765 self.html += headline_stamp.f 2577 self.html += headline_stamp.format(stamp['host'], stamp['kernel'], 2766 stamp['mode'], stamp[ 2578 stamp['mode'], stamp['time']) 2767 if 'man' in stamp and 'plat' 2579 if 'man' in stamp and 'plat' in stamp and 'cpu' in stamp and \ 2768 stamp['man'] and stam 2580 stamp['man'] and stamp['plat'] and stamp['cpu']: 2769 headline_sysinfo = '< 2581 headline_sysinfo = '<div class="stamp sysinfo">{0} {1} <i>with</i> {2}</div>\n' 2770 self.html += headline 2582 self.html += headline_sysinfo.format(stamp['man'], stamp['plat'], stamp['cpu']) 2771 2583 2772 # Function: getDeviceRows 2584 # Function: getDeviceRows 2773 # Description: 2585 # Description: 2774 # determine how may rows the devic 2586 # determine how may rows the device funcs will take 2775 # Arguments: 2587 # Arguments: 2776 # rawlist: the list of devices 2588 # rawlist: the list of devices/actions for a single phase 2777 # Output: 2589 # Output: 2778 # The total number of rows nee 2590 # The total number of rows needed to display this phase of the timeline 2779 def getDeviceRows(self, rawlist): 2591 def getDeviceRows(self, rawlist): 2780 # clear all rows and set them 2592 # clear all rows and set them to undefined 2781 sortdict = dict() 2593 sortdict = dict() 2782 for item in rawlist: 2594 for item in rawlist: 2783 item.row = -1 2595 item.row = -1 2784 sortdict[item] = item 2596 sortdict[item] = item.length 2785 sortlist = sorted(sortdict, k 2597 sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 2786 remaining = len(sortlist) 2598 remaining = len(sortlist) 2787 rowdata = dict() 2599 rowdata = dict() 2788 row = 1 2600 row = 1 2789 # try to pack each row with a 2601 # try to pack each row with as many ranges as possible 2790 while(remaining > 0): 2602 while(remaining > 0): 2791 if(row not in rowdata 2603 if(row not in rowdata): 2792 rowdata[row] 2604 rowdata[row] = [] 2793 for i in sortlist: 2605 for i in sortlist: 2794 if(i.row >= 0 2606 if(i.row >= 0): 2795 conti 2607 continue 2796 s = i.time 2608 s = i.time 2797 e = i.time + 2609 e = i.time + i.length 2798 valid = True 2610 valid = True 2799 for ritem in 2611 for ritem in rowdata[row]: 2800 rs = 2612 rs = ritem.time 2801 re = 2613 re = ritem.time + ritem.length 2802 if(no 2614 if(not (((s <= rs) and (e <= rs)) or 2803 2615 ((s >= re) and (e >= re)))): 2804 2616 valid = False 2805 2617 break 2806 if(valid): 2618 if(valid): 2807 rowda 2619 rowdata[row].append(i) 2808 i.row 2620 i.row = row 2809 remai 2621 remaining -= 1 2810 row += 1 2622 row += 1 2811 return row 2623 return row 2812 # Function: getPhaseRows 2624 # Function: getPhaseRows 2813 # Description: 2625 # Description: 2814 # Organize the timeline entrie 2626 # Organize the timeline entries into the smallest 2815 # number of rows possible, wit 2627 # number of rows possible, with no entry overlapping 2816 # Arguments: 2628 # Arguments: 2817 # devlist: the list of devices 2629 # devlist: the list of devices/actions in a group of contiguous phases 2818 # Output: 2630 # Output: 2819 # The total number of rows nee 2631 # The total number of rows needed to display this phase of the timeline 2820 def getPhaseRows(self, devlist, row=0 2632 def getPhaseRows(self, devlist, row=0, sortby='length'): 2821 # clear all rows and set them 2633 # clear all rows and set them to undefined 2822 remaining = len(devlist) 2634 remaining = len(devlist) 2823 rowdata = dict() 2635 rowdata = dict() 2824 sortdict = dict() 2636 sortdict = dict() 2825 myphases = [] 2637 myphases = [] 2826 # initialize all device rows 2638 # initialize all device rows to -1 and calculate devrows 2827 for item in devlist: 2639 for item in devlist: 2828 dev = item.dev 2640 dev = item.dev 2829 tp = (item.test, item 2641 tp = (item.test, item.phase) 2830 if tp not in myphases 2642 if tp not in myphases: 2831 myphases.appe 2643 myphases.append(tp) 2832 dev['row'] = -1 2644 dev['row'] = -1 2833 if sortby == 'start': 2645 if sortby == 'start': 2834 # sort by sta 2646 # sort by start 1st, then length 2nd 2835 sortdict[item 2647 sortdict[item] = (-1*float(dev['start']), float(dev['end']) - float(dev['start'])) 2836 else: 2648 else: 2837 # sort by len 2649 # sort by length 1st, then name 2nd 2838 sortdict[item 2650 sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) 2839 if 'src' in dev: 2651 if 'src' in dev: 2840 dev['devrows' 2652 dev['devrows'] = self.getDeviceRows(dev['src']) 2841 # sort the devlist by length 2653 # sort the devlist by length so that large items graph on top 2842 sortlist = sorted(sortdict, k 2654 sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 2843 orderedlist = [] 2655 orderedlist = [] 2844 for item in sortlist: 2656 for item in sortlist: 2845 if item.dev['pid'] == 2657 if item.dev['pid'] == -2: 2846 orderedlist.a 2658 orderedlist.append(item) 2847 for item in sortlist: 2659 for item in sortlist: 2848 if item not in ordere 2660 if item not in orderedlist: 2849 orderedlist.a 2661 orderedlist.append(item) 2850 # try to pack each row with a 2662 # try to pack each row with as many devices as possible 2851 while(remaining > 0): 2663 while(remaining > 0): 2852 rowheight = 1 2664 rowheight = 1 2853 if(row not in rowdata 2665 if(row not in rowdata): 2854 rowdata[row] 2666 rowdata[row] = [] 2855 for item in orderedli 2667 for item in orderedlist: 2856 dev = item.de 2668 dev = item.dev 2857 if(dev['row'] 2669 if(dev['row'] < 0): 2858 s = d 2670 s = dev['start'] 2859 e = d 2671 e = dev['end'] 2860 valid 2672 valid = True 2861 for r 2673 for ritem in rowdata[row]: 2862 2674 rs = ritem.dev['start'] 2863 2675 re = ritem.dev['end'] 2864 2676 if(not (((s <= rs) and (e <= rs)) or 2865 2677 ((s >= re) and (e >= re)))): 2866 2678 valid = False 2867 2679 break 2868 if(va 2680 if(valid): 2869 2681 rowdata[row].append(item) 2870 2682 dev['row'] = row 2871 2683 remaining -= 1 2872 2684 if 'devrows' in dev and dev['devrows'] > rowheight: 2873 2685 rowheight = dev['devrows'] 2874 for t, p in myphases: 2686 for t, p in myphases: 2875 if t not in s 2687 if t not in self.rowlines or t not in self.rowheight: 2876 self. 2688 self.rowlines[t] = dict() 2877 self. 2689 self.rowheight[t] = dict() 2878 if p not in s 2690 if p not in self.rowlines[t] or p not in self.rowheight[t]: 2879 self. 2691 self.rowlines[t][p] = dict() 2880 self. 2692 self.rowheight[t][p] = dict() 2881 rh = self.row 2693 rh = self.rowH 2882 # section hea 2694 # section headers should use a different row height 2883 if len(rowdat 2695 if len(rowdata[row]) == 1 and \ 2884 'html 2696 'htmlclass' in rowdata[row][0].dev and \ 2885 'sec' 2697 'sec' in rowdata[row][0].dev['htmlclass']: 2886 rh = 2698 rh = 15 2887 self.rowlines 2699 self.rowlines[t][p][row] = rowheight 2888 self.rowheigh 2700 self.rowheight[t][p][row] = rowheight * rh 2889 row += 1 2701 row += 1 2890 if(row > self.rows): 2702 if(row > self.rows): 2891 self.rows = int(row) 2703 self.rows = int(row) 2892 return row 2704 return row 2893 def phaseRowHeight(self, test, phase, 2705 def phaseRowHeight(self, test, phase, row): 2894 return self.rowheight[test][p 2706 return self.rowheight[test][phase][row] 2895 def phaseRowTop(self, test, phase, ro 2707 def phaseRowTop(self, test, phase, row): 2896 top = 0 2708 top = 0 2897 for i in sorted(self.rowheigh 2709 for i in sorted(self.rowheight[test][phase]): 2898 if i >= row: 2710 if i >= row: 2899 break 2711 break 2900 top += self.rowheight 2712 top += self.rowheight[test][phase][i] 2901 return top 2713 return top 2902 def calcTotalRows(self): 2714 def calcTotalRows(self): 2903 # Calculate the heights and o 2715 # Calculate the heights and offsets for the header and rows 2904 maxrows = 0 2716 maxrows = 0 2905 standardphases = [] 2717 standardphases = [] 2906 for t in self.rowlines: 2718 for t in self.rowlines: 2907 for p in self.rowline 2719 for p in self.rowlines[t]: 2908 total = 0 2720 total = 0 2909 for i in sort 2721 for i in sorted(self.rowlines[t][p]): 2910 total 2722 total += self.rowlines[t][p][i] 2911 if total > ma 2723 if total > maxrows: 2912 maxro 2724 maxrows = total 2913 if total == l 2725 if total == len(self.rowlines[t][p]): 2914 stand 2726 standardphases.append((t, p)) 2915 self.height = self.scaleH + ( 2727 self.height = self.scaleH + (maxrows*self.rowH) 2916 self.bodyH = self.height - se 2728 self.bodyH = self.height - self.scaleH 2917 # if there is 1 line per row, 2729 # if there is 1 line per row, draw them the standard way 2918 for t, p in standardphases: 2730 for t, p in standardphases: 2919 for i in sorted(self. 2731 for i in sorted(self.rowheight[t][p]): 2920 self.rowheigh 2732 self.rowheight[t][p][i] = float(self.bodyH)/len(self.rowlines[t][p]) 2921 def createZoomBox(self, mode='command 2733 def createZoomBox(self, mode='command', testcount=1): 2922 # Create bounding box, add bu 2734 # Create bounding box, add buttons 2923 html_zoombox = '<center><butt 2735 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 2736 html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' 2925 html_devlist1 = '<button id=" 2737 html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail{0}</button>' 2926 html_devlist2 = '<button id=" 2738 html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' 2927 if mode != 'command': 2739 if mode != 'command': 2928 if testcount > 1: 2740 if testcount > 1: 2929 self.html += 2741 self.html += html_devlist2 2930 self.html += 2742 self.html += html_devlist1.format('1') 2931 else: 2743 else: 2932 self.html += 2744 self.html += html_devlist1.format('') 2933 self.html += html_zoombox 2745 self.html += html_zoombox 2934 self.html += html_timeline.fo 2746 self.html += html_timeline.format('dmesg', self.height) 2935 # Function: createTimeScale 2747 # Function: createTimeScale 2936 # Description: 2748 # Description: 2937 # Create the timescale for a t 2749 # Create the timescale for a timeline block 2938 # Arguments: 2750 # Arguments: 2939 # m0: start time (mode begin) 2751 # m0: start time (mode begin) 2940 # mMax: end time (mode end) 2752 # mMax: end time (mode end) 2941 # tTotal: total timeline time 2753 # tTotal: total timeline time 2942 # mode: suspend or resume 2754 # mode: suspend or resume 2943 # Output: 2755 # Output: 2944 # The html code needed to disp 2756 # The html code needed to display the time scale 2945 def createTimeScale(self, m0, mMax, t 2757 def createTimeScale(self, m0, mMax, tTotal, mode): 2946 timescale = '<div class="t" s 2758 timescale = '<div class="t" style="right:{0}%">{1}</div>\n' 2947 rline = '<div class="t" style 2759 rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">{0}</div>\n' 2948 output = '<div class="timesca 2760 output = '<div class="timescale">\n' 2949 # set scale for timeline 2761 # set scale for timeline 2950 mTotal = mMax - m0 2762 mTotal = mMax - m0 2951 tS = 0.1 2763 tS = 0.1 2952 if(tTotal <= 0): 2764 if(tTotal <= 0): 2953 return output+'</div> 2765 return output+'</div>\n' 2954 if(tTotal > 4): 2766 if(tTotal > 4): 2955 tS = 1 2767 tS = 1 2956 divTotal = int(mTotal/tS) + 1 2768 divTotal = int(mTotal/tS) + 1 2957 divEdge = (mTotal - tS*(divTo 2769 divEdge = (mTotal - tS*(divTotal-1))*100/mTotal 2958 for i in range(divTotal): 2770 for i in range(divTotal): 2959 htmlline = '' 2771 htmlline = '' 2960 if(mode == 'suspend') 2772 if(mode == 'suspend'): 2961 pos = '%0.3f' 2773 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge) 2962 val = '%0.fms 2774 val = '%0.fms' % (float(i-divTotal+1)*tS*1000) 2963 if(i == divTo 2775 if(i == divTotal - 1): 2964 val = 2776 val = mode 2965 htmlline = ti 2777 htmlline = timescale.format(pos, val) 2966 else: 2778 else: 2967 pos = '%0.3f' 2779 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal)) 2968 val = '%0.fms 2780 val = '%0.fms' % (float(i)*tS*1000) 2969 htmlline = ti 2781 htmlline = timescale.format(pos, val) 2970 if(i == 0): 2782 if(i == 0): 2971 htmll 2783 htmlline = rline.format(mode) 2972 output += htmlline 2784 output += htmlline 2973 self.html += output+'</div>\n 2785 self.html += output+'</div>\n' 2974 2786 2975 # Class: TestProps 2787 # Class: TestProps 2976 # Description: 2788 # Description: 2977 # A list of values describing the prop 2789 # A list of values describing the properties of these test runs 2978 class TestProps: 2790 class TestProps: 2979 stampfmt = r'# [a-z]*-(?P<m>[0-9]{2}) !! 2791 stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ 2980 r'(?P<H>[0-9] !! 2792 '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ 2981 r' (?P<host>. !! 2793 ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' 2982 wififmt = r'^# wifi *(?P<d>\S*) *( !! 2794 wififmt = '^# wifi *(?P<d>\S*) *(?P<s>\S*) *(?P<t>[0-9\.]+).*' 2983 tstatfmt = r'^# turbostat (?P<t>\S* !! 2795 tstatfmt = '^# turbostat (?P<t>\S*)' 2984 testerrfmt = r'^# enter_sleep_error ( !! 2796 testerrfmt = '^# enter_sleep_error (?P<e>.*)' 2985 sysinfofmt = r'^# sysinfo .*' !! 2797 sysinfofmt = '^# sysinfo .*' 2986 cmdlinefmt = r'^# command \| (?P<cmd> !! 2798 cmdlinefmt = '^# command \| (?P<cmd>.*)' 2987 kparamsfmt = r'^# kparams \| (?P<kp>. !! 2799 kparamsfmt = '^# kparams \| (?P<kp>.*)' 2988 devpropfmt = r'# Device Properties: . !! 2800 devpropfmt = '# Device Properties: .*' 2989 pinfofmt = r'# platform-(?P<val>[a- !! 2801 pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)' 2990 tracertypefmt = r'# tracer: (?P<t>.*) !! 2802 tracertypefmt = '# tracer: (?P<t>.*)' 2991 firmwarefmt = r'# fwsuspend (?P<s>[0- !! 2803 firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' 2992 procexecfmt = r'ps - (?P<ps>.*)$' !! 2804 procexecfmt = 'ps - (?P<ps>.*)$' 2993 procmultifmt = r'@(?P<n>[0-9]*)\|(?P< << 2994 ftrace_line_fmt_fg = \ 2805 ftrace_line_fmt_fg = \ 2995 r'^ *(?P<time>[0-9\.]*) *\| * !! 2806 '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ 2996 r' *(?P<proc>.*)-(?P<pid>[0-9 !! 2807 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ 2997 r'[ +!#\*@$]*(?P<dur>[0-9\.]* !! 2808 '[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)' 2998 ftrace_line_fmt_nop = \ 2809 ftrace_line_fmt_nop = \ 2999 r' *(?P<proc>.*)-(?P<pid>[0-9 !! 2810 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\ 3000 r'(?P<flags>\S*) *(?P<time>[0 !! 2811 '(?P<flags>\S*) *(?P<time>[0-9\.]*): *'+\ 3001 r'(?P<msg>.*)' !! 2812 '(?P<msg>.*)' 3002 machinesuspend = r'machine_suspend\[. !! 2813 machinesuspend = 'machine_suspend\[.*' 3003 multiproclist = dict() << 3004 multiproctime = 0.0 << 3005 multiproccnt = 0 << 3006 def __init__(self): 2814 def __init__(self): 3007 self.stamp = '' 2815 self.stamp = '' 3008 self.sysinfo = '' 2816 self.sysinfo = '' 3009 self.cmdline = '' 2817 self.cmdline = '' 3010 self.testerror = [] 2818 self.testerror = [] 3011 self.turbostat = [] 2819 self.turbostat = [] 3012 self.wifi = [] 2820 self.wifi = [] 3013 self.fwdata = [] 2821 self.fwdata = [] 3014 self.ftrace_line_fmt = self.f 2822 self.ftrace_line_fmt = self.ftrace_line_fmt_nop 3015 self.cgformat = False 2823 self.cgformat = False 3016 self.data = 0 2824 self.data = 0 3017 self.ktemp = dict() 2825 self.ktemp = dict() 3018 def setTracerType(self, tracer): 2826 def setTracerType(self, tracer): 3019 if(tracer == 'function_graph' 2827 if(tracer == 'function_graph'): 3020 self.cgformat = True 2828 self.cgformat = True 3021 self.ftrace_line_fmt 2829 self.ftrace_line_fmt = self.ftrace_line_fmt_fg 3022 elif(tracer == 'nop'): 2830 elif(tracer == 'nop'): 3023 self.ftrace_line_fmt 2831 self.ftrace_line_fmt = self.ftrace_line_fmt_nop 3024 else: 2832 else: 3025 doError('Invalid trac 2833 doError('Invalid tracer format: [%s]' % tracer) 3026 def stampInfo(self, line, sv): 2834 def stampInfo(self, line, sv): 3027 if re.match(self.stampfmt, li 2835 if re.match(self.stampfmt, line): 3028 self.stamp = line 2836 self.stamp = line 3029 return True 2837 return True 3030 elif re.match(self.sysinfofmt 2838 elif re.match(self.sysinfofmt, line): 3031 self.sysinfo = line 2839 self.sysinfo = line 3032 return True 2840 return True 3033 elif re.match(self.tstatfmt, 2841 elif re.match(self.tstatfmt, line): 3034 self.turbostat.append 2842 self.turbostat.append(line) 3035 return True 2843 return True 3036 elif re.match(self.wififmt, l 2844 elif re.match(self.wififmt, line): 3037 self.wifi.append(line 2845 self.wifi.append(line) 3038 return True 2846 return True 3039 elif re.match(self.testerrfmt 2847 elif re.match(self.testerrfmt, line): 3040 self.testerror.append 2848 self.testerror.append(line) 3041 return True 2849 return True 3042 elif re.match(self.firmwarefm 2850 elif re.match(self.firmwarefmt, line): 3043 self.fwdata.append(li 2851 self.fwdata.append(line) 3044 return True 2852 return True 3045 elif(re.match(self.devpropfmt 2853 elif(re.match(self.devpropfmt, line)): 3046 self.parseDevprops(li 2854 self.parseDevprops(line, sv) 3047 return True 2855 return True 3048 elif(re.match(self.pinfofmt, 2856 elif(re.match(self.pinfofmt, line)): 3049 self.parsePlatformInf 2857 self.parsePlatformInfo(line, sv) 3050 return True 2858 return True 3051 m = re.match(self.cmdlinefmt, 2859 m = re.match(self.cmdlinefmt, line) 3052 if m: 2860 if m: 3053 self.cmdline = m.grou 2861 self.cmdline = m.group('cmd') 3054 return True 2862 return True 3055 m = re.match(self.tracertypef 2863 m = re.match(self.tracertypefmt, line) 3056 if(m): 2864 if(m): 3057 self.setTracerType(m. 2865 self.setTracerType(m.group('t')) 3058 return True 2866 return True 3059 return False 2867 return False 3060 def parseStamp(self, data, sv): 2868 def parseStamp(self, data, sv): 3061 # global test data 2869 # global test data 3062 m = re.match(self.stampfmt, s 2870 m = re.match(self.stampfmt, self.stamp) 3063 if not self.stamp or not m: 2871 if not self.stamp or not m: 3064 doError('data does no 2872 doError('data does not include the expected stamp') 3065 data.stamp = {'time': '', 'ho 2873 data.stamp = {'time': '', 'host': '', 'mode': ''} 3066 dt = datetime(int(m.group('y' 2874 dt = datetime(int(m.group('y'))+2000, int(m.group('m')), 3067 int(m.group('d')), in 2875 int(m.group('d')), int(m.group('H')), int(m.group('M')), 3068 int(m.group('S'))) 2876 int(m.group('S'))) 3069 data.stamp['time'] = dt.strft 2877 data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') 3070 data.stamp['host'] = m.group( 2878 data.stamp['host'] = m.group('host') 3071 data.stamp['mode'] = m.group( 2879 data.stamp['mode'] = m.group('mode') 3072 data.stamp['kernel'] = m.grou 2880 data.stamp['kernel'] = m.group('kernel') 3073 if re.match(self.sysinfofmt, 2881 if re.match(self.sysinfofmt, self.sysinfo): 3074 for f in self.sysinfo 2882 for f in self.sysinfo.split('|'): 3075 if '#' in f: 2883 if '#' in f: 3076 conti 2884 continue 3077 tmp = f.strip 2885 tmp = f.strip().split(':', 1) 3078 key = tmp[0] 2886 key = tmp[0] 3079 val = tmp[1] 2887 val = tmp[1] 3080 data.stamp[ke 2888 data.stamp[key] = val 3081 sv.hostname = data.stamp['hos 2889 sv.hostname = data.stamp['host'] 3082 sv.suspendmode = data.stamp[' 2890 sv.suspendmode = data.stamp['mode'] 3083 if sv.suspendmode == 'freeze' 2891 if sv.suspendmode == 'freeze': 3084 self.machinesuspend = !! 2892 self.machinesuspend = 'timekeeping_freeze\[.*' 3085 else: 2893 else: 3086 self.machinesuspend = !! 2894 self.machinesuspend = 'machine_suspend\[.*' 3087 if sv.suspendmode == 'command 2895 if sv.suspendmode == 'command' and sv.ftracefile != '': 3088 modes = ['on', 'freez 2896 modes = ['on', 'freeze', 'standby', 'mem', 'disk'] 3089 fp = sv.openlog(sv.ft 2897 fp = sv.openlog(sv.ftracefile, 'r') 3090 for line in fp: 2898 for line in fp: 3091 m = re.match( !! 2899 m = re.match('.* machine_suspend\[(?P<mode>.*)\]', line) 3092 if m and m.gr 2900 if m and m.group('mode') in ['1', '2', '3', '4']: 3093 sv.su 2901 sv.suspendmode = modes[int(m.group('mode'))] 3094 data. 2902 data.stamp['mode'] = sv.suspendmode 3095 break 2903 break 3096 fp.close() 2904 fp.close() 3097 sv.cmdline = self.cmdline 2905 sv.cmdline = self.cmdline 3098 if not sv.stamp: 2906 if not sv.stamp: 3099 sv.stamp = data.stamp 2907 sv.stamp = data.stamp 3100 # firmware data 2908 # firmware data 3101 if sv.suspendmode == 'mem' an 2909 if sv.suspendmode == 'mem' and len(self.fwdata) > data.testnumber: 3102 m = re.match(self.fir 2910 m = re.match(self.firmwarefmt, self.fwdata[data.testnumber]) 3103 if m: 2911 if m: 3104 data.fwSuspen 2912 data.fwSuspend, data.fwResume = int(m.group('s')), int(m.group('r')) 3105 if(data.fwSus 2913 if(data.fwSuspend > 0 or data.fwResume > 0): 3106 data. 2914 data.fwValid = True 3107 # turbostat data 2915 # turbostat data 3108 if len(self.turbostat) > data 2916 if len(self.turbostat) > data.testnumber: 3109 m = re.match(self.tst 2917 m = re.match(self.tstatfmt, self.turbostat[data.testnumber]) 3110 if m: 2918 if m: 3111 data.turbosta 2919 data.turbostat = m.group('t') 3112 # wifi data 2920 # wifi data 3113 if len(self.wifi) > data.test 2921 if len(self.wifi) > data.testnumber: 3114 m = re.match(self.wif 2922 m = re.match(self.wififmt, self.wifi[data.testnumber]) 3115 if m: 2923 if m: 3116 data.wifi = { 2924 data.wifi = {'dev': m.group('d'), 'stat': m.group('s'), 3117 'time 2925 'time': float(m.group('t'))} 3118 data.stamp['w 2926 data.stamp['wifi'] = m.group('d') 3119 # sleep mode enter errors 2927 # sleep mode enter errors 3120 if len(self.testerror) > data 2928 if len(self.testerror) > data.testnumber: 3121 m = re.match(self.tes 2929 m = re.match(self.testerrfmt, self.testerror[data.testnumber]) 3122 if m: 2930 if m: 3123 data.enterfai 2931 data.enterfail = m.group('e') 3124 def devprops(self, data): 2932 def devprops(self, data): 3125 props = dict() 2933 props = dict() 3126 devlist = data.split(';') 2934 devlist = data.split(';') 3127 for dev in devlist: 2935 for dev in devlist: 3128 f = dev.split(',') 2936 f = dev.split(',') 3129 if len(f) < 3: 2937 if len(f) < 3: 3130 continue 2938 continue 3131 dev = f[0] 2939 dev = f[0] 3132 props[dev] = DevProps 2940 props[dev] = DevProps() 3133 props[dev].altname = 2941 props[dev].altname = f[1] 3134 if int(f[2]): 2942 if int(f[2]): 3135 props[dev].is 2943 props[dev].isasync = True 3136 else: 2944 else: 3137 props[dev].is 2945 props[dev].isasync = False 3138 return props 2946 return props 3139 def parseDevprops(self, line, sv): 2947 def parseDevprops(self, line, sv): 3140 idx = line.index(': ') + 2 2948 idx = line.index(': ') + 2 3141 if idx >= len(line): 2949 if idx >= len(line): 3142 return 2950 return 3143 props = self.devprops(line[id 2951 props = self.devprops(line[idx:]) 3144 if sv.suspendmode == 'command 2952 if sv.suspendmode == 'command' and 'testcommandstring' in props: 3145 sv.testcommand = prop 2953 sv.testcommand = props['testcommandstring'].altname 3146 sv.devprops = props 2954 sv.devprops = props 3147 def parsePlatformInfo(self, line, sv) 2955 def parsePlatformInfo(self, line, sv): 3148 m = re.match(self.pinfofmt, l 2956 m = re.match(self.pinfofmt, line) 3149 if not m: 2957 if not m: 3150 return 2958 return 3151 name, info = m.group('val'), 2959 name, info = m.group('val'), m.group('info') 3152 if name == 'devinfo': 2960 if name == 'devinfo': 3153 sv.devprops = self.de 2961 sv.devprops = self.devprops(sv.b64unzip(info)) 3154 return 2962 return 3155 elif name == 'testcmd': 2963 elif name == 'testcmd': 3156 sv.testcommand = info 2964 sv.testcommand = info 3157 return 2965 return 3158 field = info.split('|') 2966 field = info.split('|') 3159 if len(field) < 2: 2967 if len(field) < 2: 3160 return 2968 return 3161 cmdline = field[0].strip() 2969 cmdline = field[0].strip() 3162 output = sv.b64unzip(field[1] 2970 output = sv.b64unzip(field[1].strip()) 3163 sv.platinfo.append([name, cmd 2971 sv.platinfo.append([name, cmdline, output]) 3164 2972 3165 # Class: TestRun 2973 # Class: TestRun 3166 # Description: 2974 # Description: 3167 # A container for a suspend/resume tes 2975 # A container for a suspend/resume test run. This is necessary as 3168 # there could be more than one, and th 2976 # there could be more than one, and they need to be separate. 3169 class TestRun: 2977 class TestRun: 3170 def __init__(self, dataobj): 2978 def __init__(self, dataobj): 3171 self.data = dataobj 2979 self.data = dataobj 3172 self.ftemp = dict() 2980 self.ftemp = dict() 3173 self.ttemp = dict() 2981 self.ttemp = dict() 3174 2982 3175 class ProcessMonitor: 2983 class ProcessMonitor: 3176 maxchars = 512 << 3177 def __init__(self): 2984 def __init__(self): 3178 self.proclist = dict() 2985 self.proclist = dict() 3179 self.running = False 2986 self.running = False 3180 def procstat(self): 2987 def procstat(self): 3181 c = ['cat /proc/[1-9]*/stat 2 2988 c = ['cat /proc/[1-9]*/stat 2>/dev/null'] 3182 process = Popen(c, shell=True 2989 process = Popen(c, shell=True, stdout=PIPE) 3183 running = dict() 2990 running = dict() 3184 for line in process.stdout: 2991 for line in process.stdout: 3185 data = ascii(line).sp 2992 data = ascii(line).split() 3186 pid = data[0] 2993 pid = data[0] 3187 name = re.sub('[()]', 2994 name = re.sub('[()]', '', data[1]) 3188 user = int(data[13]) 2995 user = int(data[13]) 3189 kern = int(data[14]) 2996 kern = int(data[14]) 3190 kjiff = ujiff = 0 2997 kjiff = ujiff = 0 3191 if pid not in self.pr 2998 if pid not in self.proclist: 3192 self.proclist 2999 self.proclist[pid] = {'name' : name, 'user' : user, 'kern' : kern} 3193 else: 3000 else: 3194 val = self.pr 3001 val = self.proclist[pid] 3195 ujiff = user 3002 ujiff = user - val['user'] 3196 kjiff = kern 3003 kjiff = kern - val['kern'] 3197 val['user'] = 3004 val['user'] = user 3198 val['kern'] = 3005 val['kern'] = kern 3199 if ujiff > 0 or kjiff 3006 if ujiff > 0 or kjiff > 0: 3200 running[pid] 3007 running[pid] = ujiff + kjiff 3201 process.wait() 3008 process.wait() 3202 out = [''] !! 3009 out = '' 3203 for pid in running: 3010 for pid in running: 3204 jiffies = running[pid 3011 jiffies = running[pid] 3205 val = self.proclist[p 3012 val = self.proclist[pid] 3206 if len(out[-1]) > sel !! 3013 if out: 3207 out.append('' !! 3014 out += ',' 3208 elif len(out[-1]) > 0 !! 3015 out += '%s-%s %d' % (val['name'], pid, jiffies) 3209 out[-1] += ', !! 3016 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): 3017 def processMonitor(self, tid): 3217 while self.running: 3018 while self.running: 3218 self.procstat() !! 3019 out = self.procstat() >> 3020 if out: >> 3021 sysvals.fsetVal(out, 'trace_marker') 3219 def start(self): 3022 def start(self): 3220 self.thread = Thread(target=s 3023 self.thread = Thread(target=self.processMonitor, args=(0,)) 3221 self.running = True 3024 self.running = True 3222 self.thread.start() 3025 self.thread.start() 3223 def stop(self): 3026 def stop(self): 3224 self.running = False 3027 self.running = False 3225 3028 3226 # ----------------- FUNCTIONS --------------- 3029 # ----------------- FUNCTIONS -------------------- 3227 3030 3228 # Function: doesTraceLogHaveTraceEvents 3031 # Function: doesTraceLogHaveTraceEvents 3229 # Description: 3032 # Description: 3230 # Quickly determine if the ftrace log 3033 # Quickly determine if the ftrace log has all of the trace events, 3231 # markers, and/or kprobes required for 3034 # markers, and/or kprobes required for primary parsing. 3232 def doesTraceLogHaveTraceEvents(): 3035 def doesTraceLogHaveTraceEvents(): 3233 kpcheck = ['_cal: (', '_ret: ('] 3036 kpcheck = ['_cal: (', '_ret: ('] 3234 techeck = ['suspend_resume', 'device_ !! 3037 techeck = ['suspend_resume', 'device_pm_callback'] 3235 tmcheck = ['SUSPEND START', 'RESUME C 3038 tmcheck = ['SUSPEND START', 'RESUME COMPLETE'] 3236 sysvals.usekprobes = False 3039 sysvals.usekprobes = False 3237 fp = sysvals.openlog(sysvals.ftracefi 3040 fp = sysvals.openlog(sysvals.ftracefile, 'r') 3238 for line in fp: 3041 for line in fp: 3239 # check for kprobes 3042 # check for kprobes 3240 if not sysvals.usekprobes: 3043 if not sysvals.usekprobes: 3241 for i in kpcheck: 3044 for i in kpcheck: 3242 if i in line: 3045 if i in line: 3243 sysva 3046 sysvals.usekprobes = True 3244 # check for all necessary tra 3047 # check for all necessary trace events 3245 check = techeck[:] 3048 check = techeck[:] 3246 for i in techeck: 3049 for i in techeck: 3247 if i in line: 3050 if i in line: 3248 check.remove( 3051 check.remove(i) 3249 techeck = check 3052 techeck = check 3250 # check for all necessary tra 3053 # check for all necessary trace markers 3251 check = tmcheck[:] 3054 check = tmcheck[:] 3252 for i in tmcheck: 3055 for i in tmcheck: 3253 if i in line: 3056 if i in line: 3254 check.remove( 3057 check.remove(i) 3255 tmcheck = check 3058 tmcheck = check 3256 fp.close() 3059 fp.close() 3257 sysvals.usetraceevents = True if len( !! 3060 sysvals.usetraceevents = True if len(techeck) < 2 else False 3258 sysvals.usetracemarkers = True if len 3061 sysvals.usetracemarkers = True if len(tmcheck) == 0 else False 3259 3062 3260 # Function: appendIncompleteTraceLog 3063 # Function: appendIncompleteTraceLog 3261 # Description: 3064 # Description: >> 3065 # [deprecated for kernel 3.15 or newer] 3262 # Adds callgraph data which lacks trac 3066 # Adds callgraph data which lacks trace event data. This is only 3263 # for timelines generated from 3.15 or 3067 # for timelines generated from 3.15 or older 3264 # Arguments: 3068 # Arguments: 3265 # testruns: the array of Data objects 3069 # testruns: the array of Data objects obtained from parseKernelLog 3266 def appendIncompleteTraceLog(testruns): 3070 def appendIncompleteTraceLog(testruns): 3267 # create TestRun vessels for ftrace p 3071 # create TestRun vessels for ftrace parsing 3268 testcnt = len(testruns) 3072 testcnt = len(testruns) 3269 testidx = 0 3073 testidx = 0 3270 testrun = [] 3074 testrun = [] 3271 for data in testruns: 3075 for data in testruns: 3272 testrun.append(TestRun(data)) 3076 testrun.append(TestRun(data)) 3273 3077 3274 # extract the callgraph and traceeven 3078 # extract the callgraph and traceevent data 3275 sysvals.vprint('Analyzing the ftrace 3079 sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 3276 os.path.basename(sysvals.ftra 3080 os.path.basename(sysvals.ftracefile)) 3277 tp = TestProps() 3081 tp = TestProps() 3278 tf = sysvals.openlog(sysvals.ftracefi 3082 tf = sysvals.openlog(sysvals.ftracefile, 'r') 3279 data = 0 3083 data = 0 3280 for line in tf: 3084 for line in tf: 3281 # remove any latent carriage 3085 # remove any latent carriage returns 3282 line = line.replace('\r\n', ' 3086 line = line.replace('\r\n', '') 3283 if tp.stampInfo(line, sysvals 3087 if tp.stampInfo(line, sysvals): 3284 continue 3088 continue 3285 # parse only valid lines, if 3089 # parse only valid lines, if this is not one move on 3286 m = re.match(tp.ftrace_line_f 3090 m = re.match(tp.ftrace_line_fmt, line) 3287 if(not m): 3091 if(not m): 3288 continue 3092 continue 3289 # gather the basic message da 3093 # gather the basic message data from the line 3290 m_time = m.group('time') 3094 m_time = m.group('time') 3291 m_pid = m.group('pid') 3095 m_pid = m.group('pid') 3292 m_msg = m.group('msg') 3096 m_msg = m.group('msg') 3293 if(tp.cgformat): 3097 if(tp.cgformat): 3294 m_param3 = m.group('d 3098 m_param3 = m.group('dur') 3295 else: 3099 else: 3296 m_param3 = 'traceeven 3100 m_param3 = 'traceevent' 3297 if(m_time and m_pid and m_msg 3101 if(m_time and m_pid and m_msg): 3298 t = FTraceLine(m_time 3102 t = FTraceLine(m_time, m_msg, m_param3) 3299 pid = int(m_pid) 3103 pid = int(m_pid) 3300 else: 3104 else: 3301 continue 3105 continue 3302 # the line should be a call, 3106 # the line should be a call, return, or event 3303 if(not t.fcall and not t.fret 3107 if(not t.fcall and not t.freturn and not t.fevent): 3304 continue 3108 continue 3305 # look for the suspend start 3109 # look for the suspend start marker 3306 if(t.startMarker()): 3110 if(t.startMarker()): 3307 data = testrun[testid 3111 data = testrun[testidx].data 3308 tp.parseStamp(data, s 3112 tp.parseStamp(data, sysvals) 3309 data.setStart(t.time, 3113 data.setStart(t.time, t.name) 3310 continue 3114 continue 3311 if(not data): 3115 if(not data): 3312 continue 3116 continue 3313 # find the end of resume 3117 # find the end of resume 3314 if(t.endMarker()): 3118 if(t.endMarker()): 3315 data.setEnd(t.time, t 3119 data.setEnd(t.time, t.name) 3316 testidx += 1 3120 testidx += 1 3317 if(testidx >= testcnt 3121 if(testidx >= testcnt): 3318 break 3122 break 3319 continue 3123 continue 3320 # trace event processing 3124 # trace event processing 3321 if(t.fevent): 3125 if(t.fevent): 3322 continue 3126 continue 3323 # call/return processing 3127 # call/return processing 3324 elif sysvals.usecallgraph: 3128 elif sysvals.usecallgraph: 3325 # create a callgraph 3129 # create a callgraph object for the data 3326 if(pid not in testrun 3130 if(pid not in testrun[testidx].ftemp): 3327 testrun[testi 3131 testrun[testidx].ftemp[pid] = [] 3328 testrun[testi 3132 testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 3329 # when the call is fi 3133 # when the call is finished, see which device matches it 3330 cg = testrun[testidx] 3134 cg = testrun[testidx].ftemp[pid][-1] 3331 res = cg.addLine(t) 3135 res = cg.addLine(t) 3332 if(res != 0): 3136 if(res != 0): 3333 testrun[testi 3137 testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 3334 if(res == -1): 3138 if(res == -1): 3335 testrun[testi 3139 testrun[testidx].ftemp[pid][-1].addLine(t) 3336 tf.close() 3140 tf.close() 3337 3141 3338 for test in testrun: 3142 for test in testrun: 3339 # add the callgraph data to t 3143 # add the callgraph data to the device hierarchy 3340 for pid in test.ftemp: 3144 for pid in test.ftemp: 3341 for cg in test.ftemp[ 3145 for cg in test.ftemp[pid]: 3342 if len(cg.lis 3146 if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 3343 conti 3147 continue 3344 if(not cg.pos 3148 if(not cg.postProcess()): 3345 id = 3149 id = 'task %s cpu %s' % (pid, m.group('cpu')) 3346 sysva 3150 sysvals.vprint('Sanity check failed for '+\ 3347 3151 id+', ignoring this callback') 3348 conti 3152 continue 3349 callstart = c 3153 callstart = cg.start 3350 callend = cg. 3154 callend = cg.end 3351 for p in test 3155 for p in test.data.sortedPhases(): 3352 if(te 3156 if(test.data.dmesg[p]['start'] <= callstart and 3353 3157 callstart <= test.data.dmesg[p]['end']): 3354 3158 list = test.data.dmesg[p]['list'] 3355 3159 for devname in list: 3356 3160 dev = list[devname] 3357 3161 if(pid == dev['pid'] and 3358 3162 callstart <= dev['start'] and 3359 3163 callend >= dev['end']): 3360 3164 dev['ftrace'] = cg 3361 3165 break 3362 3166 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 3167 # Function: parseTraceLog 3419 # Description: 3168 # Description: 3420 # Analyze an ftrace log output file ge 3169 # Analyze an ftrace log output file generated from this app during 3421 # the execution phase. Used when the f 3170 # the execution phase. Used when the ftrace log is the primary data source 3422 # and includes the suspend_resume and 3171 # and includes the suspend_resume and device_pm_callback trace events 3423 # The ftrace filename is taken from sy 3172 # The ftrace filename is taken from sysvals 3424 # Output: 3173 # Output: 3425 # An array of Data objects 3174 # An array of Data objects 3426 def parseTraceLog(live=False): 3175 def parseTraceLog(live=False): 3427 sysvals.vprint('Analyzing the ftrace 3176 sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 3428 os.path.basename(sysvals.ftra 3177 os.path.basename(sysvals.ftracefile)) 3429 if(os.path.exists(sysvals.ftracefile) 3178 if(os.path.exists(sysvals.ftracefile) == False): 3430 doError('%s does not exist' % 3179 doError('%s does not exist' % sysvals.ftracefile) 3431 if not live: 3180 if not live: 3432 sysvals.setupAllKprobes() 3181 sysvals.setupAllKprobes() 3433 ksuscalls = ['ksys_sync', 'pm_prepare 3182 ksuscalls = ['ksys_sync', 'pm_prepare_console'] 3434 krescalls = ['pm_restore_console'] 3183 krescalls = ['pm_restore_console'] 3435 tracewatch = ['irq_wakeup'] 3184 tracewatch = ['irq_wakeup'] 3436 if sysvals.usekprobes: 3185 if sysvals.usekprobes: 3437 tracewatch += ['sync_filesyst 3186 tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend', 3438 'syscore_resume', 're 3187 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 3439 'CPU_OFF', 'acpi_susp 3188 'CPU_OFF', 'acpi_suspend'] 3440 3189 3441 # extract the callgraph and traceeven 3190 # extract the callgraph and traceevent data 3442 s2idle_enter = hwsus = False 3191 s2idle_enter = hwsus = False >> 3192 tp = TestProps() 3443 testruns, testdata = [], [] 3193 testruns, testdata = [], [] 3444 testrun, data, limbo = 0, 0, True 3194 testrun, data, limbo = 0, 0, True >> 3195 tf = sysvals.openlog(sysvals.ftracefile, 'r') 3445 phase = 'suspend_prepare' 3196 phase = 'suspend_prepare' 3446 tp, tf = loadTraceLog() !! 3197 for line in tf: 3447 for m_time, m_proc, m_pid, m_msg, m_p !! 3198 # remove any latent carriage returns >> 3199 line = line.replace('\r\n', '') >> 3200 if tp.stampInfo(line, sysvals): >> 3201 continue >> 3202 # ignore all other commented lines >> 3203 if line[0] == '#': >> 3204 continue >> 3205 # ftrace line: parse only valid lines >> 3206 m = re.match(tp.ftrace_line_fmt, line) >> 3207 if(not m): >> 3208 continue 3448 # gather the basic message da 3209 # gather the basic message data from the line >> 3210 m_time = m.group('time') >> 3211 m_proc = m.group('proc') >> 3212 m_pid = m.group('pid') >> 3213 m_msg = m.group('msg') >> 3214 if(tp.cgformat): >> 3215 m_param3 = m.group('dur') >> 3216 else: >> 3217 m_param3 = 'traceevent' 3449 if(m_time and m_pid and m_msg 3218 if(m_time and m_pid and m_msg): 3450 t = FTraceLine(m_time 3219 t = FTraceLine(m_time, m_msg, m_param3) 3451 pid = int(m_pid) 3220 pid = int(m_pid) 3452 else: 3221 else: 3453 continue 3222 continue 3454 # the line should be a call, 3223 # the line should be a call, return, or event 3455 if(not t.fcall and not t.fret 3224 if(not t.fcall and not t.freturn and not t.fevent): 3456 continue 3225 continue 3457 # find the start of suspend 3226 # find the start of suspend 3458 if(t.startMarker()): 3227 if(t.startMarker()): 3459 data, limbo = Data(le 3228 data, limbo = Data(len(testdata)), False 3460 testdata.append(data) 3229 testdata.append(data) 3461 testrun = TestRun(dat 3230 testrun = TestRun(data) 3462 testruns.append(testr 3231 testruns.append(testrun) 3463 tp.parseStamp(data, s 3232 tp.parseStamp(data, sysvals) 3464 data.setStart(t.time, 3233 data.setStart(t.time, t.name) 3465 data.first_suspend_pr 3234 data.first_suspend_prepare = True 3466 phase = data.setPhase 3235 phase = data.setPhase('suspend_prepare', t.time, True) 3467 continue 3236 continue 3468 if(not data or limbo): 3237 if(not data or limbo): 3469 continue 3238 continue 3470 # process cpu exec line 3239 # process cpu exec line 3471 if t.type == 'tracing_mark_wr 3240 if t.type == 'tracing_mark_write': 3472 if t.name == 'CMD COM << 3473 data.tKernRes << 3474 m = re.match(tp.proce 3241 m = re.match(tp.procexecfmt, t.name) 3475 if(m): 3242 if(m): 3476 parts, msg = !! 3243 proclist = dict() 3477 m = re.match( !! 3244 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 = 3245 val = ps.split() 3490 if no !! 3246 if not val: 3491 3247 continue 3492 name 3248 name = val[0].replace('--', '-') 3493 procl 3249 proclist[name] = int(val[1]) 3494 if parts == 1 !! 3250 data.pstl[t.time] = proclist 3495 data. << 3496 elif parts == << 3497 data. << 3498 tp.mu << 3499 continue 3251 continue 3500 # find the end of resume 3252 # find the end of resume 3501 if(t.endMarker()): 3253 if(t.endMarker()): 3502 if data.tKernRes == 0 3254 if data.tKernRes == 0: 3503 data.tKernRes 3255 data.tKernRes = t.time 3504 data.handleEndMarker( 3256 data.handleEndMarker(t.time, t.name) 3505 if(not sysvals.usetra 3257 if(not sysvals.usetracemarkers): 3506 # no trace ma 3258 # no trace markers? then quit and be sure to finish recording 3507 # the event w 3259 # the event we used to trigger resume end 3508 if('thaw_proc 3260 if('thaw_processes' in testrun.ttemp and len(testrun.ttemp['thaw_processes']) > 0): 3509 # if 3261 # if an entry exists, assume this is its end 3510 testr 3262 testrun.ttemp['thaw_processes'][-1]['end'] = t.time 3511 limbo = True 3263 limbo = True 3512 continue 3264 continue 3513 # trace event processing 3265 # trace event processing 3514 if(t.fevent): 3266 if(t.fevent): 3515 if(t.type == 'suspend 3267 if(t.type == 'suspend_resume'): 3516 # suspend_res 3268 # suspend_resume trace events have two types, begin and end 3517 if(re.match(r !! 3269 if(re.match('(?P<name>.*) begin$', t.name)): 3518 isbeg 3270 isbegin = True 3519 elif(re.match !! 3271 elif(re.match('(?P<name>.*) end$', t.name)): 3520 isbeg 3272 isbegin = False 3521 else: 3273 else: 3522 conti 3274 continue 3523 if '[' in t.n 3275 if '[' in t.name: 3524 m = r !! 3276 m = re.match('(?P<name>.*)\[.*', t.name) 3525 else: 3277 else: 3526 m = r !! 3278 m = re.match('(?P<name>.*) .*', t.name) 3527 name = m.grou 3279 name = m.group('name') 3528 # ignore thes 3280 # ignore these events 3529 if(name.split 3281 if(name.split('[')[0] in tracewatch): 3530 conti 3282 continue 3531 # -- phase ch 3283 # -- phase changes -- 3532 # start of ke 3284 # start of kernel suspend 3533 if(re.match(r !! 3285 if(re.match('suspend_enter\[.*', t.name)): 3534 if(is 3286 if(isbegin and data.tKernSus == 0): 3535 3287 data.tKernSus = t.time 3536 conti 3288 continue 3537 # suspend_pre 3289 # suspend_prepare start 3538 elif(re.match !! 3290 elif(re.match('dpm_prepare\[.*', t.name)): 3539 if is 3291 if isbegin and data.first_suspend_prepare: 3540 3292 data.first_suspend_prepare = False 3541 3293 if data.tKernSus == 0: 3542 3294 data.tKernSus = t.time 3543 3295 continue 3544 phase 3296 phase = data.setPhase('suspend_prepare', t.time, isbegin) 3545 conti 3297 continue 3546 # suspend sta 3298 # suspend start 3547 elif(re.match !! 3299 elif(re.match('dpm_suspend\[.*', t.name)): 3548 phase 3300 phase = data.setPhase('suspend', t.time, isbegin) 3549 conti 3301 continue 3550 # suspend_lat 3302 # suspend_late start 3551 elif(re.match !! 3303 elif(re.match('dpm_suspend_late\[.*', t.name)): 3552 phase 3304 phase = data.setPhase('suspend_late', t.time, isbegin) 3553 conti 3305 continue 3554 # suspend_noi 3306 # suspend_noirq start 3555 elif(re.match !! 3307 elif(re.match('dpm_suspend_noirq\[.*', t.name)): 3556 phase 3308 phase = data.setPhase('suspend_noirq', t.time, isbegin) 3557 conti 3309 continue 3558 # suspend_mac 3310 # suspend_machine/resume_machine 3559 elif(re.match 3311 elif(re.match(tp.machinesuspend, t.name)): 3560 lp = 3312 lp = data.lastPhase() 3561 if(is 3313 if(isbegin): 3562 3314 hwsus = True 3563 3315 if lp.startswith('resume_machine'): 3564 3316 # trim out s2idle loops, track time trying to freeze 3565 3317 llp = data.lastPhase(2) 3566 3318 if llp.startswith('suspend_machine'): 3567 !! 3319 if 'trying' not in data.dmesg[llp]: 3568 !! 3320 data.dmesg[llp]['trying'] = 0 3569 !! 3321 data.dmesg[llp]['trying'] += \ 3570 << 3571 3322 t.time - data.dmesg[lp]['start'] 3572 3323 data.currphase = '' 3573 3324 del data.dmesg[lp] 3574 3325 continue 3575 3326 phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True) 3576 3327 data.setPhase(phase, t.time, False) 3577 3328 if data.tSuspended == 0: 3578 3329 data.tSuspended = t.time 3579 else: 3330 else: 3580 3331 if lp.startswith('resume_machine'): 3581 3332 data.dmesg[lp]['end'] = t.time 3582 3333 continue 3583 3334 phase = data.setPhase('resume_machine', t.time, True) 3584 3335 if(sysvals.suspendmode in ['mem', 'disk']): 3585 3336 susp = phase.replace('resume', 'suspend') 3586 3337 if susp in data.dmesg: 3587 3338 data.dmesg[susp]['end'] = t.time 3588 3339 data.tSuspended = t.time 3589 3340 data.tResumed = t.time 3590 conti 3341 continue 3591 # resume_noir 3342 # resume_noirq start 3592 elif(re.match !! 3343 elif(re.match('dpm_resume_noirq\[.*', t.name)): 3593 phase 3344 phase = data.setPhase('resume_noirq', t.time, isbegin) 3594 conti 3345 continue 3595 # resume_earl 3346 # resume_early start 3596 elif(re.match !! 3347 elif(re.match('dpm_resume_early\[.*', t.name)): 3597 phase 3348 phase = data.setPhase('resume_early', t.time, isbegin) 3598 conti 3349 continue 3599 # resume star 3350 # resume start 3600 elif(re.match !! 3351 elif(re.match('dpm_resume\[.*', t.name)): 3601 phase 3352 phase = data.setPhase('resume', t.time, isbegin) 3602 conti 3353 continue 3603 # resume comp 3354 # resume complete start 3604 elif(re.match !! 3355 elif(re.match('dpm_complete\[.*', t.name)): 3605 phase 3356 phase = data.setPhase('resume_complete', t.time, isbegin) 3606 conti 3357 continue 3607 # skip trace 3358 # skip trace events inside devices calls 3608 if(not data.i 3359 if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)): 3609 conti 3360 continue 3610 # global even 3361 # global events (outside device calls) are graphed 3611 if(name not i 3362 if(name not in testrun.ttemp): 3612 testr 3363 testrun.ttemp[name] = [] 3613 # special han 3364 # special handling for s2idle_enter 3614 if name == 'm 3365 if name == 'machine_suspend': 3615 if hw 3366 if hwsus: 3616 3367 s2idle_enter = hwsus = False 3617 elif 3368 elif s2idle_enter and not isbegin: 3618 3369 if(len(testrun.ttemp[name]) > 0): 3619 3370 testrun.ttemp[name][-1]['end'] = t.time 3620 3371 testrun.ttemp[name][-1]['loop'] += 1 3621 elif 3372 elif not s2idle_enter and isbegin: 3622 3373 s2idle_enter = True 3623 3374 testrun.ttemp[name].append({'begin': t.time, 3624 3375 'end': t.time, 'pid': pid, 'loop': 0}) 3625 conti 3376 continue 3626 if(isbegin): 3377 if(isbegin): 3627 # cre 3378 # create a new list entry 3628 testr 3379 testrun.ttemp[name].append(\ 3629 3380 {'begin': t.time, 'end': t.time, 'pid': pid}) 3630 else: 3381 else: 3631 if(le 3382 if(len(testrun.ttemp[name]) > 0): 3632 3383 # if an entry exists, assume this is its end 3633 3384 testrun.ttemp[name][-1]['end'] = t.time 3634 # device callback sta 3385 # device callback start 3635 elif(t.type == 'devic 3386 elif(t.type == 'device_pm_callback_start'): 3636 if phase not 3387 if phase not in data.dmesg: 3637 conti 3388 continue 3638 m = re.match( !! 3389 m = re.match('(?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*',\ 3639 t.nam 3390 t.name); 3640 if(not m): 3391 if(not m): 3641 conti 3392 continue 3642 drv = m.group 3393 drv = m.group('drv') 3643 n = m.group(' 3394 n = m.group('d') 3644 p = m.group(' 3395 p = m.group('p') 3645 if(n and p): 3396 if(n and p): 3646 data. 3397 data.newAction(phase, n, pid, p, t.time, -1, drv) 3647 if pi 3398 if pid not in data.devpids: 3648 3399 data.devpids.append(pid) 3649 # device callback fin 3400 # device callback finish 3650 elif(t.type == 'devic 3401 elif(t.type == 'device_pm_callback_end'): 3651 if phase not 3402 if phase not in data.dmesg: 3652 conti 3403 continue 3653 m = re.match( !! 3404 m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name); 3654 if(not m): 3405 if(not m): 3655 conti 3406 continue 3656 n = m.group(' 3407 n = m.group('d') 3657 dev = data.fi 3408 dev = data.findDevice(phase, n) 3658 if dev: 3409 if dev: 3659 dev[' 3410 dev['length'] = t.time - dev['start'] 3660 dev[' 3411 dev['end'] = t.time 3661 # kprobe event processing 3412 # kprobe event processing 3662 elif(t.fkprobe): 3413 elif(t.fkprobe): 3663 kprobename = t.type 3414 kprobename = t.type 3664 kprobedata = t.name 3415 kprobedata = t.name 3665 key = (kprobename, pi 3416 key = (kprobename, pid) 3666 # displayname is gene 3417 # displayname is generated from kprobe data 3667 displayname = '' 3418 displayname = '' 3668 if(t.fcall): 3419 if(t.fcall): 3669 displayname = 3420 displayname = sysvals.kprobeDisplayName(kprobename, kprobedata) 3670 if not displa 3421 if not displayname: 3671 conti 3422 continue 3672 if(key not in 3423 if(key not in tp.ktemp): 3673 tp.kt 3424 tp.ktemp[key] = [] 3674 tp.ktemp[key] 3425 tp.ktemp[key].append({ 3675 'pid' 3426 'pid': pid, 3676 'begi 3427 'begin': t.time, 3677 'end' 3428 'end': -1, 3678 'name 3429 'name': displayname, 3679 'cdat 3430 'cdata': kprobedata, 3680 'proc 3431 'proc': m_proc, 3681 }) 3432 }) 3682 # start of ke 3433 # start of kernel resume 3683 if(data.tKern 3434 if(data.tKernSus == 0 and phase == 'suspend_prepare' \ 3684 and k 3435 and kprobename in ksuscalls): 3685 data. 3436 data.tKernSus = t.time 3686 elif(t.freturn): 3437 elif(t.freturn): 3687 if(key not in 3438 if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1: 3688 conti 3439 continue 3689 e = next((x f 3440 e = next((x for x in reversed(tp.ktemp[key]) if x['end'] < 0), 0) 3690 if not e: 3441 if not e: 3691 conti 3442 continue 3692 if (t.time - << 3693 tp.kt << 3694 conti << 3695 e['end'] = t. 3443 e['end'] = t.time 3696 e['rdata'] = 3444 e['rdata'] = kprobedata 3697 # end of kern 3445 # end of kernel resume 3698 if(phase != ' 3446 if(phase != 'suspend_prepare' and kprobename in krescalls): 3699 if ph 3447 if phase in data.dmesg: 3700 3448 data.dmesg[phase]['end'] = t.time 3701 data. 3449 data.tKernRes = t.time 3702 3450 3703 # callgraph processing 3451 # callgraph processing 3704 elif sysvals.usecallgraph: 3452 elif sysvals.usecallgraph: 3705 # create a callgraph 3453 # create a callgraph object for the data 3706 key = (m_proc, pid) 3454 key = (m_proc, pid) 3707 if(key not in testrun 3455 if(key not in testrun.ftemp): 3708 testrun.ftemp 3456 testrun.ftemp[key] = [] 3709 testrun.ftemp 3457 testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 3710 # when the call is fi 3458 # when the call is finished, see which device matches it 3711 cg = testrun.ftemp[ke 3459 cg = testrun.ftemp[key][-1] 3712 res = cg.addLine(t) 3460 res = cg.addLine(t) 3713 if(res != 0): 3461 if(res != 0): 3714 testrun.ftemp 3462 testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 3715 if(res == -1): 3463 if(res == -1): 3716 testrun.ftemp 3464 testrun.ftemp[key][-1].addLine(t) >> 3465 tf.close() 3717 if len(testdata) < 1: 3466 if len(testdata) < 1: 3718 sysvals.vprint('WARNING: ftra 3467 sysvals.vprint('WARNING: ftrace start marker is missing') 3719 if data and not data.devicegroups: 3468 if data and not data.devicegroups: 3720 sysvals.vprint('WARNING: ftra 3469 sysvals.vprint('WARNING: ftrace end marker is missing') 3721 data.handleEndMarker(t.time, 3470 data.handleEndMarker(t.time, t.name) 3722 3471 3723 if sysvals.suspendmode == 'command': 3472 if sysvals.suspendmode == 'command': 3724 for test in testruns: 3473 for test in testruns: 3725 for p in test.data.so 3474 for p in test.data.sortedPhases(): 3726 if p == 'susp 3475 if p == 'suspend_prepare': 3727 test. 3476 test.data.dmesg[p]['start'] = test.data.start 3728 test. 3477 test.data.dmesg[p]['end'] = test.data.end 3729 else: 3478 else: 3730 test. 3479 test.data.dmesg[p]['start'] = test.data.end 3731 test. 3480 test.data.dmesg[p]['end'] = test.data.end 3732 test.data.tSuspended 3481 test.data.tSuspended = test.data.end 3733 test.data.tResumed = 3482 test.data.tResumed = test.data.end 3734 test.data.fwValid = F 3483 test.data.fwValid = False 3735 3484 3736 # dev source and procmon events can b 3485 # dev source and procmon events can be unreadable with mixed phase height 3737 if sysvals.usedevsrc or sysvals.usepr 3486 if sysvals.usedevsrc or sysvals.useprocmon: 3738 sysvals.mixedphaseheight = Fa 3487 sysvals.mixedphaseheight = False 3739 3488 3740 # expand phase boundaries so there ar 3489 # expand phase boundaries so there are no gaps 3741 for data in testdata: 3490 for data in testdata: 3742 lp = data.sortedPhases()[0] 3491 lp = data.sortedPhases()[0] 3743 for p in data.sortedPhases(): 3492 for p in data.sortedPhases(): 3744 if(p != lp and not (' 3493 if(p != lp and not ('machine' in p and 'machine' in lp)): 3745 data.dmesg[lp 3494 data.dmesg[lp]['end'] = data.dmesg[p]['start'] 3746 lp = p 3495 lp = p 3747 3496 3748 for i in range(len(testruns)): 3497 for i in range(len(testruns)): 3749 test = testruns[i] 3498 test = testruns[i] 3750 data = test.data 3499 data = test.data 3751 # find the total time range f 3500 # find the total time range for this test (begin, end) 3752 tlb, tle = data.start, data.e 3501 tlb, tle = data.start, data.end 3753 if i < len(testruns) - 1: 3502 if i < len(testruns) - 1: 3754 tle = testruns[i+1].d 3503 tle = testruns[i+1].data.start 3755 # add the process usage data 3504 # add the process usage data to the timeline 3756 if sysvals.useprocmon: 3505 if sysvals.useprocmon: 3757 data.createProcessUsa 3506 data.createProcessUsageEvents() 3758 # add the traceevent data to 3507 # add the traceevent data to the device hierarchy 3759 if(sysvals.usetraceevents): 3508 if(sysvals.usetraceevents): 3760 # add actual trace fu 3509 # add actual trace funcs 3761 for name in sorted(te 3510 for name in sorted(test.ttemp): 3762 for event in 3511 for event in test.ttemp[name]: 3763 if ev 3512 if event['end'] - event['begin'] <= 0: 3764 3513 continue 3765 title 3514 title = name 3766 if na 3515 if name == 'machine_suspend' and 'loop' in event: 3767 3516 title = 's2idle_enter_%dx' % event['loop'] 3768 data. 3517 data.newActionGlobal(title, event['begin'], event['end'], event['pid']) 3769 # add the kprobe base 3518 # add the kprobe based virtual tracefuncs as actual devices 3770 for key in sorted(tp. 3519 for key in sorted(tp.ktemp): 3771 name, pid = k 3520 name, pid = key 3772 if name not i 3521 if name not in sysvals.tracefuncs: 3773 conti 3522 continue 3774 if pid not in 3523 if pid not in data.devpids: 3775 data. 3524 data.devpids.append(pid) 3776 for e in tp.k 3525 for e in tp.ktemp[key]: 3777 kb, k 3526 kb, ke = e['begin'], e['end'] 3778 if ke 3527 if ke - kb < 0.000001 or tlb > kb or tle <= kb: 3779 3528 continue 3780 color 3529 color = sysvals.kprobeColor(name) 3781 data. 3530 data.newActionGlobal(e['name'], kb, ke, pid, color) 3782 # add config base kpr 3531 # add config base kprobes and dev kprobes 3783 if sysvals.usedevsrc: 3532 if sysvals.usedevsrc: 3784 for key in so 3533 for key in sorted(tp.ktemp): 3785 name, 3534 name, pid = key 3786 if na 3535 if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs: 3787 3536 continue 3788 for e 3537 for e in tp.ktemp[key]: 3789 3538 kb, ke = e['begin'], e['end'] 3790 3539 if ke - kb < 0.000001 or tlb > kb or tle <= kb: 3791 3540 continue 3792 3541 data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb, 3793 3542 ke, e['cdata'], e['rdata']) 3794 if sysvals.usecallgraph: 3543 if sysvals.usecallgraph: 3795 # add the callgraph d 3544 # add the callgraph data to the device hierarchy 3796 sortlist = dict() 3545 sortlist = dict() 3797 for key in sorted(tes 3546 for key in sorted(test.ftemp): 3798 proc, pid = k 3547 proc, pid = key 3799 for cg in tes 3548 for cg in test.ftemp[key]: 3800 if le 3549 if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 3801 3550 continue 3802 if(no 3551 if(not cg.postProcess()): 3803 3552 id = 'task %s' % (pid) 3804 3553 sysvals.vprint('Sanity check failed for '+\ 3805 3554 id+', ignoring this callback') 3806 3555 continue 3807 # mat 3556 # match cg data to devices 3808 devna 3557 devname = '' 3809 if sy 3558 if sysvals.suspendmode != 'command': 3810 3559 devname = cg.deviceMatch(pid, data) 3811 if no 3560 if not devname: 3812 3561 sortkey = '%f%f%d' % (cg.start, cg.end, pid) 3813 3562 sortlist[sortkey] = cg 3814 elif 3563 elif len(cg.list) > 1000000 and cg.name != sysvals.ftopfunc: 3815 3564 sysvals.vprint('WARNING: the callgraph for %s is massive (%d lines)' %\ 3816 3565 (devname, len(cg.list))) 3817 # create blocks for o 3566 # create blocks for orphan cg data 3818 for sortkey in sorted 3567 for sortkey in sorted(sortlist): 3819 cg = sortlist 3568 cg = sortlist[sortkey] 3820 name = cg.nam 3569 name = cg.name 3821 if sysvals.is 3570 if sysvals.isCallgraphFunc(name): 3822 sysva 3571 sysvals.vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name)) 3823 cg.ne 3572 cg.newActionFromFunction(data) 3824 if sysvals.suspendmode == 'command': 3573 if sysvals.suspendmode == 'command': 3825 return (testdata, '') 3574 return (testdata, '') 3826 3575 3827 # fill in any missing phases 3576 # fill in any missing phases 3828 error = [] 3577 error = [] 3829 for data in testdata: 3578 for data in testdata: 3830 tn = '' if len(testdata) == 1 3579 tn = '' if len(testdata) == 1 else ('%d' % (data.testnumber + 1)) 3831 terr = '' 3580 terr = '' 3832 phasedef = data.phasedef 3581 phasedef = data.phasedef 3833 lp = 'suspend_prepare' 3582 lp = 'suspend_prepare' 3834 for p in sorted(phasedef, key 3583 for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 3835 if p not in data.dmes 3584 if p not in data.dmesg: 3836 if not terr: 3585 if not terr: 3837 ph = 3586 ph = p if 'machine' in p else lp 3838 if p !! 3587 terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph) 3839 << 3840 << 3841 << 3842 << 3843 else: << 3844 << 3845 pprin 3588 pprint('TEST%s FAILED: %s' % (tn, terr)) 3846 error 3589 error.append(terr) 3847 if da 3590 if data.tSuspended == 0: 3848 3591 data.tSuspended = data.dmesg[lp]['end'] 3849 if da 3592 if data.tResumed == 0: 3850 3593 data.tResumed = data.dmesg[lp]['end'] 3851 data. 3594 data.fwValid = False 3852 sysvals.vprin 3595 sysvals.vprint('WARNING: phase "%s" is missing!' % p) 3853 lp = p 3596 lp = p 3854 if not terr and 'dev' in data 3597 if not terr and 'dev' in data.wifi and data.wifi['stat'] == 'timeout': 3855 terr = '%s%s failed i 3598 terr = '%s%s failed in wifi_resume <i>(%s %.0fs timeout)</i>' % \ 3856 (sysvals.susp 3599 (sysvals.suspendmode, tn, data.wifi['dev'], data.wifi['time']) 3857 error.append(terr) 3600 error.append(terr) 3858 if not terr and data.enterfai 3601 if not terr and data.enterfail: 3859 pprint('test%s FAILED 3602 pprint('test%s FAILED: enter %s failed with %s' % (tn, sysvals.suspendmode, data.enterfail)) 3860 terr = 'test%s failed 3603 terr = 'test%s failed to enter %s mode' % (tn, sysvals.suspendmode) 3861 error.append(terr) 3604 error.append(terr) 3862 if data.tSuspended == 0: 3605 if data.tSuspended == 0: 3863 data.tSuspended = dat 3606 data.tSuspended = data.tKernRes 3864 if data.tResumed == 0: 3607 if data.tResumed == 0: 3865 data.tResumed = data. 3608 data.tResumed = data.tSuspended 3866 3609 3867 if(len(sysvals.devicefilter) 3610 if(len(sysvals.devicefilter) > 0): 3868 data.deviceFilter(sys 3611 data.deviceFilter(sysvals.devicefilter) 3869 data.fixupInitcallsThatDidntR 3612 data.fixupInitcallsThatDidntReturn() 3870 if sysvals.usedevsrc: 3613 if sysvals.usedevsrc: 3871 data.optimizeDevSrc() 3614 data.optimizeDevSrc() 3872 3615 3873 # x2: merge any overlapping devices b 3616 # x2: merge any overlapping devices between test runs 3874 if sysvals.usedevsrc and len(testdata 3617 if sysvals.usedevsrc and len(testdata) > 1: 3875 tc = len(testdata) 3618 tc = len(testdata) 3876 for i in range(tc - 1): 3619 for i in range(tc - 1): 3877 devlist = testdata[i] 3620 devlist = testdata[i].overflowDevices() 3878 for j in range(i + 1, 3621 for j in range(i + 1, tc): 3879 testdata[j].m 3622 testdata[j].mergeOverlapDevices(devlist) 3880 testdata[0].stitchTouchingThr 3623 testdata[0].stitchTouchingThreads(testdata[1:]) 3881 return (testdata, ', '.join(error)) 3624 return (testdata, ', '.join(error)) 3882 3625 3883 # Function: loadKernelLog 3626 # Function: loadKernelLog 3884 # Description: 3627 # Description: >> 3628 # [deprecated for kernel 3.15.0 or newer] 3885 # load the dmesg file into memory and 3629 # load the dmesg file into memory and fix up any ordering issues >> 3630 # The dmesg filename is taken from sysvals 3886 # Output: 3631 # Output: 3887 # An array of empty Data objects with 3632 # An array of empty Data objects with only their dmesgtext attributes set 3888 def loadKernelLog(): 3633 def loadKernelLog(): 3889 sysvals.vprint('Analyzing the dmesg d 3634 sysvals.vprint('Analyzing the dmesg data (%s)...' % \ 3890 os.path.basename(sysvals.dmes 3635 os.path.basename(sysvals.dmesgfile)) 3891 if(os.path.exists(sysvals.dmesgfile) 3636 if(os.path.exists(sysvals.dmesgfile) == False): 3892 doError('%s does not exist' % 3637 doError('%s does not exist' % sysvals.dmesgfile) 3893 3638 3894 # there can be multiple test runs in 3639 # there can be multiple test runs in a single file 3895 tp = TestProps() 3640 tp = TestProps() 3896 tp.stamp = datetime.now().strftime('# 3641 tp.stamp = datetime.now().strftime('# suspend-%m%d%y-%H%M%S localhost mem unknown') 3897 testruns = [] 3642 testruns = [] 3898 data = 0 3643 data = 0 3899 lf = sysvals.openlog(sysvals.dmesgfil 3644 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 3900 for line in lf: 3645 for line in lf: 3901 line = line.replace('\r\n', ' 3646 line = line.replace('\r\n', '') 3902 idx = line.find('[') 3647 idx = line.find('[') 3903 if idx > 1: 3648 if idx > 1: 3904 line = line[idx:] 3649 line = line[idx:] 3905 if tp.stampInfo(line, sysvals 3650 if tp.stampInfo(line, sysvals): 3906 continue 3651 continue 3907 m = re.match(r'[ \t]*(\[ *)(? !! 3652 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 3908 if(not m): 3653 if(not m): 3909 continue 3654 continue 3910 msg = m.group("msg") 3655 msg = m.group("msg") 3911 if re.match(r'PM: Syncing fil !! 3656 if(re.match('PM: Syncing filesystems.*', msg)): 3912 re.match(r'PM: suspen << 3913 if(data): 3657 if(data): 3914 testruns.appe 3658 testruns.append(data) 3915 data = Data(len(testr 3659 data = Data(len(testruns)) 3916 tp.parseStamp(data, s 3660 tp.parseStamp(data, sysvals) 3917 if(not data): 3661 if(not data): 3918 continue 3662 continue 3919 m = re.match(r'.* *(?P<k>[0-9 !! 3663 m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg) 3920 if(m): 3664 if(m): 3921 sysvals.stamp['kernel 3665 sysvals.stamp['kernel'] = m.group('k') 3922 m = re.match(r'PM: Preparing !! 3666 m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg) 3923 if not m: !! 3667 if(m): 3924 m = re.match(r'PM: Pr << 3925 if m: << 3926 sysvals.stamp['mode'] 3668 sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m') 3927 data.dmesgtext.append(line) 3669 data.dmesgtext.append(line) 3928 lf.close() 3670 lf.close() 3929 3671 3930 if sysvals.suspendmode == 's2idle': << 3931 sysvals.suspendmode = 'freeze << 3932 elif sysvals.suspendmode == 'deep': << 3933 sysvals.suspendmode = 'mem' << 3934 if data: 3672 if data: 3935 testruns.append(data) 3673 testruns.append(data) 3936 if len(testruns) < 1: 3674 if len(testruns) < 1: 3937 doError('dmesg log has no sus 3675 doError('dmesg log has no suspend/resume data: %s' \ 3938 % sysvals.dmesgfile) 3676 % sysvals.dmesgfile) 3939 3677 3940 # fix lines with same timestamp/funct 3678 # fix lines with same timestamp/function with the call and return swapped 3941 for data in testruns: 3679 for data in testruns: 3942 last = '' 3680 last = '' 3943 for line in data.dmesgtext: 3681 for line in data.dmesgtext: 3944 ct, cf, n, p = data.i !! 3682 mc = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling '+\ 3945 rt, rf, l = data.init !! 3683 '(?P<f>.*)\+ @ .*, parent: .*', line) 3946 if ct and rt and ct = !! 3684 mr = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\ >> 3685 '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', last) >> 3686 if(mc and mr and (mc.group('t') == mr.group('t')) and >> 3687 (mc.group('f') == mr.group('f'))): 3947 i = data.dmes 3688 i = data.dmesgtext.index(last) 3948 j = data.dmes 3689 j = data.dmesgtext.index(line) 3949 data.dmesgtex 3690 data.dmesgtext[i] = line 3950 data.dmesgtex 3691 data.dmesgtext[j] = last 3951 last = line 3692 last = line 3952 return testruns 3693 return testruns 3953 3694 3954 # Function: parseKernelLog 3695 # Function: parseKernelLog 3955 # Description: 3696 # Description: >> 3697 # [deprecated for kernel 3.15.0 or newer] 3956 # Analyse a dmesg log output file gene 3698 # Analyse a dmesg log output file generated from this app during 3957 # the execution phase. Create a set of 3699 # the execution phase. Create a set of device structures in memory 3958 # for subsequent formatting in the htm 3700 # for subsequent formatting in the html output file 3959 # This call is only for legacy support 3701 # This call is only for legacy support on kernels where the ftrace 3960 # data lacks the suspend_resume or dev 3702 # data lacks the suspend_resume or device_pm_callbacks trace events. 3961 # Arguments: 3703 # Arguments: 3962 # data: an empty Data object (with dme 3704 # data: an empty Data object (with dmesgtext) obtained from loadKernelLog 3963 # Output: 3705 # Output: 3964 # The filled Data object 3706 # The filled Data object 3965 def parseKernelLog(data): 3707 def parseKernelLog(data): 3966 phase = 'suspend_runtime' 3708 phase = 'suspend_runtime' 3967 3709 3968 if(data.fwValid): 3710 if(data.fwValid): 3969 sysvals.vprint('Firmware Susp 3711 sysvals.vprint('Firmware Suspend = %u ns, Firmware Resume = %u ns' % \ 3970 (data.fwSuspend, data 3712 (data.fwSuspend, data.fwResume)) 3971 3713 3972 # dmesg phase match table 3714 # dmesg phase match table 3973 dm = { 3715 dm = { 3974 'suspend_prepare': ['PM: Sync !! 3716 'suspend_prepare': ['PM: Syncing filesystems.*'], 3975 'suspend': ['PM: Ente !! 3717 'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*'], 3976 'PM: Susp !! 3718 'suspend_late': ['PM: suspend of devices complete after.*'], 3977 'suspend_late': ['PM: susp !! 3719 'suspend_noirq': ['PM: late suspend of devices complete after.*'], 3978 !! 3720 'suspend_machine': ['PM: noirq suspend of devices complete after.*'], 3979 'suspend_noirq': ['PM: late !! 3721 'resume_machine': ['ACPI: Low-level resume complete.*'], 3980 !! 3722 'resume_noirq': ['ACPI: Waking up from system sleep state.*'], 3981 'suspend_machine': ['PM: susp !! 3723 'resume_early': ['PM: noirq resume of devices complete after.*'], 3982 !! 3724 'resume': ['PM: early resume of devices complete after.*'], 3983 !! 3725 'resume_complete': ['PM: resume of devices complete after.*'], 3984 'resume_machine': ['[PM: ]*T !! 3726 '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 } 3727 } >> 3728 if(sysvals.suspendmode == 'standby'): >> 3729 dm['resume_machine'] = ['PM: Restoring platform NVS memory'] >> 3730 elif(sysvals.suspendmode == 'disk'): >> 3731 dm['suspend_late'] = ['PM: freeze of devices complete after.*'] >> 3732 dm['suspend_noirq'] = ['PM: late freeze of devices complete after.*'] >> 3733 dm['suspend_machine'] = ['PM: noirq freeze of devices complete after.*'] >> 3734 dm['resume_machine'] = ['PM: Restoring platform NVS memory'] >> 3735 dm['resume_early'] = ['PM: noirq restore of devices complete after.*'] >> 3736 dm['resume'] = ['PM: early restore of devices complete after.*'] >> 3737 dm['resume_complete'] = ['PM: restore of devices complete after.*'] >> 3738 elif(sysvals.suspendmode == 'freeze'): >> 3739 dm['resume_machine'] = ['ACPI: resume from mwait'] 3998 3740 3999 # action table (expected events that 3741 # action table (expected events that occur and show up in dmesg) 4000 at = { 3742 at = { 4001 'sync_filesystems': { 3743 'sync_filesystems': { 4002 'smsg': '.*[Ff]+ilesy !! 3744 'smsg': 'PM: Syncing filesystems.*', 4003 'emsg': 'PM: Preparin !! 3745 'emsg': 'PM: Preparing system for mem sleep.*' }, 4004 'freeze_user_processes': { 3746 'freeze_user_processes': { 4005 'smsg': 'Freezing use !! 3747 'smsg': 'Freezing user space processes .*', 4006 'emsg': 'Freezing rem 3748 'emsg': 'Freezing remaining freezable tasks.*' }, 4007 'freeze_tasks': { 3749 'freeze_tasks': { 4008 'smsg': 'Freezing rem 3750 'smsg': 'Freezing remaining freezable tasks.*', 4009 'emsg': 'PM: Suspendi !! 3751 'emsg': 'PM: Entering (?P<mode>[a-z,A-Z]*) sleep.*' }, 4010 'ACPI prepare': { 3752 'ACPI prepare': { 4011 'smsg': 'ACPI: Prepar 3753 'smsg': 'ACPI: Preparing to enter system sleep state.*', 4012 'emsg': 'PM: Saving p 3754 'emsg': 'PM: Saving platform NVS memory.*' }, 4013 'PM vns': { 3755 'PM vns': { 4014 'smsg': 'PM: Saving p 3756 'smsg': 'PM: Saving platform NVS memory.*', 4015 'emsg': 'Disabling no 3757 'emsg': 'Disabling non-boot CPUs .*' }, 4016 } 3758 } 4017 3759 4018 t0 = -1.0 3760 t0 = -1.0 4019 cpu_start = -1.0 3761 cpu_start = -1.0 4020 prevktime = -1.0 3762 prevktime = -1.0 4021 actions = dict() 3763 actions = dict() 4022 for line in data.dmesgtext: 3764 for line in data.dmesgtext: 4023 # parse each dmesg line into 3765 # parse each dmesg line into the time and message 4024 m = re.match(r'[ \t]*(\[ *)(? !! 3766 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 4025 if(m): 3767 if(m): 4026 val = m.group('ktime' 3768 val = m.group('ktime') 4027 try: 3769 try: 4028 ktime = float 3770 ktime = float(val) 4029 except: 3771 except: 4030 continue 3772 continue 4031 msg = m.group('msg') 3773 msg = m.group('msg') 4032 # initialize data sta 3774 # initialize data start to first line time 4033 if t0 < 0: 3775 if t0 < 0: 4034 data.setStart 3776 data.setStart(ktime) 4035 t0 = ktime 3777 t0 = ktime 4036 else: 3778 else: 4037 continue 3779 continue 4038 3780 4039 # check for a phase change li 3781 # check for a phase change line 4040 phasechange = False 3782 phasechange = False 4041 for p in dm: 3783 for p in dm: 4042 for s in dm[p]: 3784 for s in dm[p]: 4043 if(re.match(s 3785 if(re.match(s, msg)): 4044 phase 3786 phasechange, phase = True, p 4045 dm[p] << 4046 break 3787 break 4047 3788 4048 # hack for determining resume 3789 # hack for determining resume_machine end for freeze 4049 if(not sysvals.usetraceevents 3790 if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \ 4050 and phase == 'resume_ 3791 and phase == 'resume_machine' and \ 4051 data.initcall_debug_c !! 3792 re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): 4052 data.setPhase(phase, 3793 data.setPhase(phase, ktime, False) 4053 phase = 'resume_noirq 3794 phase = 'resume_noirq' 4054 data.setPhase(phase, 3795 data.setPhase(phase, ktime, True) 4055 3796 4056 if phasechange: 3797 if phasechange: 4057 if phase == 'suspend_ 3798 if phase == 'suspend_prepare': 4058 data.setPhase 3799 data.setPhase(phase, ktime, True) 4059 data.setStart 3800 data.setStart(ktime) 4060 data.tKernSus 3801 data.tKernSus = ktime 4061 elif phase == 'suspen 3802 elif phase == 'suspend': 4062 lp = data.las 3803 lp = data.lastPhase() 4063 if lp: 3804 if lp: 4064 data. 3805 data.setPhase(lp, ktime, False) 4065 data.setPhase 3806 data.setPhase(phase, ktime, True) 4066 elif phase == 'suspen 3807 elif phase == 'suspend_late': 4067 lp = data.las 3808 lp = data.lastPhase() 4068 if lp: 3809 if lp: 4069 data. 3810 data.setPhase(lp, ktime, False) 4070 data.setPhase 3811 data.setPhase(phase, ktime, True) 4071 elif phase == 'suspen 3812 elif phase == 'suspend_noirq': 4072 lp = data.las 3813 lp = data.lastPhase() 4073 if lp: 3814 if lp: 4074 data. 3815 data.setPhase(lp, ktime, False) 4075 data.setPhase 3816 data.setPhase(phase, ktime, True) 4076 elif phase == 'suspen 3817 elif phase == 'suspend_machine': 4077 lp = data.las 3818 lp = data.lastPhase() 4078 if lp: 3819 if lp: 4079 data. 3820 data.setPhase(lp, ktime, False) 4080 data.setPhase 3821 data.setPhase(phase, ktime, True) 4081 elif phase == 'resume 3822 elif phase == 'resume_machine': 4082 lp = data.las 3823 lp = data.lastPhase() 4083 if(sysvals.su 3824 if(sysvals.suspendmode in ['freeze', 'standby']): 4084 data. 3825 data.tSuspended = prevktime 4085 if lp 3826 if lp: 4086 3827 data.setPhase(lp, prevktime, False) 4087 else: 3828 else: 4088 data. 3829 data.tSuspended = ktime 4089 if lp 3830 if lp: 4090 3831 data.setPhase(lp, prevktime, False) 4091 data.tResumed 3832 data.tResumed = ktime 4092 data.setPhase 3833 data.setPhase(phase, ktime, True) 4093 elif phase == 'resume 3834 elif phase == 'resume_noirq': 4094 lp = data.las 3835 lp = data.lastPhase() 4095 if lp: 3836 if lp: 4096 data. 3837 data.setPhase(lp, ktime, False) 4097 data.setPhase 3838 data.setPhase(phase, ktime, True) 4098 elif phase == 'resume 3839 elif phase == 'resume_early': 4099 lp = data.las 3840 lp = data.lastPhase() 4100 if lp: 3841 if lp: 4101 data. 3842 data.setPhase(lp, ktime, False) 4102 data.setPhase 3843 data.setPhase(phase, ktime, True) 4103 elif phase == 'resume 3844 elif phase == 'resume': 4104 lp = data.las 3845 lp = data.lastPhase() 4105 if lp: 3846 if lp: 4106 data. 3847 data.setPhase(lp, ktime, False) 4107 data.setPhase 3848 data.setPhase(phase, ktime, True) 4108 elif phase == 'resume 3849 elif phase == 'resume_complete': 4109 lp = data.las 3850 lp = data.lastPhase() 4110 if lp: 3851 if lp: 4111 data. 3852 data.setPhase(lp, ktime, False) 4112 data.setPhase 3853 data.setPhase(phase, ktime, True) 4113 elif phase == 'post_r 3854 elif phase == 'post_resume': 4114 lp = data.las 3855 lp = data.lastPhase() 4115 if lp: 3856 if lp: 4116 data. 3857 data.setPhase(lp, ktime, False) 4117 data.setEnd(k 3858 data.setEnd(ktime) 4118 data.tKernRes 3859 data.tKernRes = ktime 4119 break 3860 break 4120 3861 4121 # -- device callbacks -- 3862 # -- device callbacks -- 4122 if(phase in data.sortedPhases 3863 if(phase in data.sortedPhases()): 4123 # device init call 3864 # device init call 4124 t, f, n, p = data.ini !! 3865 if(re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): 4125 if t and f and n and !! 3866 sm = re.match('calling (?P<f>.*)\+ @ '+\ 4126 data.newActio !! 3867 '(?P<n>.*), parent: (?P<p>.*)', msg); 4127 else: !! 3868 f = sm.group('f') 4128 # device init !! 3869 n = sm.group('n') 4129 t, f, l = dat !! 3870 p = sm.group('p') 4130 if t and f an !! 3871 if(f and n and p): 4131 list !! 3872 data.newAction(phase, f, int(n), p, ktime, -1, '') 4132 if(f !! 3873 # device init return 4133 !! 3874 elif(re.match('call (?P<f>.*)\+ returned .* after '+\ 4134 !! 3875 '(?P<t>.*) usecs', msg)): 4135 !! 3876 sm = re.match('call (?P<f>.*)\+ returned .* after '+\ >> 3877 '(?P<t>.*) usecs(?P<a>.*)', msg); >> 3878 f = sm.group('f') >> 3879 t = sm.group('t') >> 3880 list = data.dmesg[phase]['list'] >> 3881 if(f in list): >> 3882 dev = list[f] >> 3883 dev['length'] = int(t) >> 3884 dev['end'] = ktime 4136 3885 4137 # if trace events are not ava 3886 # if trace events are not available, these are better than nothing 4138 if(not sysvals.usetraceevents 3887 if(not sysvals.usetraceevents): 4139 # look for known acti 3888 # look for known actions 4140 for a in sorted(at): 3889 for a in sorted(at): 4141 if(re.match(a 3890 if(re.match(at[a]['smsg'], msg)): 4142 if(a 3891 if(a not in actions): 4143 !! 3892 actions[a] = [] >> 3893 actions[a].append({'begin': ktime, 'end': ktime}) 4144 if(re.match(a 3894 if(re.match(at[a]['emsg'], msg)): 4145 if(a !! 3895 if(a in actions): 4146 3896 actions[a][-1]['end'] = ktime 4147 # now look for CPU on 3897 # now look for CPU on/off events 4148 if(re.match(r'Disabli !! 3898 if(re.match('Disabling non-boot CPUs .*', msg)): 4149 # start of fi 3899 # start of first cpu suspend 4150 cpu_start = k 3900 cpu_start = ktime 4151 elif(re.match(r'Enabl !! 3901 elif(re.match('Enabling non-boot CPUs .*', msg)): 4152 # start of fi 3902 # start of first cpu resume 4153 cpu_start = k 3903 cpu_start = ktime 4154 elif(re.match(r'smpbo !! 3904 elif(re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg)): 4155 or re.match(r << 4156 # end of a cp 3905 # end of a cpu suspend, start of the next 4157 m = re.match( !! 3906 m = re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg) 4158 if(not m): << 4159 m = r << 4160 cpu = 'CPU'+m 3907 cpu = 'CPU'+m.group('cpu') 4161 if(cpu not in 3908 if(cpu not in actions): 4162 actio 3909 actions[cpu] = [] 4163 actions[cpu]. 3910 actions[cpu].append({'begin': cpu_start, 'end': ktime}) 4164 cpu_start = k 3911 cpu_start = ktime 4165 elif(re.match(r'CPU(? !! 3912 elif(re.match('CPU(?P<cpu>[0-9]*) is up', msg)): 4166 # end of a cp 3913 # end of a cpu resume, start of the next 4167 m = re.match( !! 3914 m = re.match('CPU(?P<cpu>[0-9]*) is up', msg) 4168 cpu = 'CPU'+m 3915 cpu = 'CPU'+m.group('cpu') 4169 if(cpu not in 3916 if(cpu not in actions): 4170 actio 3917 actions[cpu] = [] 4171 actions[cpu]. 3918 actions[cpu].append({'begin': cpu_start, 'end': ktime}) 4172 cpu_start = k 3919 cpu_start = ktime 4173 prevktime = ktime 3920 prevktime = ktime 4174 data.initDevicegroups() 3921 data.initDevicegroups() 4175 3922 4176 # fill in any missing phases 3923 # fill in any missing phases 4177 phasedef = data.phasedef 3924 phasedef = data.phasedef 4178 terr, lp = '', 'suspend_prepare' 3925 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 3926 for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 4182 if p not in data.dmesg: 3927 if p not in data.dmesg: 4183 if not terr: 3928 if not terr: 4184 pprint('TEST 3929 pprint('TEST FAILED: %s failed in %s phase' % (sysvals.suspendmode, lp)) 4185 terr = '%s fa 3930 terr = '%s failed in %s phase' % (sysvals.suspendmode, lp) 4186 if data.tSusp 3931 if data.tSuspended == 0: 4187 data. 3932 data.tSuspended = data.dmesg[lp]['end'] 4188 if data.tResu 3933 if data.tResumed == 0: 4189 data. 3934 data.tResumed = data.dmesg[lp]['end'] 4190 sysvals.vprint('WARNI 3935 sysvals.vprint('WARNING: phase "%s" is missing!' % p) 4191 lp = p 3936 lp = p 4192 lp = data.sortedPhases()[0] 3937 lp = data.sortedPhases()[0] 4193 for p in data.sortedPhases(): 3938 for p in data.sortedPhases(): 4194 if(p != lp and not ('machine' 3939 if(p != lp and not ('machine' in p and 'machine' in lp)): 4195 data.dmesg[lp]['end'] 3940 data.dmesg[lp]['end'] = data.dmesg[p]['start'] 4196 lp = p 3941 lp = p 4197 if data.tSuspended == 0: 3942 if data.tSuspended == 0: 4198 data.tSuspended = data.tKernR 3943 data.tSuspended = data.tKernRes 4199 if data.tResumed == 0: 3944 if data.tResumed == 0: 4200 data.tResumed = data.tSuspend 3945 data.tResumed = data.tSuspended 4201 3946 4202 # fill in any actions we've found 3947 # fill in any actions we've found 4203 for name in sorted(actions): 3948 for name in sorted(actions): 4204 for event in actions[name]: 3949 for event in actions[name]: 4205 data.newActionGlobal( 3950 data.newActionGlobal(name, event['begin'], event['end']) 4206 3951 4207 if(len(sysvals.devicefilter) > 0): 3952 if(len(sysvals.devicefilter) > 0): 4208 data.deviceFilter(sysvals.dev 3953 data.deviceFilter(sysvals.devicefilter) 4209 data.fixupInitcallsThatDidntReturn() 3954 data.fixupInitcallsThatDidntReturn() 4210 return True 3955 return True 4211 3956 4212 def callgraphHTML(sv, hf, num, cg, title, col 3957 def callgraphHTML(sv, hf, num, cg, title, color, devid): 4213 html_func_top = '<article id="{0}" cl 3958 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 3959 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' 3960 html_func_end = '</article>\n' 4216 html_func_leaf = '<article>{0} {1}</a 3961 html_func_leaf = '<article>{0} {1}</article>\n' 4217 3962 4218 cgid = devid 3963 cgid = devid 4219 if cg.id: 3964 if cg.id: 4220 cgid += cg.id 3965 cgid += cg.id 4221 cglen = (cg.end - cg.start) * 1000 3966 cglen = (cg.end - cg.start) * 1000 4222 if cglen < sv.mincglen: 3967 if cglen < sv.mincglen: 4223 return num 3968 return num 4224 3969 4225 fmt = '<r>(%.3f ms @ '+sv.timeformat+' 3970 fmt = '<r>(%.3f ms @ '+sv.timeformat+' to '+sv.timeformat+')</r>' 4226 flen = fmt % (cglen, cg.start, cg.end 3971 flen = fmt % (cglen, cg.start, cg.end) 4227 hf.write(html_func_top.format(cgid, c 3972 hf.write(html_func_top.format(cgid, color, num, title, flen)) 4228 num += 1 3973 num += 1 4229 for line in cg.list: 3974 for line in cg.list: 4230 if(line.length < 0.000000001) 3975 if(line.length < 0.000000001): 4231 flen = '' 3976 flen = '' 4232 else: 3977 else: 4233 fmt = '<n>(%.3f ms @ ' 3978 fmt = '<n>(%.3f ms @ '+sv.timeformat+')</n>' 4234 flen = fmt % (line.le 3979 flen = fmt % (line.length*1000, line.time) 4235 if line.isLeaf(): 3980 if line.isLeaf(): 4236 if line.length * 1000 << 4237 continue << 4238 hf.write(html_func_le 3981 hf.write(html_func_leaf.format(line.name, flen)) 4239 elif line.freturn: 3982 elif line.freturn: 4240 hf.write(html_func_en 3983 hf.write(html_func_end) 4241 else: 3984 else: 4242 hf.write(html_func_st 3985 hf.write(html_func_start.format(num, line.name, flen)) 4243 num += 1 3986 num += 1 4244 hf.write(html_func_end) 3987 hf.write(html_func_end) 4245 return num 3988 return num 4246 3989 4247 def addCallgraphs(sv, hf, data): 3990 def addCallgraphs(sv, hf, data): 4248 hf.write('<section id="callgraphs" cl 3991 hf.write('<section id="callgraphs" class="callgraph">\n') 4249 # write out the ftrace data converted 3992 # write out the ftrace data converted to html 4250 num = 0 3993 num = 0 4251 for p in data.sortedPhases(): 3994 for p in data.sortedPhases(): 4252 if sv.cgphase and p != sv.cgp 3995 if sv.cgphase and p != sv.cgphase: 4253 continue 3996 continue 4254 list = data.dmesg[p]['list'] 3997 list = data.dmesg[p]['list'] 4255 for d in data.sortedDevices(p 3998 for d in data.sortedDevices(p): 4256 if len(sv.cgfilter) > 3999 if len(sv.cgfilter) > 0 and d not in sv.cgfilter: 4257 continue 4000 continue 4258 dev = list[d] 4001 dev = list[d] 4259 color = 'white' 4002 color = 'white' 4260 if 'color' in data.dm 4003 if 'color' in data.dmesg[p]: 4261 color = data. 4004 color = data.dmesg[p]['color'] 4262 if 'color' in dev: 4005 if 'color' in dev: 4263 color = dev[' 4006 color = dev['color'] 4264 name = d if '[' not i 4007 name = d if '[' not in d else d.split('[')[0] 4265 if(d in sv.devprops): 4008 if(d in sv.devprops): 4266 name = sv.dev 4009 name = sv.devprops[d].altName(d) 4267 if 'drv' in dev and d 4010 if 'drv' in dev and dev['drv']: 4268 name += ' {%s 4011 name += ' {%s}' % dev['drv'] 4269 if sv.suspendmode in 4012 if sv.suspendmode in suspendmodename: 4270 name += ' '+p 4013 name += ' '+p 4271 if('ftrace' in dev): 4014 if('ftrace' in dev): 4272 cg = dev['ftr 4015 cg = dev['ftrace'] 4273 if cg.name == 4016 if cg.name == sv.ftopfunc: 4274 name 4017 name = 'top level suspend/resume call' 4275 num = callgra 4018 num = callgraphHTML(sv, hf, num, cg, 4276 name, 4019 name, color, dev['id']) 4277 if('ftraces' in dev): 4020 if('ftraces' in dev): 4278 for cg in dev 4021 for cg in dev['ftraces']: 4279 num = 4022 num = callgraphHTML(sv, hf, num, cg, 4280 4023 name+' → '+cg.name, color, dev['id']) 4281 hf.write('\n\n </section>\n') 4024 hf.write('\n\n </section>\n') 4282 4025 4283 def summaryCSS(title, center=True): 4026 def summaryCSS(title, center=True): 4284 tdcenter = 'text-align:center;' if ce 4027 tdcenter = 'text-align:center;' if center else '' 4285 out = '<!DOCTYPE html>\n<html>\n<head 4028 out = '<!DOCTYPE html>\n<html>\n<head>\n\ 4286 <meta http-equiv="content-type" conte 4029 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 4287 <title>'+title+'</title>\n\ 4030 <title>'+title+'</title>\n\ 4288 <style type=\'text/css\'>\n\ 4031 <style type=\'text/css\'>\n\ 4289 .stamp {width: 100%;text-alig 4032 .stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\ 4290 table {width:100%;border-coll 4033 table {width:100%;border-collapse: collapse;border:1px solid;}\n\ 4291 th {border: 1px solid black;b 4034 th {border: 1px solid black;background:#222;color:white;}\n\ 4292 td {font: 14px "Times New Rom 4035 td {font: 14px "Times New Roman";'+tdcenter+'}\n\ 4293 tr.head td {border: 1px solid 4036 tr.head td {border: 1px solid black;background:#aaa;}\n\ 4294 tr.alt {background-color:#ddd 4037 tr.alt {background-color:#ddd;}\n\ 4295 tr.notice {color:red;}\n\ 4038 tr.notice {color:red;}\n\ 4296 .minval {background-color:#BB 4039 .minval {background-color:#BBFFBB;}\n\ 4297 .medval {background-color:#BB 4040 .medval {background-color:#BBBBFF;}\n\ 4298 .maxval {background-color:#FF 4041 .maxval {background-color:#FFBBBB;}\n\ 4299 .head a {color:#000;text-deco 4042 .head a {color:#000;text-decoration: none;}\n\ 4300 </style>\n</head>\n<body>\n' 4043 </style>\n</head>\n<body>\n' 4301 return out 4044 return out 4302 4045 4303 # Function: createHTMLSummarySimple 4046 # Function: createHTMLSummarySimple 4304 # Description: 4047 # Description: 4305 # Create summary html file for a serie 4048 # Create summary html file for a series of tests 4306 # Arguments: 4049 # Arguments: 4307 # testruns: array of Data objects from 4050 # testruns: array of Data objects from parseTraceLog 4308 def createHTMLSummarySimple(testruns, htmlfil 4051 def createHTMLSummarySimple(testruns, htmlfile, title): 4309 # write the html header first (html h 4052 # write the html header first (html head, css code, up to body start) 4310 html = summaryCSS('Summary - SleepGra 4053 html = summaryCSS('Summary - SleepGraph') 4311 4054 4312 # extract the test data into list 4055 # extract the test data into list 4313 list = dict() 4056 list = dict() 4314 tAvg, tMin, tMax, tMed = [0.0, 0.0], 4057 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 4058 iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 4316 num = 0 4059 num = 0 4317 useturbo = usewifi = False 4060 useturbo = usewifi = False 4318 lastmode = '' 4061 lastmode = '' 4319 cnt = dict() 4062 cnt = dict() 4320 for data in sorted(testruns, key=lamb 4063 for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])): 4321 mode = data['mode'] 4064 mode = data['mode'] 4322 if mode not in list: 4065 if mode not in list: 4323 list[mode] = {'data': 4066 list[mode] = {'data': [], 'avg': [0,0], 'min': [0,0], 'max': [0,0], 'med': [0,0]} 4324 if lastmode and lastmode != m 4067 if lastmode and lastmode != mode and num > 0: 4325 for i in range(2): 4068 for i in range(2): 4326 s = sorted(tM 4069 s = sorted(tMed[i]) 4327 list[lastmode 4070 list[lastmode]['med'][i] = s[int(len(s)//2)] 4328 iMed[i] = tMe 4071 iMed[i] = tMed[i][list[lastmode]['med'][i]] 4329 list[lastmode]['avg'] 4072 list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 4330 list[lastmode]['min'] 4073 list[lastmode]['min'] = tMin 4331 list[lastmode]['max'] 4074 list[lastmode]['max'] = tMax 4332 list[lastmode]['idx'] 4075 list[lastmode]['idx'] = (iMin, iMed, iMax) 4333 tAvg, tMin, tMax, tMe 4076 tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 4334 iMin, iMed, iMax = [0 4077 iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 4335 num = 0 4078 num = 0 4336 pkgpc10 = syslpi = wifi = '' 4079 pkgpc10 = syslpi = wifi = '' 4337 if 'pkgpc10' in data and 'sys 4080 if 'pkgpc10' in data and 'syslpi' in data: 4338 pkgpc10, syslpi, uset 4081 pkgpc10, syslpi, useturbo = data['pkgpc10'], data['syslpi'], True 4339 if 'wifi' in data: 4082 if 'wifi' in data: 4340 wifi, usewifi = data[ 4083 wifi, usewifi = data['wifi'], True 4341 res = data['result'] 4084 res = data['result'] 4342 tVal = [float(data['suspend'] 4085 tVal = [float(data['suspend']), float(data['resume'])] 4343 list[mode]['data'].append([da 4086 list[mode]['data'].append([data['host'], data['kernel'], 4344 data['time'], tVal[0] 4087 data['time'], tVal[0], tVal[1], data['url'], res, 4345 data['issues'], data[ 4088 data['issues'], data['sus_worst'], data['sus_worsttime'], 4346 data['res_worst'], da !! 4089 data['res_worst'], data['res_worsttime'], pkgpc10, syslpi, wifi]) 4347 (data['fullmode'] if << 4348 idx = len(list[mode]['data']) 4090 idx = len(list[mode]['data']) - 1 4349 if res.startswith('fail in'): 4091 if res.startswith('fail in'): 4350 res = 'fail' 4092 res = 'fail' 4351 if res not in cnt: 4093 if res not in cnt: 4352 cnt[res] = 1 4094 cnt[res] = 1 4353 else: 4095 else: 4354 cnt[res] += 1 4096 cnt[res] += 1 4355 if res == 'pass': 4097 if res == 'pass': 4356 for i in range(2): 4098 for i in range(2): 4357 tMed[i][tVal[ 4099 tMed[i][tVal[i]] = idx 4358 tAvg[i] += tV 4100 tAvg[i] += tVal[i] 4359 if tMin[i] == 4101 if tMin[i] == 0 or tVal[i] < tMin[i]: 4360 iMin[ 4102 iMin[i] = idx 4361 tMin[ 4103 tMin[i] = tVal[i] 4362 if tMax[i] == 4104 if tMax[i] == 0 or tVal[i] > tMax[i]: 4363 iMax[ 4105 iMax[i] = idx 4364 tMax[ 4106 tMax[i] = tVal[i] 4365 num += 1 4107 num += 1 4366 lastmode = mode 4108 lastmode = mode 4367 if lastmode and num > 0: 4109 if lastmode and num > 0: 4368 for i in range(2): 4110 for i in range(2): 4369 s = sorted(tMed[i]) 4111 s = sorted(tMed[i]) 4370 list[lastmode]['med'] 4112 list[lastmode]['med'][i] = s[int(len(s)//2)] 4371 iMed[i] = tMed[i][lis 4113 iMed[i] = tMed[i][list[lastmode]['med'][i]] 4372 list[lastmode]['avg'] = [tAvg 4114 list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 4373 list[lastmode]['min'] = tMin 4115 list[lastmode]['min'] = tMin 4374 list[lastmode]['max'] = tMax 4116 list[lastmode]['max'] = tMax 4375 list[lastmode]['idx'] = (iMin 4117 list[lastmode]['idx'] = (iMin, iMed, iMax) 4376 4118 4377 # group test header 4119 # group test header 4378 desc = [] 4120 desc = [] 4379 for ilk in sorted(cnt, reverse=True): 4121 for ilk in sorted(cnt, reverse=True): 4380 if cnt[ilk] > 0: 4122 if cnt[ilk] > 0: 4381 desc.append('%d %s' % 4123 desc.append('%d %s' % (cnt[ilk], ilk)) 4382 html += '<div class="stamp">%s (%d te 4124 html += '<div class="stamp">%s (%d tests: %s)</div>\n' % (title, len(testruns), ', '.join(desc)) 4383 th = '\t<th>{0}</th>\n' 4125 th = '\t<th>{0}</th>\n' 4384 td = '\t<td>{0}</td>\n' 4126 td = '\t<td>{0}</td>\n' 4385 tdh = '\t<td{1}>{0}</td>\n' 4127 tdh = '\t<td{1}>{0}</td>\n' 4386 tdlink = '\t<td><a href="{0}">html</a 4128 tdlink = '\t<td><a href="{0}">html</a></td>\n' 4387 cols = 12 4129 cols = 12 4388 if useturbo: 4130 if useturbo: 4389 cols += 2 4131 cols += 2 4390 if usewifi: 4132 if usewifi: 4391 cols += 1 4133 cols += 1 4392 colspan = '%d' % cols 4134 colspan = '%d' % cols 4393 4135 4394 # table header 4136 # table header 4395 html += '<table>\n<tr>\n' + th.format 4137 html += '<table>\n<tr>\n' + th.format('#') +\ 4396 th.format('Mode') + th.format 4138 th.format('Mode') + th.format('Host') + th.format('Kernel') +\ 4397 th.format('Test Time') + th.f 4139 th.format('Test Time') + th.format('Result') + th.format('Issues') +\ 4398 th.format('Suspend') + th.for 4140 th.format('Suspend') + th.format('Resume') +\ 4399 th.format('Worst Suspend Devi 4141 th.format('Worst Suspend Device') + th.format('SD Time') +\ 4400 th.format('Worst Resume Devic 4142 th.format('Worst Resume Device') + th.format('RD Time') 4401 if useturbo: 4143 if useturbo: 4402 html += th.format('PkgPC10') 4144 html += th.format('PkgPC10') + th.format('SysLPI') 4403 if usewifi: 4145 if usewifi: 4404 html += th.format('Wifi') 4146 html += th.format('Wifi') 4405 html += th.format('Detail')+'</tr>\n' 4147 html += th.format('Detail')+'</tr>\n' 4406 # export list into html 4148 # export list into html 4407 head = '<tr class="head"><td>{0}</td> 4149 head = '<tr class="head"><td>{0}</td><td>{1}</td>'+\ 4408 '<td colspan='+colspan+' clas 4150 '<td colspan='+colspan+' class="sus">Suspend Avg={2} '+\ 4409 '<span class=minval><a href=" 4151 '<span class=minval><a href="#s{10}min">Min={3}</a></span> '+\ 4410 '<span class=medval><a href=" 4152 '<span class=medval><a href="#s{10}med">Med={4}</a></span> '+\ 4411 '<span class=maxval><a href=" 4153 '<span class=maxval><a href="#s{10}max">Max={5}</a></span> '+\ 4412 'Resume Avg={6} '+\ 4154 'Resume Avg={6} '+\ 4413 '<span class=minval><a href=" 4155 '<span class=minval><a href="#r{10}min">Min={7}</a></span> '+\ 4414 '<span class=medval><a href=" 4156 '<span class=medval><a href="#r{10}med">Med={8}</a></span> '+\ 4415 '<span class=maxval><a href=" 4157 '<span class=maxval><a href="#r{10}max">Max={9}</a></span></td>'+\ 4416 '</tr>\n' 4158 '</tr>\n' 4417 headnone = '<tr class="head"><td>{0}< 4159 headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan='+\ 4418 colspan+'></td></tr>\n' 4160 colspan+'></td></tr>\n' 4419 for mode in sorted(list): 4161 for mode in sorted(list): 4420 # header line for each suspen 4162 # header line for each suspend mode 4421 num = 0 4163 num = 0 4422 tAvg, tMin, tMax, tMed = list 4164 tAvg, tMin, tMax, tMed = list[mode]['avg'], list[mode]['min'],\ 4423 list[mode]['max'], li 4165 list[mode]['max'], list[mode]['med'] 4424 count = len(list[mode]['data' 4166 count = len(list[mode]['data']) 4425 if 'idx' in list[mode]: 4167 if 'idx' in list[mode]: 4426 iMin, iMed, iMax = li 4168 iMin, iMed, iMax = list[mode]['idx'] 4427 html += head.format(' 4169 html += head.format('%d' % count, mode.upper(), 4428 '%.3f' % tAvg 4170 '%.3f' % tAvg[0], '%.3f' % tMin[0], '%.3f' % tMed[0], '%.3f' % tMax[0], 4429 '%.3f' % tAvg 4171 '%.3f' % tAvg[1], '%.3f' % tMin[1], '%.3f' % tMed[1], '%.3f' % tMax[1], 4430 mode.lower() 4172 mode.lower() 4431 ) 4173 ) 4432 else: 4174 else: 4433 iMin = iMed = iMax = 4175 iMin = iMed = iMax = [-1, -1, -1] 4434 html += headnone.form 4176 html += headnone.format('%d' % count, mode.upper()) 4435 for d in list[mode]['data']: 4177 for d in list[mode]['data']: 4436 # row classes - alter 4178 # row classes - alternate row color 4437 rcls = ['alt'] if num 4179 rcls = ['alt'] if num % 2 == 1 else [] 4438 if d[6] != 'pass': 4180 if d[6] != 'pass': 4439 rcls.append(' 4181 rcls.append('notice') 4440 html += '<tr class="' 4182 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4441 # figure out if the l 4183 # figure out if the line has sus or res highlighted 4442 idx = list[mode]['dat 4184 idx = list[mode]['data'].index(d) 4443 tHigh = ['', ''] 4185 tHigh = ['', ''] 4444 for i in range(2): 4186 for i in range(2): 4445 tag = 's%s' % 4187 tag = 's%s' % mode if i == 0 else 'r%s' % mode 4446 if idx == iMi 4188 if idx == iMin[i]: 4447 tHigh 4189 tHigh[i] = ' id="%smin" class=minval title="Minimum"' % tag 4448 elif idx == i 4190 elif idx == iMax[i]: 4449 tHigh 4191 tHigh[i] = ' id="%smax" class=maxval title="Maximum"' % tag 4450 elif idx == i 4192 elif idx == iMed[i]: 4451 tHigh 4193 tHigh[i] = ' id="%smed" class=medval title="Median"' % tag 4452 html += td.format("%d 4194 html += td.format("%d" % (list[mode]['data'].index(d) + 1)) # row 4453 html += td.format(d[1 !! 4195 html += td.format(mode) # mode 4454 html += td.format(d[0 4196 html += td.format(d[0]) # host 4455 html += td.format(d[1 4197 html += td.format(d[1]) # kernel 4456 html += td.format(d[2 4198 html += td.format(d[2]) # time 4457 html += td.format(d[6 4199 html += td.format(d[6]) # result 4458 html += td.format(d[7 4200 html += td.format(d[7]) # issues 4459 html += tdh.format('% 4201 html += tdh.format('%.3f ms' % d[3], tHigh[0]) if d[3] else td.format('') # suspend 4460 html += tdh.format('% 4202 html += tdh.format('%.3f ms' % d[4], tHigh[1]) if d[4] else td.format('') # resume 4461 html += td.format(d[8 4203 html += td.format(d[8]) # sus_worst 4462 html += td.format('%. 4204 html += td.format('%.3f ms' % d[9]) if d[9] else td.format('') # sus_worst time 4463 html += td.format(d[1 4205 html += td.format(d[10]) # res_worst 4464 html += td.format('%. 4206 html += td.format('%.3f ms' % d[11]) if d[11] else td.format('') # res_worst time 4465 if useturbo: 4207 if useturbo: 4466 html += td.fo 4208 html += td.format(d[12]) # pkg_pc10 4467 html += td.fo 4209 html += td.format(d[13]) # syslpi 4468 if usewifi: 4210 if usewifi: 4469 html += td.fo 4211 html += td.format(d[14]) # wifi 4470 html += tdlink.format 4212 html += tdlink.format(d[5]) if d[5] else td.format('') # url 4471 html += '</tr>\n' 4213 html += '</tr>\n' 4472 num += 1 4214 num += 1 4473 4215 4474 # flush the data to file 4216 # flush the data to file 4475 hf = open(htmlfile, 'w') 4217 hf = open(htmlfile, 'w') 4476 hf.write(html+'</table>\n</body>\n</h 4218 hf.write(html+'</table>\n</body>\n</html>\n') 4477 hf.close() 4219 hf.close() 4478 4220 4479 def createHTMLDeviceSummary(testruns, htmlfil 4221 def createHTMLDeviceSummary(testruns, htmlfile, title): 4480 html = summaryCSS('Device Summary - S 4222 html = summaryCSS('Device Summary - SleepGraph', False) 4481 4223 4482 # create global device list from all 4224 # create global device list from all tests 4483 devall = dict() 4225 devall = dict() 4484 for data in testruns: 4226 for data in testruns: 4485 host, url, devlist = data['ho 4227 host, url, devlist = data['host'], data['url'], data['devlist'] 4486 for type in devlist: 4228 for type in devlist: 4487 if type not in devall 4229 if type not in devall: 4488 devall[type] 4230 devall[type] = dict() 4489 mdevlist, devlist = d 4231 mdevlist, devlist = devall[type], data['devlist'][type] 4490 for name in devlist: 4232 for name in devlist: 4491 length = devl 4233 length = devlist[name] 4492 if name not i 4234 if name not in mdevlist: 4493 mdevl 4235 mdevlist[name] = {'name': name, 'host': host, 4494 4236 'worst': length, 'total': length, 'count': 1, 4495 4237 'url': url} 4496 else: 4238 else: 4497 if le 4239 if length > mdevlist[name]['worst']: 4498 4240 mdevlist[name]['worst'] = length 4499 4241 mdevlist[name]['url'] = url 4500 4242 mdevlist[name]['host'] = host 4501 mdevl 4243 mdevlist[name]['total'] += length 4502 mdevl 4244 mdevlist[name]['count'] += 1 4503 4245 4504 # generate the html 4246 # generate the html 4505 th = '\t<th>{0}</th>\n' 4247 th = '\t<th>{0}</th>\n' 4506 td = '\t<td align=center>{0}</td>\n' 4248 td = '\t<td align=center>{0}</td>\n' 4507 tdr = '\t<td align=right>{0}</td>\n' 4249 tdr = '\t<td align=right>{0}</td>\n' 4508 tdlink = '\t<td align=center><a href= 4250 tdlink = '\t<td align=center><a href="{0}">html</a></td>\n' 4509 limit = 1 4251 limit = 1 4510 for type in sorted(devall, reverse=Tr 4252 for type in sorted(devall, reverse=True): 4511 num = 0 4253 num = 0 4512 devlist = devall[type] 4254 devlist = devall[type] 4513 # table header 4255 # table header 4514 html += '<div class="stamp">% 4256 html += '<div class="stamp">%s (%s devices > %d ms)</div><table>\n' % \ 4515 (title, type.upper(), 4257 (title, type.upper(), limit) 4516 html += '<tr>\n' + '<th align 4258 html += '<tr>\n' + '<th align=right>Device Name</th>' +\ 4517 th.format('Average Ti 4259 th.format('Average Time') + th.format('Count') +\ 4518 th.format('Worst Time 4260 th.format('Worst Time') + th.format('Host (worst time)') +\ 4519 th.format('Link (wors 4261 th.format('Link (worst time)') + '</tr>\n' 4520 for name in sorted(devlist, k 4262 for name in sorted(devlist, key=lambda k:(devlist[k]['worst'], \ 4521 devlist[k]['total'], 4263 devlist[k]['total'], devlist[k]['name']), reverse=True): 4522 data = devall[type][n 4264 data = devall[type][name] 4523 data['average'] = dat 4265 data['average'] = data['total'] / data['count'] 4524 if data['average'] < 4266 if data['average'] < limit: 4525 continue 4267 continue 4526 # row classes - alter 4268 # row classes - alternate row color 4527 rcls = ['alt'] if num 4269 rcls = ['alt'] if num % 2 == 1 else [] 4528 html += '<tr class="' 4270 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4529 html += tdr.format(da 4271 html += tdr.format(data['name']) # name 4530 html += td.format('%. 4272 html += td.format('%.3f ms' % data['average']) # average 4531 html += td.format(dat 4273 html += td.format(data['count']) # count 4532 html += td.format('%. 4274 html += td.format('%.3f ms' % data['worst']) # worst 4533 html += td.format(dat 4275 html += td.format(data['host']) # host 4534 html += tdlink.format 4276 html += tdlink.format(data['url']) # url 4535 html += '</tr>\n' 4277 html += '</tr>\n' 4536 num += 1 4278 num += 1 4537 html += '</table>\n' 4279 html += '</table>\n' 4538 4280 4539 # flush the data to file 4281 # flush the data to file 4540 hf = open(htmlfile, 'w') 4282 hf = open(htmlfile, 'w') 4541 hf.write(html+'</body>\n</html>\n') 4283 hf.write(html+'</body>\n</html>\n') 4542 hf.close() 4284 hf.close() 4543 return devall 4285 return devall 4544 4286 4545 def createHTMLIssuesSummary(testruns, issues, 4287 def createHTMLIssuesSummary(testruns, issues, htmlfile, title, extra=''): 4546 multihost = len([e for e in issues if 4288 multihost = len([e for e in issues if len(e['urls']) > 1]) > 0 4547 html = summaryCSS('Issues Summary - S 4289 html = summaryCSS('Issues Summary - SleepGraph', False) 4548 total = len(testruns) 4290 total = len(testruns) 4549 4291 4550 # generate the html 4292 # generate the html 4551 th = '\t<th>{0}</th>\n' 4293 th = '\t<th>{0}</th>\n' 4552 td = '\t<td align={0}>{1}</td>\n' 4294 td = '\t<td align={0}>{1}</td>\n' 4553 tdlink = '<a href="{1}">{0}</a>' 4295 tdlink = '<a href="{1}">{0}</a>' 4554 subtitle = '%d issues' % len(issues) 4296 subtitle = '%d issues' % len(issues) if len(issues) > 0 else 'no issues' 4555 html += '<div class="stamp">%s (%s)</ 4297 html += '<div class="stamp">%s (%s)</div><table>\n' % (title, subtitle) 4556 html += '<tr>\n' + th.format('Issue') 4298 html += '<tr>\n' + th.format('Issue') + th.format('Count') 4557 if multihost: 4299 if multihost: 4558 html += th.format('Hosts') 4300 html += th.format('Hosts') 4559 html += th.format('Tests') + th.forma 4301 html += th.format('Tests') + th.format('Fail Rate') +\ 4560 th.format('First Instance') + 4302 th.format('First Instance') + '</tr>\n' 4561 4303 4562 num = 0 4304 num = 0 4563 for e in sorted(issues, key=lambda v: 4305 for e in sorted(issues, key=lambda v:v['count'], reverse=True): 4564 testtotal = 0 4306 testtotal = 0 4565 links = [] 4307 links = [] 4566 for host in sorted(e['urls']) 4308 for host in sorted(e['urls']): 4567 links.append(tdlink.f 4309 links.append(tdlink.format(host, e['urls'][host][0])) 4568 testtotal += len(e['u 4310 testtotal += len(e['urls'][host]) 4569 rate = '%d/%d (%.2f%%)' % (te 4311 rate = '%d/%d (%.2f%%)' % (testtotal, total, 100*float(testtotal)/float(total)) 4570 # row classes - alternate row 4312 # row classes - alternate row color 4571 rcls = ['alt'] if num % 2 == 4313 rcls = ['alt'] if num % 2 == 1 else [] 4572 html += '<tr class="'+(' '.jo 4314 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4573 html += td.format('left', e[' 4315 html += td.format('left', e['line']) # issue 4574 html += td.format('center', e 4316 html += td.format('center', e['count']) # count 4575 if multihost: 4317 if multihost: 4576 html += td.format('ce 4318 html += td.format('center', len(e['urls'])) # hosts 4577 html += td.format('center', t 4319 html += td.format('center', testtotal) # test count 4578 html += td.format('center', r 4320 html += td.format('center', rate) # test rate 4579 html += td.format('center now 4321 html += td.format('center nowrap', '<br>'.join(links)) # links 4580 html += '</tr>\n' 4322 html += '</tr>\n' 4581 num += 1 4323 num += 1 4582 4324 4583 # flush the data to file 4325 # flush the data to file 4584 hf = open(htmlfile, 'w') 4326 hf = open(htmlfile, 'w') 4585 hf.write(html+'</table>\n'+extra+'</b 4327 hf.write(html+'</table>\n'+extra+'</body>\n</html>\n') 4586 hf.close() 4328 hf.close() 4587 return issues 4329 return issues 4588 4330 4589 def ordinal(value): 4331 def ordinal(value): 4590 suffix = 'th' 4332 suffix = 'th' 4591 if value < 10 or value > 19: 4333 if value < 10 or value > 19: 4592 if value % 10 == 1: 4334 if value % 10 == 1: 4593 suffix = 'st' 4335 suffix = 'st' 4594 elif value % 10 == 2: 4336 elif value % 10 == 2: 4595 suffix = 'nd' 4337 suffix = 'nd' 4596 elif value % 10 == 3: 4338 elif value % 10 == 3: 4597 suffix = 'rd' 4339 suffix = 'rd' 4598 return '%d%s' % (value, suffix) 4340 return '%d%s' % (value, suffix) 4599 4341 4600 # Function: createHTML 4342 # Function: createHTML 4601 # Description: 4343 # Description: 4602 # Create the output html file from the 4344 # Create the output html file from the resident test data 4603 # Arguments: 4345 # Arguments: 4604 # testruns: array of Data objects from 4346 # testruns: array of Data objects from parseKernelLog or parseTraceLog 4605 # Output: 4347 # Output: 4606 # True if the html file was created, f 4348 # True if the html file was created, false if it failed 4607 def createHTML(testruns, testfail): 4349 def createHTML(testruns, testfail): 4608 if len(testruns) < 1: 4350 if len(testruns) < 1: 4609 pprint('ERROR: Not enough tes 4351 pprint('ERROR: Not enough test data to build a timeline') 4610 return 4352 return 4611 4353 4612 kerror = False 4354 kerror = False 4613 for data in testruns: 4355 for data in testruns: 4614 if data.kerror: 4356 if data.kerror: 4615 kerror = True 4357 kerror = True 4616 if(sysvals.suspendmode in ['f 4358 if(sysvals.suspendmode in ['freeze', 'standby']): 4617 data.trimFreezeTime(t 4359 data.trimFreezeTime(testruns[-1].tSuspended) 4618 else: 4360 else: 4619 data.getMemTime() 4361 data.getMemTime() 4620 4362 4621 # html function templates 4363 # html function templates 4622 html_error = '<div id="{1}" title="ke 4364 html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">{2}→</div>\n' 4623 html_traceevent = '<div title="{0}" c 4365 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 4366 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 4367 html_timetotal = '<table class="time1">\n<tr>'\ 4626 '<td class="green" title="{3} 4368 '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ 4627 '<td class="yellow" title="{4 4369 '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ 4628 '</tr>\n</table>\n' 4370 '</tr>\n</table>\n' 4629 html_timetotal2 = '<table class="time 4371 html_timetotal2 = '<table class="time1">\n<tr>'\ 4630 '<td class="green" title="{4} 4372 '<td class="green" title="{4}">{3} Suspend Time: <b>{0} ms</b></td>'\ 4631 '<td class="gray" title="time 4373 '<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 4374 '<td class="yellow" title="{5}">{3} Resume Time: <b>{2} ms</b></td>'\ 4633 '</tr>\n</table>\n' 4375 '</tr>\n</table>\n' 4634 html_timetotal3 = '<table class="time 4376 html_timetotal3 = '<table class="time1">\n<tr>'\ 4635 '<td class="green">Execution 4377 '<td class="green">Execution Time: <b>{0} ms</b></td>'\ 4636 '<td class="yellow">Command: 4378 '<td class="yellow">Command: <b>{1}</b></td>'\ 4637 '</tr>\n</table>\n' 4379 '</tr>\n</table>\n' 4638 html_fail = '<table class="testfail"> 4380 html_fail = '<table class="testfail"><tr><td>{0}</td></tr></table>\n' 4639 html_kdesc = '<td class="{3}" title=" 4381 html_kdesc = '<td class="{3}" title="time spent in kernel execution">{0}Kernel {2}: {1} ms</td>' 4640 html_fwdesc = '<td class="{3}" title= 4382 html_fwdesc = '<td class="{3}" title="time spent in firmware">{0}Firmware {2}: {1} ms</td>' 4641 html_wifdesc = '<td class="yellow" ti 4383 html_wifdesc = '<td class="yellow" title="time for wifi to reconnect after resume complete ({2})">{0}Wifi Resume: {1}</td>' 4642 4384 4643 # html format variables 4385 # html format variables 4644 scaleH = 20 4386 scaleH = 20 4645 if kerror: 4387 if kerror: 4646 scaleH = 40 4388 scaleH = 40 4647 4389 4648 # device timeline 4390 # device timeline 4649 devtl = Timeline(30, scaleH) 4391 devtl = Timeline(30, scaleH) 4650 4392 4651 # write the test title and general in 4393 # write the test title and general info header 4652 devtl.createHeader(sysvals, testruns[ 4394 devtl.createHeader(sysvals, testruns[0].stamp) 4653 4395 4654 # Generate the header for this timeli 4396 # Generate the header for this timeline 4655 for data in testruns: 4397 for data in testruns: 4656 tTotal = data.end - data.star 4398 tTotal = data.end - data.start 4657 if(tTotal == 0): 4399 if(tTotal == 0): 4658 doError('No timeline 4400 doError('No timeline data') 4659 if sysvals.suspendmode == 'co 4401 if sysvals.suspendmode == 'command': 4660 run_time = '%.0f' % ( 4402 run_time = '%.0f' % (tTotal * 1000) 4661 if sysvals.testcomman 4403 if sysvals.testcommand: 4662 testdesc = sy 4404 testdesc = sysvals.testcommand 4663 else: 4405 else: 4664 testdesc = 'u 4406 testdesc = 'unknown' 4665 if(len(testruns) > 1) 4407 if(len(testruns) > 1): 4666 testdesc = or 4408 testdesc = ordinal(data.testnumber+1)+' '+testdesc 4667 thtml = html_timetota 4409 thtml = html_timetotal3.format(run_time, testdesc) 4668 devtl.html += thtml 4410 devtl.html += thtml 4669 continue 4411 continue 4670 # typical full suspend/resume 4412 # typical full suspend/resume header 4671 stot, rtot = sktime, rktime = 4413 stot, rtot = sktime, rktime = data.getTimeValues() 4672 ssrc, rsrc, testdesc, testdes 4414 ssrc, rsrc, testdesc, testdesc2 = ['kernel'], ['kernel'], 'Kernel', '' 4673 if data.fwValid: 4415 if data.fwValid: 4674 stot += (data.fwSuspe 4416 stot += (data.fwSuspend/1000000.0) 4675 rtot += (data.fwResum 4417 rtot += (data.fwResume/1000000.0) 4676 ssrc.append('firmware 4418 ssrc.append('firmware') 4677 rsrc.append('firmware 4419 rsrc.append('firmware') 4678 testdesc = 'Total' 4420 testdesc = 'Total' 4679 if 'time' in data.wifi and da 4421 if 'time' in data.wifi and data.wifi['stat'] != 'timeout': 4680 rtot += data.end - da 4422 rtot += data.end - data.tKernRes + (data.wifi['time'] * 1000.0) 4681 rsrc.append('wifi') 4423 rsrc.append('wifi') 4682 testdesc = 'Total' 4424 testdesc = 'Total' 4683 suspend_time, resume_time = ' 4425 suspend_time, resume_time = '%.3f' % stot, '%.3f' % rtot 4684 stitle = 'time from kernel su 4426 stitle = 'time from kernel suspend start to %s mode [%s time]' % \ 4685 (sysvals.suspendmode, 4427 (sysvals.suspendmode, ' & '.join(ssrc)) 4686 rtitle = 'time from %s mode t 4428 rtitle = 'time from %s mode to kernel resume complete [%s time]' % \ 4687 (sysvals.suspendmode, 4429 (sysvals.suspendmode, ' & '.join(rsrc)) 4688 if(len(testruns) > 1): 4430 if(len(testruns) > 1): 4689 testdesc = testdesc2 4431 testdesc = testdesc2 = ordinal(data.testnumber+1) 4690 testdesc2 += ' ' 4432 testdesc2 += ' ' 4691 if(len(data.tLow) == 0): 4433 if(len(data.tLow) == 0): 4692 thtml = html_timetota 4434 thtml = html_timetotal.format(suspend_time, \ 4693 resume_time, 4435 resume_time, testdesc, stitle, rtitle) 4694 else: 4436 else: 4695 low_time = '+'.join(d 4437 low_time = '+'.join(data.tLow) 4696 thtml = html_timetota 4438 thtml = html_timetotal2.format(suspend_time, low_time, \ 4697 resume_time, 4439 resume_time, testdesc, stitle, rtitle) 4698 devtl.html += thtml 4440 devtl.html += thtml 4699 if not data.fwValid and 'dev' 4441 if not data.fwValid and 'dev' not in data.wifi: 4700 continue 4442 continue 4701 # extra detail when the times 4443 # extra detail when the times come from multiple sources 4702 thtml = '<table class="time2" 4444 thtml = '<table class="time2">\n<tr>' 4703 thtml += html_kdesc.format(te 4445 thtml += html_kdesc.format(testdesc2, '%.3f'%sktime, 'Suspend', 'green') 4704 if data.fwValid: 4446 if data.fwValid: 4705 sftime = '%.3f'%(data 4447 sftime = '%.3f'%(data.fwSuspend / 1000000.0) 4706 rftime = '%.3f'%(data 4448 rftime = '%.3f'%(data.fwResume / 1000000.0) 4707 thtml += html_fwdesc. 4449 thtml += html_fwdesc.format(testdesc2, sftime, 'Suspend', 'green') 4708 thtml += html_fwdesc. 4450 thtml += html_fwdesc.format(testdesc2, rftime, 'Resume', 'yellow') 4709 thtml += html_kdesc.format(te 4451 thtml += html_kdesc.format(testdesc2, '%.3f'%rktime, 'Resume', 'yellow') 4710 if 'time' in data.wifi: 4452 if 'time' in data.wifi: 4711 if data.wifi['stat'] 4453 if data.wifi['stat'] != 'timeout': 4712 wtime = '%.0f 4454 wtime = '%.0f ms'%(data.end - data.tKernRes + (data.wifi['time'] * 1000.0)) 4713 else: 4455 else: 4714 wtime = 'TIME 4456 wtime = 'TIMEOUT' 4715 thtml += html_wifdesc 4457 thtml += html_wifdesc.format(testdesc2, wtime, data.wifi['dev']) 4716 thtml += '</tr>\n</table>\n' 4458 thtml += '</tr>\n</table>\n' 4717 devtl.html += thtml 4459 devtl.html += thtml 4718 if testfail: 4460 if testfail: 4719 devtl.html += html_fail.forma 4461 devtl.html += html_fail.format(testfail) 4720 4462 4721 # time scale for potentially multiple 4463 # time scale for potentially multiple datasets 4722 t0 = testruns[0].start 4464 t0 = testruns[0].start 4723 tMax = testruns[-1].end 4465 tMax = testruns[-1].end 4724 tTotal = tMax - t0 4466 tTotal = tMax - t0 4725 4467 4726 # determine the maximum number of row 4468 # determine the maximum number of rows we need to draw 4727 fulllist = [] 4469 fulllist = [] 4728 threadlist = [] 4470 threadlist = [] 4729 pscnt = 0 4471 pscnt = 0 4730 devcnt = 0 4472 devcnt = 0 4731 for data in testruns: 4473 for data in testruns: 4732 data.selectTimelineDevices('% 4474 data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen) 4733 for group in data.devicegroup 4475 for group in data.devicegroups: 4734 devlist = [] 4476 devlist = [] 4735 for phase in group: 4477 for phase in group: 4736 for devname i 4478 for devname in sorted(data.tdevlist[phase]): 4737 d = D 4479 d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname]) 4738 devli 4480 devlist.append(d) 4739 if d. 4481 if d.isa('kth'): 4740 4482 threadlist.append(d) 4741 else: 4483 else: 4742 4484 if d.isa('ps'): 4743 4485 pscnt += 1 4744 4486 else: 4745 4487 devcnt += 1 4746 4488 fulllist.append(d) 4747 if sysvals.mixedphase 4489 if sysvals.mixedphaseheight: 4748 devtl.getPhas 4490 devtl.getPhaseRows(devlist) 4749 if not sysvals.mixedphaseheight: 4491 if not sysvals.mixedphaseheight: 4750 if len(threadlist) > 0 and le 4492 if len(threadlist) > 0 and len(fulllist) > 0: 4751 if pscnt > 0 and devc 4493 if pscnt > 0 and devcnt > 0: 4752 msg = 'user p 4494 msg = 'user processes & device pm callbacks' 4753 elif pscnt > 0: 4495 elif pscnt > 0: 4754 msg = 'user p 4496 msg = 'user processes' 4755 else: 4497 else: 4756 msg = 'device 4498 msg = 'device pm callbacks' 4757 d = testruns[0].addHo 4499 d = testruns[0].addHorizontalDivider(msg, testruns[-1].end) 4758 fulllist.insert(0, d) 4500 fulllist.insert(0, d) 4759 devtl.getPhaseRows(fulllist) 4501 devtl.getPhaseRows(fulllist) 4760 if len(threadlist) > 0: 4502 if len(threadlist) > 0: 4761 d = testruns[0].addHo 4503 d = testruns[0].addHorizontalDivider('asynchronous kernel threads', testruns[-1].end) 4762 threadlist.insert(0, 4504 threadlist.insert(0, d) 4763 devtl.getPhaseRows(th 4505 devtl.getPhaseRows(threadlist, devtl.rows) 4764 devtl.calcTotalRows() 4506 devtl.calcTotalRows() 4765 4507 4766 # draw the full timeline 4508 # draw the full timeline 4767 devtl.createZoomBox(sysvals.suspendmo 4509 devtl.createZoomBox(sysvals.suspendmode, len(testruns)) 4768 for data in testruns: 4510 for data in testruns: 4769 # draw each test run and bloc 4511 # draw each test run and block chronologically 4770 phases = {'suspend':[],'resum 4512 phases = {'suspend':[],'resume':[]} 4771 for phase in data.sortedPhase 4513 for phase in data.sortedPhases(): 4772 if data.dmesg[phase][ 4514 if data.dmesg[phase]['start'] >= data.tSuspended: 4773 phases['resum 4515 phases['resume'].append(phase) 4774 else: 4516 else: 4775 phases['suspe 4517 phases['suspend'].append(phase) 4776 # now draw the actual timelin 4518 # now draw the actual timeline blocks 4777 for dir in phases: 4519 for dir in phases: 4778 # draw suspend and re 4520 # draw suspend and resume blocks separately 4779 bname = '%s%d' % (dir 4521 bname = '%s%d' % (dir[0], data.testnumber) 4780 if dir == 'suspend': 4522 if dir == 'suspend': 4781 m0 = data.sta 4523 m0 = data.start 4782 mMax = data.t 4524 mMax = data.tSuspended 4783 left = '%f' % 4525 left = '%f' % (((m0-t0)*100.0)/tTotal) 4784 else: 4526 else: 4785 m0 = data.tSu 4527 m0 = data.tSuspended 4786 mMax = data.e 4528 mMax = data.end 4787 # in an x2 ru 4529 # in an x2 run, remove any gap between blocks 4788 if len(testru 4530 if len(testruns) > 1 and data.testnumber == 0: 4789 mMax 4531 mMax = testruns[1].start 4790 left = '%f' % 4532 left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal) 4791 mTotal = mMax - m0 4533 mTotal = mMax - m0 4792 # if a timeline block 4534 # if a timeline block is 0 length, skip altogether 4793 if mTotal == 0: 4535 if mTotal == 0: 4794 continue 4536 continue 4795 width = '%f' % (((mTo 4537 width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal) 4796 devtl.html += devtl.h 4538 devtl.html += devtl.html_tblock.format(bname, left, width, devtl.scaleH) 4797 for b in phases[dir]: 4539 for b in phases[dir]: 4798 # draw the ph 4540 # draw the phase color background 4799 phase = data. 4541 phase = data.dmesg[b] 4800 length = phas 4542 length = phase['end']-phase['start'] 4801 left = '%f' % 4543 left = '%f' % (((phase['start']-m0)*100.0)/mTotal) 4802 width = '%f' 4544 width = '%f' % ((length*100.0)/mTotal) 4803 devtl.html += 4545 devtl.html += devtl.html_phase.format(left, width, \ 4804 '%.3f 4546 '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ 4805 data. 4547 data.dmesg[b]['color'], '') 4806 for e in data.errorin 4548 for e in data.errorinfo[dir]: 4807 # draw red li 4549 # draw red lines for any kernel errors found 4808 type, t, idx1 4550 type, t, idx1, idx2 = e 4809 id = '%d_%d' 4551 id = '%d_%d' % (idx1, idx2) 4810 right = '%f' 4552 right = '%f' % (((mMax-t)*100.0)/mTotal) 4811 devtl.html += 4553 devtl.html += html_error.format(right, id, type) 4812 for b in phases[dir]: 4554 for b in phases[dir]: 4813 # draw the de 4555 # draw the devices for this phase 4814 phaselist = d 4556 phaselist = data.dmesg[b]['list'] 4815 for d in sort 4557 for d in sorted(data.tdevlist[b]): 4816 dname !! 4558 dname = d if '[' not in d else d.split('[')[0] 4817 name, 4559 name, dev = dname, phaselist[d] 4818 drv = 4560 drv = xtraclass = xtrainfo = xtrastyle = '' 4819 if 'h 4561 if 'htmlclass' in dev: 4820 4562 xtraclass = dev['htmlclass'] 4821 if 'c 4563 if 'color' in dev: 4822 4564 xtrastyle = 'background:%s;' % dev['color'] 4823 if(d 4565 if(d in sysvals.devprops): 4824 4566 name = sysvals.devprops[d].altName(d) 4825 4567 xtraclass = sysvals.devprops[d].xtraClass() 4826 4568 xtrainfo = sysvals.devprops[d].xtraInfo() 4827 elif 4569 elif xtraclass == ' kth': 4828 4570 xtrainfo = ' kernel_thread' 4829 if('d 4571 if('drv' in dev and dev['drv']): 4830 4572 drv = ' {%s}' % dev['drv'] 4831 rowhe 4573 rowheight = devtl.phaseRowHeight(data.testnumber, b, dev['row']) 4832 rowto 4574 rowtop = devtl.phaseRowTop(data.testnumber, b, dev['row']) 4833 top = 4575 top = '%.3f' % (rowtop + devtl.scaleH) 4834 left 4576 left = '%f' % (((dev['start']-m0)*100)/mTotal) 4835 width 4577 width = '%f' % (((dev['end']-dev['start'])*100)/mTotal) 4836 lengt 4578 length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) 4837 title 4579 title = name+drv+xtrainfo+length 4838 if sy 4580 if sysvals.suspendmode == 'command': 4839 4581 title += sysvals.testcommand 4840 elif 4582 elif xtraclass == ' ps': 4841 4583 if 'suspend' in b: 4842 4584 title += 'pre_suspend_process' 4843 4585 else: 4844 4586 title += 'post_resume_process' 4845 else: 4587 else: 4846 4588 title += b 4847 devtl 4589 devtl.html += devtl.html_device.format(dev['id'], \ 4848 4590 title, left, top, '%.3f'%rowheight, width, \ 4849 4591 dname+drv, xtraclass, xtrastyle) 4850 if('c 4592 if('cpuexec' in dev): 4851 4593 for t in sorted(dev['cpuexec']): 4852 4594 start, end = t >> 4595 j = float(dev['cpuexec'][t]) / 5 >> 4596 if j > 1.0: >> 4597 j = 1.0 4853 4598 height = '%.3f' % (rowheight/3) 4854 4599 top = '%.3f' % (rowtop + devtl.scaleH + 2*rowheight/3) 4855 4600 left = '%f' % (((start-m0)*100)/mTotal) 4856 4601 width = '%f' % ((end-start)*100/mTotal) 4857 !! 4602 color = 'rgba(255, 0, 0, %f)' % j 4858 4603 devtl.html += \ 4859 4604 html_cpuexec.format(left, top, height, width, color) 4860 if('s 4605 if('src' not in dev): 4861 4606 continue 4862 # dra 4607 # draw any trace events for this device 4863 for e 4608 for e in dev['src']: 4864 4609 if e.length == 0: 4865 4610 continue 4866 4611 height = '%.3f' % devtl.rowH 4867 4612 top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH)) 4868 4613 left = '%f' % (((e.time-m0)*100)/mTotal) 4869 4614 width = '%f' % (e.length*100/mTotal) 4870 4615 xtrastyle = '' 4871 4616 if e.color: 4872 4617 xtrastyle = 'background:%s;' % e.color 4873 4618 devtl.html += \ 4874 4619 html_traceevent.format(e.title(), \ 4875 4620 left, top, height, width, e.text(), '', xtrastyle) 4876 # draw the time scale 4621 # draw the time scale, try to make the number of labels readable 4877 devtl.createTimeScale 4622 devtl.createTimeScale(m0, mMax, tTotal, dir) 4878 devtl.html += '</div> 4623 devtl.html += '</div>\n' 4879 4624 4880 # timeline is finished 4625 # timeline is finished 4881 devtl.html += '</div>\n</div>\n' 4626 devtl.html += '</div>\n</div>\n' 4882 4627 4883 # draw a legend which describes the p 4628 # draw a legend which describes the phases by color 4884 if sysvals.suspendmode != 'command': 4629 if sysvals.suspendmode != 'command': 4885 phasedef = testruns[-1].phase 4630 phasedef = testruns[-1].phasedef 4886 devtl.html += '<div class="le 4631 devtl.html += '<div class="legend">\n' 4887 pdelta = 100.0/len(phasedef.k 4632 pdelta = 100.0/len(phasedef.keys()) 4888 pmargin = pdelta / 4.0 4633 pmargin = pdelta / 4.0 4889 for phase in sorted(phasedef, 4634 for phase in sorted(phasedef, key=lambda k:phasedef[k]['order']): 4890 id, p = '', phasedef[ 4635 id, p = '', phasedef[phase] 4891 for word in phase.spl 4636 for word in phase.split('_'): 4892 id += word[0] 4637 id += word[0] 4893 order = '%.2f' % ((p[ 4638 order = '%.2f' % ((p['order'] * pdelta) + pmargin) 4894 name = phase.replace( 4639 name = phase.replace('_', ' ') 4895 devtl.html += devtl.h 4640 devtl.html += devtl.html_legend.format(order, p['color'], name, id) 4896 devtl.html += '</div>\n' 4641 devtl.html += '</div>\n' 4897 4642 4898 hf = open(sysvals.htmlfile, 'w') 4643 hf = open(sysvals.htmlfile, 'w') 4899 addCSS(hf, sysvals, len(testruns), ke 4644 addCSS(hf, sysvals, len(testruns), kerror) 4900 4645 4901 # write the device timeline 4646 # write the device timeline 4902 hf.write(devtl.html) 4647 hf.write(devtl.html) 4903 hf.write('<div id="devicedetailtitle" 4648 hf.write('<div id="devicedetailtitle"></div>\n') 4904 hf.write('<div id="devicedetail" styl 4649 hf.write('<div id="devicedetail" style="display:none;">\n') 4905 # draw the colored boxes for the devi 4650 # draw the colored boxes for the device detail section 4906 for data in testruns: 4651 for data in testruns: 4907 hf.write('<div id="devicedeta 4652 hf.write('<div id="devicedetail%d">\n' % data.testnumber) 4908 pscolor = 'linear-gradient(to 4653 pscolor = 'linear-gradient(to top left, #ccc, #eee)' 4909 hf.write(devtl.html_phaselet. 4654 hf.write(devtl.html_phaselet.format('pre_suspend_process', \ 4910 '0', '0', pscolor)) 4655 '0', '0', pscolor)) 4911 for b in data.sortedPhases(): 4656 for b in data.sortedPhases(): 4912 phase = data.dmesg[b] 4657 phase = data.dmesg[b] 4913 length = phase['end'] 4658 length = phase['end']-phase['start'] 4914 left = '%.3f' % (((ph 4659 left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) 4915 width = '%.3f' % ((le 4660 width = '%.3f' % ((length*100.0)/tTotal) 4916 hf.write(devtl.html_p 4661 hf.write(devtl.html_phaselet.format(b, left, width, \ 4917 data.dmesg[b] 4662 data.dmesg[b]['color'])) 4918 hf.write(devtl.html_phaselet. 4663 hf.write(devtl.html_phaselet.format('post_resume_process', \ 4919 '0', '0', pscolor)) 4664 '0', '0', pscolor)) 4920 if sysvals.suspendmode == 'co 4665 if sysvals.suspendmode == 'command': 4921 hf.write(devtl.html_p 4666 hf.write(devtl.html_phaselet.format('cmdexec', '0', '0', pscolor)) 4922 hf.write('</div>\n') 4667 hf.write('</div>\n') 4923 hf.write('</div>\n') 4668 hf.write('</div>\n') 4924 4669 4925 # write the ftrace data (callgraph) 4670 # write the ftrace data (callgraph) 4926 if sysvals.cgtest >= 0 and len(testru 4671 if sysvals.cgtest >= 0 and len(testruns) > sysvals.cgtest: 4927 data = testruns[sysvals.cgtes 4672 data = testruns[sysvals.cgtest] 4928 else: 4673 else: 4929 data = testruns[-1] 4674 data = testruns[-1] 4930 if sysvals.usecallgraph: 4675 if sysvals.usecallgraph: 4931 addCallgraphs(sysvals, hf, da 4676 addCallgraphs(sysvals, hf, data) 4932 4677 4933 # add the test log as a hidden div 4678 # add the test log as a hidden div 4934 if sysvals.testlog and sysvals.logmsg 4679 if sysvals.testlog and sysvals.logmsg: 4935 hf.write('<div id="testlog" s 4680 hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') 4936 # add the dmesg log as a hidden div 4681 # add the dmesg log as a hidden div 4937 if sysvals.dmesglog and sysvals.dmesg 4682 if sysvals.dmesglog and sysvals.dmesgfile: 4938 hf.write('<div id="dmesglog" 4683 hf.write('<div id="dmesglog" style="display:none;">\n') 4939 lf = sysvals.openlog(sysvals. 4684 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 4940 for line in lf: 4685 for line in lf: 4941 line = line.replace(' 4686 line = line.replace('<', '<').replace('>', '>') 4942 hf.write(line) 4687 hf.write(line) 4943 lf.close() 4688 lf.close() 4944 hf.write('</div>\n') 4689 hf.write('</div>\n') 4945 # add the ftrace log as a hidden div 4690 # add the ftrace log as a hidden div 4946 if sysvals.ftracelog and sysvals.ftra 4691 if sysvals.ftracelog and sysvals.ftracefile: 4947 hf.write('<div id="ftracelog" 4692 hf.write('<div id="ftracelog" style="display:none;">\n') 4948 lf = sysvals.openlog(sysvals. 4693 lf = sysvals.openlog(sysvals.ftracefile, 'r') 4949 for line in lf: 4694 for line in lf: 4950 hf.write(line) 4695 hf.write(line) 4951 lf.close() 4696 lf.close() 4952 hf.write('</div>\n') 4697 hf.write('</div>\n') 4953 4698 4954 # write the footer and close 4699 # write the footer and close 4955 addScriptCode(hf, testruns) 4700 addScriptCode(hf, testruns) 4956 hf.write('</body>\n</html>\n') 4701 hf.write('</body>\n</html>\n') 4957 hf.close() 4702 hf.close() 4958 return True 4703 return True 4959 4704 4960 def addCSS(hf, sv, testcount=1, kerror=False, 4705 def addCSS(hf, sv, testcount=1, kerror=False, extra=''): 4961 kernel = sv.stamp['kernel'] 4706 kernel = sv.stamp['kernel'] 4962 host = sv.hostname[0].upper()+sv.host 4707 host = sv.hostname[0].upper()+sv.hostname[1:] 4963 mode = sv.suspendmode 4708 mode = sv.suspendmode 4964 if sv.suspendmode in suspendmodename: 4709 if sv.suspendmode in suspendmodename: 4965 mode = suspendmodename[sv.sus 4710 mode = suspendmodename[sv.suspendmode] 4966 title = host+' '+mode+' '+kernel 4711 title = host+' '+mode+' '+kernel 4967 4712 4968 # various format changes by flags 4713 # various format changes by flags 4969 cgchk = 'checked' 4714 cgchk = 'checked' 4970 cgnchk = 'not(:checked)' 4715 cgnchk = 'not(:checked)' 4971 if sv.cgexp: 4716 if sv.cgexp: 4972 cgchk = 'not(:checked)' 4717 cgchk = 'not(:checked)' 4973 cgnchk = 'checked' 4718 cgnchk = 'checked' 4974 4719 4975 hoverZ = 'z-index:8;' 4720 hoverZ = 'z-index:8;' 4976 if sv.usedevsrc: 4721 if sv.usedevsrc: 4977 hoverZ = '' 4722 hoverZ = '' 4978 4723 4979 devlistpos = 'absolute' 4724 devlistpos = 'absolute' 4980 if testcount > 1: 4725 if testcount > 1: 4981 devlistpos = 'relative' 4726 devlistpos = 'relative' 4982 4727 4983 scaleTH = 20 4728 scaleTH = 20 4984 if kerror: 4729 if kerror: 4985 scaleTH = 60 4730 scaleTH = 60 4986 4731 4987 # write the html header first (html h 4732 # write the html header first (html head, css code, up to body start) 4988 html_header = '<!DOCTYPE html>\n<html 4733 html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ 4989 <meta http-equiv="content-type" conte 4734 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 4990 <title>'+title+'</title>\n\ 4735 <title>'+title+'</title>\n\ 4991 <style type=\'text/css\'>\n\ 4736 <style type=\'text/css\'>\n\ 4992 body {overflow-y:scroll;}\n\ 4737 body {overflow-y:scroll;}\n\ 4993 .stamp {width:100%;text-align 4738 .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ 4994 .stamp.sysinfo {font:10px Ari 4739 .stamp.sysinfo {font:10px Arial;}\n\ 4995 .callgraph {margin-top:30px;b 4740 .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ 4996 .callgraph article * {padding 4741 .callgraph article * {padding-left:28px;}\n\ 4997 h1 {color:black;font:bold 30p 4742 h1 {color:black;font:bold 30px Times;}\n\ 4998 t0 {color:black;font:bold 30p 4743 t0 {color:black;font:bold 30px Times;}\n\ 4999 t1 {color:black;font:30px Tim 4744 t1 {color:black;font:30px Times;}\n\ 5000 t2 {color:black;font:25px Tim 4745 t2 {color:black;font:25px Times;}\n\ 5001 t3 {color:black;font:20px Tim 4746 t3 {color:black;font:20px Times;white-space:nowrap;}\n\ 5002 t4 {color:black;font:bold 30p 4747 t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ 5003 cS {font:bold 13px Times;}\n\ 4748 cS {font:bold 13px Times;}\n\ 5004 table {width:100%;}\n\ 4749 table {width:100%;}\n\ 5005 .gray {background:rgba(80,80, 4750 .gray {background:rgba(80,80,80,0.1);}\n\ 5006 .green {background:rgba(204,2 4751 .green {background:rgba(204,255,204,0.4);}\n\ 5007 .purple {background:rgba(128, 4752 .purple {background:rgba(128,0,128,0.2);}\n\ 5008 .yellow {background:rgba(255, 4753 .yellow {background:rgba(255,255,204,0.4);}\n\ 5009 .blue {background:rgba(169,20 4754 .blue {background:rgba(169,208,245,0.4);}\n\ 5010 .time1 {font:22px Arial;borde 4755 .time1 {font:22px Arial;border:1px solid;}\n\ 5011 .time2 {font:15px Arial;borde 4756 .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ 5012 .testfail {font:bold 22px Ari 4757 .testfail {font:bold 22px Arial;color:red;border:1px dashed;}\n\ 5013 td {text-align:center;}\n\ 4758 td {text-align:center;}\n\ 5014 r {color:#500000;font:15px Ta 4759 r {color:#500000;font:15px Tahoma;}\n\ 5015 n {color:#505050;font:15px Ta 4760 n {color:#505050;font:15px Tahoma;}\n\ 5016 .tdhl {color:red;}\n\ 4761 .tdhl {color:red;}\n\ 5017 .hide {display:none;}\n\ 4762 .hide {display:none;}\n\ 5018 .pf {display:none;}\n\ 4763 .pf {display:none;}\n\ 5019 .pf:'+cgchk+' + label {backgr 4764 .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 4765 .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 4766 .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ 5022 .zoombox {position:relative;w 4767 .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ 5023 .timeline {position:relative; 4768 .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ 5024 .thread {position:absolute;he 4769 .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 4770 .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ 5026 .thread:hover {background:whi 4771 .thread:hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 5027 .thread.sec,.thread.sec:hover 4772 .thread.sec,.thread.sec:hover {background:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ 5028 .hover {background:white;bord 4773 .hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 5029 .hover.sync {background:white 4774 .hover.sync {background:white;}\n\ 5030 .hover.bg,.hover.kth,.hover.s 4775 .hover.bg,.hover.kth,.hover.sync,.hover.ps {background:white;}\n\ 5031 .jiffie {position:absolute;po 4776 .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ 5032 .traceevent {position:absolut 4777 .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 4778 .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ 5034 .phase {position:absolute;ove 4779 .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ 5035 .phaselet {float:left;overflo 4780 .phaselet {float:left;overflow:hidden;border:0px;text-align:center;min-height:100px;font-size:24px;}\n\ 5036 .t {position:absolute;line-he 4781 .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 4782 .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 4783 .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ 5039 .legend .square {position:abs 4784 .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 4785 button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ 5041 .btnfmt {position:relative;fl 4786 .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 4787 .devlist {position:'+devlistpos+';width:190px;}\n\ 5043 a:link {color:white;text-deco 4788 a:link {color:white;text-decoration:none;}\n\ 5044 a:visited {color:white;}\n\ 4789 a:visited {color:white;}\n\ 5045 a:hover {color:white;}\n\ 4790 a:hover {color:white;}\n\ 5046 a:active {color:white;}\n\ 4791 a:active {color:white;}\n\ 5047 .version {position:relative;f 4792 .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ 5048 #devicedetail {min-height:100 4793 #devicedetail {min-height:100px;box-shadow:5px 5px 20px black;}\n\ 5049 .tblock {position:absolute;he 4794 .tblock {position:absolute;height:100%;background:#ddd;}\n\ 5050 .tback {position:absolute;wid 4795 .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ 5051 .bg {z-index:1;}\n\ 4796 .bg {z-index:1;}\n\ 5052 '+extra+'\ 4797 '+extra+'\ 5053 </style>\n</head>\n<body>\n' 4798 </style>\n</head>\n<body>\n' 5054 hf.write(html_header) 4799 hf.write(html_header) 5055 4800 5056 # Function: addScriptCode 4801 # Function: addScriptCode 5057 # Description: 4802 # Description: 5058 # Adds the javascript code to the outp 4803 # Adds the javascript code to the output html 5059 # Arguments: 4804 # Arguments: 5060 # hf: the open html file pointer 4805 # hf: the open html file pointer 5061 # testruns: array of Data objects from 4806 # testruns: array of Data objects from parseKernelLog or parseTraceLog 5062 def addScriptCode(hf, testruns): 4807 def addScriptCode(hf, testruns): 5063 t0 = testruns[0].start * 1000 4808 t0 = testruns[0].start * 1000 5064 tMax = testruns[-1].end * 1000 4809 tMax = testruns[-1].end * 1000 5065 hf.write('<script type="text/javascri << 5066 # create an array in javascript memor 4810 # create an array in javascript memory with the device details 5067 detail = ' var devtable = [];\n' 4811 detail = ' var devtable = [];\n' 5068 for data in testruns: 4812 for data in testruns: 5069 topo = data.deviceTopology() 4813 topo = data.deviceTopology() 5070 detail += ' devtable[%d] 4814 detail += ' devtable[%d] = "%s";\n' % (data.testnumber, topo) 5071 detail += ' var bounds = [%f,%f]; 4815 detail += ' var bounds = [%f,%f];\n' % (t0, tMax) 5072 # add the code which will manipulate 4816 # add the code which will manipulate the data in the browser 5073 hf.write(detail); !! 4817 script_code = \ 5074 script_code = r""" var resolutio !! 4818 '<script type="text/javascript">\n'+detail+\ 5075 var dragval = [0, 0]; !! 4819 ' var resolution = -1;\n'\ 5076 function redrawTimescale(t0, tMax, tS !! 4820 ' var dragval = [0, 0];\n'\ 5077 var rline = '<div class="t" s !! 4821 ' function redrawTimescale(t0, tMax, tS) {\n'\ 5078 var tTotal = tMax - t0; !! 4822 ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;">\';\n'\ 5079 var list = document.getElemen !! 4823 ' var tTotal = tMax - t0;\n'\ 5080 for (var i = 0; i < list.leng !! 4824 ' var list = document.getElementsByClassName("tblock");\n'\ 5081 var timescale = list[ !! 4825 ' for (var i = 0; i < list.length; i++) {\n'\ 5082 var m0 = t0 + (tTotal !! 4826 ' var timescale = list[i].getElementsByClassName("timescale")[0];\n'\ 5083 var mTotal = tTotal*p !! 4827 ' var m0 = t0 + (tTotal*parseFloat(list[i].style.left)/100);\n'\ 5084 var mMax = m0 + mTota !! 4828 ' var mTotal = tTotal*parseFloat(list[i].style.width)/100;\n'\ 5085 var html = ""; !! 4829 ' var mMax = m0 + mTotal;\n'\ 5086 var divTotal = Math.f !! 4830 ' var html = "";\n'\ 5087 if(divTotal > 1000) c !! 4831 ' var divTotal = Math.floor(mTotal/tS) + 1;\n'\ 5088 var divEdge = (mTotal !! 4832 ' if(divTotal > 1000) continue;\n'\ 5089 var pos = 0.0, val = !! 4833 ' var divEdge = (mTotal - tS*(divTotal-1))*100/mTotal;\n'\ 5090 for (var j = 0; j < d !! 4834 ' var pos = 0.0, val = 0.0;\n'\ 5091 var htmlline !! 4835 ' for (var j = 0; j < divTotal; j++) {\n'\ 5092 var mode = li !! 4836 ' var htmlline = "";\n'\ 5093 if(mode == "s !! 4837 ' var mode = list[i].id[5];\n'\ 5094 pos = !! 4838 ' if(mode == "s") {\n'\ 5095 val = !! 4839 ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\ 5096 if(j !! 4840 ' val = (j-divTotal+1)*tS;\n'\ 5097 !! 4841 ' if(j == divTotal - 1)\n'\ 5098 else !! 4842 ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S→</cS></div>\';\n'\ 5099 !! 4843 ' else\n'\ 5100 } else { !! 4844 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 5101 pos = !! 4845 ' } else {\n'\ 5102 val = !! 4846 ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ 5103 htmll !! 4847 ' val = (j)*tS;\n'\ 5104 if(j !! 4848 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 5105 !! 4849 ' if(j == 0)\n'\ 5106 !! 4850 ' if(mode == "r")\n'\ 5107 !! 4851 ' htmlline = rline+"<cS>←R</cS></div>";\n'\ 5108 !! 4852 ' else\n'\ 5109 } !! 4853 ' htmlline = rline+"<cS>0ms</div>";\n'\ 5110 html += htmll !! 4854 ' }\n'\ 5111 } !! 4855 ' html += htmlline;\n'\ 5112 timescale.innerHTML = !! 4856 ' }\n'\ 5113 } !! 4857 ' timescale.innerHTML = html;\n'\ 5114 } !! 4858 ' }\n'\ 5115 function zoomTimeline() { !! 4859 ' }\n'\ 5116 var dmesg = document.getEleme !! 4860 ' function zoomTimeline() {\n'\ 5117 var zoombox = document.getEle !! 4861 ' var dmesg = document.getElementById("dmesg");\n'\ 5118 var left = zoombox.scrollLeft !! 4862 ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 5119 var val = parseFloat(dmesg.st !! 4863 ' var left = zoombox.scrollLeft;\n'\ 5120 var newval = 100; !! 4864 ' var val = parseFloat(dmesg.style.width);\n'\ 5121 var sh = window.outerWidth / !! 4865 ' var newval = 100;\n'\ 5122 if(this.id == "zoomin") { !! 4866 ' var sh = window.outerWidth / 2;\n'\ 5123 newval = val * 1.2; !! 4867 ' if(this.id == "zoomin") {\n'\ 5124 if(newval > 910034) n !! 4868 ' newval = val * 1.2;\n'\ 5125 dmesg.style.width = n !! 4869 ' if(newval > 910034) newval = 910034;\n'\ 5126 zoombox.scrollLeft = !! 4870 ' dmesg.style.width = newval+"%";\n'\ 5127 } else if (this.id == "zoomou !! 4871 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 5128 newval = val / 1.2; !! 4872 ' } else if (this.id == "zoomout") {\n'\ 5129 if(newval < 100) newv !! 4873 ' newval = val / 1.2;\n'\ 5130 dmesg.style.width = n !! 4874 ' if(newval < 100) newval = 100;\n'\ 5131 zoombox.scrollLeft = !! 4875 ' dmesg.style.width = newval+"%";\n'\ 5132 } else { !! 4876 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 5133 zoombox.scrollLeft = !! 4877 ' } else {\n'\ 5134 dmesg.style.width = " !! 4878 ' zoombox.scrollLeft = 0;\n'\ 5135 } !! 4879 ' dmesg.style.width = "100%";\n'\ 5136 var tS = [10000, 5000, 2000, !! 4880 ' }\n'\ 5137 var t0 = bounds[0]; !! 4881 ' var tS = [10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1];\n'\ 5138 var tMax = bounds[1]; !! 4882 ' var t0 = bounds[0];\n'\ 5139 var tTotal = tMax - t0; !! 4883 ' var tMax = bounds[1];\n'\ 5140 var wTotal = tTotal * 100.0 / !! 4884 ' var tTotal = tMax - t0;\n'\ 5141 var idx = 7*window.innerWidth !! 4885 ' var wTotal = tTotal * 100.0 / newval;\n'\ 5142 for(var i = 0; (i < tS.length !! 4886 ' var idx = 7*window.innerWidth/1100;\n'\ 5143 if(i >= tS.length) i = tS.len !! 4887 ' for(var i = 0; (i < tS.length)&&((wTotal / tS[i]) < idx); i++);\n'\ 5144 if(tS[i] == resolution) retur !! 4888 ' if(i >= tS.length) i = tS.length - 1;\n'\ 5145 resolution = tS[i]; !! 4889 ' if(tS[i] == resolution) return;\n'\ 5146 redrawTimescale(t0, tMax, tS[ !! 4890 ' resolution = tS[i];\n'\ 5147 } !! 4891 ' redrawTimescale(t0, tMax, tS[i]);\n'\ 5148 function deviceName(title) { !! 4892 ' }\n'\ 5149 var name = title.slice(0, tit !! 4893 ' function deviceName(title) {\n'\ 5150 return name; !! 4894 ' var name = title.slice(0, title.indexOf(" ("));\n'\ 5151 } !! 4895 ' return name;\n'\ 5152 function deviceHover() { !! 4896 ' }\n'\ 5153 var name = deviceName(this.ti !! 4897 ' function deviceHover() {\n'\ 5154 var dmesg = document.getEleme !! 4898 ' var name = deviceName(this.title);\n'\ 5155 var dev = dmesg.getElementsBy !! 4899 ' var dmesg = document.getElementById("dmesg");\n'\ 5156 var cpu = -1; !! 4900 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5157 if(name.match("CPU_ON\[[0-9]* !! 4901 ' var cpu = -1;\n'\ 5158 cpu = parseInt(name.s !! 4902 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 5159 else if(name.match("CPU_OFF\[ !! 4903 ' cpu = parseInt(name.slice(7));\n'\ 5160 cpu = parseInt(name.s !! 4904 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 5161 for (var i = 0; i < dev.lengt !! 4905 ' cpu = parseInt(name.slice(8));\n'\ 5162 dname = deviceName(de !! 4906 ' for (var i = 0; i < dev.length; i++) {\n'\ 5163 var cname = dev[i].cl !! 4907 ' dname = deviceName(dev[i].title);\n'\ 5164 if((cpu >= 0 && dname !! 4908 ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 5165 (name == dnam !! 4909 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 5166 { !! 4910 ' (name == dname))\n'\ 5167 dev[i].classN !! 4911 ' {\n'\ 5168 } else { !! 4912 ' dev[i].className = "hover "+cname;\n'\ 5169 dev[i].classN !! 4913 ' } else {\n'\ 5170 } !! 4914 ' dev[i].className = cname;\n'\ 5171 } !! 4915 ' }\n'\ 5172 } !! 4916 ' }\n'\ 5173 function deviceUnhover() { !! 4917 ' }\n'\ 5174 var dmesg = document.getEleme !! 4918 ' function deviceUnhover() {\n'\ 5175 var dev = dmesg.getElementsBy !! 4919 ' var dmesg = document.getElementById("dmesg");\n'\ 5176 for (var i = 0; i < dev.lengt !! 4920 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5177 dev[i].className = de !! 4921 ' for (var i = 0; i < dev.length; i++) {\n'\ 5178 } !! 4922 ' dev[i].className = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 5179 } !! 4923 ' }\n'\ 5180 function deviceTitle(title, total, cp !! 4924 ' }\n'\ 5181 var prefix = "Total"; !! 4925 ' function deviceTitle(title, total, cpu) {\n'\ 5182 if(total.length > 3) { !! 4926 ' var prefix = "Total";\n'\ 5183 prefix = "Average"; !! 4927 ' if(total.length > 3) {\n'\ 5184 total[1] = (total[1]+ !! 4928 ' prefix = "Average";\n'\ 5185 total[2] = (total[2]+ !! 4929 ' total[1] = (total[1]+total[3])/2;\n'\ 5186 } !! 4930 ' total[2] = (total[2]+total[4])/2;\n'\ 5187 var devtitle = document.getEl !! 4931 ' }\n'\ 5188 var name = deviceName(title); !! 4932 ' var devtitle = document.getElementById("devicedetailtitle");\n'\ 5189 if(cpu >= 0) name = "CPU"+cpu !! 4933 ' var name = deviceName(title);\n'\ 5190 var driver = ""; !! 4934 ' if(cpu >= 0) name = "CPU"+cpu;\n'\ 5191 var tS = "<t2>(</t2>"; !! 4935 ' var driver = "";\n'\ 5192 var tR = "<t2>)</t2>"; !! 4936 ' var tS = "<t2>(</t2>";\n'\ 5193 if(total[1] > 0) !! 4937 ' var tR = "<t2>)</t2>";\n'\ 5194 tS = "<t2>("+prefix+" !! 4938 ' if(total[1] > 0)\n'\ 5195 if(total[2] > 0) !! 4939 ' tS = "<t2>("+prefix+" Suspend:</t2><t0> "+total[1].toFixed(3)+" ms</t0> ";\n'\ 5196 tR = " <t2>"+prefix+" !! 4940 ' if(total[2] > 0)\n'\ 5197 var s = title.indexOf("{"); !! 4941 ' tR = " <t2>"+prefix+" Resume:</t2><t0> "+total[2].toFixed(3)+" ms<t2>)</t2></t0>";\n'\ 5198 var e = title.indexOf("}"); !! 4942 ' var s = title.indexOf("{");\n'\ 5199 if((s >= 0) && (e >= 0)) !! 4943 ' var e = title.indexOf("}");\n'\ 5200 driver = title.slice(< !! 4944 ' if((s >= 0) && (e >= 0))\n'\ 5201 if(total[1] > 0 && total[2] > !! 4945 ' driver = title.slice(s+1, e) + " <t1>@</t1> ";\n'\ 5202 devtitle.innerHTML = !! 4946 ' if(total[1] > 0 && total[2] > 0)\n'\ 5203 else !! 4947 ' devtitle.innerHTML = "<t0>"+driver+name+"</t0> "+tS+tR;\n'\ 5204 devtitle.innerHTML = !! 4948 ' else\n'\ 5205 return name; !! 4949 ' devtitle.innerHTML = "<t0>"+title+"</t0>";\n'\ 5206 } !! 4950 ' return name;\n'\ 5207 function deviceDetail() { !! 4951 ' }\n'\ 5208 var devinfo = document.getEle !! 4952 ' function deviceDetail() {\n'\ 5209 devinfo.style.display = "bloc !! 4953 ' var devinfo = document.getElementById("devicedetail");\n'\ 5210 var name = deviceName(this.ti !! 4954 ' devinfo.style.display = "block";\n'\ 5211 var cpu = -1; !! 4955 ' var name = deviceName(this.title);\n'\ 5212 if(name.match("CPU_ON\[[0-9]* !! 4956 ' var cpu = -1;\n'\ 5213 cpu = parseInt(name.s !! 4957 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 5214 else if(name.match("CPU_OFF\[ !! 4958 ' cpu = parseInt(name.slice(7));\n'\ 5215 cpu = parseInt(name.s !! 4959 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 5216 var dmesg = document.getEleme !! 4960 ' cpu = parseInt(name.slice(8));\n'\ 5217 var dev = dmesg.getElementsBy !! 4961 ' var dmesg = document.getElementById("dmesg");\n'\ 5218 var idlist = []; !! 4962 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5219 var pdata = [[]]; !! 4963 ' var idlist = [];\n'\ 5220 if(document.getElementById("d !! 4964 ' var pdata = [[]];\n'\ 5221 pdata = [[], []]; !! 4965 ' if(document.getElementById("devicedetail1"))\n'\ 5222 var pd = pdata[0]; !! 4966 ' pdata = [[], []];\n'\ 5223 var total = [0.0, 0.0, 0.0]; !! 4967 ' var pd = pdata[0];\n'\ 5224 for (var i = 0; i < dev.lengt !! 4968 ' var total = [0.0, 0.0, 0.0];\n'\ 5225 dname = deviceName(de !! 4969 ' for (var i = 0; i < dev.length; i++) {\n'\ 5226 if((cpu >= 0 && dname !! 4970 ' dname = deviceName(dev[i].title);\n'\ 5227 (name == dnam !! 4971 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 5228 { !! 4972 ' (name == dname))\n'\ 5229 idlist[idlist !! 4973 ' {\n'\ 5230 var tidx = 1; !! 4974 ' idlist[idlist.length] = dev[i].id;\n'\ 5231 if(dev[i].id[ !! 4975 ' var tidx = 1;\n'\ 5232 pd = !! 4976 ' if(dev[i].id[0] == "a") {\n'\ 5233 } else { !! 4977 ' pd = pdata[0];\n'\ 5234 if(pd !! 4978 ' } else {\n'\ 5235 if(to !! 4979 ' if(pdata.length == 1) pdata[1] = [];\n'\ 5236 pd = !! 4980 ' if(total.length == 3) total[3]=total[4]=0.0;\n'\ 5237 tidx !! 4981 ' pd = pdata[1];\n'\ 5238 } !! 4982 ' tidx = 3;\n'\ 5239 var info = de !! 4983 ' }\n'\ 5240 var pname = i !! 4984 ' var info = dev[i].title.split(" ");\n'\ 5241 pd[pname] = p !! 4985 ' var pname = info[info.length-1];\n'\ 5242 total[0] += p !! 4986 ' pd[pname] = parseFloat(info[info.length-3].slice(1));\n'\ 5243 if(pname.inde !! 4987 ' total[0] += pd[pname];\n'\ 5244 total !! 4988 ' if(pname.indexOf("suspend") >= 0)\n'\ 5245 else !! 4989 ' total[tidx] += pd[pname];\n'\ 5246 total !! 4990 ' else\n'\ 5247 } !! 4991 ' total[tidx+1] += pd[pname];\n'\ 5248 } !! 4992 ' }\n'\ 5249 var devname = deviceTitle(thi !! 4993 ' }\n'\ 5250 var left = 0.0; !! 4994 ' var devname = deviceTitle(this.title, total, cpu);\n'\ 5251 for (var t = 0; t < pdata.len !! 4995 ' var left = 0.0;\n'\ 5252 pd = pdata[t]; !! 4996 ' for (var t = 0; t < pdata.length; t++) {\n'\ 5253 devinfo = document.ge !! 4997 ' pd = pdata[t];\n'\ 5254 var phases = devinfo. !! 4998 ' devinfo = document.getElementById("devicedetail"+t);\n'\ 5255 for (var i = 0; i < p !! 4999 ' var phases = devinfo.getElementsByClassName("phaselet");\n'\ 5256 if(phases[i]. !! 5000 ' for (var i = 0; i < phases.length; i++) {\n'\ 5257 var w !! 5001 ' if(phases[i].id in pd) {\n'\ 5258 var f !! 5002 ' var w = 100.0*pd[phases[i].id]/total[0];\n'\ 5259 if(w !! 5003 ' var fs = 32;\n'\ 5260 var f !! 5004 ' if(w < 8) fs = 4*w | 0;\n'\ 5261 phase !! 5005 ' var fs2 = fs*3/4;\n'\ 5262 phase !! 5006 ' phases[i].style.width = w+"%";\n'\ 5263 phase !! 5007 ' phases[i].style.left = left+"%";\n'\ 5264 left !! 5008 ' phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\ 5265 var t !! 5009 ' left += w;\n'\ 5266 var p !! 5010 ' var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\ 5267 phase !! 5011 ' var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";\n'\ 5268 } else { !! 5012 ' phases[i].innerHTML = time+pname;\n'\ 5269 phase !! 5013 ' } else {\n'\ 5270 phase !! 5014 ' phases[i].style.width = "0%";\n'\ 5271 } !! 5015 ' phases[i].style.left = left+"%";\n'\ 5272 } !! 5016 ' }\n'\ 5273 } !! 5017 ' }\n'\ 5274 if(typeof devstats !== 'undef !! 5018 ' }\n'\ 5275 callDetail(this.id, t !! 5019 ' if(typeof devstats !== \'undefined\')\n'\ 5276 var cglist = document.getElem !! 5020 ' callDetail(this.id, this.title);\n'\ 5277 if(!cglist) return; !! 5021 ' var cglist = document.getElementById("callgraphs");\n'\ 5278 var cg = cglist.getElementsBy !! 5022 ' if(!cglist) return;\n'\ 5279 if(cg.length < 10) return; !! 5023 ' var cg = cglist.getElementsByClassName("atop");\n'\ 5280 for (var i = 0; i < cg.length !! 5024 ' if(cg.length < 10) return;\n'\ 5281 cgid = cg[i].id.split !! 5025 ' for (var i = 0; i < cg.length; i++) {\n'\ 5282 if(idlist.indexOf(cgi !! 5026 ' cgid = cg[i].id.split("x")[0]\n'\ 5283 cg[i].style.d !! 5027 ' if(idlist.indexOf(cgid) >= 0) {\n'\ 5284 } else { !! 5028 ' cg[i].style.display = "block";\n'\ 5285 cg[i].style.d !! 5029 ' } else {\n'\ 5286 } !! 5030 ' cg[i].style.display = "none";\n'\ 5287 } !! 5031 ' }\n'\ 5288 } !! 5032 ' }\n'\ 5289 function callDetail(devid, devtitle) !! 5033 ' }\n'\ 5290 if(!(devid in devstats) || de !! 5034 ' function callDetail(devid, devtitle) {\n'\ 5291 return; !! 5035 ' if(!(devid in devstats) || devstats[devid].length < 1)\n'\ 5292 var list = devstats[devid]; !! 5036 ' return;\n'\ 5293 var tmp = devtitle.split(" ") !! 5037 ' var list = devstats[devid];\n'\ 5294 var name = tmp[0], phase = tm !! 5038 ' var tmp = devtitle.split(" ");\n'\ 5295 var dd = document.getElementB !! 5039 ' var name = tmp[0], phase = tmp[tmp.length-1];\n'\ 5296 var total = parseFloat(tmp[1] !! 5040 ' var dd = document.getElementById(phase);\n'\ 5297 var mlist = []; !! 5041 ' var total = parseFloat(tmp[1].slice(1));\n'\ 5298 var maxlen = 0; !! 5042 ' var mlist = [];\n'\ 5299 var info = [] !! 5043 ' var maxlen = 0;\n'\ 5300 for(var i in list) { !! 5044 ' var info = []\n'\ 5301 if(list[i][0] == "@") !! 5045 ' for(var i in list) {\n'\ 5302 info = list[i !! 5046 ' if(list[i][0] == "@") {\n'\ 5303 continue; !! 5047 ' info = list[i].split("|");\n'\ 5304 } !! 5048 ' continue;\n'\ 5305 var tmp = list[i].spl !! 5049 ' }\n'\ 5306 var t = parseFloat(tm !! 5050 ' var tmp = list[i].split("|");\n'\ 5307 var p = (t*100.0/tota !! 5051 ' var t = parseFloat(tmp[0]), f = tmp[1], c = parseInt(tmp[2]);\n'\ 5308 mlist[mlist.length] = !! 5052 ' var p = (t*100.0/total).toFixed(2);\n'\ 5309 if(f.length > maxlen) !! 5053 ' mlist[mlist.length] = [f, c, t.toFixed(2), p+"%"];\n'\ 5310 maxlen = f.le !! 5054 ' if(f.length > maxlen)\n'\ 5311 } !! 5055 ' maxlen = f.length;\n'\ 5312 var pad = 5; !! 5056 ' }\n'\ 5313 if(mlist.length == 0) pad = 3 !! 5057 ' var pad = 5;\n'\ 5314 var html = '<div style="paddi !! 5058 ' if(mlist.length == 0) pad = 30;\n'\ 5315 if(info.length > 2) !! 5059 ' var html = \'<div style="padding-top:\'+pad+\'px"><t3> <b>\'+name+\':</b>\';\n'\ 5316 html += " start=<b>"+ !! 5060 ' if(info.length > 2)\n'\ 5317 if(info.length > 3) !! 5061 ' html += " start=<b>"+info[1]+"</b>, end=<b>"+info[2]+"</b>";\n'\ 5318 html += ", length<i>( !! 5062 ' if(info.length > 3)\n'\ 5319 if(info.length > 4) !! 5063 ' html += ", length<i>(w/o overhead)</i>=<b>"+info[3]+" ms</b>";\n'\ 5320 html += ", return=<b> !! 5064 ' if(info.length > 4)\n'\ 5321 html += "</t3></div>"; !! 5065 ' html += ", return=<b>"+info[4]+"</b>";\n'\ 5322 if(mlist.length > 0) { !! 5066 ' html += "</t3></div>";\n'\ 5323 html += '<table class !! 5067 ' if(mlist.length > 0) {\n'\ 5324 for(var i in mlist) !! 5068 ' html += \'<table class=fstat style="padding-top:\'+(maxlen*5)+\'px;"><tr><th>Function</th>\';\n'\ 5325 html += "<td !! 5069 ' for(var i in mlist)\n'\ 5326 html += "</tr><tr><th !! 5070 ' html += "<td class=vt>"+mlist[i][0]+"</td>";\n'\ 5327 for(var i in mlist) !! 5071 ' html += "</tr><tr><th>Calls</th>";\n'\ 5328 html += "<td> !! 5072 ' for(var i in mlist)\n'\ 5329 html += "</tr><tr><th !! 5073 ' html += "<td>"+mlist[i][1]+"</td>";\n'\ 5330 for(var i in mlist) !! 5074 ' html += "</tr><tr><th>Time(ms)</th>";\n'\ 5331 html += "<td> !! 5075 ' for(var i in mlist)\n'\ 5332 html += "</tr><tr><th !! 5076 ' html += "<td>"+mlist[i][2]+"</td>";\n'\ 5333 for(var i in mlist) !! 5077 ' html += "</tr><tr><th>Percent</th>";\n'\ 5334 html += "<td> !! 5078 ' for(var i in mlist)\n'\ 5335 html += "</tr></table !! 5079 ' html += "<td>"+mlist[i][3]+"</td>";\n'\ 5336 } !! 5080 ' html += "</tr></table>";\n'\ 5337 dd.innerHTML = html; !! 5081 ' }\n'\ 5338 var height = (maxlen*5)+100; !! 5082 ' dd.innerHTML = html;\n'\ 5339 dd.style.height = height+"px" !! 5083 ' var height = (maxlen*5)+100;\n'\ 5340 document.getElementById("devi !! 5084 ' dd.style.height = height+"px";\n'\ 5341 } !! 5085 ' document.getElementById("devicedetail").style.height = height+"px";\n'\ 5342 function callSelect() { !! 5086 ' }\n'\ 5343 var cglist = document.getElem !! 5087 ' function callSelect() {\n'\ 5344 if(!cglist) return; !! 5088 ' var cglist = document.getElementById("callgraphs");\n'\ 5345 var cg = cglist.getElementsBy !! 5089 ' if(!cglist) return;\n'\ 5346 for (var i = 0; i < cg.length !! 5090 ' var cg = cglist.getElementsByClassName("atop");\n'\ 5347 if(this.id == cg[i].i !! 5091 ' for (var i = 0; i < cg.length; i++) {\n'\ 5348 cg[i].style.d !! 5092 ' if(this.id == cg[i].id) {\n'\ 5349 } else { !! 5093 ' cg[i].style.display = "block";\n'\ 5350 cg[i].style.d !! 5094 ' } else {\n'\ 5351 } !! 5095 ' cg[i].style.display = "none";\n'\ 5352 } !! 5096 ' }\n'\ 5353 } !! 5097 ' }\n'\ 5354 function devListWindow(e) { !! 5098 ' }\n'\ 5355 var win = window.open(); !! 5099 ' function devListWindow(e) {\n'\ 5356 var html = "<title>"+e.target !! 5100 ' var win = window.open();\n'\ 5357 "<style type=\"text/c !! 5101 ' var html = "<title>"+e.target.innerHTML+"</title>"+\n'\ 5358 " ul {list-style-ty !! 5102 ' "<style type=\\"text/css\\">"+\n'\ 5359 "</style>" !! 5103 ' " ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\ 5360 var dt = devtable[0]; !! 5104 ' "</style>"\n'\ 5361 if(e.target.id != "devlist1") !! 5105 ' var dt = devtable[0];\n'\ 5362 dt = devtable[1]; !! 5106 ' if(e.target.id != "devlist1")\n'\ 5363 win.document.write(html+dt); !! 5107 ' dt = devtable[1];\n'\ 5364 } !! 5108 ' win.document.write(html+dt);\n'\ 5365 function errWindow() { !! 5109 ' }\n'\ 5366 var range = this.id.split("_" !! 5110 ' function errWindow() {\n'\ 5367 var idx1 = parseInt(range[0]) !! 5111 ' var range = this.id.split("_");\n'\ 5368 var idx2 = parseInt(range[1]) !! 5112 ' var idx1 = parseInt(range[0]);\n'\ 5369 var win = window.open(); !! 5113 ' var idx2 = parseInt(range[1]);\n'\ 5370 var log = document.getElement !! 5114 ' var win = window.open();\n'\ 5371 var title = "<title>dmesg log !! 5115 ' var log = document.getElementById("dmesglog");\n'\ 5372 var text = log.innerHTML.spli !! 5116 ' var title = "<title>dmesg log</title>";\n'\ 5373 var html = ""; !! 5117 ' var text = log.innerHTML.split("\\n");\n'\ 5374 for(var i = 0; i < text.lengt !! 5118 ' var html = "";\n'\ 5375 if(i == idx1) { !! 5119 ' for(var i = 0; i < text.length; i++) {\n'\ 5376 html += "<e i !! 5120 ' if(i == idx1) {\n'\ 5377 } else if(i > idx1 && !! 5121 ' html += "<e id=target>"+text[i]+"</e>\\n";\n'\ 5378 html += "<e>" !! 5122 ' } else if(i > idx1 && i <= idx2) {\n'\ 5379 } else { !! 5123 ' html += "<e>"+text[i]+"</e>\\n";\n'\ 5380 html += text[ !! 5124 ' } else {\n'\ 5381 } !! 5125 ' html += text[i]+"\\n";\n'\ 5382 } !! 5126 ' }\n'\ 5383 win.document.write("<style>e{ !! 5127 ' }\n'\ 5384 win.location.hash = "#target" !! 5128 ' win.document.write("<style>e{color:red}</style>"+title+"<pre>"+html+"</pre>");\n'\ 5385 win.document.close(); !! 5129 ' win.location.hash = "#target";\n'\ 5386 } !! 5130 ' win.document.close();\n'\ 5387 function logWindow(e) { !! 5131 ' }\n'\ 5388 var name = e.target.id.slice( !! 5132 ' function logWindow(e) {\n'\ 5389 var win = window.open(); !! 5133 ' var name = e.target.id.slice(4);\n'\ 5390 var log = document.getElement !! 5134 ' var win = window.open();\n'\ 5391 var title = "<title>"+documen !! 5135 ' var log = document.getElementById(name+"log");\n'\ 5392 win.document.write(title+"<pr !! 5136 ' var title = "<title>"+document.title.split(" ")[0]+" "+name+" log</title>";\n'\ 5393 win.document.close(); !! 5137 ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ 5394 } !! 5138 ' win.document.close();\n'\ 5395 function onMouseDown(e) { !! 5139 ' }\n'\ 5396 dragval[0] = e.clientX; !! 5140 ' function onMouseDown(e) {\n'\ 5397 dragval[1] = document.getElem !! 5141 ' dragval[0] = e.clientX;\n'\ 5398 document.onmousemove = onMous !! 5142 ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ 5399 } !! 5143 ' document.onmousemove = onMouseMove;\n'\ 5400 function onMouseMove(e) { !! 5144 ' }\n'\ 5401 var zoombox = document.getEle !! 5145 ' function onMouseMove(e) {\n'\ 5402 zoombox.scrollLeft = dragval[ !! 5146 ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 5403 } !! 5147 ' zoombox.scrollLeft = dragval[1] + dragval[0] - e.clientX;\n'\ 5404 function onMouseUp(e) { !! 5148 ' }\n'\ 5405 document.onmousemove = null; !! 5149 ' function onMouseUp(e) {\n'\ 5406 } !! 5150 ' document.onmousemove = null;\n'\ 5407 function onKeyPress(e) { !! 5151 ' }\n'\ 5408 var c = e.charCode; !! 5152 ' function onKeyPress(e) {\n'\ 5409 if(c != 42 && c != 43 && c != !! 5153 ' var c = e.charCode;\n'\ 5410 var click = document.createEv !! 5154 ' if(c != 42 && c != 43 && c != 45) return;\n'\ 5411 click.initEvent("click", true !! 5155 ' var click = document.createEvent("Events");\n'\ 5412 if(c == 43) !! 5156 ' click.initEvent("click", true, false);\n'\ 5413 document.getElementBy !! 5157 ' if(c == 43) \n'\ 5414 else if(c == 45) !! 5158 ' document.getElementById("zoomin").dispatchEvent(click);\n'\ 5415 document.getElementBy !! 5159 ' else if(c == 45)\n'\ 5416 else if(c == 42) !! 5160 ' document.getElementById("zoomout").dispatchEvent(click);\n'\ 5417 document.getElementBy !! 5161 ' else if(c == 42)\n'\ 5418 } !! 5162 ' document.getElementById("zoomdef").dispatchEvent(click);\n'\ 5419 window.addEventListener("resize", fun !! 5163 ' }\n'\ 5420 window.addEventListener("load", funct !! 5164 ' window.addEventListener("resize", function () {zoomTimeline();});\n'\ 5421 var dmesg = document.getEleme !! 5165 ' window.addEventListener("load", function () {\n'\ 5422 dmesg.style.width = "100%" !! 5166 ' var dmesg = document.getElementById("dmesg");\n'\ 5423 dmesg.onmousedown = onMouseDo !! 5167 ' dmesg.style.width = "100%"\n'\ 5424 document.onmouseup = onMouseU !! 5168 ' dmesg.onmousedown = onMouseDown;\n'\ 5425 document.onkeypress = onKeyPr !! 5169 ' document.onmouseup = onMouseUp;\n'\ 5426 document.getElementById("zoom !! 5170 ' document.onkeypress = onKeyPress;\n'\ 5427 document.getElementById("zoom !! 5171 ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ 5428 document.getElementById("zoom !! 5172 ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ 5429 var list = document.getElemen !! 5173 ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ 5430 for (var i = 0; i < list.leng !! 5174 ' var list = document.getElementsByClassName("err");\n'\ 5431 list[i].onclick = err !! 5175 ' for (var i = 0; i < list.length; i++)\n'\ 5432 var list = document.getElemen !! 5176 ' list[i].onclick = errWindow;\n'\ 5433 for (var i = 0; i < list.leng !! 5177 ' var list = document.getElementsByClassName("logbtn");\n'\ 5434 list[i].onclick = log !! 5178 ' for (var i = 0; i < list.length; i++)\n'\ 5435 list = document.getElementsBy !! 5179 ' list[i].onclick = logWindow;\n'\ 5436 for (var i = 0; i < list.leng !! 5180 ' list = document.getElementsByClassName("devlist");\n'\ 5437 list[i].onclick = dev !! 5181 ' for (var i = 0; i < list.length; i++)\n'\ 5438 var dev = dmesg.getElementsBy !! 5182 ' list[i].onclick = devListWindow;\n'\ 5439 for (var i = 0; i < dev.lengt !! 5183 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5440 dev[i].onclick = devi !! 5184 ' for (var i = 0; i < dev.length; i++) {\n'\ 5441 dev[i].onmouseover = !! 5185 ' dev[i].onclick = deviceDetail;\n'\ 5442 dev[i].onmouseout = d !! 5186 ' dev[i].onmouseover = deviceHover;\n'\ 5443 } !! 5187 ' dev[i].onmouseout = deviceUnhover;\n'\ 5444 var dev = dmesg.getElementsBy !! 5188 ' }\n'\ 5445 for (var i = 0; i < dev.lengt !! 5189 ' var dev = dmesg.getElementsByClassName("srccall");\n'\ 5446 dev[i].onclick = call !! 5190 ' for (var i = 0; i < dev.length; i++)\n'\ 5447 zoomTimeline(); !! 5191 ' dev[i].onclick = callSelect;\n'\ 5448 }); !! 5192 ' zoomTimeline();\n'\ 5449 </script> """ !! 5193 ' });\n'\ >> 5194 '</script>\n' 5450 hf.write(script_code); 5195 hf.write(script_code); 5451 5196 >> 5197 def setRuntimeSuspend(before=True): >> 5198 global sysvals >> 5199 sv = sysvals >> 5200 if sv.rs == 0: >> 5201 return >> 5202 if before: >> 5203 # runtime suspend disable or enable >> 5204 if sv.rs > 0: >> 5205 sv.rstgt, sv.rsval, sv.rsdir = 'on', 'auto', 'enabled' >> 5206 else: >> 5207 sv.rstgt, sv.rsval, sv.rsdir = 'auto', 'on', 'disabled' >> 5208 pprint('CONFIGURING RUNTIME SUSPEND...') >> 5209 sv.rslist = deviceInfo(sv.rstgt) >> 5210 for i in sv.rslist: >> 5211 sv.setVal(sv.rsval, i) >> 5212 pprint('runtime suspend %s on all devices (%d changed)' % (sv.rsdir, len(sv.rslist))) >> 5213 pprint('waiting 5 seconds...') >> 5214 time.sleep(5) >> 5215 else: >> 5216 # runtime suspend re-enable or re-disable >> 5217 for i in sv.rslist: >> 5218 sv.setVal(sv.rstgt, i) >> 5219 pprint('runtime suspend settings restored on %d devices' % len(sv.rslist)) >> 5220 5452 # Function: executeSuspend 5221 # Function: executeSuspend 5453 # Description: 5222 # Description: 5454 # Execute system suspend through the s 5223 # Execute system suspend through the sysfs interface, then copy the output 5455 # dmesg and ftrace files to the test o 5224 # dmesg and ftrace files to the test output directory. 5456 def executeSuspend(quiet=False): 5225 def executeSuspend(quiet=False): 5457 sv, tp, pm = sysvals, sysvals.tpath, !! 5226 pm = ProcessMonitor() 5458 if sv.wifi: !! 5227 tp = sysvals.tpath 5459 wifi = sv.checkWifi() !! 5228 if sysvals.wifi: 5460 sv.dlog('wifi check, connecte !! 5229 wifi = sysvals.checkWifi() 5461 testdata = [] 5230 testdata = [] 5462 # run these commands to prepare the s 5231 # run these commands to prepare the system for suspend 5463 if sv.display: !! 5232 if sysvals.display: 5464 if not quiet: 5233 if not quiet: 5465 pprint('SET DISPLAY T !! 5234 pprint('SET DISPLAY TO %s' % sysvals.display.upper()) 5466 ret = sv.displayControl(sv.di !! 5235 displayControl(sysvals.display) 5467 sv.dlog('xset display %s, ret << 5468 time.sleep(1) 5236 time.sleep(1) 5469 if sv.sync: !! 5237 if sysvals.sync: 5470 if not quiet: 5238 if not quiet: 5471 pprint('SYNCING FILES 5239 pprint('SYNCING FILESYSTEMS') 5472 sv.dlog('syncing filesystems' << 5473 call('sync', shell=True) 5240 call('sync', shell=True) 5474 sv.dlog('read dmesg') !! 5241 # mark the start point in the kernel ring buffer just as we start 5475 sv.initdmesg() !! 5242 sysvals.initdmesg() 5476 sv.dlog('cmdinfo before') !! 5243 # start ftrace 5477 sv.cmdinfo(True) !! 5244 if(sysvals.usecallgraph or sysvals.usetraceevents): 5478 sv.start(pm) !! 5245 if not quiet: >> 5246 pprint('START TRACING') >> 5247 sysvals.fsetVal('1', 'tracing_on') >> 5248 if sysvals.useprocmon: >> 5249 pm.start() >> 5250 sysvals.cmdinfo(True) 5479 # execute however many s/r runs reque 5251 # execute however many s/r runs requested 5480 for count in range(1,sv.execcount+1): !! 5252 for count in range(1,sysvals.execcount+1): 5481 # x2delay in between test run 5253 # x2delay in between test runs 5482 if(count > 1 and sv.x2delay > !! 5254 if(count > 1 and sysvals.x2delay > 0): 5483 sv.fsetVal('WAIT %d' !! 5255 sysvals.fsetVal('WAIT %d' % sysvals.x2delay, 'trace_marker') 5484 time.sleep(sv.x2delay !! 5256 time.sleep(sysvals.x2delay/1000.0) 5485 sv.fsetVal('WAIT END' !! 5257 sysvals.fsetVal('WAIT END', 'trace_marker') 5486 # start message 5258 # start message 5487 if sv.testcommand != '': !! 5259 if sysvals.testcommand != '': 5488 pprint('COMMAND START 5260 pprint('COMMAND START') 5489 else: 5261 else: 5490 if(sv.rtcwake): !! 5262 if(sysvals.rtcwake): 5491 pprint('SUSPE 5263 pprint('SUSPEND START') 5492 else: 5264 else: 5493 pprint('SUSPE 5265 pprint('SUSPEND START (press a key to resume)') 5494 # set rtcwake 5266 # set rtcwake 5495 if(sv.rtcwake): !! 5267 if(sysvals.rtcwake): 5496 if not quiet: 5268 if not quiet: 5497 pprint('will !! 5269 pprint('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime) 5498 sv.dlog('enable RTC w !! 5270 sysvals.rtcWakeAlarmOn() 5499 sv.rtcWakeAlarmOn() << 5500 # start of suspend trace mark 5271 # start of suspend trace marker 5501 sv.fsetVal(datetime.now().str !! 5272 if(sysvals.usecallgraph or sysvals.usetraceevents): >> 5273 sysvals.fsetVal(datetime.now().strftime(sysvals.tmstart), 'trace_marker') 5502 # predelay delay 5274 # predelay delay 5503 if(count == 1 and sv.predelay !! 5275 if(count == 1 and sysvals.predelay > 0): 5504 sv.fsetVal('WAIT %d' !! 5276 sysvals.fsetVal('WAIT %d' % sysvals.predelay, 'trace_marker') 5505 time.sleep(sv.predela !! 5277 time.sleep(sysvals.predelay/1000.0) 5506 sv.fsetVal('WAIT END' !! 5278 sysvals.fsetVal('WAIT END', 'trace_marker') 5507 # initiate suspend or command 5279 # initiate suspend or command 5508 sv.dlog('system executing a s << 5509 tdata = {'error': ''} 5280 tdata = {'error': ''} 5510 if sv.testcommand != '': !! 5281 if sysvals.testcommand != '': 5511 res = call(sv.testcom !! 5282 res = call(sysvals.testcommand+' 2>&1', shell=True); 5512 if res != 0: 5283 if res != 0: 5513 tdata['error' 5284 tdata['error'] = 'cmd returned %d' % res 5514 else: 5285 else: 5515 s0ixready = sv.s0ixSu !! 5286 mode = sysvals.suspendmode 5516 mode = sv.suspendmode !! 5287 if sysvals.memmode and os.path.exists(sysvals.mempowerfile): 5517 if sv.memmode and os. << 5518 mode = 'mem' 5288 mode = 'mem' 5519 sv.testVal(sv !! 5289 pf = open(sysvals.mempowerfile, 'w') 5520 if sv.diskmode and os !! 5290 pf.write(sysvals.memmode) >> 5291 pf.close() >> 5292 if sysvals.diskmode and os.path.exists(sysvals.diskpowerfile): 5521 mode = 'disk' 5293 mode = 'disk' 5522 sv.testVal(sv !! 5294 pf = open(sysvals.diskpowerfile, 'w') 5523 if sv.acpidebug: !! 5295 pf.write(sysvals.diskmode) 5524 sv.testVal(sv !! 5296 pf.close() 5525 if ((mode == 'freeze' !! 5297 if mode == 'freeze' and sysvals.haveTurbostat(): 5526 and sv.haveTu << 5527 # execution w 5298 # execution will pause here 5528 retval, turbo !! 5299 turbo = sysvals.turbostat() 5529 if retval != << 5530 tdata << 5531 if turbo: 5300 if turbo: 5532 tdata 5301 tdata['turbo'] = turbo 5533 else: 5302 else: 5534 pf = open(sv. !! 5303 pf = open(sysvals.powerfile, 'w') 5535 pf.write(mode 5304 pf.write(mode) 5536 # execution w 5305 # execution will pause here 5537 try: 5306 try: 5538 pf.fl << 5539 pf.cl 5307 pf.close() 5540 except Except 5308 except Exception as e: 5541 tdata 5309 tdata['error'] = str(e) 5542 sv.fsetVal('CMD COMPLETE', 't !! 5310 if(sysvals.rtcwake): 5543 sv.dlog('system returned') !! 5311 sysvals.rtcWakeAlarmOff() 5544 # reset everything << 5545 sv.testVal('restoreall') << 5546 if(sv.rtcwake): << 5547 sv.dlog('disable RTC << 5548 sv.rtcWakeAlarmOff() << 5549 # postdelay delay 5312 # postdelay delay 5550 if(count == sv.execcount and !! 5313 if(count == sysvals.execcount and sysvals.postdelay > 0): 5551 sv.fsetVal('WAIT %d' !! 5314 sysvals.fsetVal('WAIT %d' % sysvals.postdelay, 'trace_marker') 5552 time.sleep(sv.postdel !! 5315 time.sleep(sysvals.postdelay/1000.0) 5553 sv.fsetVal('WAIT END' !! 5316 sysvals.fsetVal('WAIT END', 'trace_marker') 5554 # return from suspend 5317 # return from suspend 5555 pprint('RESUME COMPLETE') 5318 pprint('RESUME COMPLETE') 5556 if(count < sv.execcount): !! 5319 if(sysvals.usecallgraph or sysvals.usetraceevents): 5557 sv.fsetVal(datetime.n !! 5320 sysvals.fsetVal(datetime.now().strftime(sysvals.tmend), 'trace_marker') 5558 elif(not sv.wifitrace): !! 5321 if sysvals.wifi and wifi: 5559 sv.fsetVal(datetime.n !! 5322 tdata['wifi'] = sysvals.pollWifi(wifi) 5560 sv.stop(pm) !! 5323 if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'): 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 5324 tdata['fw'] = getFPDT(False) 5573 testdata.append(tdata) 5325 testdata.append(tdata) 5574 sv.dlog('cmdinfo after') !! 5326 cmdafter = sysvals.cmdinfo(False) 5575 cmdafter = sv.cmdinfo(False) !! 5327 # stop ftrace >> 5328 if(sysvals.usecallgraph or sysvals.usetraceevents): >> 5329 if sysvals.useprocmon: >> 5330 pm.stop() >> 5331 sysvals.fsetVal('0', 'tracing_on') 5576 # grab a copy of the dmesg output 5332 # grab a copy of the dmesg output 5577 if not quiet: 5333 if not quiet: 5578 pprint('CAPTURING DMESG') 5334 pprint('CAPTURING DMESG') 5579 sv.getdmesg(testdata) !! 5335 sysvals.getdmesg(testdata) 5580 # grab a copy of the ftrace output 5336 # grab a copy of the ftrace output 5581 if sv.useftrace: !! 5337 if(sysvals.usecallgraph or sysvals.usetraceevents): 5582 if not quiet: 5338 if not quiet: 5583 pprint('CAPTURING TRA 5339 pprint('CAPTURING TRACE') 5584 op = sv.writeDatafileHeader(s !! 5340 op = sysvals.writeDatafileHeader(sysvals.ftracefile, testdata) 5585 fp = open(tp+'trace', 'rb') !! 5341 fp = open(tp+'trace', 'r') 5586 op.write(ascii(fp.read())) !! 5342 for line in fp: >> 5343 op.write(line) 5587 op.close() 5344 op.close() 5588 sv.fsetVal('', 'trace') !! 5345 sysvals.fsetVal('', 'trace') 5589 sv.platforminfo(cmdafter) !! 5346 sysvals.platforminfo(cmdafter) 5590 5347 5591 def readFile(file): 5348 def readFile(file): 5592 if os.path.islink(file): 5349 if os.path.islink(file): 5593 return os.readlink(file).spli 5350 return os.readlink(file).split('/')[-1] 5594 else: 5351 else: 5595 return sysvals.getVal(file).s 5352 return sysvals.getVal(file).strip() 5596 5353 5597 # Function: ms2nice 5354 # Function: ms2nice 5598 # Description: 5355 # Description: 5599 # Print out a very concise time string 5356 # Print out a very concise time string in minutes and seconds 5600 # Output: 5357 # Output: 5601 # The time string, e.g. "1901m16s" 5358 # The time string, e.g. "1901m16s" 5602 def ms2nice(val): 5359 def ms2nice(val): 5603 val = int(val) 5360 val = int(val) 5604 h = val // 3600000 5361 h = val // 3600000 5605 m = (val // 60000) % 60 5362 m = (val // 60000) % 60 5606 s = (val // 1000) % 60 5363 s = (val // 1000) % 60 5607 if h > 0: 5364 if h > 0: 5608 return '%d:%02d:%02d' % (h, m 5365 return '%d:%02d:%02d' % (h, m, s) 5609 if m > 0: 5366 if m > 0: 5610 return '%02d:%02d' % (m, s) 5367 return '%02d:%02d' % (m, s) 5611 return '%ds' % s 5368 return '%ds' % s 5612 5369 5613 def yesno(val): 5370 def yesno(val): 5614 list = {'enabled':'A', 'disabled':'S' 5371 list = {'enabled':'A', 'disabled':'S', 'auto':'E', 'on':'D', 5615 'active':'A', 'suspended':'S' 5372 'active':'A', 'suspended':'S', 'suspending':'S'} 5616 if val not in list: 5373 if val not in list: 5617 return ' ' 5374 return ' ' 5618 return list[val] 5375 return list[val] 5619 5376 5620 # Function: deviceInfo 5377 # Function: deviceInfo 5621 # Description: 5378 # Description: 5622 # Detect all the USB hosts and devices 5379 # Detect all the USB hosts and devices currently connected and add 5623 # a list of USB device names to sysval 5380 # a list of USB device names to sysvals for better timeline readability 5624 def deviceInfo(output=''): 5381 def deviceInfo(output=''): 5625 if not output: 5382 if not output: 5626 pprint('LEGEND\n'\ 5383 pprint('LEGEND\n'\ 5627 '---------------------------- 5384 '---------------------------------------------------------------------------------------------\n'\ 5628 ' A = async/sync PM queue (A 5385 ' A = async/sync PM queue (A/S) C = runtime active children\n'\ 5629 ' R = runtime suspend enable 5386 ' R = runtime suspend enabled/disabled (E/D) rACTIVE = runtime active (min/sec)\n'\ 5630 ' S = runtime status active/ 5387 ' S = runtime status active/suspended (A/S) rSUSPEND = runtime suspend (min/sec)\n'\ 5631 ' U = runtime usage count\n' 5388 ' U = runtime usage count\n'\ 5632 '---------------------------- 5389 '---------------------------------------------------------------------------------------------\n'\ 5633 'DEVICE N 5390 'DEVICE NAME A R S U C rACTIVE rSUSPEND\n'\ 5634 '---------------------------- 5391 '---------------------------------------------------------------------------------------------') 5635 5392 5636 res = [] 5393 res = [] 5637 tgtval = 'runtime_status' 5394 tgtval = 'runtime_status' 5638 lines = dict() 5395 lines = dict() 5639 for dirname, dirnames, filenames in o 5396 for dirname, dirnames, filenames in os.walk('/sys/devices'): 5640 if(not re.match(r'.*/power', !! 5397 if(not re.match('.*/power', dirname) or 5641 'control' not in file 5398 'control' not in filenames or 5642 tgtval not in filenam 5399 tgtval not in filenames): 5643 continue 5400 continue 5644 name = '' 5401 name = '' 5645 dirname = dirname[:-6] 5402 dirname = dirname[:-6] 5646 device = dirname.split('/')[- 5403 device = dirname.split('/')[-1] 5647 power = dict() 5404 power = dict() 5648 power[tgtval] = readFile('%s/ 5405 power[tgtval] = readFile('%s/power/%s' % (dirname, tgtval)) 5649 # only list devices which sup 5406 # only list devices which support runtime suspend 5650 if power[tgtval] not in ['act 5407 if power[tgtval] not in ['active', 'suspended', 'suspending']: 5651 continue 5408 continue 5652 for i in ['product', 'driver' 5409 for i in ['product', 'driver', 'subsystem']: 5653 file = '%s/%s' % (dir 5410 file = '%s/%s' % (dirname, i) 5654 if os.path.exists(fil 5411 if os.path.exists(file): 5655 name = readFi 5412 name = readFile(file) 5656 break 5413 break 5657 for i in ['async', 'control', 5414 for i in ['async', 'control', 'runtime_status', 'runtime_usage', 5658 'runtime_active_kids' 5415 'runtime_active_kids', 'runtime_active_time', 5659 'runtime_suspended_ti 5416 'runtime_suspended_time']: 5660 if i in filenames: 5417 if i in filenames: 5661 power[i] = re 5418 power[i] = readFile('%s/power/%s' % (dirname, i)) 5662 if output: 5419 if output: 5663 if power['control'] = 5420 if power['control'] == output: 5664 res.append('% 5421 res.append('%s/power/control' % dirname) 5665 continue 5422 continue 5666 lines[dirname] = '%-26s %-26s 5423 lines[dirname] = '%-26s %-26s %1s %1s %1s %1s %1s %10s %10s' % \ 5667 (device[:26], name[:2 5424 (device[:26], name[:26], 5668 yesno(power['async']) 5425 yesno(power['async']), \ 5669 yesno(power['control' 5426 yesno(power['control']), \ 5670 yesno(power['runtime_ 5427 yesno(power['runtime_status']), \ 5671 power['runtime_usage' 5428 power['runtime_usage'], \ 5672 power['runtime_active 5429 power['runtime_active_kids'], \ 5673 ms2nice(power['runtim 5430 ms2nice(power['runtime_active_time']), \ 5674 ms2nice(power['runtim 5431 ms2nice(power['runtime_suspended_time'])) 5675 for i in sorted(lines): 5432 for i in sorted(lines): 5676 print(lines[i]) 5433 print(lines[i]) 5677 return res 5434 return res 5678 5435 5679 # Function: getModes 5436 # Function: getModes 5680 # Description: 5437 # Description: 5681 # Determine the supported power modes 5438 # Determine the supported power modes on this system 5682 # Output: 5439 # Output: 5683 # A string list of the available modes 5440 # A string list of the available modes 5684 def getModes(): 5441 def getModes(): 5685 modes = [] 5442 modes = [] 5686 if(os.path.exists(sysvals.powerfile)) 5443 if(os.path.exists(sysvals.powerfile)): 5687 fp = open(sysvals.powerfile, 5444 fp = open(sysvals.powerfile, 'r') 5688 modes = fp.read().split() 5445 modes = fp.read().split() 5689 fp.close() 5446 fp.close() 5690 if(os.path.exists(sysvals.mempowerfil 5447 if(os.path.exists(sysvals.mempowerfile)): 5691 deep = False 5448 deep = False 5692 fp = open(sysvals.mempowerfil 5449 fp = open(sysvals.mempowerfile, 'r') 5693 for m in fp.read().split(): 5450 for m in fp.read().split(): 5694 memmode = m.strip('[] 5451 memmode = m.strip('[]') 5695 if memmode == 'deep': 5452 if memmode == 'deep': 5696 deep = True 5453 deep = True 5697 else: 5454 else: 5698 modes.append( 5455 modes.append('mem-%s' % memmode) 5699 fp.close() 5456 fp.close() 5700 if 'mem' in modes and not dee 5457 if 'mem' in modes and not deep: 5701 modes.remove('mem') 5458 modes.remove('mem') 5702 if('disk' in modes and os.path.exists 5459 if('disk' in modes and os.path.exists(sysvals.diskpowerfile)): 5703 fp = open(sysvals.diskpowerfi 5460 fp = open(sysvals.diskpowerfile, 'r') 5704 for m in fp.read().split(): 5461 for m in fp.read().split(): 5705 modes.append('disk-%s 5462 modes.append('disk-%s' % m.strip('[]')) 5706 fp.close() 5463 fp.close() 5707 return modes 5464 return modes 5708 5465 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 5466 # Function: dmidecode 5744 # Description: 5467 # Description: 5745 # Read the bios tables and pull out sy 5468 # Read the bios tables and pull out system info 5746 # Arguments: 5469 # Arguments: 5747 # mempath: /dev/mem or custom mem path 5470 # mempath: /dev/mem or custom mem path 5748 # fatal: True to exit on error, False 5471 # fatal: True to exit on error, False to return empty dict 5749 # Output: 5472 # Output: 5750 # A dict object with all available key 5473 # A dict object with all available key/values 5751 def dmidecode(mempath, fatal=False): 5474 def dmidecode(mempath, fatal=False): 5752 out = dict() 5475 out = dict() 5753 if(not (os.path.exists(mempath) and o << 5754 return dmidecode_backup(out, << 5755 5476 5756 # the list of values to retrieve, wit 5477 # the list of values to retrieve, with hardcoded (type, idx) 5757 info = { 5478 info = { 5758 'bios-vendor': (0, 4), 5479 'bios-vendor': (0, 4), 5759 'bios-version': (0, 5), 5480 'bios-version': (0, 5), 5760 'bios-release-date': (0, 8), 5481 'bios-release-date': (0, 8), 5761 'system-manufacturer': (1, 4) 5482 'system-manufacturer': (1, 4), 5762 'system-product-name': (1, 5) 5483 'system-product-name': (1, 5), 5763 'system-version': (1, 6), 5484 'system-version': (1, 6), 5764 'system-serial-number': (1, 7 5485 'system-serial-number': (1, 7), 5765 'baseboard-manufacturer': (2, 5486 'baseboard-manufacturer': (2, 4), 5766 'baseboard-product-name': (2, 5487 'baseboard-product-name': (2, 5), 5767 'baseboard-version': (2, 6), 5488 'baseboard-version': (2, 6), 5768 'baseboard-serial-number': (2 5489 'baseboard-serial-number': (2, 7), 5769 'chassis-manufacturer': (3, 4 5490 'chassis-manufacturer': (3, 4), >> 5491 'chassis-type': (3, 5), 5770 'chassis-version': (3, 6), 5492 'chassis-version': (3, 6), 5771 'chassis-serial-number': (3, 5493 'chassis-serial-number': (3, 7), 5772 'processor-manufacturer': (4, 5494 'processor-manufacturer': (4, 7), 5773 'processor-version': (4, 16), 5495 'processor-version': (4, 16), 5774 } 5496 } >> 5497 if(not os.path.exists(mempath)): >> 5498 if(fatal): >> 5499 doError('file does not exist: %s' % mempath) >> 5500 return out >> 5501 if(not os.access(mempath, os.R_OK)): >> 5502 if(fatal): >> 5503 doError('file is not readable: %s' % mempath) >> 5504 return out 5775 5505 5776 # by default use legacy scan, but try 5506 # by default use legacy scan, but try to use EFI first 5777 memaddr, memsize = 0xf0000, 0x10000 !! 5507 memaddr = 0xf0000 >> 5508 memsize = 0x10000 5778 for ep in ['/sys/firmware/efi/systab' 5509 for ep in ['/sys/firmware/efi/systab', '/proc/efi/systab']: 5779 if not os.path.exists(ep) or 5510 if not os.path.exists(ep) or not os.access(ep, os.R_OK): 5780 continue 5511 continue 5781 fp = open(ep, 'r') 5512 fp = open(ep, 'r') 5782 buf = fp.read() 5513 buf = fp.read() 5783 fp.close() 5514 fp.close() 5784 i = buf.find('SMBIOS=') 5515 i = buf.find('SMBIOS=') 5785 if i >= 0: 5516 if i >= 0: 5786 try: 5517 try: 5787 memaddr = int 5518 memaddr = int(buf[i+7:], 16) 5788 memsize = 0x2 5519 memsize = 0x20 5789 except: 5520 except: 5790 continue 5521 continue 5791 5522 5792 # read in the memory for scanning 5523 # read in the memory for scanning 5793 try: 5524 try: 5794 fp = open(mempath, 'rb') 5525 fp = open(mempath, 'rb') 5795 fp.seek(memaddr) 5526 fp.seek(memaddr) 5796 buf = fp.read(memsize) 5527 buf = fp.read(memsize) 5797 except: 5528 except: 5798 return dmidecode_backup(out, !! 5529 if(fatal): >> 5530 doError('DMI table is unreachable, sorry') >> 5531 else: >> 5532 pprint('WARNING: /dev/mem is not readable, ignoring DMI data') >> 5533 return out 5799 fp.close() 5534 fp.close() 5800 5535 5801 # search for either an SM table or DM 5536 # search for either an SM table or DMI table 5802 i = base = length = num = 0 5537 i = base = length = num = 0 5803 while(i < memsize): 5538 while(i < memsize): 5804 if buf[i:i+4] == b'_SM_' and 5539 if buf[i:i+4] == b'_SM_' and i < memsize - 16: 5805 length = struct.unpac 5540 length = struct.unpack('H', buf[i+22:i+24])[0] 5806 base, num = struct.un 5541 base, num = struct.unpack('IH', buf[i+24:i+30]) 5807 break 5542 break 5808 elif buf[i:i+5] == b'_DMI_': 5543 elif buf[i:i+5] == b'_DMI_': 5809 length = struct.unpac 5544 length = struct.unpack('H', buf[i+6:i+8])[0] 5810 base, num = struct.un 5545 base, num = struct.unpack('IH', buf[i+8:i+14]) 5811 break 5546 break 5812 i += 16 5547 i += 16 5813 if base == 0 and length == 0 and num 5548 if base == 0 and length == 0 and num == 0: 5814 return dmidecode_backup(out, !! 5549 if(fatal): >> 5550 doError('Neither SMBIOS nor DMI were found') >> 5551 else: >> 5552 return out 5815 5553 5816 # read in the SM or DMI table 5554 # read in the SM or DMI table 5817 try: 5555 try: 5818 fp = open(mempath, 'rb') 5556 fp = open(mempath, 'rb') 5819 fp.seek(base) 5557 fp.seek(base) 5820 buf = fp.read(length) 5558 buf = fp.read(length) 5821 except: 5559 except: 5822 return dmidecode_backup(out, !! 5560 if(fatal): >> 5561 doError('DMI table is unreachable, sorry') >> 5562 else: >> 5563 pprint('WARNING: /dev/mem is not readable, ignoring DMI data') >> 5564 return out 5823 fp.close() 5565 fp.close() 5824 5566 5825 # scan the table for the values we wa 5567 # scan the table for the values we want 5826 count = i = 0 5568 count = i = 0 5827 while(count < num and i <= len(buf) - 5569 while(count < num and i <= len(buf) - 4): 5828 type, size, handle = struct.u 5570 type, size, handle = struct.unpack('BBH', buf[i:i+4]) 5829 n = i + size 5571 n = i + size 5830 while n < len(buf) - 1: 5572 while n < len(buf) - 1: 5831 if 0 == struct.unpack 5573 if 0 == struct.unpack('H', buf[n:n+2])[0]: 5832 break 5574 break 5833 n += 1 5575 n += 1 5834 data = buf[i+size:n+2].split( 5576 data = buf[i+size:n+2].split(b'\0') 5835 for name in info: 5577 for name in info: 5836 itype, idxadr = info[ 5578 itype, idxadr = info[name] 5837 if itype == type: 5579 if itype == type: 5838 idx = struct. 5580 idx = struct.unpack('B', buf[i+idxadr:i+idxadr+1])[0] 5839 if idx > 0 an 5581 if idx > 0 and idx < len(data) - 1: 5840 s = d 5582 s = data[idx-1].decode('utf-8') 5841 if s. 5583 if s.strip() and s.strip().lower() != 'to be filled by o.e.m.': 5842 5584 out[name] = s 5843 i = n + 2 5585 i = n + 2 5844 count += 1 5586 count += 1 5845 return out 5587 return out 5846 5588 >> 5589 def displayControl(cmd): >> 5590 xset, ret = 'timeout 10 xset -d :0.0 {0}', 0 >> 5591 if sysvals.sudouser: >> 5592 xset = 'sudo -u %s %s' % (sysvals.sudouser, xset) >> 5593 if cmd == 'init': >> 5594 ret = call(xset.format('dpms 0 0 0'), shell=True) >> 5595 if not ret: >> 5596 ret = call(xset.format('s off'), shell=True) >> 5597 elif cmd == 'reset': >> 5598 ret = call(xset.format('s reset'), shell=True) >> 5599 elif cmd in ['on', 'off', 'standby', 'suspend']: >> 5600 b4 = displayControl('stat') >> 5601 ret = call(xset.format('dpms force %s' % cmd), shell=True) >> 5602 if not ret: >> 5603 curr = displayControl('stat') >> 5604 sysvals.vprint('Display Switched: %s -> %s' % (b4, curr)) >> 5605 if curr != cmd: >> 5606 sysvals.vprint('WARNING: Display failed to change to %s' % cmd) >> 5607 if ret: >> 5608 sysvals.vprint('WARNING: Display failed to change to %s with xset' % cmd) >> 5609 return ret >> 5610 elif cmd == 'stat': >> 5611 fp = Popen(xset.format('q').split(' '), stdout=PIPE).stdout >> 5612 ret = 'unknown' >> 5613 for line in fp: >> 5614 m = re.match('[\s]*Monitor is (?P<m>.*)', ascii(line)) >> 5615 if(m and len(m.group('m')) >= 2): >> 5616 out = m.group('m').lower() >> 5617 ret = out[3:] if out[0:2] == 'in' else out >> 5618 break >> 5619 fp.close() >> 5620 return ret >> 5621 5847 # Function: getFPDT 5622 # Function: getFPDT 5848 # Description: 5623 # Description: 5849 # Read the acpi bios tables and pull o 5624 # Read the acpi bios tables and pull out FPDT, the firmware data 5850 # Arguments: 5625 # Arguments: 5851 # output: True to output the info to s 5626 # output: True to output the info to stdout, False otherwise 5852 def getFPDT(output): 5627 def getFPDT(output): 5853 rectype = {} 5628 rectype = {} 5854 rectype[0] = 'Firmware Basic Boot Per 5629 rectype[0] = 'Firmware Basic Boot Performance Record' 5855 rectype[1] = 'S3 Performance Table Re 5630 rectype[1] = 'S3 Performance Table Record' 5856 prectype = {} 5631 prectype = {} 5857 prectype[0] = 'Basic S3 Resume Perfor 5632 prectype[0] = 'Basic S3 Resume Performance Record' 5858 prectype[1] = 'Basic S3 Suspend Perfo 5633 prectype[1] = 'Basic S3 Suspend Performance Record' 5859 5634 5860 sysvals.rootCheck(True) 5635 sysvals.rootCheck(True) 5861 if(not os.path.exists(sysvals.fpdtpat 5636 if(not os.path.exists(sysvals.fpdtpath)): 5862 if(output): 5637 if(output): 5863 doError('file does no 5638 doError('file does not exist: %s' % sysvals.fpdtpath) 5864 return False 5639 return False 5865 if(not os.access(sysvals.fpdtpath, os 5640 if(not os.access(sysvals.fpdtpath, os.R_OK)): 5866 if(output): 5641 if(output): 5867 doError('file is not 5642 doError('file is not readable: %s' % sysvals.fpdtpath) 5868 return False 5643 return False 5869 if(not os.path.exists(sysvals.mempath 5644 if(not os.path.exists(sysvals.mempath)): 5870 if(output): 5645 if(output): 5871 doError('file does no 5646 doError('file does not exist: %s' % sysvals.mempath) 5872 return False 5647 return False 5873 if(not os.access(sysvals.mempath, os. 5648 if(not os.access(sysvals.mempath, os.R_OK)): 5874 if(output): 5649 if(output): 5875 doError('file is not 5650 doError('file is not readable: %s' % sysvals.mempath) 5876 return False 5651 return False 5877 5652 5878 fp = open(sysvals.fpdtpath, 'rb') 5653 fp = open(sysvals.fpdtpath, 'rb') 5879 buf = fp.read() 5654 buf = fp.read() 5880 fp.close() 5655 fp.close() 5881 5656 5882 if(len(buf) < 36): 5657 if(len(buf) < 36): 5883 if(output): 5658 if(output): 5884 doError('Invalid FPDT 5659 doError('Invalid FPDT table data, should '+\ 5885 'be at least 5660 'be at least 36 bytes') 5886 return False 5661 return False 5887 5662 5888 table = struct.unpack('4sIBB6s8sI4sI' 5663 table = struct.unpack('4sIBB6s8sI4sI', buf[0:36]) 5889 if(output): 5664 if(output): 5890 pprint('\n'\ 5665 pprint('\n'\ 5891 'Firmware Performance Data Ta 5666 'Firmware Performance Data Table (%s)\n'\ 5892 ' Signature 5667 ' Signature : %s\n'\ 5893 ' Table Length 5668 ' Table Length : %u\n'\ 5894 ' Revision 5669 ' Revision : %u\n'\ 5895 ' Checksum 5670 ' Checksum : 0x%x\n'\ 5896 ' OEM ID 5671 ' OEM ID : %s\n'\ 5897 ' OEM Table ID 5672 ' OEM Table ID : %s\n'\ 5898 ' OEM Revision 5673 ' OEM Revision : %u\n'\ 5899 ' Creator ID 5674 ' Creator ID : %s\n'\ 5900 ' Creator Revision 5675 ' Creator Revision : 0x%x\n'\ 5901 '' % (ascii(table[0]), ascii( 5676 '' % (ascii(table[0]), ascii(table[0]), table[1], table[2], 5902 table[3], ascii(table 5677 table[3], ascii(table[4]), ascii(table[5]), table[6], 5903 ascii(table[7]), tabl 5678 ascii(table[7]), table[8])) 5904 5679 5905 if(table[0] != b'FPDT'): 5680 if(table[0] != b'FPDT'): 5906 if(output): 5681 if(output): 5907 doError('Invalid FPDT 5682 doError('Invalid FPDT table') 5908 return False 5683 return False 5909 if(len(buf) <= 36): 5684 if(len(buf) <= 36): 5910 return False 5685 return False 5911 i = 0 5686 i = 0 5912 fwData = [0, 0] 5687 fwData = [0, 0] 5913 records = buf[36:] 5688 records = buf[36:] 5914 try: 5689 try: 5915 fp = open(sysvals.mempath, 'r 5690 fp = open(sysvals.mempath, 'rb') 5916 except: 5691 except: 5917 pprint('WARNING: /dev/mem is 5692 pprint('WARNING: /dev/mem is not readable, ignoring the FPDT data') 5918 return False 5693 return False 5919 while(i < len(records)): 5694 while(i < len(records)): 5920 header = struct.unpack('HBB', 5695 header = struct.unpack('HBB', records[i:i+4]) 5921 if(header[0] not in rectype): 5696 if(header[0] not in rectype): 5922 i += header[1] 5697 i += header[1] 5923 continue 5698 continue 5924 if(header[1] != 16): 5699 if(header[1] != 16): 5925 i += header[1] 5700 i += header[1] 5926 continue 5701 continue 5927 addr = struct.unpack('Q', rec 5702 addr = struct.unpack('Q', records[i+8:i+16])[0] 5928 try: 5703 try: 5929 fp.seek(addr) 5704 fp.seek(addr) 5930 first = fp.read(8) 5705 first = fp.read(8) 5931 except: 5706 except: 5932 if(output): 5707 if(output): 5933 pprint('Bad a 5708 pprint('Bad address 0x%x in %s' % (addr, sysvals.mempath)) 5934 return [0, 0] 5709 return [0, 0] 5935 rechead = struct.unpack('4sI' 5710 rechead = struct.unpack('4sI', first) 5936 recdata = fp.read(rechead[1]- 5711 recdata = fp.read(rechead[1]-8) 5937 if(rechead[0] == b'FBPT'): 5712 if(rechead[0] == b'FBPT'): 5938 record = struct.unpac 5713 record = struct.unpack('HBBIQQQQQ', recdata[:48]) 5939 if(output): 5714 if(output): 5940 pprint('%s (% 5715 pprint('%s (%s)\n'\ 5941 ' 5716 ' Reset END : %u ns\n'\ 5942 ' OS Loader 5717 ' OS Loader LoadImage Start : %u ns\n'\ 5943 ' OS Loader S 5718 ' OS Loader StartImage Start : %u ns\n'\ 5944 ' ExitBoo 5719 ' ExitBootServices Entry : %u ns\n'\ 5945 ' ExitBo 5720 ' ExitBootServices Exit : %u ns'\ 5946 '' % (rectype 5721 '' % (rectype[header[0]], ascii(rechead[0]), record[4], record[5], 5947 recor 5722 record[6], record[7], record[8])) 5948 elif(rechead[0] == b'S3PT'): 5723 elif(rechead[0] == b'S3PT'): 5949 if(output): 5724 if(output): 5950 pprint('%s (% 5725 pprint('%s (%s)' % (rectype[header[0]], ascii(rechead[0]))) 5951 j = 0 5726 j = 0 5952 while(j < len(recdata 5727 while(j < len(recdata)): 5953 prechead = st 5728 prechead = struct.unpack('HBB', recdata[j:j+4]) 5954 if(prechead[0 5729 if(prechead[0] not in prectype): 5955 conti 5730 continue 5956 if(prechead[0 5731 if(prechead[0] == 0): 5957 recor 5732 record = struct.unpack('IIQQ', recdata[j:j+prechead[1]]) 5958 fwDat 5733 fwData[1] = record[2] 5959 if(ou 5734 if(output): 5960 5735 pprint(' %s\n'\ 5961 5736 ' Resume Count : %u\n'\ 5962 5737 ' FullResume : %u ns\n'\ 5963 5738 ' AverageResume : %u ns'\ 5964 5739 '' % (prectype[prechead[0]], record[1], 5965 5740 record[2], record[3])) 5966 elif(prechead 5741 elif(prechead[0] == 1): 5967 recor 5742 record = struct.unpack('QQ', recdata[j+4:j+prechead[1]]) 5968 fwDat 5743 fwData[0] = record[1] - record[0] 5969 if(ou 5744 if(output): 5970 5745 pprint(' %s\n'\ 5971 5746 ' SuspendStart : %u ns\n'\ 5972 5747 ' SuspendEnd : %u ns\n'\ 5973 5748 ' SuspendTime : %u ns'\ 5974 5749 '' % (prectype[prechead[0]], record[0], 5975 5750 record[1], fwData[0])) 5976 5751 5977 j += prechead 5752 j += prechead[1] 5978 if(output): 5753 if(output): 5979 pprint('') 5754 pprint('') 5980 i += header[1] 5755 i += header[1] 5981 fp.close() 5756 fp.close() 5982 return fwData 5757 return fwData 5983 5758 5984 # Function: statusCheck 5759 # Function: statusCheck 5985 # Description: 5760 # Description: 5986 # Verify that the requested command an 5761 # Verify that the requested command and options will work, and 5987 # print the results to the terminal 5762 # print the results to the terminal 5988 # Output: 5763 # Output: 5989 # True if the test will work, False if 5764 # True if the test will work, False if not 5990 def statusCheck(probecheck=False): 5765 def statusCheck(probecheck=False): 5991 status = '' 5766 status = '' 5992 5767 5993 pprint('Checking this system (%s)...' 5768 pprint('Checking this system (%s)...' % platform.node()) 5994 5769 5995 # check we have root access 5770 # check we have root access 5996 res = sysvals.colorText('NO (No featu 5771 res = sysvals.colorText('NO (No features of this tool will work!)') 5997 if(sysvals.rootCheck(False)): 5772 if(sysvals.rootCheck(False)): 5998 res = 'YES' 5773 res = 'YES' 5999 pprint(' have root access: %s' % r 5774 pprint(' have root access: %s' % res) 6000 if(res != 'YES'): 5775 if(res != 'YES'): 6001 pprint(' Try running this 5776 pprint(' Try running this script with sudo') 6002 return 'missing root access' 5777 return 'missing root access' 6003 5778 6004 # check sysfs is mounted 5779 # check sysfs is mounted 6005 res = sysvals.colorText('NO (No featu 5780 res = sysvals.colorText('NO (No features of this tool will work!)') 6006 if(os.path.exists(sysvals.powerfile)) 5781 if(os.path.exists(sysvals.powerfile)): 6007 res = 'YES' 5782 res = 'YES' 6008 pprint(' is sysfs mounted: %s' % r 5783 pprint(' is sysfs mounted: %s' % res) 6009 if(res != 'YES'): 5784 if(res != 'YES'): 6010 return 'sysfs is missing' 5785 return 'sysfs is missing' 6011 5786 6012 # check target mode is a valid mode 5787 # check target mode is a valid mode 6013 if sysvals.suspendmode != 'command': 5788 if sysvals.suspendmode != 'command': 6014 res = sysvals.colorText('NO') 5789 res = sysvals.colorText('NO') 6015 modes = getModes() 5790 modes = getModes() 6016 if(sysvals.suspendmode in mod 5791 if(sysvals.suspendmode in modes): 6017 res = 'YES' 5792 res = 'YES' 6018 else: 5793 else: 6019 status = '%s mode is 5794 status = '%s mode is not supported' % sysvals.suspendmode 6020 pprint(' is "%s" a valid p 5795 pprint(' is "%s" a valid power mode: %s' % (sysvals.suspendmode, res)) 6021 if(res == 'NO'): 5796 if(res == 'NO'): 6022 pprint(' valid p 5797 pprint(' valid power modes are: %s' % modes) 6023 pprint(' please 5798 pprint(' please choose one with -m') 6024 5799 6025 # check if ftrace is available 5800 # check if ftrace is available 6026 if sysvals.useftrace: !! 5801 res = sysvals.colorText('NO') 6027 res = sysvals.colorText('NO') !! 5802 ftgood = sysvals.verifyFtrace() 6028 sysvals.useftrace = sysvals.v !! 5803 if(ftgood): 6029 efmt = '"{0}" uses ftrace, an !! 5804 res = 'YES' 6030 if sysvals.useftrace: !! 5805 elif(sysvals.usecallgraph): 6031 res = 'YES' !! 5806 status = 'ftrace is not properly supported' 6032 elif sysvals.usecallgraph: !! 5807 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 5808 6040 # check if kprobes are available 5809 # check if kprobes are available 6041 if sysvals.usekprobes: 5810 if sysvals.usekprobes: 6042 res = sysvals.colorText('NO') 5811 res = sysvals.colorText('NO') 6043 sysvals.usekprobes = sysvals. 5812 sysvals.usekprobes = sysvals.verifyKprobes() 6044 if(sysvals.usekprobes): 5813 if(sysvals.usekprobes): 6045 res = 'YES' 5814 res = 'YES' 6046 else: 5815 else: 6047 sysvals.usedevsrc = F 5816 sysvals.usedevsrc = False 6048 pprint(' are kprobes suppo 5817 pprint(' are kprobes supported: %s' % res) 6049 5818 6050 # what data source are we using 5819 # what data source are we using 6051 res = 'DMESG (very limited, ftrace is !! 5820 res = 'DMESG' 6052 if sysvals.useftrace: !! 5821 if(ftgood): 6053 sysvals.usetraceevents = True 5822 sysvals.usetraceevents = True 6054 for e in sysvals.traceevents: 5823 for e in sysvals.traceevents: 6055 if not os.path.exists 5824 if not os.path.exists(sysvals.epath+e): 6056 sysvals.usetr 5825 sysvals.usetraceevents = False 6057 if(sysvals.usetraceevents): 5826 if(sysvals.usetraceevents): 6058 res = 'FTRACE (all tr 5827 res = 'FTRACE (all trace events found)' 6059 pprint(' timeline data source: %s' 5828 pprint(' timeline data source: %s' % res) 6060 5829 6061 # check if rtcwake 5830 # check if rtcwake 6062 res = sysvals.colorText('NO') 5831 res = sysvals.colorText('NO') 6063 if(sysvals.rtcpath != ''): 5832 if(sysvals.rtcpath != ''): 6064 res = 'YES' 5833 res = 'YES' 6065 elif(sysvals.rtcwake): 5834 elif(sysvals.rtcwake): 6066 status = 'rtcwake is not prop 5835 status = 'rtcwake is not properly supported' 6067 pprint(' is rtcwake supported: %s' 5836 pprint(' is rtcwake supported: %s' % res) 6068 5837 6069 # check info commands 5838 # check info commands 6070 pprint(' optional commands this to 5839 pprint(' optional commands this tool may use for info:') 6071 no = sysvals.colorText('MISSING') 5840 no = sysvals.colorText('MISSING') 6072 yes = sysvals.colorText('FOUND', 32) 5841 yes = sysvals.colorText('FOUND', 32) 6073 for c in ['turbostat', 'mcelog', 'lsp !! 5842 for c in ['turbostat', 'mcelog', 'lspci', 'lsusb']: 6074 if c == 'turbostat': 5843 if c == 'turbostat': 6075 res = yes if sysvals. 5844 res = yes if sysvals.haveTurbostat() else no 6076 else: 5845 else: 6077 res = yes if sysvals. 5846 res = yes if sysvals.getExec(c) else no 6078 pprint(' %s: %s' % (c, 5847 pprint(' %s: %s' % (c, res)) 6079 5848 6080 if not probecheck: 5849 if not probecheck: 6081 return status 5850 return status 6082 5851 6083 # verify kprobes 5852 # verify kprobes 6084 if sysvals.usekprobes: 5853 if sysvals.usekprobes: 6085 for name in sysvals.tracefunc 5854 for name in sysvals.tracefuncs: 6086 sysvals.defaultKprobe 5855 sysvals.defaultKprobe(name, sysvals.tracefuncs[name]) 6087 if sysvals.usedevsrc: 5856 if sysvals.usedevsrc: 6088 for name in sysvals.d 5857 for name in sysvals.dev_tracefuncs: 6089 sysvals.defau 5858 sysvals.defaultKprobe(name, sysvals.dev_tracefuncs[name]) 6090 sysvals.addKprobes(True) 5859 sysvals.addKprobes(True) 6091 5860 6092 return status 5861 return status 6093 5862 6094 # Function: doError 5863 # Function: doError 6095 # Description: 5864 # Description: 6096 # generic error function for catastrph 5865 # generic error function for catastrphic failures 6097 # Arguments: 5866 # Arguments: 6098 # msg: the error message to print 5867 # msg: the error message to print 6099 # help: True if printHelp should be ca 5868 # help: True if printHelp should be called after, False otherwise 6100 def doError(msg, help=False): 5869 def doError(msg, help=False): 6101 if(help == True): 5870 if(help == True): 6102 printHelp() 5871 printHelp() 6103 pprint('ERROR: %s\n' % msg) 5872 pprint('ERROR: %s\n' % msg) 6104 sysvals.outputResult({'error':msg}) 5873 sysvals.outputResult({'error':msg}) 6105 sys.exit(1) 5874 sys.exit(1) 6106 5875 6107 # Function: getArgInt 5876 # Function: getArgInt 6108 # Description: 5877 # Description: 6109 # pull out an integer argument from th 5878 # pull out an integer argument from the command line with checks 6110 def getArgInt(name, args, min, max, main=True 5879 def getArgInt(name, args, min, max, main=True): 6111 if main: 5880 if main: 6112 try: 5881 try: 6113 arg = next(args) 5882 arg = next(args) 6114 except: 5883 except: 6115 doError(name+': no ar 5884 doError(name+': no argument supplied', True) 6116 else: 5885 else: 6117 arg = args 5886 arg = args 6118 try: 5887 try: 6119 val = int(arg) 5888 val = int(arg) 6120 except: 5889 except: 6121 doError(name+': non-integer v 5890 doError(name+': non-integer value given', True) 6122 if(val < min or val > max): 5891 if(val < min or val > max): 6123 doError(name+': value should 5892 doError(name+': value should be between %d and %d' % (min, max), True) 6124 return val 5893 return val 6125 5894 6126 # Function: getArgFloat 5895 # Function: getArgFloat 6127 # Description: 5896 # Description: 6128 # pull out a float argument from the c 5897 # pull out a float argument from the command line with checks 6129 def getArgFloat(name, args, min, max, main=Tr 5898 def getArgFloat(name, args, min, max, main=True): 6130 if main: 5899 if main: 6131 try: 5900 try: 6132 arg = next(args) 5901 arg = next(args) 6133 except: 5902 except: 6134 doError(name+': no ar 5903 doError(name+': no argument supplied', True) 6135 else: 5904 else: 6136 arg = args 5905 arg = args 6137 try: 5906 try: 6138 val = float(arg) 5907 val = float(arg) 6139 except: 5908 except: 6140 doError(name+': non-numerical 5909 doError(name+': non-numerical value given', True) 6141 if(val < min or val > max): 5910 if(val < min or val > max): 6142 doError(name+': value should 5911 doError(name+': value should be between %f and %f' % (min, max), True) 6143 return val 5912 return val 6144 5913 6145 def processData(live=False, quiet=False): 5914 def processData(live=False, quiet=False): 6146 if not quiet: 5915 if not quiet: 6147 pprint('PROCESSING: %s' % sys 5916 pprint('PROCESSING: %s' % sysvals.htmlfile) 6148 sysvals.vprint('usetraceevents=%s, us 5917 sysvals.vprint('usetraceevents=%s, usetracemarkers=%s, usekprobes=%s' % \ 6149 (sysvals.usetraceevents, sysv 5918 (sysvals.usetraceevents, sysvals.usetracemarkers, sysvals.usekprobes)) 6150 error = '' 5919 error = '' 6151 if(sysvals.usetraceevents): 5920 if(sysvals.usetraceevents): 6152 testruns, error = parseTraceL 5921 testruns, error = parseTraceLog(live) 6153 if sysvals.dmesgfile: 5922 if sysvals.dmesgfile: 6154 for data in testruns: 5923 for data in testruns: 6155 data.extractE 5924 data.extractErrorInfo() 6156 else: 5925 else: 6157 testruns = loadKernelLog() 5926 testruns = loadKernelLog() 6158 for data in testruns: 5927 for data in testruns: 6159 parseKernelLog(data) 5928 parseKernelLog(data) 6160 if(sysvals.ftracefile and (sy 5929 if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): 6161 appendIncompleteTrace 5930 appendIncompleteTraceLog(testruns) 6162 if not sysvals.stamp: 5931 if not sysvals.stamp: 6163 pprint('ERROR: data does not 5932 pprint('ERROR: data does not include the expected stamp') 6164 return (testruns, {'error': ' 5933 return (testruns, {'error': 'timeline generation failed'}) 6165 shown = ['os', 'bios', 'biosdate', 'c !! 5934 shown = ['bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr', 6166 'memsz', 'mode', 'num 5935 'memsz', 'mode', 'numcpu', 'plat', 'time', 'wifi'] 6167 sysvals.vprint('System Info:') 5936 sysvals.vprint('System Info:') 6168 for key in sorted(sysvals.stamp): 5937 for key in sorted(sysvals.stamp): 6169 if key in shown: 5938 if key in shown: 6170 sysvals.vprint(' % 5939 sysvals.vprint(' %-8s : %s' % (key.upper(), sysvals.stamp[key])) 6171 sysvals.vprint('Command:\n %s' % s 5940 sysvals.vprint('Command:\n %s' % sysvals.cmdline) 6172 for data in testruns: 5941 for data in testruns: 6173 if data.turbostat: 5942 if data.turbostat: 6174 idx, s = 0, 'Turbosta 5943 idx, s = 0, 'Turbostat:\n ' 6175 for val in data.turbo 5944 for val in data.turbostat.split('|'): 6176 idx += len(va 5945 idx += len(val) + 1 6177 if idx >= 80: 5946 if idx >= 80: 6178 idx = 5947 idx = 0 6179 s += 5948 s += '\n ' 6180 s += val + ' 5949 s += val + ' ' 6181 sysvals.vprint(s) 5950 sysvals.vprint(s) 6182 data.printDetails() 5951 data.printDetails() 6183 if len(sysvals.platinfo) > 0: 5952 if len(sysvals.platinfo) > 0: 6184 sysvals.vprint('\nPlatform In 5953 sysvals.vprint('\nPlatform Info:') 6185 for info in sysvals.platinfo: 5954 for info in sysvals.platinfo: 6186 sysvals.vprint('[%s - 5955 sysvals.vprint('[%s - %s]' % (info[0], info[1])) 6187 sysvals.vprint(info[2 5956 sysvals.vprint(info[2]) 6188 sysvals.vprint('') 5957 sysvals.vprint('') 6189 if sysvals.cgdump: 5958 if sysvals.cgdump: 6190 for data in testruns: 5959 for data in testruns: 6191 data.debugPrint() 5960 data.debugPrint() 6192 sys.exit(0) 5961 sys.exit(0) 6193 if len(testruns) < 1: 5962 if len(testruns) < 1: 6194 pprint('ERROR: Not enough tes 5963 pprint('ERROR: Not enough test data to build a timeline') 6195 return (testruns, {'error': ' 5964 return (testruns, {'error': 'timeline generation failed'}) 6196 sysvals.vprint('Creating the html tim 5965 sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile) 6197 createHTML(testruns, error) 5966 createHTML(testruns, error) 6198 if not quiet: 5967 if not quiet: 6199 pprint('DONE: %s' % sys 5968 pprint('DONE: %s' % sysvals.htmlfile) 6200 data = testruns[0] 5969 data = testruns[0] 6201 stamp = data.stamp 5970 stamp = data.stamp 6202 stamp['suspend'], stamp['resume'] = d 5971 stamp['suspend'], stamp['resume'] = data.getTimeValues() 6203 if data.fwValid: 5972 if data.fwValid: 6204 stamp['fwsuspend'], stamp['fw 5973 stamp['fwsuspend'], stamp['fwresume'] = data.fwSuspend, data.fwResume 6205 if error: 5974 if error: 6206 stamp['error'] = error 5975 stamp['error'] = error 6207 return (testruns, stamp) 5976 return (testruns, stamp) 6208 5977 6209 # Function: rerunTest 5978 # Function: rerunTest 6210 # Description: 5979 # Description: 6211 # generate an output from an existing 5980 # generate an output from an existing set of ftrace/dmesg logs 6212 def rerunTest(htmlfile=''): 5981 def rerunTest(htmlfile=''): 6213 if sysvals.ftracefile: 5982 if sysvals.ftracefile: 6214 doesTraceLogHaveTraceEvents() 5983 doesTraceLogHaveTraceEvents() 6215 if not sysvals.dmesgfile and not sysv 5984 if not sysvals.dmesgfile and not sysvals.usetraceevents: 6216 doError('recreating this html 5985 doError('recreating this html output requires a dmesg file') 6217 if htmlfile: 5986 if htmlfile: 6218 sysvals.htmlfile = htmlfile 5987 sysvals.htmlfile = htmlfile 6219 else: 5988 else: 6220 sysvals.setOutputFile() 5989 sysvals.setOutputFile() 6221 if os.path.exists(sysvals.htmlfile): 5990 if os.path.exists(sysvals.htmlfile): 6222 if not os.path.isfile(sysvals 5991 if not os.path.isfile(sysvals.htmlfile): 6223 doError('a directory 5992 doError('a directory already exists with this name: %s' % sysvals.htmlfile) 6224 elif not os.access(sysvals.ht 5993 elif not os.access(sysvals.htmlfile, os.W_OK): 6225 doError('missing perm 5994 doError('missing permission to write to %s' % sysvals.htmlfile) 6226 testruns, stamp = processData() 5995 testruns, stamp = processData() 6227 sysvals.resetlog() 5996 sysvals.resetlog() 6228 return stamp 5997 return stamp 6229 5998 6230 # Function: runTest 5999 # Function: runTest 6231 # Description: 6000 # Description: 6232 # execute a suspend/resume, gather the 6001 # execute a suspend/resume, gather the logs, and generate the output 6233 def runTest(n=0, quiet=False): 6002 def runTest(n=0, quiet=False): 6234 # prepare for the test 6003 # prepare for the test 6235 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) 6004 sysvals.initFtrace(quiet) >> 6005 sysvals.initTestOutput('suspend') 6250 6006 6251 # execute the test 6007 # execute the test 6252 executeSuspend(quiet) 6008 executeSuspend(quiet) 6253 sysvals.cleanupFtrace() 6009 sysvals.cleanupFtrace() 6254 if sysvals.skiphtml: 6010 if sysvals.skiphtml: 6255 sysvals.outputResult({}, n) 6011 sysvals.outputResult({}, n) 6256 sysvals.sudoUserchown(sysvals 6012 sysvals.sudoUserchown(sysvals.testdir) 6257 return 6013 return 6258 testruns, stamp = processData(True, q 6014 testruns, stamp = processData(True, quiet) 6259 for data in testruns: 6015 for data in testruns: 6260 del data 6016 del data 6261 sysvals.sudoUserchown(sysvals.testdir 6017 sysvals.sudoUserchown(sysvals.testdir) 6262 sysvals.outputResult(stamp, n) 6018 sysvals.outputResult(stamp, n) 6263 if 'error' in stamp: 6019 if 'error' in stamp: 6264 return 2 6020 return 2 6265 return 0 6021 return 0 6266 6022 6267 def find_in_html(html, start, end, firstonly= 6023 def find_in_html(html, start, end, firstonly=True): 6268 cnt, out, list = len(html), [], [] 6024 cnt, out, list = len(html), [], [] 6269 if firstonly: 6025 if firstonly: 6270 m = re.search(start, html) 6026 m = re.search(start, html) 6271 if m: 6027 if m: 6272 list.append(m) 6028 list.append(m) 6273 else: 6029 else: 6274 list = re.finditer(start, htm 6030 list = re.finditer(start, html) 6275 for match in list: 6031 for match in list: 6276 s = match.end() 6032 s = match.end() 6277 e = cnt if (len(out) < 1 or s 6033 e = cnt if (len(out) < 1 or s + 10000 > cnt) else s + 10000 6278 m = re.search(end, html[s:e]) 6034 m = re.search(end, html[s:e]) 6279 if not m: 6035 if not m: 6280 break 6036 break 6281 e = s + m.start() 6037 e = s + m.start() 6282 str = html[s:e] 6038 str = html[s:e] 6283 if end == 'ms': 6039 if end == 'ms': 6284 num = re.search(r'[-+ 6040 num = re.search(r'[-+]?\d*\.\d+|\d+', str) 6285 str = num.group() if 6041 str = num.group() if num else 'NaN' 6286 if firstonly: 6042 if firstonly: 6287 return str 6043 return str 6288 out.append(str) 6044 out.append(str) 6289 if firstonly: 6045 if firstonly: 6290 return '' 6046 return '' 6291 return out 6047 return out 6292 6048 6293 def data_from_html(file, outpath, issues, ful 6049 def data_from_html(file, outpath, issues, fulldetail=False): 6294 try: !! 6050 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 6051 sysvals.htmlfile = os.path.relpath(file, outpath) 6299 # extract general info 6052 # extract general info 6300 suspend = find_in_html(html, 'Kernel 6053 suspend = find_in_html(html, 'Kernel Suspend', 'ms') 6301 resume = find_in_html(html, 'Kernel R 6054 resume = find_in_html(html, 'Kernel Resume', 'ms') 6302 sysinfo = find_in_html(html, '<div cl 6055 sysinfo = find_in_html(html, '<div class="stamp sysinfo">', '</div>') 6303 line = find_in_html(html, '<div class 6056 line = find_in_html(html, '<div class="stamp">', '</div>') 6304 stmp = line.split() 6057 stmp = line.split() 6305 if not suspend or not resume or len(s 6058 if not suspend or not resume or len(stmp) != 8: 6306 return False 6059 return False 6307 try: 6060 try: 6308 dt = datetime.strptime(' '.jo 6061 dt = datetime.strptime(' '.join(stmp[3:]), '%B %d %Y, %I:%M:%S %p') 6309 except: 6062 except: 6310 return False 6063 return False 6311 sysvals.hostname = stmp[0] 6064 sysvals.hostname = stmp[0] 6312 tstr = dt.strftime('%Y/%m/%d %H:%M:%S 6065 tstr = dt.strftime('%Y/%m/%d %H:%M:%S') 6313 error = find_in_html(html, '<table cl 6066 error = find_in_html(html, '<table class="testfail"><tr><td>', '</td>') 6314 if error: 6067 if error: 6315 m = re.match(r'[a-z0-9]* fail !! 6068 m = re.match('[a-z0-9]* failed in (?P<p>\S*).*', error) 6316 if m: 6069 if m: 6317 result = 'fail in %s' 6070 result = 'fail in %s' % m.group('p') 6318 else: 6071 else: 6319 result = 'fail' 6072 result = 'fail' 6320 else: 6073 else: 6321 result = 'pass' 6074 result = 'pass' 6322 # extract error info 6075 # extract error info 6323 tp, ilist = False, [] 6076 tp, ilist = False, [] 6324 extra = dict() 6077 extra = dict() 6325 log = find_in_html(html, '<div id="dm 6078 log = find_in_html(html, '<div id="dmesglog" style="display:none;">', 6326 '</div>').strip() 6079 '</div>').strip() 6327 if log: 6080 if log: 6328 d = Data(0) 6081 d = Data(0) 6329 d.end = 999999999 6082 d.end = 999999999 6330 d.dmesgtext = log.split('\n') 6083 d.dmesgtext = log.split('\n') 6331 tp = d.extractErrorInfo() 6084 tp = d.extractErrorInfo() 6332 if len(issues) < 100: !! 6085 for msg in tp.msglist: 6333 for msg in tp.msglist !! 6086 sysvals.errorSummary(issues, msg) 6334 sysvals.error << 6335 if stmp[2] == 'freeze': 6087 if stmp[2] == 'freeze': 6336 extra = d.turbostatIn 6088 extra = d.turbostatInfo() 6337 elist = dict() 6089 elist = dict() 6338 for dir in d.errorinfo: 6090 for dir in d.errorinfo: 6339 for err in d.errorinf 6091 for err in d.errorinfo[dir]: 6340 if err[0] not 6092 if err[0] not in elist: 6341 elist 6093 elist[err[0]] = 0 6342 elist[err[0]] 6094 elist[err[0]] += 1 6343 for i in elist: 6095 for i in elist: 6344 ilist.append('%sx%d' 6096 ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i) 6345 line = find_in_html(log, '# w !! 6097 wifi = find_in_html(html, 'Wifi Resume: ', '</td>') 6346 if line: !! 6098 if wifi: 6347 extra['wifi'] = line !! 6099 extra['wifi'] = wifi 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 6100 low = find_in_html(html, 'freeze time: <b>', ' ms</b>') 6357 for lowstr in ['waking', '+']: !! 6101 if low and 'waking' in low: 6358 if not low: !! 6102 issue = 'FREEZEWAKE' 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 6103 match = [i for i in issues if i['match'] == issue] 6368 if len(match) > 0: 6104 if len(match) > 0: 6369 match[0]['count'] += 6105 match[0]['count'] += 1 6370 if sysvals.hostname n 6106 if sysvals.hostname not in match[0]['urls']: 6371 match[0]['url 6107 match[0]['urls'][sysvals.hostname] = [sysvals.htmlfile] 6372 elif sysvals.htmlfile 6108 elif sysvals.htmlfile not in match[0]['urls'][sysvals.hostname]: 6373 match[0]['url 6109 match[0]['urls'][sysvals.hostname].append(sysvals.htmlfile) 6374 else: 6110 else: 6375 issues.append({ 6111 issues.append({ 6376 'match': issu 6112 'match': issue, 'count': 1, 'line': issue, 6377 'urls': {sysv 6113 'urls': {sysvals.hostname: [sysvals.htmlfile]}, 6378 }) 6114 }) 6379 ilist.append(issue) 6115 ilist.append(issue) 6380 # extract device info 6116 # extract device info 6381 devices = dict() 6117 devices = dict() 6382 for line in html.split('\n'): 6118 for line in html.split('\n'): 6383 m = re.match(r' *<div id=\"[a !! 6119 m = re.match(' *<div id=\"[a,0-9]*\" *title=\"(?P<title>.*)\" class=\"thread.*', line) 6384 if not m or 'thread kth' in l 6120 if not m or 'thread kth' in line or 'thread sec' in line: 6385 continue 6121 continue 6386 m = re.match(r'(?P<n>.*) \((? !! 6122 m = re.match('(?P<n>.*) \((?P<t>[0-9,\.]*) ms\) (?P<p>.*)', m.group('title')) 6387 if not m: 6123 if not m: 6388 continue 6124 continue 6389 name, time, phase = m.group(' 6125 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 6126 if ' async' in name or ' sync' in name: 6393 name = ' '.join(name. 6127 name = ' '.join(name.split(' ')[:-1]) 6394 if phase.startswith('suspend' 6128 if phase.startswith('suspend'): 6395 d = 'suspend' 6129 d = 'suspend' 6396 elif phase.startswith('resume 6130 elif phase.startswith('resume'): 6397 d = 'resume' 6131 d = 'resume' 6398 else: 6132 else: 6399 continue 6133 continue 6400 if d not in devices: 6134 if d not in devices: 6401 devices[d] = dict() 6135 devices[d] = dict() 6402 if name not in devices[d]: 6136 if name not in devices[d]: 6403 devices[d][name] = 0. 6137 devices[d][name] = 0.0 6404 devices[d][name] += float(tim 6138 devices[d][name] += float(time) 6405 # create worst device info 6139 # create worst device info 6406 worst = dict() 6140 worst = dict() 6407 for d in ['suspend', 'resume']: 6141 for d in ['suspend', 'resume']: 6408 worst[d] = {'name':'', 'time' 6142 worst[d] = {'name':'', 'time': 0.0} 6409 dev = devices[d] if d in devi 6143 dev = devices[d] if d in devices else 0 6410 if dev and len(dev.keys()) > 6144 if dev and len(dev.keys()) > 0: 6411 n = sorted(dev, key=l 6145 n = sorted(dev, key=lambda k:(dev[k], k), reverse=True)[0] 6412 worst[d]['name'], wor 6146 worst[d]['name'], worst[d]['time'] = n, dev[n] 6413 data = { 6147 data = { 6414 'mode': stmp[2], 6148 'mode': stmp[2], 6415 'host': stmp[0], 6149 'host': stmp[0], 6416 'kernel': stmp[1], 6150 'kernel': stmp[1], 6417 'sysinfo': sysinfo, 6151 'sysinfo': sysinfo, 6418 'time': tstr, 6152 'time': tstr, 6419 'result': result, 6153 'result': result, 6420 'issues': ' '.join(ilist), 6154 'issues': ' '.join(ilist), 6421 'suspend': suspend, 6155 'suspend': suspend, 6422 'resume': resume, 6156 'resume': resume, 6423 'devlist': devices, 6157 'devlist': devices, 6424 'sus_worst': worst['suspend'] 6158 'sus_worst': worst['suspend']['name'], 6425 'sus_worsttime': worst['suspe 6159 'sus_worsttime': worst['suspend']['time'], 6426 'res_worst': worst['resume'][ 6160 'res_worst': worst['resume']['name'], 6427 'res_worsttime': worst['resum 6161 'res_worsttime': worst['resume']['time'], 6428 'url': sysvals.htmlfile, 6162 'url': sysvals.htmlfile, 6429 } 6163 } 6430 for key in extra: 6164 for key in extra: 6431 data[key] = extra[key] 6165 data[key] = extra[key] 6432 if fulldetail: 6166 if fulldetail: 6433 data['funclist'] = find_in_ht 6167 data['funclist'] = find_in_html(html, '<div title="', '" class="traceevent"', False) 6434 if tp: 6168 if tp: 6435 for arg in ['-multi ', '-info 6169 for arg in ['-multi ', '-info ']: 6436 if arg in tp.cmdline: 6170 if arg in tp.cmdline: 6437 data['target' 6171 data['target'] = tp.cmdline[tp.cmdline.find(arg):].split()[1] 6438 break 6172 break 6439 return data 6173 return data 6440 6174 6441 def genHtml(subdir, force=False): 6175 def genHtml(subdir, force=False): 6442 for dirname, dirnames, filenames in o 6176 for dirname, dirnames, filenames in os.walk(subdir): 6443 sysvals.dmesgfile = sysvals.f 6177 sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = '' 6444 for filename in filenames: 6178 for filename in filenames: 6445 file = os.path.join(d 6179 file = os.path.join(dirname, filename) 6446 if sysvals.usable(fil 6180 if sysvals.usable(file): 6447 if(re.match(r !! 6181 if(re.match('.*_dmesg.txt', filename)): 6448 sysva 6182 sysvals.dmesgfile = file 6449 elif(re.match !! 6183 elif(re.match('.*_ftrace.txt', filename)): 6450 sysva 6184 sysvals.ftracefile = file 6451 sysvals.setOutputFile() 6185 sysvals.setOutputFile() 6452 if (sysvals.dmesgfile or sysv 6186 if (sysvals.dmesgfile or sysvals.ftracefile) and sysvals.htmlfile and \ 6453 (force or not sysvals !! 6187 (force or not sysvals.usable(sysvals.htmlfile)): 6454 pprint('FTRACE: %s' % 6188 pprint('FTRACE: %s' % sysvals.ftracefile) 6455 if sysvals.dmesgfile: 6189 if sysvals.dmesgfile: 6456 pprint('DMESG 6190 pprint('DMESG : %s' % sysvals.dmesgfile) 6457 rerunTest() 6191 rerunTest() 6458 6192 6459 # Function: runSummary 6193 # Function: runSummary 6460 # Description: 6194 # Description: 6461 # create a summary of tests in a sub-d 6195 # create a summary of tests in a sub-directory 6462 def runSummary(subdir, local=True, genhtml=Fa 6196 def runSummary(subdir, local=True, genhtml=False): 6463 inpath = os.path.abspath(subdir) 6197 inpath = os.path.abspath(subdir) 6464 outpath = os.path.abspath('.') if loc 6198 outpath = os.path.abspath('.') if local else inpath 6465 pprint('Generating a summary of folde 6199 pprint('Generating a summary of folder:\n %s' % inpath) 6466 if genhtml: 6200 if genhtml: 6467 genHtml(subdir) 6201 genHtml(subdir) 6468 target, issues, testruns = '', [], [] 6202 target, issues, testruns = '', [], [] 6469 desc = {'host':[],'mode':[],'kernel': 6203 desc = {'host':[],'mode':[],'kernel':[]} 6470 for dirname, dirnames, filenames in o 6204 for dirname, dirnames, filenames in os.walk(subdir): 6471 for filename in filenames: 6205 for filename in filenames: 6472 if(not re.match(r'.*. !! 6206 if(not re.match('.*.html', filename)): 6473 continue 6207 continue 6474 data = data_from_html 6208 data = data_from_html(os.path.join(dirname, filename), outpath, issues) 6475 if(not data): 6209 if(not data): 6476 continue 6210 continue 6477 if 'target' in data: 6211 if 'target' in data: 6478 target = data 6212 target = data['target'] 6479 testruns.append(data) 6213 testruns.append(data) 6480 for key in desc: 6214 for key in desc: 6481 if data[key] 6215 if data[key] not in desc[key]: 6482 desc[ 6216 desc[key].append(data[key]) 6483 pprint('Summary files:') 6217 pprint('Summary files:') 6484 if len(desc['host']) == len(desc['mod 6218 if len(desc['host']) == len(desc['mode']) == len(desc['kernel']) == 1: 6485 title = '%s %s %s' % (desc['h 6219 title = '%s %s %s' % (desc['host'][0], desc['kernel'][0], desc['mode'][0]) 6486 if target: 6220 if target: 6487 title += ' %s' % targ 6221 title += ' %s' % target 6488 else: 6222 else: 6489 title = inpath 6223 title = inpath 6490 createHTMLSummarySimple(testruns, os. 6224 createHTMLSummarySimple(testruns, os.path.join(outpath, 'summary.html'), title) 6491 pprint(' summary.html - tab 6225 pprint(' summary.html - tabular list of test data found') 6492 createHTMLDeviceSummary(testruns, os. 6226 createHTMLDeviceSummary(testruns, os.path.join(outpath, 'summary-devices.html'), title) 6493 pprint(' summary-devices.html - ker 6227 pprint(' summary-devices.html - kernel device list sorted by total execution time') 6494 createHTMLIssuesSummary(testruns, iss 6228 createHTMLIssuesSummary(testruns, issues, os.path.join(outpath, 'summary-issues.html'), title) 6495 pprint(' summary-issues.html - ker 6229 pprint(' summary-issues.html - kernel issues found sorted by frequency') 6496 6230 6497 # Function: checkArgBool 6231 # Function: checkArgBool 6498 # Description: 6232 # Description: 6499 # check if a boolean string value is t 6233 # check if a boolean string value is true or false 6500 def checkArgBool(name, value): 6234 def checkArgBool(name, value): 6501 if value in switchvalues: 6235 if value in switchvalues: 6502 if value in switchoff: 6236 if value in switchoff: 6503 return False 6237 return False 6504 return True 6238 return True 6505 doError('invalid boolean --> (%s: %s) 6239 doError('invalid boolean --> (%s: %s), use "true/false" or "1/0"' % (name, value), True) 6506 return False 6240 return False 6507 6241 6508 # Function: configFromFile 6242 # Function: configFromFile 6509 # Description: 6243 # Description: 6510 # Configure the script via the info in 6244 # Configure the script via the info in a config file 6511 def configFromFile(file): 6245 def configFromFile(file): 6512 Config = configparser.ConfigParser() 6246 Config = configparser.ConfigParser() 6513 6247 6514 Config.read(file) 6248 Config.read(file) 6515 sections = Config.sections() 6249 sections = Config.sections() 6516 overridekprobes = False 6250 overridekprobes = False 6517 overridedevkprobes = False 6251 overridedevkprobes = False 6518 if 'Settings' in sections: 6252 if 'Settings' in sections: 6519 for opt in Config.options('Se 6253 for opt in Config.options('Settings'): 6520 value = Config.get('S 6254 value = Config.get('Settings', opt).lower() 6521 option = opt.lower() 6255 option = opt.lower() 6522 if(option == 'verbose 6256 if(option == 'verbose'): 6523 sysvals.verbo 6257 sysvals.verbose = checkArgBool(option, value) 6524 elif(option == 'addlo 6258 elif(option == 'addlogs'): 6525 sysvals.dmesg 6259 sysvals.dmesglog = sysvals.ftracelog = checkArgBool(option, value) 6526 elif(option == 'dev') 6260 elif(option == 'dev'): 6527 sysvals.usede 6261 sysvals.usedevsrc = checkArgBool(option, value) 6528 elif(option == 'proc' 6262 elif(option == 'proc'): 6529 sysvals.usepr 6263 sysvals.useprocmon = checkArgBool(option, value) 6530 elif(option == 'x2'): 6264 elif(option == 'x2'): 6531 if checkArgBo 6265 if checkArgBool(option, value): 6532 sysva 6266 sysvals.execcount = 2 6533 elif(option == 'callg 6267 elif(option == 'callgraph'): 6534 sysvals.useca 6268 sysvals.usecallgraph = checkArgBool(option, value) 6535 elif(option == 'overr 6269 elif(option == 'override-timeline-functions'): 6536 overridekprob 6270 overridekprobes = checkArgBool(option, value) 6537 elif(option == 'overr 6271 elif(option == 'override-dev-timeline-functions'): 6538 overridedevkp 6272 overridedevkprobes = checkArgBool(option, value) 6539 elif(option == 'skiph 6273 elif(option == 'skiphtml'): 6540 sysvals.skiph 6274 sysvals.skiphtml = checkArgBool(option, value) 6541 elif(option == 'sync' 6275 elif(option == 'sync'): 6542 sysvals.sync 6276 sysvals.sync = checkArgBool(option, value) 6543 elif(option == 'rs' o 6277 elif(option == 'rs' or option == 'runtimesuspend'): 6544 if value in s 6278 if value in switchvalues: 6545 if va 6279 if value in switchoff: 6546 6280 sysvals.rs = -1 6547 else: 6281 else: 6548 6282 sysvals.rs = 1 6549 else: 6283 else: 6550 doErr 6284 doError('invalid value --> (%s: %s), use "enable/disable"' % (option, value), True) 6551 elif(option == 'displ 6285 elif(option == 'display'): 6552 disopt = ['on 6286 disopt = ['on', 'off', 'standby', 'suspend'] 6553 if value not 6287 if value not in disopt: 6554 doErr 6288 doError('invalid value --> (%s: %s), use %s' % (option, value, disopt), True) 6555 sysvals.displ 6289 sysvals.display = value 6556 elif(option == 'gzip' 6290 elif(option == 'gzip'): 6557 sysvals.gzip 6291 sysvals.gzip = checkArgBool(option, value) 6558 elif(option == 'cgfil 6292 elif(option == 'cgfilter'): 6559 sysvals.setCa 6293 sysvals.setCallgraphFilter(value) 6560 elif(option == 'cgski 6294 elif(option == 'cgskip'): 6561 if value in s 6295 if value in switchoff: 6562 sysva 6296 sysvals.cgskip = '' 6563 else: 6297 else: 6564 sysva 6298 sysvals.cgskip = sysvals.configFile(val) 6565 if(no 6299 if(not sysvals.cgskip): 6566 6300 doError('%s does not exist' % sysvals.cgskip) 6567 elif(option == 'cgtes 6301 elif(option == 'cgtest'): 6568 sysvals.cgtes 6302 sysvals.cgtest = getArgInt('cgtest', value, 0, 1, False) 6569 elif(option == 'cgpha 6303 elif(option == 'cgphase'): 6570 d = Data(0) 6304 d = Data(0) 6571 if value not 6305 if value not in d.phasedef: 6572 doErr 6306 doError('invalid phase --> (%s: %s), valid phases are %s'\ 6573 6307 % (option, value, d.phasedef.keys()), True) 6574 sysvals.cgpha 6308 sysvals.cgphase = value 6575 elif(option == 'fadd' 6309 elif(option == 'fadd'): 6576 file = sysval 6310 file = sysvals.configFile(value) 6577 if(not file): 6311 if(not file): 6578 doErr 6312 doError('%s does not exist' % value) 6579 sysvals.addFt 6313 sysvals.addFtraceFilterFunctions(file) 6580 elif(option == 'resul 6314 elif(option == 'result'): 6581 sysvals.resul 6315 sysvals.result = value 6582 elif(option == 'multi 6316 elif(option == 'multi'): 6583 nums = value. 6317 nums = value.split() 6584 if len(nums) 6318 if len(nums) != 2: 6585 doErr 6319 doError('multi requires 2 integers (exec_count and delay)', True) 6586 sysvals.multi 6320 sysvals.multiinit(nums[0], nums[1]) 6587 elif(option == 'devic 6321 elif(option == 'devicefilter'): 6588 sysvals.setDe 6322 sysvals.setDeviceFilter(value) 6589 elif(option == 'expan 6323 elif(option == 'expandcg'): 6590 sysvals.cgexp 6324 sysvals.cgexp = checkArgBool(option, value) 6591 elif(option == 'srgap 6325 elif(option == 'srgap'): 6592 if checkArgBo 6326 if checkArgBool(option, value): 6593 sysva 6327 sysvals.srgap = 5 6594 elif(option == 'mode' 6328 elif(option == 'mode'): 6595 sysvals.suspe 6329 sysvals.suspendmode = value 6596 elif(option == 'comma 6330 elif(option == 'command' or option == 'cmd'): 6597 sysvals.testc 6331 sysvals.testcommand = value 6598 elif(option == 'x2del 6332 elif(option == 'x2delay'): 6599 sysvals.x2del 6333 sysvals.x2delay = getArgInt('x2delay', value, 0, 60000, False) 6600 elif(option == 'prede 6334 elif(option == 'predelay'): 6601 sysvals.prede 6335 sysvals.predelay = getArgInt('predelay', value, 0, 60000, False) 6602 elif(option == 'postd 6336 elif(option == 'postdelay'): 6603 sysvals.postd 6337 sysvals.postdelay = getArgInt('postdelay', value, 0, 60000, False) 6604 elif(option == 'maxde 6338 elif(option == 'maxdepth'): 6605 sysvals.max_g 6339 sysvals.max_graph_depth = getArgInt('maxdepth', value, 0, 1000, False) 6606 elif(option == 'rtcwa 6340 elif(option == 'rtcwake'): 6607 if value in s 6341 if value in switchoff: 6608 sysva 6342 sysvals.rtcwake = False 6609 else: 6343 else: 6610 sysva 6344 sysvals.rtcwake = True 6611 sysva 6345 sysvals.rtcwaketime = getArgInt('rtcwake', value, 0, 3600, False) 6612 elif(option == 'timep 6346 elif(option == 'timeprec'): 6613 sysvals.setPr 6347 sysvals.setPrecision(getArgInt('timeprec', value, 0, 6, False)) 6614 elif(option == 'minde 6348 elif(option == 'mindev'): 6615 sysvals.minde 6349 sysvals.mindevlen = getArgFloat('mindev', value, 0.0, 10000.0, False) 6616 elif(option == 'calll 6350 elif(option == 'callloop-maxgap'): 6617 sysvals.calll 6351 sysvals.callloopmaxgap = getArgFloat('callloop-maxgap', value, 0.0, 1.0, False) 6618 elif(option == 'calll 6352 elif(option == 'callloop-maxlen'): 6619 sysvals.calll 6353 sysvals.callloopmaxgap = getArgFloat('callloop-maxlen', value, 0.0, 1.0, False) 6620 elif(option == 'mincg 6354 elif(option == 'mincg'): 6621 sysvals.mincg 6355 sysvals.mincglen = getArgFloat('mincg', value, 0.0, 10000.0, False) 6622 elif(option == 'bufsi 6356 elif(option == 'bufsize'): 6623 sysvals.bufsi 6357 sysvals.bufsize = getArgInt('bufsize', value, 1, 1024*1024*8, False) 6624 elif(option == 'outpu 6358 elif(option == 'output-dir'): 6625 sysvals.outdi 6359 sysvals.outdir = sysvals.setOutputFolder(value) 6626 6360 6627 if sysvals.suspendmode == 'command' a 6361 if sysvals.suspendmode == 'command' and not sysvals.testcommand: 6628 doError('No command supplied 6362 doError('No command supplied for mode "command"') 6629 6363 6630 # compatibility errors 6364 # compatibility errors 6631 if sysvals.usedevsrc and sysvals.usec 6365 if sysvals.usedevsrc and sysvals.usecallgraph: 6632 doError('-dev is not compatib 6366 doError('-dev is not compatible with -f') 6633 if sysvals.usecallgraph and sysvals.u 6367 if sysvals.usecallgraph and sysvals.useprocmon: 6634 doError('-proc is not compati 6368 doError('-proc is not compatible with -f') 6635 6369 6636 if overridekprobes: 6370 if overridekprobes: 6637 sysvals.tracefuncs = dict() 6371 sysvals.tracefuncs = dict() 6638 if overridedevkprobes: 6372 if overridedevkprobes: 6639 sysvals.dev_tracefuncs = dict 6373 sysvals.dev_tracefuncs = dict() 6640 6374 6641 kprobes = dict() 6375 kprobes = dict() 6642 kprobesec = 'dev_timeline_functions_' 6376 kprobesec = 'dev_timeline_functions_'+platform.machine() 6643 if kprobesec in sections: 6377 if kprobesec in sections: 6644 for name in Config.options(kp 6378 for name in Config.options(kprobesec): 6645 text = Config.get(kpr 6379 text = Config.get(kprobesec, name) 6646 kprobes[name] = (text 6380 kprobes[name] = (text, True) 6647 kprobesec = 'timeline_functions_'+pla 6381 kprobesec = 'timeline_functions_'+platform.machine() 6648 if kprobesec in sections: 6382 if kprobesec in sections: 6649 for name in Config.options(kp 6383 for name in Config.options(kprobesec): 6650 if name in kprobes: 6384 if name in kprobes: 6651 doError('Dupl 6385 doError('Duplicate timeline function found "%s"' % (name)) 6652 text = Config.get(kpr 6386 text = Config.get(kprobesec, name) 6653 kprobes[name] = (text 6387 kprobes[name] = (text, False) 6654 6388 6655 for name in kprobes: 6389 for name in kprobes: 6656 function = name 6390 function = name 6657 format = name 6391 format = name 6658 color = '' 6392 color = '' 6659 args = dict() 6393 args = dict() 6660 text, dev = kprobes[name] 6394 text, dev = kprobes[name] 6661 data = text.split() 6395 data = text.split() 6662 i = 0 6396 i = 0 6663 for val in data: 6397 for val in data: 6664 # bracketted strings 6398 # bracketted strings are special formatting, read them separately 6665 if val[0] == '[' and 6399 if val[0] == '[' and val[-1] == ']': 6666 for prop in v 6400 for prop in val[1:-1].split(','): 6667 p = p 6401 p = prop.split('=') 6668 if p[ 6402 if p[0] == 'color': 6669 6403 try: 6670 6404 color = int(p[1], 16) 6671 6405 color = '#'+p[1] 6672 6406 except: 6673 6407 color = p[1] 6674 continue 6408 continue 6675 # first real arg shou 6409 # first real arg should be the format string 6676 if i == 0: 6410 if i == 0: 6677 format = val 6411 format = val 6678 # all other args are 6412 # all other args are actual function args 6679 else: 6413 else: 6680 d = val.split 6414 d = val.split('=') 6681 args[d[0]] = 6415 args[d[0]] = d[1] 6682 i += 1 6416 i += 1 6683 if not function or not format 6417 if not function or not format: 6684 doError('Invalid kpro 6418 doError('Invalid kprobe: %s' % name) 6685 for arg in re.findall('{(?P<n 6419 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format): 6686 if arg not in args: 6420 if arg not in args: 6687 doError('Kpro 6421 doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 6688 if (dev and name in sysvals.d 6422 if (dev and name in sysvals.dev_tracefuncs) or (not dev and name in sysvals.tracefuncs): 6689 doError('Duplicate ti 6423 doError('Duplicate timeline function found "%s"' % (name)) 6690 6424 6691 kp = { 6425 kp = { 6692 'name': name, 6426 'name': name, 6693 'func': function, 6427 'func': function, 6694 'format': format, 6428 'format': format, 6695 sysvals.archargs: arg 6429 sysvals.archargs: args 6696 } 6430 } 6697 if color: 6431 if color: 6698 kp['color'] = color 6432 kp['color'] = color 6699 if dev: 6433 if dev: 6700 sysvals.dev_tracefunc 6434 sysvals.dev_tracefuncs[name] = kp 6701 else: 6435 else: 6702 sysvals.tracefuncs[na 6436 sysvals.tracefuncs[name] = kp 6703 6437 6704 # Function: printHelp 6438 # Function: printHelp 6705 # Description: 6439 # Description: 6706 # print out the help text 6440 # print out the help text 6707 def printHelp(): 6441 def printHelp(): 6708 pprint('\n%s v%s\n'\ 6442 pprint('\n%s v%s\n'\ 6709 'Usage: sudo sleepgraph <options> <co 6443 'Usage: sudo sleepgraph <options> <commands>\n'\ 6710 '\n'\ 6444 '\n'\ 6711 'Description:\n'\ 6445 'Description:\n'\ 6712 ' This tool is designed to assist ke 6446 ' This tool is designed to assist kernel and OS developers in optimizing\n'\ 6713 ' their linux stack\'s suspend/resum 6447 ' their linux stack\'s suspend/resume time. Using a kernel image built\n'\ 6714 ' with a few extra options enabled, 6448 ' with a few extra options enabled, the tool will execute a suspend and\n'\ 6715 ' capture dmesg and ftrace data unti 6449 ' capture dmesg and ftrace data until resume is complete. This data is\n'\ 6716 ' transformed into a device timeline 6450 ' transformed into a device timeline and an optional callgraph to give\n'\ 6717 ' a detailed view of which devices/s 6451 ' a detailed view of which devices/subsystems are taking the most\n'\ 6718 ' time in suspend/resume.\n'\ 6452 ' time in suspend/resume.\n'\ 6719 '\n'\ 6453 '\n'\ 6720 ' If no specific command is given, t 6454 ' If no specific command is given, the default behavior is to initiate\n'\ 6721 ' a suspend/resume and capture the d 6455 ' a suspend/resume and capture the dmesg/ftrace output as an html timeline.\n'\ 6722 '\n'\ 6456 '\n'\ 6723 ' Generates output files in subdirec 6457 ' Generates output files in subdirectory: suspend-yymmdd-HHMMSS\n'\ 6724 ' HTML output: < 6458 ' HTML output: <hostname>_<mode>.html\n'\ 6725 ' raw dmesg output: < 6459 ' raw dmesg output: <hostname>_<mode>_dmesg.txt\n'\ 6726 ' raw ftrace output: < 6460 ' raw ftrace output: <hostname>_<mode>_ftrace.txt\n'\ 6727 '\n'\ 6461 '\n'\ 6728 'Options:\n'\ 6462 'Options:\n'\ 6729 ' -h Print this help text 6463 ' -h Print this help text\n'\ 6730 ' -v Print the current to 6464 ' -v Print the current tool version\n'\ 6731 ' -config fn Pull arguments and c 6465 ' -config fn Pull arguments and config options from file fn\n'\ 6732 ' -verbose Print extra informat 6466 ' -verbose Print extra information during execution and analysis\n'\ 6733 ' -m mode Mode to initiate for 6467 ' -m mode Mode to initiate for suspend (default: %s)\n'\ 6734 ' -o name Overrides the output 6468 ' -o name Overrides the output subdirectory name when running a new test\n'\ 6735 ' default: suspend-{da 6469 ' default: suspend-{date}-{time}\n'\ 6736 ' -rtcwake t Wakeup t seconds aft 6470 ' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)\n'\ 6737 ' -addlogs Add the dmesg and ft 6471 ' -addlogs Add the dmesg and ftrace logs to the html output\n'\ 6738 ' -noturbostat Dont use turbostat i 6472 ' -noturbostat Dont use turbostat in freeze mode (default: disabled)\n'\ 6739 ' -srgap Add a visible gap in 6473 ' -srgap Add a visible gap in the timeline between sus/res (default: disabled)\n'\ 6740 ' -skiphtml Run the test and cap 6474 ' -skiphtml Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\ 6741 ' -result fn Export a results tab 6475 ' -result fn Export a results table to a text file for parsing.\n'\ 6742 ' -wifi If a wifi connection 6476 ' -wifi If a wifi connection is available, check that it reconnects after resume.\n'\ 6743 ' -wifitrace Trace kernel executi << 6744 ' -netfix Use netfix to reset << 6745 ' [testprep]\n'\ 6477 ' [testprep]\n'\ 6746 ' -sync Sync the filesystems 6478 ' -sync Sync the filesystems before starting the test\n'\ 6747 ' -rs on/off Enable/disable runti 6479 ' -rs on/off Enable/disable runtime suspend for all devices, restore all after test\n'\ 6748 ' -display m Change the display m 6480 ' -display m Change the display mode to m for the test (on/off/standby/suspend)\n'\ 6749 ' [advanced]\n'\ 6481 ' [advanced]\n'\ 6750 ' -gzip Gzip the trace and d 6482 ' -gzip Gzip the trace and dmesg logs to save space\n'\ 6751 ' -cmd {s} Run the timeline ove 6483 ' -cmd {s} Run the timeline over a custom command, e.g. "sync -d"\n'\ 6752 ' -proc Add usermode process 6484 ' -proc Add usermode process info into the timeline (default: disabled)\n'\ 6753 ' -dev Add kernel function 6485 ' -dev Add kernel function calls and threads to the timeline (default: disabled)\n'\ 6754 ' -x2 Run two suspend/resu 6486 ' -x2 Run two suspend/resumes back to back (default: disabled)\n'\ 6755 ' -x2delay t Include t ms delay b 6487 ' -x2delay t Include t ms delay between multiple test runs (default: 0 ms)\n'\ 6756 ' -predelay t Include t ms delay b 6488 ' -predelay t Include t ms delay before 1st suspend (default: 0 ms)\n'\ 6757 ' -postdelay t Include t ms delay a 6489 ' -postdelay t Include t ms delay after last resume (default: 0 ms)\n'\ 6758 ' -mindev ms Discard all device b 6490 ' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 6759 ' -multi n d Execute <n> consecut 6491 ' -multi n d Execute <n> consecutive tests at <d> seconds intervals. If <n> is followed\n'\ 6760 ' by a "d", "h", or "m 6492 ' by a "d", "h", or "m" execute for <n> days, hours, or mins instead.\n'\ 6761 ' The outputs will be 6493 ' The outputs will be created in a new subdirectory with a summary page.\n'\ 6762 ' -maxfail n Abort a -multi run a 6494 ' -maxfail n Abort a -multi run after n consecutive fails (default is 0 = never abort)\n'\ 6763 ' [debug]\n'\ 6495 ' [debug]\n'\ 6764 ' -f Use ftrace to create 6496 ' -f Use ftrace to create device callgraphs (default: disabled)\n'\ 6765 ' -ftop Use ftrace on the to 6497 ' -ftop Use ftrace on the top level call: "%s" (default: disabled)\n'\ 6766 ' -maxdepth N limit the callgraph 6498 ' -maxdepth N limit the callgraph data to N call levels (default: 0=all)\n'\ 6767 ' -expandcg pre-expand the callg 6499 ' -expandcg pre-expand the callgraph data in the html output (default: disabled)\n'\ 6768 ' -fadd file Add functions to be 6500 ' -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 6501 ' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names\n'\ 6770 ' -mincg ms Discard all callgrap 6502 ' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 6771 ' -cgphase P Only show callgraph 6503 ' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)\n'\ 6772 ' -cgtest N Only show callgraph 6504 ' -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 6505 ' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)\n'\ 6774 ' -cgfilter S Filter the callgraph 6506 ' -cgfilter S Filter the callgraph output in the timeline\n'\ 6775 ' -cgskip file Callgraph functions 6507 ' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\ 6776 ' -bufsize N Set trace buffer siz 6508 ' -bufsize N Set trace buffer size to N kilo-bytes (default: all of free memory)\n'\ 6777 ' -devdump Print out all the ra 6509 ' -devdump Print out all the raw device data for each phase\n'\ 6778 ' -cgdump Print out all the ra 6510 ' -cgdump Print out all the raw callgraph data\n'\ 6779 '\n'\ 6511 '\n'\ 6780 'Other commands:\n'\ 6512 'Other commands:\n'\ 6781 ' -modes List available suspe 6513 ' -modes List available suspend modes\n'\ 6782 ' -status Test to see if the s 6514 ' -status Test to see if the system is enabled to run this tool\n'\ 6783 ' -fpdt Print out the conten 6515 ' -fpdt Print out the contents of the ACPI Firmware Performance Data Table\n'\ 6784 ' -wificheck Print out wifi conne 6516 ' -wificheck Print out wifi connection info\n'\ 6785 ' -x<mode> Test xset by togglin 6517 ' -x<mode> Test xset by toggling the given mode (on/off/standby/suspend)\n'\ 6786 ' -sysinfo Print out system inf 6518 ' -sysinfo Print out system info extracted from BIOS\n'\ 6787 ' -devinfo Print out the pm set 6519 ' -devinfo Print out the pm settings of all devices which support runtime suspend\n'\ 6788 ' -cmdinfo Print out all the pl 6520 ' -cmdinfo Print out all the platform info collected before and after suspend/resume\n'\ 6789 ' -flist Print the list of fu 6521 ' -flist Print the list of functions currently being captured in ftrace\n'\ 6790 ' -flistall Print all functions 6522 ' -flistall Print all functions capable of being captured in ftrace\n'\ 6791 ' -summary dir Create a summary of 6523 ' -summary dir Create a summary of tests in this dir [-genhtml builds missing html]\n'\ 6792 ' [redo]\n'\ 6524 ' [redo]\n'\ 6793 ' -ftrace ftracefile Create HTML o 6525 ' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)\n'\ 6794 ' -dmesg dmesgfile Create HTML o 6526 ' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)\n'\ 6795 '' % (sysvals.title, sysvals.version, 6527 '' % (sysvals.title, sysvals.version, sysvals.suspendmode, sysvals.ftopfunc)) 6796 return True 6528 return True 6797 6529 6798 # ----------------- MAIN -------------------- 6530 # ----------------- MAIN -------------------- 6799 # exec start (skipped if script is loaded as 6531 # exec start (skipped if script is loaded as library) 6800 if __name__ == '__main__': 6532 if __name__ == '__main__': 6801 genhtml = False 6533 genhtml = False 6802 cmd = '' 6534 cmd = '' 6803 simplecmds = ['-sysinfo', '-modes', ' 6535 simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall', 6804 '-devinfo', '-status', '-xon' 6536 '-devinfo', '-status', '-xon', '-xoff', '-xstandby', '-xsuspend', 6805 '-xinit', '-xreset', '-xstat' 6537 '-xinit', '-xreset', '-xstat', '-wificheck', '-cmdinfo'] 6806 if '-f' in sys.argv: 6538 if '-f' in sys.argv: 6807 sysvals.cgskip = sysvals.conf 6539 sysvals.cgskip = sysvals.configFile('cgskip.txt') 6808 # loop through the command line argum 6540 # loop through the command line arguments 6809 args = iter(sys.argv[1:]) 6541 args = iter(sys.argv[1:]) 6810 for arg in args: 6542 for arg in args: 6811 if(arg == '-m'): 6543 if(arg == '-m'): 6812 try: 6544 try: 6813 val = next(ar 6545 val = next(args) 6814 except: 6546 except: 6815 doError('No m 6547 doError('No mode supplied', True) 6816 if val == 'command' a 6548 if val == 'command' and not sysvals.testcommand: 6817 doError('No c 6549 doError('No command supplied for mode "command"', True) 6818 sysvals.suspendmode = 6550 sysvals.suspendmode = val 6819 elif(arg in simplecmds): 6551 elif(arg in simplecmds): 6820 cmd = arg[1:] 6552 cmd = arg[1:] 6821 elif(arg == '-h'): 6553 elif(arg == '-h'): 6822 printHelp() 6554 printHelp() 6823 sys.exit(0) 6555 sys.exit(0) 6824 elif(arg == '-v'): 6556 elif(arg == '-v'): 6825 pprint("Version %s" % 6557 pprint("Version %s" % sysvals.version) 6826 sys.exit(0) 6558 sys.exit(0) 6827 elif(arg == '-debugtiming'): << 6828 debugtiming = True << 6829 elif(arg == '-x2'): 6559 elif(arg == '-x2'): 6830 sysvals.execcount = 2 6560 sysvals.execcount = 2 6831 elif(arg == '-x2delay'): 6561 elif(arg == '-x2delay'): 6832 sysvals.x2delay = get 6562 sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000) 6833 elif(arg == '-predelay'): 6563 elif(arg == '-predelay'): 6834 sysvals.predelay = ge 6564 sysvals.predelay = getArgInt('-predelay', args, 0, 60000) 6835 elif(arg == '-postdelay'): 6565 elif(arg == '-postdelay'): 6836 sysvals.postdelay = g 6566 sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000) 6837 elif(arg == '-f'): 6567 elif(arg == '-f'): 6838 sysvals.usecallgraph 6568 sysvals.usecallgraph = True 6839 elif(arg == '-ftop'): 6569 elif(arg == '-ftop'): 6840 sysvals.usecallgraph 6570 sysvals.usecallgraph = True 6841 sysvals.ftop = True 6571 sysvals.ftop = True 6842 sysvals.usekprobes = 6572 sysvals.usekprobes = False 6843 elif(arg == '-skiphtml'): 6573 elif(arg == '-skiphtml'): 6844 sysvals.skiphtml = Tr 6574 sysvals.skiphtml = True 6845 elif(arg == '-cgdump'): 6575 elif(arg == '-cgdump'): 6846 sysvals.cgdump = True 6576 sysvals.cgdump = True 6847 elif(arg == '-devdump'): 6577 elif(arg == '-devdump'): 6848 sysvals.devdump = Tru 6578 sysvals.devdump = True 6849 elif(arg == '-genhtml'): 6579 elif(arg == '-genhtml'): 6850 genhtml = True 6580 genhtml = True 6851 elif(arg == '-addlogs'): 6581 elif(arg == '-addlogs'): 6852 sysvals.dmesglog = sy 6582 sysvals.dmesglog = sysvals.ftracelog = True 6853 elif(arg == '-nologs'): 6583 elif(arg == '-nologs'): 6854 sysvals.dmesglog = sy 6584 sysvals.dmesglog = sysvals.ftracelog = False 6855 elif(arg == '-addlogdmesg'): 6585 elif(arg == '-addlogdmesg'): 6856 sysvals.dmesglog = Tr 6586 sysvals.dmesglog = True 6857 elif(arg == '-addlogftrace'): 6587 elif(arg == '-addlogftrace'): 6858 sysvals.ftracelog = T 6588 sysvals.ftracelog = True 6859 elif(arg == '-noturbostat'): 6589 elif(arg == '-noturbostat'): 6860 sysvals.tstat = False 6590 sysvals.tstat = False 6861 elif(arg == '-verbose'): 6591 elif(arg == '-verbose'): 6862 sysvals.verbose = Tru 6592 sysvals.verbose = True 6863 elif(arg == '-proc'): 6593 elif(arg == '-proc'): 6864 sysvals.useprocmon = 6594 sysvals.useprocmon = True 6865 elif(arg == '-dev'): 6595 elif(arg == '-dev'): 6866 sysvals.usedevsrc = T 6596 sysvals.usedevsrc = True 6867 elif(arg == '-sync'): 6597 elif(arg == '-sync'): 6868 sysvals.sync = True 6598 sysvals.sync = True 6869 elif(arg == '-wifi'): 6599 elif(arg == '-wifi'): 6870 sysvals.wifi = True 6600 sysvals.wifi = True 6871 elif(arg == '-wifitrace'): << 6872 sysvals.wifitrace = T << 6873 elif(arg == '-netfix'): << 6874 sysvals.netfix = True << 6875 elif(arg == '-gzip'): 6601 elif(arg == '-gzip'): 6876 sysvals.gzip = True 6602 sysvals.gzip = True 6877 elif(arg == '-info'): 6603 elif(arg == '-info'): 6878 try: 6604 try: 6879 val = next(ar 6605 val = next(args) 6880 except: 6606 except: 6881 doError('-inf 6607 doError('-info requires one string argument', True) 6882 elif(arg == '-desc'): << 6883 try: << 6884 val = next(ar << 6885 except: << 6886 doError('-des << 6887 elif(arg == '-rs'): 6608 elif(arg == '-rs'): 6888 try: 6609 try: 6889 val = next(ar 6610 val = next(args) 6890 except: 6611 except: 6891 doError('-rs 6612 doError('-rs requires "enable" or "disable"', True) 6892 if val.lower() in swi 6613 if val.lower() in switchvalues: 6893 if val.lower( 6614 if val.lower() in switchoff: 6894 sysva 6615 sysvals.rs = -1 6895 else: 6616 else: 6896 sysva 6617 sysvals.rs = 1 6897 else: 6618 else: 6898 doError('inva 6619 doError('invalid option: %s, use "enable/disable" or "on/off"' % val, True) 6899 elif(arg == '-display'): 6620 elif(arg == '-display'): 6900 try: 6621 try: 6901 val = next(ar 6622 val = next(args) 6902 except: 6623 except: 6903 doError('-dis 6624 doError('-display requires an mode value', True) 6904 disopt = ['on', 'off' 6625 disopt = ['on', 'off', 'standby', 'suspend'] 6905 if val.lower() not in 6626 if val.lower() not in disopt: 6906 doError('vali 6627 doError('valid display mode values are %s' % disopt, True) 6907 sysvals.display = val 6628 sysvals.display = val.lower() 6908 elif(arg == '-maxdepth'): 6629 elif(arg == '-maxdepth'): 6909 sysvals.max_graph_dep 6630 sysvals.max_graph_depth = getArgInt('-maxdepth', args, 0, 1000) 6910 elif(arg == '-rtcwake'): 6631 elif(arg == '-rtcwake'): 6911 try: 6632 try: 6912 val = next(ar 6633 val = next(args) 6913 except: 6634 except: 6914 doError('No r 6635 doError('No rtcwake time supplied', True) 6915 if val.lower() in swi 6636 if val.lower() in switchoff: 6916 sysvals.rtcwa 6637 sysvals.rtcwake = False 6917 else: 6638 else: 6918 sysvals.rtcwa 6639 sysvals.rtcwake = True 6919 sysvals.rtcwa 6640 sysvals.rtcwaketime = getArgInt('-rtcwake', val, 0, 3600, False) 6920 elif(arg == '-timeprec'): 6641 elif(arg == '-timeprec'): 6921 sysvals.setPrecision( 6642 sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6)) 6922 elif(arg == '-mindev'): 6643 elif(arg == '-mindev'): 6923 sysvals.mindevlen = g 6644 sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0) 6924 elif(arg == '-mincg'): 6645 elif(arg == '-mincg'): 6925 sysvals.mincglen = ge 6646 sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0) 6926 elif(arg == '-bufsize'): 6647 elif(arg == '-bufsize'): 6927 sysvals.bufsize = get 6648 sysvals.bufsize = getArgInt('-bufsize', args, 1, 1024*1024*8) 6928 elif(arg == '-cgtest'): 6649 elif(arg == '-cgtest'): 6929 sysvals.cgtest = getA 6650 sysvals.cgtest = getArgInt('-cgtest', args, 0, 1) 6930 elif(arg == '-cgphase'): 6651 elif(arg == '-cgphase'): 6931 try: 6652 try: 6932 val = next(ar 6653 val = next(args) 6933 except: 6654 except: 6934 doError('No p 6655 doError('No phase name supplied', True) 6935 d = Data(0) 6656 d = Data(0) 6936 if val not in d.phase 6657 if val not in d.phasedef: 6937 doError('inva 6658 doError('invalid phase --> (%s: %s), valid phases are %s'\ 6938 % (ar 6659 % (arg, val, d.phasedef.keys()), True) 6939 sysvals.cgphase = val 6660 sysvals.cgphase = val 6940 elif(arg == '-cgfilter'): 6661 elif(arg == '-cgfilter'): 6941 try: 6662 try: 6942 val = next(ar 6663 val = next(args) 6943 except: 6664 except: 6944 doError('No c 6665 doError('No callgraph functions supplied', True) 6945 sysvals.setCallgraphF 6666 sysvals.setCallgraphFilter(val) 6946 elif(arg == '-skipkprobe'): 6667 elif(arg == '-skipkprobe'): 6947 try: 6668 try: 6948 val = next(ar 6669 val = next(args) 6949 except: 6670 except: 6950 doError('No k 6671 doError('No kprobe functions supplied', True) 6951 sysvals.skipKprobes(v 6672 sysvals.skipKprobes(val) 6952 elif(arg == '-cgskip'): 6673 elif(arg == '-cgskip'): 6953 try: 6674 try: 6954 val = next(ar 6675 val = next(args) 6955 except: 6676 except: 6956 doError('No f 6677 doError('No file supplied', True) 6957 if val.lower() in swi 6678 if val.lower() in switchoff: 6958 sysvals.cgski 6679 sysvals.cgskip = '' 6959 else: 6680 else: 6960 sysvals.cgski 6681 sysvals.cgskip = sysvals.configFile(val) 6961 if(not sysval 6682 if(not sysvals.cgskip): 6962 doErr 6683 doError('%s does not exist' % sysvals.cgskip) 6963 elif(arg == '-callloop-maxgap 6684 elif(arg == '-callloop-maxgap'): 6964 sysvals.callloopmaxga 6685 sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', args, 0.0, 1.0) 6965 elif(arg == '-callloop-maxlen 6686 elif(arg == '-callloop-maxlen'): 6966 sysvals.callloopmaxle 6687 sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0) 6967 elif(arg == '-cmd'): 6688 elif(arg == '-cmd'): 6968 try: 6689 try: 6969 val = next(ar 6690 val = next(args) 6970 except: 6691 except: 6971 doError('No c 6692 doError('No command string supplied', True) 6972 sysvals.testcommand = 6693 sysvals.testcommand = val 6973 sysvals.suspendmode = 6694 sysvals.suspendmode = 'command' 6974 elif(arg == '-expandcg'): 6695 elif(arg == '-expandcg'): 6975 sysvals.cgexp = True 6696 sysvals.cgexp = True 6976 elif(arg == '-srgap'): 6697 elif(arg == '-srgap'): 6977 sysvals.srgap = 5 6698 sysvals.srgap = 5 6978 elif(arg == '-maxfail'): 6699 elif(arg == '-maxfail'): 6979 sysvals.maxfail = get 6700 sysvals.maxfail = getArgInt('-maxfail', args, 0, 1000000) 6980 elif(arg == '-multi'): 6701 elif(arg == '-multi'): 6981 try: 6702 try: 6982 c, d = next(a 6703 c, d = next(args), next(args) 6983 except: 6704 except: 6984 doError('-mul 6705 doError('-multi requires two values', True) 6985 sysvals.multiinit(c, 6706 sysvals.multiinit(c, d) 6986 elif(arg == '-o'): 6707 elif(arg == '-o'): 6987 try: 6708 try: 6988 val = next(ar 6709 val = next(args) 6989 except: 6710 except: 6990 doError('No s 6711 doError('No subdirectory name supplied', True) 6991 sysvals.outdir = sysv 6712 sysvals.outdir = sysvals.setOutputFolder(val) 6992 elif(arg == '-config'): 6713 elif(arg == '-config'): 6993 try: 6714 try: 6994 val = next(ar 6715 val = next(args) 6995 except: 6716 except: 6996 doError('No t 6717 doError('No text file supplied', True) 6997 file = sysvals.config 6718 file = sysvals.configFile(val) 6998 if(not file): 6719 if(not file): 6999 doError('%s d 6720 doError('%s does not exist' % val) 7000 configFromFile(file) 6721 configFromFile(file) 7001 elif(arg == '-fadd'): 6722 elif(arg == '-fadd'): 7002 try: 6723 try: 7003 val = next(ar 6724 val = next(args) 7004 except: 6725 except: 7005 doError('No t 6726 doError('No text file supplied', True) 7006 file = sysvals.config 6727 file = sysvals.configFile(val) 7007 if(not file): 6728 if(not file): 7008 doError('%s d 6729 doError('%s does not exist' % val) 7009 sysvals.addFtraceFilt 6730 sysvals.addFtraceFilterFunctions(file) 7010 elif(arg == '-dmesg'): 6731 elif(arg == '-dmesg'): 7011 try: 6732 try: 7012 val = next(ar 6733 val = next(args) 7013 except: 6734 except: 7014 doError('No d 6735 doError('No dmesg file supplied', True) 7015 sysvals.notestrun = T 6736 sysvals.notestrun = True 7016 sysvals.dmesgfile = v 6737 sysvals.dmesgfile = val 7017 if(os.path.exists(sys 6738 if(os.path.exists(sysvals.dmesgfile) == False): 7018 doError('%s d 6739 doError('%s does not exist' % sysvals.dmesgfile) 7019 elif(arg == '-ftrace'): 6740 elif(arg == '-ftrace'): 7020 try: 6741 try: 7021 val = next(ar 6742 val = next(args) 7022 except: 6743 except: 7023 doError('No f 6744 doError('No ftrace file supplied', True) 7024 sysvals.notestrun = T 6745 sysvals.notestrun = True 7025 sysvals.ftracefile = 6746 sysvals.ftracefile = val 7026 if(os.path.exists(sys 6747 if(os.path.exists(sysvals.ftracefile) == False): 7027 doError('%s d 6748 doError('%s does not exist' % sysvals.ftracefile) 7028 elif(arg == '-summary'): 6749 elif(arg == '-summary'): 7029 try: 6750 try: 7030 val = next(ar 6751 val = next(args) 7031 except: 6752 except: 7032 doError('No d 6753 doError('No directory supplied', True) 7033 cmd = 'summary' 6754 cmd = 'summary' 7034 sysvals.outdir = val 6755 sysvals.outdir = val 7035 sysvals.notestrun = T 6756 sysvals.notestrun = True 7036 if(os.path.isdir(val) 6757 if(os.path.isdir(val) == False): 7037 doError('%s i 6758 doError('%s is not accesible' % val) 7038 elif(arg == '-filter'): 6759 elif(arg == '-filter'): 7039 try: 6760 try: 7040 val = next(ar 6761 val = next(args) 7041 except: 6762 except: 7042 doError('No d 6763 doError('No devnames supplied', True) 7043 sysvals.setDeviceFilt 6764 sysvals.setDeviceFilter(val) 7044 elif(arg == '-result'): 6765 elif(arg == '-result'): 7045 try: 6766 try: 7046 val = next(ar 6767 val = next(args) 7047 except: 6768 except: 7048 doError('No r 6769 doError('No result file supplied', True) 7049 sysvals.result = val 6770 sysvals.result = val 7050 sysvals.signalHandler 6771 sysvals.signalHandlerInit() 7051 else: 6772 else: 7052 doError('Invalid argu 6773 doError('Invalid argument: '+arg, True) 7053 6774 7054 # compatibility errors 6775 # compatibility errors 7055 if(sysvals.usecallgraph and sysvals.u 6776 if(sysvals.usecallgraph and sysvals.usedevsrc): 7056 doError('-dev is not compatib 6777 doError('-dev is not compatible with -f') 7057 if(sysvals.usecallgraph and sysvals.u 6778 if(sysvals.usecallgraph and sysvals.useprocmon): 7058 doError('-proc is not compati 6779 doError('-proc is not compatible with -f') 7059 6780 7060 if sysvals.usecallgraph and sysvals.c 6781 if sysvals.usecallgraph and sysvals.cgskip: 7061 sysvals.vprint('Using cgskip 6782 sysvals.vprint('Using cgskip file: %s' % sysvals.cgskip) 7062 sysvals.setCallgraphBlacklist 6783 sysvals.setCallgraphBlacklist(sysvals.cgskip) 7063 6784 7064 # callgraph size cannot exceed device 6785 # callgraph size cannot exceed device size 7065 if sysvals.mincglen < sysvals.mindevl 6786 if sysvals.mincglen < sysvals.mindevlen: 7066 sysvals.mincglen = sysvals.mi 6787 sysvals.mincglen = sysvals.mindevlen 7067 6788 7068 # remove existing buffers before calc 6789 # remove existing buffers before calculating memory 7069 if(sysvals.usecallgraph or sysvals.us 6790 if(sysvals.usecallgraph or sysvals.usedevsrc): 7070 sysvals.fsetVal('16', 'buffer 6791 sysvals.fsetVal('16', 'buffer_size_kb') 7071 sysvals.cpuInfo() 6792 sysvals.cpuInfo() 7072 6793 7073 # just run a utility command and exit 6794 # just run a utility command and exit 7074 if(cmd != ''): 6795 if(cmd != ''): 7075 ret = 0 6796 ret = 0 7076 if(cmd == 'status'): 6797 if(cmd == 'status'): 7077 if not statusCheck(Tr 6798 if not statusCheck(True): 7078 ret = 1 6799 ret = 1 7079 elif(cmd == 'fpdt'): 6800 elif(cmd == 'fpdt'): 7080 if not getFPDT(True): 6801 if not getFPDT(True): 7081 ret = 1 6802 ret = 1 7082 elif(cmd == 'sysinfo'): 6803 elif(cmd == 'sysinfo'): 7083 sysvals.printSystemIn 6804 sysvals.printSystemInfo(True) 7084 elif(cmd == 'devinfo'): 6805 elif(cmd == 'devinfo'): 7085 deviceInfo() 6806 deviceInfo() 7086 elif(cmd == 'modes'): 6807 elif(cmd == 'modes'): 7087 pprint(getModes()) 6808 pprint(getModes()) 7088 elif(cmd == 'flist'): 6809 elif(cmd == 'flist'): 7089 sysvals.getFtraceFilt 6810 sysvals.getFtraceFilterFunctions(True) 7090 elif(cmd == 'flistall'): 6811 elif(cmd == 'flistall'): 7091 sysvals.getFtraceFilt 6812 sysvals.getFtraceFilterFunctions(False) 7092 elif(cmd == 'summary'): 6813 elif(cmd == 'summary'): 7093 runSummary(sysvals.ou 6814 runSummary(sysvals.outdir, True, genhtml) 7094 elif(cmd in ['xon', 'xoff', ' 6815 elif(cmd in ['xon', 'xoff', 'xstandby', 'xsuspend', 'xinit', 'xreset']): 7095 sysvals.verbose = Tru 6816 sysvals.verbose = True 7096 ret = sysvals.display !! 6817 ret = displayControl(cmd[1:]) 7097 elif(cmd == 'xstat'): 6818 elif(cmd == 'xstat'): 7098 pprint('Display Statu !! 6819 pprint('Display Status: %s' % displayControl('stat').upper()) 7099 elif(cmd == 'wificheck'): 6820 elif(cmd == 'wificheck'): 7100 dev = sysvals.checkWi 6821 dev = sysvals.checkWifi() 7101 if dev: 6822 if dev: 7102 print('%s is 6823 print('%s is connected' % sysvals.wifiDetails(dev)) 7103 else: 6824 else: 7104 print('No wif 6825 print('No wifi connection found') 7105 elif(cmd == 'cmdinfo'): 6826 elif(cmd == 'cmdinfo'): 7106 for out in sysvals.cm 6827 for out in sysvals.cmdinfo(False, True): 7107 print('[%s - 6828 print('[%s - %s]\n%s\n' % out) 7108 sys.exit(ret) 6829 sys.exit(ret) 7109 6830 7110 # if instructed, re-analyze existing 6831 # if instructed, re-analyze existing data files 7111 if(sysvals.notestrun): 6832 if(sysvals.notestrun): 7112 stamp = rerunTest(sysvals.out 6833 stamp = rerunTest(sysvals.outdir) 7113 sysvals.outputResult(stamp) 6834 sysvals.outputResult(stamp) 7114 sys.exit(0) 6835 sys.exit(0) 7115 6836 7116 # verify that we can run a test 6837 # verify that we can run a test 7117 error = statusCheck() 6838 error = statusCheck() 7118 if(error): 6839 if(error): 7119 doError(error) 6840 doError(error) 7120 6841 7121 # extract mem/disk extra modes and co 6842 # extract mem/disk extra modes and convert 7122 mode = sysvals.suspendmode 6843 mode = sysvals.suspendmode 7123 if mode.startswith('mem'): 6844 if mode.startswith('mem'): 7124 memmode = mode.split('-', 1)[ 6845 memmode = mode.split('-', 1)[-1] if '-' in mode else 'deep' 7125 if memmode == 'shallow': 6846 if memmode == 'shallow': 7126 mode = 'standby' 6847 mode = 'standby' 7127 elif memmode == 's2idle': 6848 elif memmode == 's2idle': 7128 mode = 'freeze' 6849 mode = 'freeze' 7129 else: 6850 else: 7130 mode = 'mem' 6851 mode = 'mem' 7131 sysvals.memmode = memmode 6852 sysvals.memmode = memmode 7132 sysvals.suspendmode = mode 6853 sysvals.suspendmode = mode 7133 if mode.startswith('disk-'): 6854 if mode.startswith('disk-'): 7134 sysvals.diskmode = mode.split 6855 sysvals.diskmode = mode.split('-', 1)[-1] 7135 sysvals.suspendmode = 'disk' 6856 sysvals.suspendmode = 'disk' >> 6857 7136 sysvals.systemInfo(dmidecode(sysvals. 6858 sysvals.systemInfo(dmidecode(sysvals.mempath)) 7137 6859 >> 6860 setRuntimeSuspend(True) >> 6861 if sysvals.display: >> 6862 displayControl('init') 7138 failcnt, ret = 0, 0 6863 failcnt, ret = 0, 0 7139 if sysvals.multitest['run']: 6864 if sysvals.multitest['run']: 7140 # run multiple tests in a sep 6865 # run multiple tests in a separate subdirectory 7141 if not sysvals.outdir: 6866 if not sysvals.outdir: 7142 if 'time' in sysvals. 6867 if 'time' in sysvals.multitest: 7143 s = '-%dm' % 6868 s = '-%dm' % sysvals.multitest['time'] 7144 else: 6869 else: 7145 s = '-x%d' % 6870 s = '-x%d' % sysvals.multitest['count'] 7146 sysvals.outdir = date 6871 sysvals.outdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S'+s) 7147 if not os.path.isdir(sysvals. 6872 if not os.path.isdir(sysvals.outdir): 7148 os.makedirs(sysvals.o 6873 os.makedirs(sysvals.outdir) 7149 sysvals.sudoUserchown(sysvals 6874 sysvals.sudoUserchown(sysvals.outdir) 7150 finish = datetime.now() 6875 finish = datetime.now() 7151 if 'time' in sysvals.multites 6876 if 'time' in sysvals.multitest: 7152 finish += timedelta(m 6877 finish += timedelta(minutes=sysvals.multitest['time']) 7153 for i in range(sysvals.multit 6878 for i in range(sysvals.multitest['count']): 7154 sysvals.multistat(Tru 6879 sysvals.multistat(True, i, finish) 7155 if i != 0 and sysvals 6880 if i != 0 and sysvals.multitest['delay'] > 0: 7156 pprint('Waiti 6881 pprint('Waiting %d seconds...' % (sysvals.multitest['delay'])) 7157 time.sleep(sy 6882 time.sleep(sysvals.multitest['delay']) 7158 fmt = 'suspend-%y%m%d 6883 fmt = 'suspend-%y%m%d-%H%M%S' 7159 sysvals.testdir = os. 6884 sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt)) 7160 ret = runTest(i+1, no !! 6885 ret = runTest(i+1, True) 7161 failcnt = 0 if not re 6886 failcnt = 0 if not ret else failcnt + 1 7162 if sysvals.maxfail > 6887 if sysvals.maxfail > 0 and failcnt >= sysvals.maxfail: 7163 pprint('Maxim 6888 pprint('Maximum fail count of %d reached, aborting multitest' % (sysvals.maxfail)) 7164 break 6889 break >> 6890 time.sleep(5) 7165 sysvals.resetlog() 6891 sysvals.resetlog() 7166 sysvals.multistat(Fal 6892 sysvals.multistat(False, i, finish) 7167 if 'time' in sysvals. 6893 if 'time' in sysvals.multitest and datetime.now() >= finish: 7168 break 6894 break 7169 if not sysvals.skiphtml: 6895 if not sysvals.skiphtml: 7170 runSummary(sysvals.ou 6896 runSummary(sysvals.outdir, False, False) 7171 sysvals.sudoUserchown(sysvals 6897 sysvals.sudoUserchown(sysvals.outdir) 7172 else: 6898 else: 7173 if sysvals.outdir: 6899 if sysvals.outdir: 7174 sysvals.testdir = sys 6900 sysvals.testdir = sysvals.outdir 7175 # run the test in the current 6901 # run the test in the current directory 7176 ret = runTest() 6902 ret = runTest() 7177 << 7178 # reset to default values after testi << 7179 if sysvals.display: 6903 if sysvals.display: 7180 sysvals.displayControl('reset !! 6904 displayControl('reset') 7181 if sysvals.rs != 0: !! 6905 setRuntimeSuspend(False) 7182 sysvals.setRuntimeSuspend(Fal << 7183 sys.exit(ret) 6906 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.