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.8' 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 95 acpidebug = True 102 tstat = True 96 tstat = True 103 wifitrace = False << 104 mindevlen = 0.0001 97 mindevlen = 0.0001 105 mincglen = 0.0 98 mincglen = 0.0 106 cgphase = '' 99 cgphase = '' 107 cgtest = -1 100 cgtest = -1 108 cgskip = '' 101 cgskip = '' 109 maxfail = 0 102 maxfail = 0 110 multitest = {'run': False, 'count': 10 103 multitest = {'run': False, 'count': 1000000, 'delay': 0} 111 max_graph_depth = 0 104 max_graph_depth = 0 112 callloopmaxgap = 0.0001 105 callloopmaxgap = 0.0001 113 callloopmaxlen = 0.005 106 callloopmaxlen = 0.005 114 bufsize = 0 107 bufsize = 0 115 cpucount = 0 108 cpucount = 0 116 memtotal = 204800 109 memtotal = 204800 117 memfree = 204800 110 memfree = 204800 118 osversion = '' << 119 srgap = 0 111 srgap = 0 120 cgexp = False 112 cgexp = False 121 testdir = '' 113 testdir = '' 122 outdir = '' 114 outdir = '' 123 tpath = '/sys/kernel/tracing/' !! 115 tpath = '/sys/kernel/debug/tracing/' 124 fpdtpath = '/sys/firmware/acpi/tables/ 116 fpdtpath = '/sys/firmware/acpi/tables/FPDT' 125 epath = '/sys/kernel/tracing/events/po !! 117 epath = '/sys/kernel/debug/tracing/events/power/' 126 pmdpath = '/sys/power/pm_debug_message 118 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/ 119 acpipath='/sys/module/acpi/parameters/debug_level' 130 traceevents = [ 120 traceevents = [ 131 'suspend_resume', 121 'suspend_resume', 132 'wakeup_source_activate', 122 'wakeup_source_activate', 133 'wakeup_source_deactivate', 123 'wakeup_source_deactivate', 134 'device_pm_callback_end', 124 'device_pm_callback_end', 135 'device_pm_callback_start' 125 'device_pm_callback_start' 136 ] 126 ] 137 logmsg = '' 127 logmsg = '' 138 testcommand = '' 128 testcommand = '' 139 mempath = '/dev/mem' 129 mempath = '/dev/mem' 140 powerfile = '/sys/power/state' 130 powerfile = '/sys/power/state' 141 mempowerfile = '/sys/power/mem_sleep' 131 mempowerfile = '/sys/power/mem_sleep' 142 diskpowerfile = '/sys/power/disk' 132 diskpowerfile = '/sys/power/disk' 143 suspendmode = 'mem' 133 suspendmode = 'mem' 144 memmode = '' 134 memmode = '' 145 diskmode = '' 135 diskmode = '' 146 hostname = 'localhost' 136 hostname = 'localhost' 147 prefix = 'test' 137 prefix = 'test' 148 teststamp = '' 138 teststamp = '' 149 sysstamp = '' 139 sysstamp = '' 150 dmesgstart = 0.0 140 dmesgstart = 0.0 151 dmesgfile = '' 141 dmesgfile = '' 152 ftracefile = '' 142 ftracefile = '' 153 htmlfile = 'output.html' 143 htmlfile = 'output.html' 154 result = '' 144 result = '' 155 rtcwake = True 145 rtcwake = True 156 rtcwaketime = 15 146 rtcwaketime = 15 157 rtcpath = '' 147 rtcpath = '' 158 devicefilter = [] 148 devicefilter = [] 159 cgfilter = [] 149 cgfilter = [] 160 stamp = 0 150 stamp = 0 161 execcount = 1 151 execcount = 1 162 x2delay = 0 152 x2delay = 0 163 skiphtml = False 153 skiphtml = False 164 usecallgraph = False 154 usecallgraph = False 165 ftopfunc = 'pm_suspend' 155 ftopfunc = 'pm_suspend' 166 ftop = False 156 ftop = False 167 usetraceevents = False 157 usetraceevents = False 168 usetracemarkers = True 158 usetracemarkers = True 169 useftrace = True << 170 usekprobes = True 159 usekprobes = True 171 usedevsrc = False 160 usedevsrc = False 172 useprocmon = False 161 useprocmon = False 173 notestrun = False 162 notestrun = False 174 cgdump = False 163 cgdump = False 175 devdump = False 164 devdump = False 176 mixedphaseheight = True 165 mixedphaseheight = True 177 devprops = dict() 166 devprops = dict() 178 cfgdef = dict() 167 cfgdef = dict() 179 platinfo = [] 168 platinfo = [] 180 predelay = 0 169 predelay = 0 181 postdelay = 0 170 postdelay = 0 182 tmstart = 'SUSPEND START %Y%m%d-%H:%M: 171 tmstart = 'SUSPEND START %Y%m%d-%H:%M:%S.%f' 183 tmend = 'RESUME COMPLETE %Y%m%d-%H:%M: 172 tmend = 'RESUME COMPLETE %Y%m%d-%H:%M:%S.%f' 184 tracefuncs = { 173 tracefuncs = { 185 'async_synchronize_full': {}, << 186 'sys_sync': {}, 174 'sys_sync': {}, 187 'ksys_sync': {}, 175 'ksys_sync': {}, 188 '__pm_notifier_call_chain': {} 176 '__pm_notifier_call_chain': {}, 189 'pm_prepare_console': {}, 177 'pm_prepare_console': {}, 190 'pm_notifier_call_chain': {}, 178 'pm_notifier_call_chain': {}, 191 'freeze_processes': {}, 179 'freeze_processes': {}, 192 'freeze_kernel_threads': {}, 180 'freeze_kernel_threads': {}, 193 'pm_restrict_gfp_mask': {}, 181 'pm_restrict_gfp_mask': {}, 194 'acpi_suspend_begin': {}, 182 'acpi_suspend_begin': {}, 195 'acpi_hibernation_begin': {}, 183 'acpi_hibernation_begin': {}, 196 'acpi_hibernation_enter': {}, 184 'acpi_hibernation_enter': {}, 197 'acpi_hibernation_leave': {}, 185 'acpi_hibernation_leave': {}, 198 'acpi_pm_freeze': {}, 186 'acpi_pm_freeze': {}, 199 'acpi_pm_thaw': {}, 187 'acpi_pm_thaw': {}, 200 'acpi_s2idle_end': {}, 188 'acpi_s2idle_end': {}, 201 'acpi_s2idle_sync': {}, 189 'acpi_s2idle_sync': {}, 202 'acpi_s2idle_begin': {}, 190 'acpi_s2idle_begin': {}, 203 'acpi_s2idle_prepare': {}, 191 'acpi_s2idle_prepare': {}, 204 'acpi_s2idle_prepare_late': {} 192 'acpi_s2idle_prepare_late': {}, 205 'acpi_s2idle_wake': {}, 193 'acpi_s2idle_wake': {}, 206 'acpi_s2idle_wakeup': {}, 194 'acpi_s2idle_wakeup': {}, 207 'acpi_s2idle_restore': {}, 195 'acpi_s2idle_restore': {}, 208 'acpi_s2idle_restore_early': { 196 'acpi_s2idle_restore_early': {}, 209 'hibernate_preallocate_memory' 197 'hibernate_preallocate_memory': {}, 210 'create_basic_memory_bitmaps': 198 'create_basic_memory_bitmaps': {}, 211 'swsusp_write': {}, 199 'swsusp_write': {}, 212 'suspend_console': {}, 200 'suspend_console': {}, 213 'acpi_pm_prepare': {}, 201 'acpi_pm_prepare': {}, 214 'syscore_suspend': {}, 202 'syscore_suspend': {}, 215 'arch_enable_nonboot_cpus_end' 203 'arch_enable_nonboot_cpus_end': {}, 216 'syscore_resume': {}, 204 'syscore_resume': {}, 217 'acpi_pm_finish': {}, 205 'acpi_pm_finish': {}, 218 'resume_console': {}, 206 'resume_console': {}, 219 'acpi_pm_end': {}, 207 'acpi_pm_end': {}, 220 'pm_restore_gfp_mask': {}, 208 'pm_restore_gfp_mask': {}, 221 'thaw_processes': {}, 209 'thaw_processes': {}, 222 'pm_restore_console': {}, 210 'pm_restore_console': {}, 223 'CPU_OFF': { 211 'CPU_OFF': { 224 'func':'_cpu_down', 212 'func':'_cpu_down', 225 'args_x86_64': {'cpu': 213 'args_x86_64': {'cpu':'%di:s32'}, 226 'format': 'CPU_OFF[{cp 214 'format': 'CPU_OFF[{cpu}]' 227 }, 215 }, 228 'CPU_ON': { 216 'CPU_ON': { 229 'func':'_cpu_up', 217 'func':'_cpu_up', 230 'args_x86_64': {'cpu': 218 'args_x86_64': {'cpu':'%di:s32'}, 231 'format': 'CPU_ON[{cpu 219 'format': 'CPU_ON[{cpu}]' 232 }, 220 }, 233 } 221 } 234 dev_tracefuncs = { 222 dev_tracefuncs = { 235 # general wait/delay/sleep 223 # general wait/delay/sleep 236 'msleep': { 'args_x86_64': {'t 224 'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 }, 237 'schedule_timeout': { 'args_x8 225 'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 }, 238 'udelay': { 'func':'__const_ud 226 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 }, 239 'usleep_range': { 'args_x86_64 227 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 }, 240 'mutex_lock_slowpath': { 'func 228 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 }, 241 'acpi_os_stall': {'ub': 1}, 229 'acpi_os_stall': {'ub': 1}, 242 'rt_mutex_slowlock': {'ub': 1} 230 'rt_mutex_slowlock': {'ub': 1}, 243 # ACPI 231 # ACPI 244 'acpi_resume_power_resources': 232 'acpi_resume_power_resources': {}, 245 'acpi_ps_execute_method': { 'a 233 'acpi_ps_execute_method': { 'args_x86_64': { 246 'fullpath':'+0(+40(%di 234 'fullpath':'+0(+40(%di)):string', 247 }}, 235 }}, 248 # mei_me 236 # mei_me 249 'mei_reset': {}, 237 'mei_reset': {}, 250 # filesystem 238 # filesystem 251 'ext4_sync_fs': {}, 239 'ext4_sync_fs': {}, 252 # 80211 240 # 80211 253 'ath10k_bmi_read_memory': { 'a 241 'ath10k_bmi_read_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 254 'ath10k_bmi_write_memory': { ' 242 'ath10k_bmi_write_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 255 'ath10k_bmi_fast_download': { 243 'ath10k_bmi_fast_download': { 'args_x86_64': {'length':'%cx:s32'} }, 256 'iwlagn_mac_start': {}, 244 'iwlagn_mac_start': {}, 257 'iwlagn_alloc_bcast_station': 245 'iwlagn_alloc_bcast_station': {}, 258 'iwl_trans_pcie_start_hw': {}, 246 'iwl_trans_pcie_start_hw': {}, 259 'iwl_trans_pcie_start_fw': {}, 247 'iwl_trans_pcie_start_fw': {}, 260 'iwl_run_init_ucode': {}, 248 'iwl_run_init_ucode': {}, 261 'iwl_load_ucode_wait_alive': { 249 'iwl_load_ucode_wait_alive': {}, 262 'iwl_alive_start': {}, 250 'iwl_alive_start': {}, 263 'iwlagn_mac_stop': {}, 251 'iwlagn_mac_stop': {}, 264 'iwlagn_mac_suspend': {}, 252 'iwlagn_mac_suspend': {}, 265 'iwlagn_mac_resume': {}, 253 'iwlagn_mac_resume': {}, 266 'iwlagn_mac_add_interface': {} 254 'iwlagn_mac_add_interface': {}, 267 'iwlagn_mac_remove_interface': 255 'iwlagn_mac_remove_interface': {}, 268 'iwlagn_mac_change_interface': 256 'iwlagn_mac_change_interface': {}, 269 'iwlagn_mac_config': {}, 257 'iwlagn_mac_config': {}, 270 'iwlagn_configure_filter': {}, 258 'iwlagn_configure_filter': {}, 271 'iwlagn_mac_hw_scan': {}, 259 'iwlagn_mac_hw_scan': {}, 272 'iwlagn_bss_info_changed': {}, 260 'iwlagn_bss_info_changed': {}, 273 'iwlagn_mac_channel_switch': { 261 'iwlagn_mac_channel_switch': {}, 274 'iwlagn_mac_flush': {}, 262 'iwlagn_mac_flush': {}, 275 # ATA 263 # ATA 276 'ata_eh_recover': { 'args_x86_ 264 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} }, 277 # i915 265 # i915 278 'i915_gem_resume': {}, 266 'i915_gem_resume': {}, 279 'i915_restore_state': {}, 267 'i915_restore_state': {}, 280 'intel_opregion_setup': {}, 268 'intel_opregion_setup': {}, 281 'g4x_pre_enable_dp': {}, 269 'g4x_pre_enable_dp': {}, 282 'vlv_pre_enable_dp': {}, 270 'vlv_pre_enable_dp': {}, 283 'chv_pre_enable_dp': {}, 271 'chv_pre_enable_dp': {}, 284 'g4x_enable_dp': {}, 272 'g4x_enable_dp': {}, 285 'vlv_enable_dp': {}, 273 'vlv_enable_dp': {}, 286 'intel_hpd_init': {}, 274 'intel_hpd_init': {}, 287 'intel_opregion_register': {}, 275 'intel_opregion_register': {}, 288 'intel_dp_detect': {}, 276 'intel_dp_detect': {}, 289 'intel_hdmi_detect': {}, 277 'intel_hdmi_detect': {}, 290 'intel_opregion_init': {}, 278 'intel_opregion_init': {}, 291 'intel_fbdev_set_suspend': {}, 279 'intel_fbdev_set_suspend': {}, 292 } 280 } 293 infocmds = [ 281 infocmds = [ 294 [0, 'sysinfo', 'uname', '-a'], << 295 [0, 'cpuinfo', 'head', '-7', ' << 296 [0, 'kparams', 'cat', '/proc/c 282 [0, 'kparams', 'cat', '/proc/cmdline'], 297 [0, 'mcelog', 'mcelog'], 283 [0, 'mcelog', 'mcelog'], 298 [0, 'pcidevices', 'lspci', '-t 284 [0, 'pcidevices', 'lspci', '-tv'], 299 [0, 'usbdevices', 'lsusb', '-t !! 285 [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 286 [1, 'interrupts', 'cat', '/proc/interrupts'], 306 [1, 'wakeups', 'cat', '/sys/ke 287 [1, 'wakeups', 'cat', '/sys/kernel/debug/wakeup_sources'], 307 [2, 'gpecounts', 'sh', '-c', ' 288 [2, 'gpecounts', 'sh', '-c', 'grep -v invalid /sys/firmware/acpi/interrupts/*'], 308 [2, 'suspendstats', 'sh', '-c' 289 [2, 'suspendstats', 'sh', '-c', 'grep -v invalid /sys/power/suspend_stats/*'], 309 [2, 'cpuidle', 'sh', '-c', 'gr 290 [2, 'cpuidle', 'sh', '-c', 'grep -v invalid /sys/devices/system/cpu/cpu*/cpuidle/state*/s2idle/*'], 310 [2, 'battery', 'sh', '-c', 'gr 291 [2, 'battery', 'sh', '-c', 'grep -v invalid /sys/class/power_supply/*/*'], 311 [2, 'thermal', 'sh', '-c', 'gr << 312 ] 292 ] 313 cgblacklist = [] 293 cgblacklist = [] 314 kprobes = dict() 294 kprobes = dict() 315 timeformat = '%.3f' 295 timeformat = '%.3f' 316 cmdline = '%s %s' % \ 296 cmdline = '%s %s' % \ 317 (os.path.basename(sys. 297 (os.path.basename(sys.argv[0]), ' '.join(sys.argv[1:])) 318 sudouser = '' 298 sudouser = '' 319 def __init__(self): 299 def __init__(self): 320 self.archargs = 'args_'+platfo 300 self.archargs = 'args_'+platform.machine() 321 self.hostname = platform.node( 301 self.hostname = platform.node() 322 if(self.hostname == ''): 302 if(self.hostname == ''): 323 self.hostname = 'local 303 self.hostname = 'localhost' 324 rtc = "rtc0" 304 rtc = "rtc0" 325 if os.path.exists('/dev/rtc'): 305 if os.path.exists('/dev/rtc'): 326 rtc = os.readlink('/de 306 rtc = os.readlink('/dev/rtc') 327 rtc = '/sys/class/rtc/'+rtc 307 rtc = '/sys/class/rtc/'+rtc 328 if os.path.exists(rtc) and os. 308 if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \ 329 os.path.exists(rtc+'/t 309 os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'): 330 self.rtcpath = rtc 310 self.rtcpath = rtc 331 if (hasattr(sys.stdout, 'isatt 311 if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): 332 self.ansi = True 312 self.ansi = True 333 self.testdir = datetime.now(). 313 self.testdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S') 334 if os.getuid() == 0 and 'SUDO_ 314 if os.getuid() == 0 and 'SUDO_USER' in os.environ and \ 335 os.environ['SUDO_USER' 315 os.environ['SUDO_USER']: 336 self.sudouser = os.env 316 self.sudouser = os.environ['SUDO_USER'] 337 def resetlog(self): 317 def resetlog(self): 338 self.logmsg = '' 318 self.logmsg = '' 339 self.platinfo = [] 319 self.platinfo = [] 340 def vprint(self, msg): 320 def vprint(self, msg): 341 self.logmsg += msg+'\n' 321 self.logmsg += msg+'\n' 342 if self.verbose or msg.startsw 322 if self.verbose or msg.startswith('WARNING:'): 343 pprint(msg) 323 pprint(msg) 344 def signalHandler(self, signum, frame) 324 def signalHandler(self, signum, frame): 345 if not self.result: 325 if not self.result: 346 return 326 return 347 signame = self.signames[signum 327 signame = self.signames[signum] if signum in self.signames else 'UNKNOWN' 348 msg = 'Signal %s caused a tool 328 msg = 'Signal %s caused a tool exit, line %d' % (signame, frame.f_lineno) 349 self.outputResult({'error':msg 329 self.outputResult({'error':msg}) 350 sys.exit(3) 330 sys.exit(3) 351 def signalHandlerInit(self): 331 def signalHandlerInit(self): 352 capture = ['BUS', 'SYS', 'XCPU 332 capture = ['BUS', 'SYS', 'XCPU', 'XFSZ', 'PWR', 'HUP', 'INT', 'QUIT', 353 'ILL', 'ABRT', 'FPE', 333 'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM'] 354 self.signames = dict() 334 self.signames = dict() 355 for i in capture: 335 for i in capture: 356 s = 'SIG'+i 336 s = 'SIG'+i 357 try: 337 try: 358 signum = getat 338 signum = getattr(signal, s) 359 signal.signal( 339 signal.signal(signum, self.signalHandler) 360 except: 340 except: 361 continue 341 continue 362 self.signames[signum] 342 self.signames[signum] = s 363 def rootCheck(self, fatal=True): 343 def rootCheck(self, fatal=True): 364 if(os.access(self.powerfile, o 344 if(os.access(self.powerfile, os.W_OK)): 365 return True 345 return True 366 if fatal: 346 if fatal: 367 msg = 'This command re 347 msg = 'This command requires sysfs mount and root access' 368 pprint('ERROR: %s\n' % 348 pprint('ERROR: %s\n' % msg) 369 self.outputResult({'er 349 self.outputResult({'error':msg}) 370 sys.exit(1) 350 sys.exit(1) 371 return False 351 return False 372 def rootUser(self, fatal=False): 352 def rootUser(self, fatal=False): 373 if 'USER' in os.environ and os 353 if 'USER' in os.environ and os.environ['USER'] == 'root': 374 return True 354 return True 375 if fatal: 355 if fatal: 376 msg = 'This command mu 356 msg = 'This command must be run as root' 377 pprint('ERROR: %s\n' % 357 pprint('ERROR: %s\n' % msg) 378 self.outputResult({'er 358 self.outputResult({'error':msg}) 379 sys.exit(1) 359 sys.exit(1) 380 return False 360 return False 381 def usable(self, file, ishtml=False): !! 361 def usable(self, file): 382 if not os.path.exists(file) or !! 362 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): 363 def getExec(self, cmd): 395 try: 364 try: 396 fp = Popen(['which', c 365 fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout 397 out = ascii(fp.read()) 366 out = ascii(fp.read()).strip() 398 fp.close() 367 fp.close() 399 except: 368 except: 400 out = '' 369 out = '' 401 if out: 370 if out: 402 return out 371 return out 403 for path in ['/sbin', '/bin', 372 for path in ['/sbin', '/bin', '/usr/sbin', '/usr/bin', 404 '/usr/local/sbin', '/u 373 '/usr/local/sbin', '/usr/local/bin']: 405 cmdfull = os.path.join 374 cmdfull = os.path.join(path, cmd) 406 if os.path.exists(cmdf 375 if os.path.exists(cmdfull): 407 return cmdfull 376 return cmdfull 408 return out 377 return out 409 def setPrecision(self, num): 378 def setPrecision(self, num): 410 if num < 0 or num > 6: 379 if num < 0 or num > 6: 411 return 380 return 412 self.timeformat = '%.{0}f'.for 381 self.timeformat = '%.{0}f'.format(num) 413 def setOutputFolder(self, value): 382 def setOutputFolder(self, value): 414 args = dict() 383 args = dict() 415 n = datetime.now() 384 n = datetime.now() 416 args['date'] = n.strftime('%y% 385 args['date'] = n.strftime('%y%m%d') 417 args['time'] = n.strftime('%H% 386 args['time'] = n.strftime('%H%M%S') 418 args['hostname'] = args['host' 387 args['hostname'] = args['host'] = self.hostname 419 args['mode'] = self.suspendmod 388 args['mode'] = self.suspendmode 420 return value.format(**args) 389 return value.format(**args) 421 def setOutputFile(self): 390 def setOutputFile(self): 422 if self.dmesgfile != '': 391 if self.dmesgfile != '': 423 m = re.match(r'(?P<nam !! 392 m = re.match('(?P<name>.*)_dmesg\.txt.*', self.dmesgfile) 424 if(m): 393 if(m): 425 self.htmlfile 394 self.htmlfile = m.group('name')+'.html' 426 if self.ftracefile != '': 395 if self.ftracefile != '': 427 m = re.match(r'(?P<nam !! 396 m = re.match('(?P<name>.*)_ftrace\.txt.*', self.ftracefile) 428 if(m): 397 if(m): 429 self.htmlfile 398 self.htmlfile = m.group('name')+'.html' 430 def systemInfo(self, info): 399 def systemInfo(self, info): 431 p = m = '' 400 p = m = '' 432 if 'baseboard-manufacturer' in 401 if 'baseboard-manufacturer' in info: 433 m = info['baseboard-ma 402 m = info['baseboard-manufacturer'] 434 elif 'system-manufacturer' in 403 elif 'system-manufacturer' in info: 435 m = info['system-manuf 404 m = info['system-manufacturer'] 436 if 'system-product-name' in in 405 if 'system-product-name' in info: 437 p = info['system-produ 406 p = info['system-product-name'] 438 elif 'baseboard-product-name' 407 elif 'baseboard-product-name' in info: 439 p = info['baseboard-pr 408 p = info['baseboard-product-name'] 440 if m[:5].lower() == 'intel' an 409 if m[:5].lower() == 'intel' and 'baseboard-product-name' in info: 441 p = info['baseboard-pr 410 p = info['baseboard-product-name'] 442 c = info['processor-version'] 411 c = info['processor-version'] if 'processor-version' in info else '' 443 b = info['bios-version'] if 'b 412 b = info['bios-version'] if 'bios-version' in info else '' 444 r = info['bios-release-date'] 413 r = info['bios-release-date'] if 'bios-release-date' in info else '' 445 self.sysstamp = '# sysinfo | m 414 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 415 (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) 416 def printSystemInfo(self, fatal=False): 450 self.rootCheck(True) 417 self.rootCheck(True) 451 out = dmidecode(self.mempath, 418 out = dmidecode(self.mempath, fatal) 452 if len(out) < 1: 419 if len(out) < 1: 453 return 420 return 454 fmt = '%-24s: %s' 421 fmt = '%-24s: %s' 455 if self.osversion: << 456 print(fmt % ('os-versi << 457 for name in sorted(out): 422 for name in sorted(out): 458 print(fmt % (name, out 423 print(fmt % (name, out[name])) 459 print(fmt % ('cpucount', ('%d' 424 print(fmt % ('cpucount', ('%d' % self.cpucount))) 460 print(fmt % ('memtotal', ('%d 425 print(fmt % ('memtotal', ('%d kB' % self.memtotal))) 461 print(fmt % ('memfree', ('%d k 426 print(fmt % ('memfree', ('%d kB' % self.memfree))) 462 def cpuInfo(self): 427 def cpuInfo(self): 463 self.cpucount = 0 428 self.cpucount = 0 464 if os.path.exists('/proc/cpuin !! 429 fp = open('/proc/cpuinfo', 'r') 465 with open('/proc/cpuin !! 430 for line in fp: 466 for line in fp !! 431 if re.match('^processor[ \t]*:[ \t]*[0-9]*', line): 467 if re. !! 432 self.cpucount += 1 468 !! 433 fp.close() 469 if os.path.exists('/proc/memin !! 434 fp = open('/proc/meminfo', 'r') 470 with open('/proc/memin !! 435 for line in fp: 471 for line in fp !! 436 m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line) 472 m = re !! 437 if m: 473 if m: !! 438 self.memtotal = int(m.group('sz')) 474 !! 439 m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line) 475 m = re !! 440 if m: 476 if m: !! 441 self.memfree = int(m.group('sz')) 477 !! 442 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): 443 def initTestOutput(self, name): 484 self.prefix = self.hostname 444 self.prefix = self.hostname 485 v = open('/proc/version', 'r') 445 v = open('/proc/version', 'r').read().strip() 486 kver = v.split()[2] 446 kver = v.split()[2] 487 fmt = name+'-%m%d%y-%H%M%S' 447 fmt = name+'-%m%d%y-%H%M%S' 488 testtime = datetime.now().strf 448 testtime = datetime.now().strftime(fmt) 489 self.teststamp = \ 449 self.teststamp = \ 490 '# '+testtime+' '+self 450 '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver 491 ext = '' 451 ext = '' 492 if self.gzip: 452 if self.gzip: 493 ext = '.gz' 453 ext = '.gz' 494 self.dmesgfile = \ 454 self.dmesgfile = \ 495 self.testdir+'/'+self. 455 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt'+ext 496 self.ftracefile = \ 456 self.ftracefile = \ 497 self.testdir+'/'+self. 457 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt'+ext 498 self.htmlfile = \ 458 self.htmlfile = \ 499 self.testdir+'/'+self. 459 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' 500 if not os.path.isdir(self.test 460 if not os.path.isdir(self.testdir): 501 os.makedirs(self.testd 461 os.makedirs(self.testdir) 502 self.sudoUserchown(self.testdi 462 self.sudoUserchown(self.testdir) 503 def getValueList(self, value): 463 def getValueList(self, value): 504 out = [] 464 out = [] 505 for i in value.split(','): 465 for i in value.split(','): 506 if i.strip(): 466 if i.strip(): 507 out.append(i.s 467 out.append(i.strip()) 508 return out 468 return out 509 def setDeviceFilter(self, value): 469 def setDeviceFilter(self, value): 510 self.devicefilter = self.getVa 470 self.devicefilter = self.getValueList(value) 511 def setCallgraphFilter(self, value): 471 def setCallgraphFilter(self, value): 512 self.cgfilter = self.getValueL 472 self.cgfilter = self.getValueList(value) 513 def skipKprobes(self, value): 473 def skipKprobes(self, value): 514 for k in self.getValueList(val 474 for k in self.getValueList(value): 515 if k in self.tracefunc 475 if k in self.tracefuncs: 516 del self.trace 476 del self.tracefuncs[k] 517 if k in self.dev_trace 477 if k in self.dev_tracefuncs: 518 del self.dev_t 478 del self.dev_tracefuncs[k] 519 def setCallgraphBlacklist(self, file): 479 def setCallgraphBlacklist(self, file): 520 self.cgblacklist = self.listFr 480 self.cgblacklist = self.listFromFile(file) 521 def rtcWakeAlarmOn(self): 481 def rtcWakeAlarmOn(self): 522 call('echo 0 > '+self.rtcpath+ 482 call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True) 523 nowtime = open(self.rtcpath+'/ 483 nowtime = open(self.rtcpath+'/since_epoch', 'r').read().strip() 524 if nowtime: 484 if nowtime: 525 nowtime = int(nowtime) 485 nowtime = int(nowtime) 526 else: 486 else: 527 # if hardware time fai 487 # if hardware time fails, use the software time 528 nowtime = int(datetime 488 nowtime = int(datetime.now().strftime('%s')) 529 alarm = nowtime + self.rtcwake 489 alarm = nowtime + self.rtcwaketime 530 call('echo %d > %s/wakealarm' 490 call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True) 531 def rtcWakeAlarmOff(self): 491 def rtcWakeAlarmOff(self): 532 call('echo 0 > %s/wakealarm' % 492 call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True) 533 def initdmesg(self): 493 def initdmesg(self): 534 # get the latest time stamp fr 494 # get the latest time stamp from the dmesg log 535 lines = Popen('dmesg', stdout= 495 lines = Popen('dmesg', stdout=PIPE).stdout.readlines() 536 ktime = '0' 496 ktime = '0' 537 for line in reversed(lines): 497 for line in reversed(lines): 538 line = ascii(line).rep 498 line = ascii(line).replace('\r\n', '') 539 idx = line.find('[') 499 idx = line.find('[') 540 if idx > 1: 500 if idx > 1: 541 line = line[id 501 line = line[idx:] 542 m = re.match(r'[ \t]*( !! 502 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 543 if(m): 503 if(m): 544 ktime = m.grou 504 ktime = m.group('ktime') 545 break 505 break 546 self.dmesgstart = float(ktime) 506 self.dmesgstart = float(ktime) 547 def getdmesg(self, testdata): 507 def getdmesg(self, testdata): 548 op = self.writeDatafileHeader( 508 op = self.writeDatafileHeader(self.dmesgfile, testdata) 549 # store all new dmesg lines si 509 # store all new dmesg lines since initdmesg was called 550 fp = Popen('dmesg', stdout=PIP 510 fp = Popen('dmesg', stdout=PIPE).stdout 551 for line in fp: 511 for line in fp: 552 line = ascii(line).rep 512 line = ascii(line).replace('\r\n', '') 553 idx = line.find('[') 513 idx = line.find('[') 554 if idx > 1: 514 if idx > 1: 555 line = line[id 515 line = line[idx:] 556 m = re.match(r'[ \t]*( !! 516 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 557 if(not m): 517 if(not m): 558 continue 518 continue 559 ktime = float(m.group( 519 ktime = float(m.group('ktime')) 560 if ktime > self.dmesgs 520 if ktime > self.dmesgstart: 561 op.write(line) 521 op.write(line) 562 fp.close() 522 fp.close() 563 op.close() 523 op.close() 564 def listFromFile(self, file): 524 def listFromFile(self, file): 565 list = [] 525 list = [] 566 fp = open(file) 526 fp = open(file) 567 for i in fp.read().split('\n') 527 for i in fp.read().split('\n'): 568 i = i.strip() 528 i = i.strip() 569 if i and i[0] != '#': 529 if i and i[0] != '#': 570 list.append(i) 530 list.append(i) 571 fp.close() 531 fp.close() 572 return list 532 return list 573 def addFtraceFilterFunctions(self, fil 533 def addFtraceFilterFunctions(self, file): 574 for i in self.listFromFile(fil 534 for i in self.listFromFile(file): 575 if len(i) < 2: 535 if len(i) < 2: 576 continue 536 continue 577 self.tracefuncs[i] = d 537 self.tracefuncs[i] = dict() 578 def getFtraceFilterFunctions(self, cur 538 def getFtraceFilterFunctions(self, current): 579 self.rootCheck(True) 539 self.rootCheck(True) 580 if not current: 540 if not current: 581 call('cat '+self.tpath 541 call('cat '+self.tpath+'available_filter_functions', shell=True) 582 return 542 return 583 master = self.listFromFile(sel 543 master = self.listFromFile(self.tpath+'available_filter_functions') 584 for i in sorted(self.tracefunc 544 for i in sorted(self.tracefuncs): 585 if 'func' in self.trac 545 if 'func' in self.tracefuncs[i]: 586 i = self.trace 546 i = self.tracefuncs[i]['func'] 587 if i in master: 547 if i in master: 588 print(i) 548 print(i) 589 else: 549 else: 590 print(self.col 550 print(self.colorText(i)) 591 def setFtraceFilterFunctions(self, lis 551 def setFtraceFilterFunctions(self, list): 592 master = self.listFromFile(sel 552 master = self.listFromFile(self.tpath+'available_filter_functions') 593 flist = '' 553 flist = '' 594 for i in list: 554 for i in list: 595 if i not in master: 555 if i not in master: 596 continue 556 continue 597 if ' [' in i: 557 if ' [' in i: 598 flist += i.spl 558 flist += i.split(' ')[0]+'\n' 599 else: 559 else: 600 flist += i+'\n 560 flist += i+'\n' 601 fp = open(self.tpath+'set_grap 561 fp = open(self.tpath+'set_graph_function', 'w') 602 fp.write(flist) 562 fp.write(flist) 603 fp.close() 563 fp.close() 604 def basicKprobe(self, name): 564 def basicKprobe(self, name): 605 self.kprobes[name] = {'name': 565 self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name} 606 def defaultKprobe(self, name, kdata): 566 def defaultKprobe(self, name, kdata): 607 k = kdata 567 k = kdata 608 for field in ['name', 'format' 568 for field in ['name', 'format', 'func']: 609 if field not in k: 569 if field not in k: 610 k[field] = nam 570 k[field] = name 611 if self.archargs in k: 571 if self.archargs in k: 612 k['args'] = k[self.arc 572 k['args'] = k[self.archargs] 613 else: 573 else: 614 k['args'] = dict() 574 k['args'] = dict() 615 k['format'] = name 575 k['format'] = name 616 self.kprobes[name] = k 576 self.kprobes[name] = k 617 def kprobeColor(self, name): 577 def kprobeColor(self, name): 618 if name not in self.kprobes or 578 if name not in self.kprobes or 'color' not in self.kprobes[name]: 619 return '' 579 return '' 620 return self.kprobes[name]['col 580 return self.kprobes[name]['color'] 621 def kprobeDisplayName(self, name, data 581 def kprobeDisplayName(self, name, dataraw): 622 if name not in self.kprobes: 582 if name not in self.kprobes: 623 self.basicKprobe(name) 583 self.basicKprobe(name) 624 data = '' 584 data = '' 625 quote=0 585 quote=0 626 # first remvoe any spaces insi 586 # first remvoe any spaces inside quotes, and the quotes 627 for c in dataraw: 587 for c in dataraw: 628 if c == '"': 588 if c == '"': 629 quote = (quote 589 quote = (quote + 1) % 2 630 if quote and c == ' ': 590 if quote and c == ' ': 631 data += '_' 591 data += '_' 632 elif c != '"': 592 elif c != '"': 633 data += c 593 data += c 634 fmt, args = self.kprobes[name] 594 fmt, args = self.kprobes[name]['format'], self.kprobes[name]['args'] 635 arglist = dict() 595 arglist = dict() 636 # now process the args 596 # now process the args 637 for arg in sorted(args): 597 for arg in sorted(args): 638 arglist[arg] = '' 598 arglist[arg] = '' 639 m = re.match(r'.* '+ar !! 599 m = re.match('.* '+arg+'=(?P<arg>.*) ', data); 640 if m: 600 if m: 641 arglist[arg] = 601 arglist[arg] = m.group('arg') 642 else: 602 else: 643 m = re.match(r !! 603 m = re.match('.* '+arg+'=(?P<arg>.*)', data); 644 if m: 604 if m: 645 arglis 605 arglist[arg] = m.group('arg') 646 out = fmt.format(**arglist) 606 out = fmt.format(**arglist) 647 out = out.replace(' ', '_').re 607 out = out.replace(' ', '_').replace('"', '') 648 return out 608 return out 649 def kprobeText(self, kname, kprobe): 609 def kprobeText(self, kname, kprobe): 650 name = fmt = func = kname 610 name = fmt = func = kname 651 args = dict() 611 args = dict() 652 if 'name' in kprobe: 612 if 'name' in kprobe: 653 name = kprobe['name'] 613 name = kprobe['name'] 654 if 'format' in kprobe: 614 if 'format' in kprobe: 655 fmt = kprobe['format'] 615 fmt = kprobe['format'] 656 if 'func' in kprobe: 616 if 'func' in kprobe: 657 func = kprobe['func'] 617 func = kprobe['func'] 658 if self.archargs in kprobe: 618 if self.archargs in kprobe: 659 args = kprobe[self.arc 619 args = kprobe[self.archargs] 660 if 'args' in kprobe: 620 if 'args' in kprobe: 661 args = kprobe['args'] 621 args = kprobe['args'] 662 if re.findall('{(?P<n>[a-z,A-Z 622 if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func): 663 doError('Kprobe "%s" h 623 doError('Kprobe "%s" has format info in the function name "%s"' % (name, func)) 664 for arg in re.findall('{(?P<n> 624 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt): 665 if arg not in args: 625 if arg not in args: 666 doError('Kprob 626 doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 667 val = 'p:%s_cal %s' % (name, f 627 val = 'p:%s_cal %s' % (name, func) 668 for i in sorted(args): 628 for i in sorted(args): 669 val += ' %s=%s' % (i, 629 val += ' %s=%s' % (i, args[i]) 670 val += '\nr:%s_ret %s $retval\ 630 val += '\nr:%s_ret %s $retval\n' % (name, func) 671 return val 631 return val 672 def addKprobes(self, output=False): 632 def addKprobes(self, output=False): 673 if len(self.kprobes) < 1: 633 if len(self.kprobes) < 1: 674 return 634 return 675 if output: 635 if output: 676 pprint(' kprobe fun 636 pprint(' kprobe functions in this kernel:') 677 # first test each kprobe 637 # first test each kprobe 678 rejects = [] 638 rejects = [] 679 # sort kprobes: trace, ub-dev, 639 # sort kprobes: trace, ub-dev, custom, dev 680 kpl = [[], [], [], []] 640 kpl = [[], [], [], []] 681 linesout = len(self.kprobes) 641 linesout = len(self.kprobes) 682 for name in sorted(self.kprobe 642 for name in sorted(self.kprobes): 683 res = self.colorText(' 643 res = self.colorText('YES', 32) 684 if not self.testKprobe 644 if not self.testKprobe(name, self.kprobes[name]): 685 res = self.col 645 res = self.colorText('NO') 686 rejects.append 646 rejects.append(name) 687 else: 647 else: 688 if name in sel 648 if name in self.tracefuncs: 689 kpl[0] 649 kpl[0].append(name) 690 elif name in s 650 elif name in self.dev_tracefuncs: 691 if 'ub 651 if 'ub' in self.dev_tracefuncs[name]: 692 652 kpl[1].append(name) 693 else: 653 else: 694 654 kpl[3].append(name) 695 else: 655 else: 696 kpl[2] 656 kpl[2].append(name) 697 if output: 657 if output: 698 pprint(' 658 pprint(' %s: %s' % (name, res)) 699 kplist = kpl[0] + kpl[1] + kpl 659 kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3] 700 # remove all failed ones from 660 # remove all failed ones from the list 701 for name in rejects: 661 for name in rejects: 702 self.kprobes.pop(name) 662 self.kprobes.pop(name) 703 # set the kprobes all at once 663 # set the kprobes all at once 704 self.fsetVal('', 'kprobe_event 664 self.fsetVal('', 'kprobe_events') 705 kprobeevents = '' 665 kprobeevents = '' 706 for kp in kplist: 666 for kp in kplist: 707 kprobeevents += self.k 667 kprobeevents += self.kprobeText(kp, self.kprobes[kp]) 708 self.fsetVal(kprobeevents, 'kp 668 self.fsetVal(kprobeevents, 'kprobe_events') 709 if output: 669 if output: 710 check = self.fgetVal(' 670 check = self.fgetVal('kprobe_events') 711 linesack = (len(check. 671 linesack = (len(check.split('\n')) - 1) // 2 712 pprint(' kprobe fun 672 pprint(' kprobe functions enabled: %d/%d' % (linesack, linesout)) 713 self.fsetVal('1', 'events/kpro 673 self.fsetVal('1', 'events/kprobes/enable') 714 def testKprobe(self, kname, kprobe): 674 def testKprobe(self, kname, kprobe): 715 self.fsetVal('0', 'events/kpro 675 self.fsetVal('0', 'events/kprobes/enable') 716 kprobeevents = self.kprobeText 676 kprobeevents = self.kprobeText(kname, kprobe) 717 if not kprobeevents: 677 if not kprobeevents: 718 return False 678 return False 719 try: 679 try: 720 self.fsetVal(kprobeeve 680 self.fsetVal(kprobeevents, 'kprobe_events') 721 check = self.fgetVal(' 681 check = self.fgetVal('kprobe_events') 722 except: 682 except: 723 return False 683 return False 724 linesout = len(kprobeevents.sp 684 linesout = len(kprobeevents.split('\n')) 725 linesack = len(check.split('\n 685 linesack = len(check.split('\n')) 726 if linesack < linesout: 686 if linesack < linesout: 727 return False 687 return False 728 return True 688 return True 729 def setVal(self, val, file): 689 def setVal(self, val, file): 730 if not os.path.exists(file): 690 if not os.path.exists(file): 731 return False 691 return False 732 try: 692 try: 733 fp = open(file, 'wb', 693 fp = open(file, 'wb', 0) 734 fp.write(val.encode()) 694 fp.write(val.encode()) 735 fp.flush() 695 fp.flush() 736 fp.close() 696 fp.close() 737 except: 697 except: 738 return False 698 return False 739 return True 699 return True 740 def fsetVal(self, val, path): 700 def fsetVal(self, val, path): 741 if not self.useftrace: << 742 return False << 743 return self.setVal(val, self.t 701 return self.setVal(val, self.tpath+path) 744 def getVal(self, file): 702 def getVal(self, file): 745 res = '' 703 res = '' 746 if not os.path.exists(file): 704 if not os.path.exists(file): 747 return res 705 return res 748 try: 706 try: 749 fp = open(file, 'r') 707 fp = open(file, 'r') 750 res = fp.read() 708 res = fp.read() 751 fp.close() 709 fp.close() 752 except: 710 except: 753 pass 711 pass 754 return res 712 return res 755 def fgetVal(self, path): 713 def fgetVal(self, path): 756 if not self.useftrace: << 757 return '' << 758 return self.getVal(self.tpath+ 714 return self.getVal(self.tpath+path) 759 def cleanupFtrace(self): 715 def cleanupFtrace(self): 760 if self.useftrace: !! 716 if(self.usecallgraph or self.usetraceevents or self.usedevsrc): 761 self.fsetVal('0', 'eve 717 self.fsetVal('0', 'events/kprobes/enable') 762 self.fsetVal('', 'kpro 718 self.fsetVal('', 'kprobe_events') 763 self.fsetVal('1024', ' 719 self.fsetVal('1024', 'buffer_size_kb') 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 self.testVal(self.pmdpath, 'basic', '1') 789 # set the trace clock to globa 744 # set the trace clock to global 790 self.fsetVal('global', 'trace_ 745 self.fsetVal('global', 'trace_clock') 791 self.fsetVal('nop', 'current_t 746 self.fsetVal('nop', 'current_tracer') 792 # set trace buffer to an appro 747 # set trace buffer to an appropriate value 793 cpus = max(1, self.cpucount) 748 cpus = max(1, self.cpucount) 794 if self.bufsize > 0: 749 if self.bufsize > 0: 795 tgtsize = self.bufsize 750 tgtsize = self.bufsize 796 elif self.usecallgraph or self 751 elif self.usecallgraph or self.usedevsrc: 797 bmax = (1*1024*1024) i 752 bmax = (1*1024*1024) if self.suspendmode in ['disk', 'command'] \ 798 else (3*1024*1 753 else (3*1024*1024) 799 tgtsize = min(self.mem 754 tgtsize = min(self.memfree, bmax) 800 else: 755 else: 801 tgtsize = 65536 756 tgtsize = 65536 802 while not self.fsetVal('%d' % 757 while not self.fsetVal('%d' % (tgtsize // cpus), 'buffer_size_kb'): 803 # if the size failed t 758 # if the size failed to set, lower it and keep trying 804 tgtsize -= 65536 759 tgtsize -= 65536 805 if tgtsize < 65536: 760 if tgtsize < 65536: 806 tgtsize = int( 761 tgtsize = int(self.fgetVal('buffer_size_kb')) * cpus 807 break 762 break 808 self.vprint('Setting trace buf 763 self.vprint('Setting trace buffers to %d kB (%d kB per cpu)' % (tgtsize, tgtsize/cpus)) 809 # initialize the callgraph tra 764 # initialize the callgraph trace 810 if(self.usecallgraph): 765 if(self.usecallgraph): 811 # set trace type 766 # set trace type 812 self.fsetVal('function 767 self.fsetVal('function_graph', 'current_tracer') 813 self.fsetVal('', 'set_ 768 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 769 # set trace format options 819 self.fsetVal('print-pa 770 self.fsetVal('print-parent', 'trace_options') 820 self.fsetVal('funcgrap 771 self.fsetVal('funcgraph-abstime', 'trace_options') 821 self.fsetVal('funcgrap 772 self.fsetVal('funcgraph-cpu', 'trace_options') 822 self.fsetVal('funcgrap 773 self.fsetVal('funcgraph-duration', 'trace_options') 823 self.fsetVal('funcgrap 774 self.fsetVal('funcgraph-proc', 'trace_options') 824 self.fsetVal('funcgrap 775 self.fsetVal('funcgraph-tail', 'trace_options') 825 self.fsetVal('nofuncgr 776 self.fsetVal('nofuncgraph-overhead', 'trace_options') 826 self.fsetVal('context- 777 self.fsetVal('context-info', 'trace_options') 827 self.fsetVal('graph-ti 778 self.fsetVal('graph-time', 'trace_options') 828 self.fsetVal('%d' % se 779 self.fsetVal('%d' % self.max_graph_depth, 'max_graph_depth') 829 cf = ['dpm_run_callbac 780 cf = ['dpm_run_callback'] 830 if(self.usetraceevents 781 if(self.usetraceevents): 831 cf += ['dpm_pr 782 cf += ['dpm_prepare', 'dpm_complete'] 832 for fn in self.tracefu 783 for fn in self.tracefuncs: 833 if 'func' in s 784 if 'func' in self.tracefuncs[fn]: 834 cf.app 785 cf.append(self.tracefuncs[fn]['func']) 835 else: 786 else: 836 cf.app 787 cf.append(fn) 837 if self.ftop: 788 if self.ftop: 838 self.setFtrace 789 self.setFtraceFilterFunctions([self.ftopfunc]) 839 else: 790 else: 840 self.setFtrace 791 self.setFtraceFilterFunctions(cf) 841 # initialize the kprobe trace 792 # initialize the kprobe trace 842 elif self.usekprobes: 793 elif self.usekprobes: 843 for name in self.trace 794 for name in self.tracefuncs: 844 self.defaultKp 795 self.defaultKprobe(name, self.tracefuncs[name]) 845 if self.usedevsrc: 796 if self.usedevsrc: 846 for name in se 797 for name in self.dev_tracefuncs: 847 self.d 798 self.defaultKprobe(name, self.dev_tracefuncs[name]) 848 if not quiet: 799 if not quiet: 849 pprint('INITIA !! 800 pprint('INITIALIZING KPROBES...') 850 self.addKprobes(self.v 801 self.addKprobes(self.verbose) 851 if(self.usetraceevents): 802 if(self.usetraceevents): 852 # turn trace events on 803 # turn trace events on 853 events = iter(self.tra 804 events = iter(self.traceevents) 854 for e in events: 805 for e in events: 855 self.fsetVal(' 806 self.fsetVal('1', 'events/power/'+e+'/enable') 856 # clear the trace buffer 807 # clear the trace buffer 857 self.fsetVal('', 'trace') 808 self.fsetVal('', 'trace') 858 def verifyFtrace(self): 809 def verifyFtrace(self): 859 # files needed for any trace d 810 # files needed for any trace data 860 files = ['buffer_size_kb', 'cu 811 files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock', 861 'trace_marker 812 'trace_marker', 'trace_options', 'tracing_on'] 862 # files needed for callgraph t 813 # files needed for callgraph trace data 863 tp = self.tpath 814 tp = self.tpath 864 if(self.usecallgraph): 815 if(self.usecallgraph): 865 files += [ 816 files += [ 866 'available_fil 817 'available_filter_functions', 867 'set_ftrace_fi 818 'set_ftrace_filter', 868 'set_graph_fun 819 'set_graph_function' 869 ] 820 ] 870 for f in files: 821 for f in files: 871 if(os.path.exists(tp+f 822 if(os.path.exists(tp+f) == False): 872 return False 823 return False 873 return True 824 return True 874 def verifyKprobes(self): 825 def verifyKprobes(self): 875 # files needed for kprobes to 826 # files needed for kprobes to work 876 files = ['kprobe_events', 'eve 827 files = ['kprobe_events', 'events'] 877 tp = self.tpath 828 tp = self.tpath 878 for f in files: 829 for f in files: 879 if(os.path.exists(tp+f 830 if(os.path.exists(tp+f) == False): 880 return False 831 return False 881 return True 832 return True 882 def colorText(self, str, color=31): 833 def colorText(self, str, color=31): 883 if not self.ansi: 834 if not self.ansi: 884 return str 835 return str 885 return '\x1B[%d;40m%s\x1B[m' % 836 return '\x1B[%d;40m%s\x1B[m' % (color, str) 886 def writeDatafileHeader(self, filename 837 def writeDatafileHeader(self, filename, testdata): 887 fp = self.openlog(filename, 'w 838 fp = self.openlog(filename, 'w') 888 fp.write('%s\n%s\n# command | 839 fp.write('%s\n%s\n# command | %s\n' % (self.teststamp, self.sysstamp, self.cmdline)) 889 for test in testdata: 840 for test in testdata: 890 if 'fw' in test: 841 if 'fw' in test: 891 fw = test['fw' 842 fw = test['fw'] 892 if(fw): 843 if(fw): 893 fp.wri 844 fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) 894 if 'turbo' in test: 845 if 'turbo' in test: 895 fp.write('# tu 846 fp.write('# turbostat %s\n' % test['turbo']) 896 if 'wifi' in test: 847 if 'wifi' in test: 897 fp.write('# wi 848 fp.write('# wifi %s\n' % test['wifi']) 898 if 'netfix' in test: << 899 fp.write('# ne << 900 if test['error'] or le 849 if test['error'] or len(testdata) > 1: 901 fp.write('# en 850 fp.write('# enter_sleep_error %s\n' % test['error']) 902 return fp 851 return fp 903 def sudoUserchown(self, dir): 852 def sudoUserchown(self, dir): 904 if os.path.exists(dir) and sel 853 if os.path.exists(dir) and self.sudouser: 905 cmd = 'chown -R {0}:{0 854 cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' 906 call(cmd.format(self.s 855 call(cmd.format(self.sudouser, dir), shell=True) 907 def outputResult(self, testdata, num=0 856 def outputResult(self, testdata, num=0): 908 if not self.result: 857 if not self.result: 909 return 858 return 910 n = '' 859 n = '' 911 if num > 0: 860 if num > 0: 912 n = '%d' % num 861 n = '%d' % num 913 fp = open(self.result, 'a') 862 fp = open(self.result, 'a') 914 if 'error' in testdata: 863 if 'error' in testdata: 915 fp.write('result%s: fa 864 fp.write('result%s: fail\n' % n) 916 fp.write('error%s: %s\ 865 fp.write('error%s: %s\n' % (n, testdata['error'])) 917 else: 866 else: 918 fp.write('result%s: pa 867 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', 868 for v in ['suspend', 'resume', 'boot', 'lastinit']: 922 if v in testdata: 869 if v in testdata: 923 fp.write('%s%s 870 fp.write('%s%s: %.3f\n' % (v, n, testdata[v])) 924 for v in ['fwsuspend', 'fwresu 871 for v in ['fwsuspend', 'fwresume']: 925 if v in testdata: 872 if v in testdata: 926 fp.write('%s%s 873 fp.write('%s%s: %.3f\n' % (v, n, testdata[v] / 1000000.0)) 927 if 'bugurl' in testdata: 874 if 'bugurl' in testdata: 928 fp.write('url%s: %s\n' 875 fp.write('url%s: %s\n' % (n, testdata['bugurl'])) 929 fp.close() 876 fp.close() 930 self.sudoUserchown(self.result 877 self.sudoUserchown(self.result) 931 def configFile(self, file): 878 def configFile(self, file): 932 dir = os.path.dirname(os.path. 879 dir = os.path.dirname(os.path.realpath(__file__)) 933 if os.path.exists(file): 880 if os.path.exists(file): 934 return file 881 return file 935 elif os.path.exists(dir+'/'+fi 882 elif os.path.exists(dir+'/'+file): 936 return dir+'/'+file 883 return dir+'/'+file 937 elif os.path.exists(dir+'/conf 884 elif os.path.exists(dir+'/config/'+file): 938 return dir+'/config/'+ 885 return dir+'/config/'+file 939 return '' 886 return '' 940 def openlog(self, filename, mode): 887 def openlog(self, filename, mode): 941 isgz = self.gzip 888 isgz = self.gzip 942 if mode == 'r': 889 if mode == 'r': 943 try: 890 try: 944 with gzip.open 891 with gzip.open(filename, mode+'t') as fp: 945 test = 892 test = fp.read(64) 946 isgz = True 893 isgz = True 947 except: 894 except: 948 isgz = False 895 isgz = False 949 if isgz: 896 if isgz: 950 return gzip.open(filen 897 return gzip.open(filename, mode+'t') 951 return open(filename, mode) 898 return open(filename, mode) 952 def putlog(self, filename, text): 899 def putlog(self, filename, text): 953 with self.openlog(filename, 'a 900 with self.openlog(filename, 'a') as fp: 954 fp.write(text) 901 fp.write(text) 955 fp.close() 902 fp.close() 956 def dlog(self, text): 903 def dlog(self, text): 957 if not self.dmesgfile: << 958 return << 959 self.putlog(self.dmesgfile, '# 904 self.putlog(self.dmesgfile, '# %s\n' % text) 960 def flog(self, text): 905 def flog(self, text): 961 self.putlog(self.ftracefile, t 906 self.putlog(self.ftracefile, text) 962 def b64unzip(self, data): 907 def b64unzip(self, data): 963 try: 908 try: 964 out = codecs.decode(ba 909 out = codecs.decode(base64.b64decode(data), 'zlib').decode() 965 except: 910 except: 966 out = data 911 out = data 967 return out 912 return out 968 def b64zip(self, data): 913 def b64zip(self, data): 969 out = base64.b64encode(codecs. 914 out = base64.b64encode(codecs.encode(data.encode(), 'zlib')).decode() 970 return out 915 return out 971 def platforminfo(self, cmdafter): 916 def platforminfo(self, cmdafter): 972 # add platform info on to a co 917 # add platform info on to a completed ftrace file 973 if not os.path.exists(self.ftr 918 if not os.path.exists(self.ftracefile): 974 return False 919 return False 975 footer = '#\n' 920 footer = '#\n' 976 921 977 # add test command string line 922 # add test command string line if need be 978 if self.suspendmode == 'comman 923 if self.suspendmode == 'command' and self.testcommand: 979 footer += '# platform- 924 footer += '# platform-testcmd: %s\n' % (self.testcommand) 980 925 981 # get a list of target devices 926 # get a list of target devices from the ftrace file 982 props = dict() 927 props = dict() 983 tp = TestProps() 928 tp = TestProps() 984 tf = self.openlog(self.ftracef 929 tf = self.openlog(self.ftracefile, 'r') 985 for line in tf: 930 for line in tf: 986 if tp.stampInfo(line, 931 if tp.stampInfo(line, self): 987 continue 932 continue 988 # parse only valid lin 933 # parse only valid lines, if this is not one move on 989 m = re.match(tp.ftrace 934 m = re.match(tp.ftrace_line_fmt, line) 990 if(not m or 'device_pm 935 if(not m or 'device_pm_callback_start' not in line): 991 continue 936 continue 992 m = re.match(r'.*: (?P !! 937 m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg')); 993 if(not m): 938 if(not m): 994 continue 939 continue 995 dev = m.group('d') 940 dev = m.group('d') 996 if dev not in props: 941 if dev not in props: 997 props[dev] = D 942 props[dev] = DevProps() 998 tf.close() 943 tf.close() 999 944 1000 # now get the syspath for eac 945 # now get the syspath for each target device 1001 for dirname, dirnames, filena 946 for dirname, dirnames, filenames in os.walk('/sys/devices'): 1002 if(re.match(r'.*/powe !! 947 if(re.match('.*/power', dirname) and 'async' in filenames): 1003 dev = dirname 948 dev = dirname.split('/')[-2] 1004 if dev in pro 949 if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)): 1005 props 950 props[dev].syspath = dirname[:-6] 1006 951 1007 # now fill in the properties 952 # now fill in the properties for our target devices 1008 for dev in sorted(props): 953 for dev in sorted(props): 1009 dirname = props[dev]. 954 dirname = props[dev].syspath 1010 if not dirname or not 955 if not dirname or not os.path.exists(dirname): 1011 continue 956 continue 1012 props[dev].isasync = !! 957 with open(dirname+'/power/async') as fp: 1013 if os.path.exists(dir !! 958 text = fp.read() 1014 fp = open(dir !! 959 props[dev].isasync = False 1015 if 'enabled' !! 960 if 'enabled' in text: 1016 props 961 props[dev].isasync = True 1017 fp.close() << 1018 fields = os.listdir(d 962 fields = os.listdir(dirname) 1019 for file in ['product !! 963 if 'product' in fields: 1020 if file not i !! 964 with open(dirname+'/product', 'rb') as fp: 1021 conti !! 965 props[dev].altname = ascii(fp.read()) 1022 try: !! 966 elif 'name' in fields: 1023 with !! 967 with open(dirname+'/name', 'rb') as fp: 1024 !! 968 props[dev].altname = ascii(fp.read()) 1025 except: !! 969 elif 'model' in fields: 1026 conti !! 970 with open(dirname+'/model', 'rb') as fp: 1027 if file == 'i !! 971 props[dev].altname = ascii(fp.read()) 1028 idv, !! 972 elif 'description' in fields: 1029 try: !! 973 with open(dirname+'/description', 'rb') as fp: 1030 !! 974 props[dev].altname = ascii(fp.read()) 1031 !! 975 elif 'id' in fields: 1032 excep !! 976 with open(dirname+'/id', 'rb') as fp: 1033 !! 977 props[dev].altname = ascii(fp.read()) 1034 !! 978 elif 'idVendor' in fields and 'idProduct' in fields: 1035 props !! 979 idv, idp = '', '' 1036 break !! 980 with open(dirname+'/idVendor', 'rb') as fp: >> 981 idv = ascii(fp.read()).strip() >> 982 with open(dirname+'/idProduct', 'rb') as fp: >> 983 idp = ascii(fp.read()).strip() >> 984 props[dev].altname = '%s:%s' % (idv, idp) 1037 if props[dev].altname 985 if props[dev].altname: 1038 out = props[d 986 out = props[dev].altname.strip().replace('\n', ' ')\ 1039 .repl 987 .replace(',', ' ').replace(';', ' ') 1040 props[dev].al 988 props[dev].altname = out 1041 989 1042 # add a devinfo line to the b 990 # add a devinfo line to the bottom of ftrace 1043 out = '' 991 out = '' 1044 for dev in sorted(props): 992 for dev in sorted(props): 1045 out += props[dev].out 993 out += props[dev].out(dev) 1046 footer += '# platform-devinfo 994 footer += '# platform-devinfo: %s\n' % self.b64zip(out) 1047 995 1048 # add a line for each of thes 996 # add a line for each of these commands with their outputs 1049 for name, cmdline, info in cm 997 for name, cmdline, info in cmdafter: 1050 footer += '# platform 998 footer += '# platform-%s: %s | %s\n' % (name, cmdline, self.b64zip(info)) 1051 self.flog(footer) 999 self.flog(footer) 1052 return True 1000 return True 1053 def commonPrefix(self, list): 1001 def commonPrefix(self, list): 1054 if len(list) < 2: 1002 if len(list) < 2: 1055 return '' 1003 return '' 1056 prefix = list[0] 1004 prefix = list[0] 1057 for s in list[1:]: 1005 for s in list[1:]: 1058 while s[:len(prefix)] 1006 while s[:len(prefix)] != prefix and prefix: 1059 prefix = pref 1007 prefix = prefix[:len(prefix)-1] 1060 if not prefix: 1008 if not prefix: 1061 break 1009 break 1062 if '/' in prefix and prefix[- 1010 if '/' in prefix and prefix[-1] != '/': 1063 prefix = prefix[0:pre 1011 prefix = prefix[0:prefix.rfind('/')+1] 1064 return prefix 1012 return prefix 1065 def dictify(self, text, format): 1013 def dictify(self, text, format): 1066 out = dict() 1014 out = dict() 1067 header = True if format == 1 1015 header = True if format == 1 else False 1068 delim = ' ' if format == 1 el 1016 delim = ' ' if format == 1 else ':' 1069 for line in text.split('\n'): 1017 for line in text.split('\n'): 1070 if header: 1018 if header: 1071 header, out[' 1019 header, out['@'] = False, line 1072 continue 1020 continue 1073 line = line.strip() 1021 line = line.strip() 1074 if delim in line: 1022 if delim in line: 1075 data = line.s 1023 data = line.split(delim, 1) 1076 num = re.sear 1024 num = re.search(r'[\d]+', data[1]) 1077 if format == 1025 if format == 2 and num: 1078 out[d 1026 out[data[0].strip()] = num.group() 1079 else: 1027 else: 1080 out[d 1028 out[data[0].strip()] = data[1] 1081 return out 1029 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) 1030 def cmdinfo(self, begin, debug=False): 1097 out = [] 1031 out = [] 1098 if begin: 1032 if begin: 1099 self.cmd1 = dict() 1033 self.cmd1 = dict() 1100 for cargs in self.infocmds: 1034 for cargs in self.infocmds: 1101 delta, name, args = c !! 1035 delta, name = cargs[0], cargs[1] 1102 for i in range(len(ar !! 1036 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 1037 if not cmdpath or (begin and not delta): 1107 continue 1038 continue 1108 self.dlog('[%s]' % cm 1039 self.dlog('[%s]' % cmdline) 1109 try: 1040 try: 1110 fp = Popen([c !! 1041 fp = Popen([cmdpath]+cargs[3:], stdout=PIPE, stderr=PIPE).stdout 1111 info = ascii( 1042 info = ascii(fp.read()).strip() 1112 fp.close() 1043 fp.close() 1113 except: 1044 except: 1114 continue 1045 continue 1115 if not debug and begi 1046 if not debug and begin: 1116 self.cmd1[nam 1047 self.cmd1[name] = self.dictify(info, delta) 1117 elif not debug and de 1048 elif not debug and delta and name in self.cmd1: 1118 before, after 1049 before, after = self.cmd1[name], self.dictify(info, delta) 1119 dinfo = ('\t% !! 1050 dinfo = ('\t%s\n' % before['@']) if '@' in before else '' 1120 prefix = self 1051 prefix = self.commonPrefix(list(before.keys())) 1121 for key in so 1052 for key in sorted(before): 1122 if ke 1053 if key in after and before[key] != after[key]: 1123 1054 title = key.replace(prefix, '') 1124 1055 if delta == 2: 1125 1056 dinfo += '\t%s : %s -> %s\n' % \ 1126 1057 (title, before[key].strip(), after[key].strip()) 1127 1058 else: 1128 1059 dinfo += '%10s (start) : %s\n%10s (after) : %s\n' % \ 1129 1060 (title, before[key], title, after[key]) 1130 dinfo = '\tno 1061 dinfo = '\tnothing changed' if not dinfo else dinfo.rstrip() 1131 out.append((n 1062 out.append((name, cmdline, dinfo)) 1132 else: 1063 else: 1133 out.append((n 1064 out.append((name, cmdline, '\tnothing' if not info else info)) 1134 return out 1065 return out 1135 def testVal(self, file, fmt='basic', 1066 def testVal(self, file, fmt='basic', value=''): 1136 if file == 'restoreall': 1067 if file == 'restoreall': 1137 for f in self.cfgdef: 1068 for f in self.cfgdef: 1138 if os.path.ex 1069 if os.path.exists(f): 1139 fp = 1070 fp = open(f, 'w') 1140 fp.wr 1071 fp.write(self.cfgdef[f]) 1141 fp.cl 1072 fp.close() 1142 self.cfgdef = dict() 1073 self.cfgdef = dict() 1143 elif value and os.path.exists 1074 elif value and os.path.exists(file): 1144 fp = open(file, 'r+') 1075 fp = open(file, 'r+') 1145 if fmt == 'radio': 1076 if fmt == 'radio': 1146 m = re.match( !! 1077 m = re.match('.*\[(?P<v>.*)\].*', fp.read()) 1147 if m: 1078 if m: 1148 self. 1079 self.cfgdef[file] = m.group('v') 1149 elif fmt == 'acpi': 1080 elif fmt == 'acpi': 1150 line = fp.rea 1081 line = fp.read().strip().split('\n')[-1] 1151 m = re.match( !! 1082 m = re.match('.* (?P<v>[0-9A-Fx]*) .*', line) 1152 if m: 1083 if m: 1153 self. 1084 self.cfgdef[file] = m.group('v') 1154 else: 1085 else: 1155 self.cfgdef[f 1086 self.cfgdef[file] = fp.read().strip() 1156 fp.write(value) 1087 fp.write(value) 1157 fp.close() 1088 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): 1089 def haveTurbostat(self): 1168 if not self.tstat: 1090 if not self.tstat: 1169 return False 1091 return False 1170 cmd = self.getExec('turbostat 1092 cmd = self.getExec('turbostat') 1171 if not cmd: 1093 if not cmd: 1172 return False 1094 return False 1173 fp = Popen([cmd, '-v'], stdou 1095 fp = Popen([cmd, '-v'], stdout=PIPE, stderr=PIPE).stderr 1174 out = ascii(fp.read()).strip( 1096 out = ascii(fp.read()).strip() 1175 fp.close() 1097 fp.close() 1176 if re.match(r'turbostat versi !! 1098 if re.match('turbostat version .*', out): 1177 self.vprint(out) 1099 self.vprint(out) 1178 return True 1100 return True 1179 return False 1101 return False 1180 def turbostat(self, s0ixready): !! 1102 def turbostat(self): 1181 cmd = self.getExec('turbostat 1103 cmd = self.getExec('turbostat') 1182 rawout = keyline = valline = 1104 rawout = keyline = valline = '' 1183 fullcmd = '%s -q -S echo free 1105 fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile) 1184 fp = Popen(['sh', '-c', fullc !! 1106 fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE).stderr 1185 for line in fp.stderr: !! 1107 for line in fp: 1186 line = ascii(line) 1108 line = ascii(line) 1187 rawout += line 1109 rawout += line 1188 if keyline and vallin 1110 if keyline and valline: 1189 continue 1111 continue 1190 if re.match(r'(?i)Avg !! 1112 if re.match('(?i)Avg_MHz.*', line): 1191 keyline = lin 1113 keyline = line.strip().split() 1192 elif keyline: 1114 elif keyline: 1193 valline = lin 1115 valline = line.strip().split() 1194 fp.wait() !! 1116 fp.close() 1195 if not keyline or not valline 1117 if not keyline or not valline or len(keyline) != len(valline): 1196 errmsg = 'unrecognize 1118 errmsg = 'unrecognized turbostat output:\n'+rawout.strip() 1197 self.vprint(errmsg) 1119 self.vprint(errmsg) 1198 if not self.verbose: 1120 if not self.verbose: 1199 pprint(errmsg 1121 pprint(errmsg) 1200 return (fp.returncode !! 1122 return '' 1201 if self.verbose: 1123 if self.verbose: 1202 pprint(rawout.strip() 1124 pprint(rawout.strip()) 1203 out = [] 1125 out = [] 1204 for key in keyline: 1126 for key in keyline: 1205 idx = keyline.index(k 1127 idx = keyline.index(key) 1206 val = valline[idx] 1128 val = valline[idx] 1207 if key == 'SYS%LPI' a << 1208 continue << 1209 out.append('%s=%s' % 1129 out.append('%s=%s' % (key, val)) 1210 return (fp.returncode, '|'.jo !! 1130 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): 1131 def wifiDetails(self, dev): 1220 try: 1132 try: 1221 info = open('/sys/cla 1133 info = open('/sys/class/net/%s/device/uevent' % dev, 'r').read().strip() 1222 except: 1134 except: 1223 return dev 1135 return dev 1224 vals = [dev] 1136 vals = [dev] 1225 for prop in info.split('\n'): 1137 for prop in info.split('\n'): 1226 if prop.startswith('D 1138 if prop.startswith('DRIVER=') or prop.startswith('PCI_ID='): 1227 vals.append(p 1139 vals.append(prop.split('=')[-1]) 1228 return ':'.join(vals) 1140 return ':'.join(vals) 1229 def checkWifi(self, dev=''): 1141 def checkWifi(self, dev=''): 1230 try: 1142 try: 1231 w = open('/proc/net/w 1143 w = open('/proc/net/wireless', 'r').read().strip() 1232 except: 1144 except: 1233 return '' 1145 return '' 1234 for line in reversed(w.split( 1146 for line in reversed(w.split('\n')): 1235 m = re.match(r' *(?P< !! 1147 m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', w.split('\n')[-1]) 1236 if not m or (dev and 1148 if not m or (dev and dev != m.group('dev')): 1237 continue 1149 continue 1238 return m.group('dev') 1150 return m.group('dev') 1239 return '' 1151 return '' 1240 def pollWifi(self, dev, timeout=10): !! 1152 def pollWifi(self, dev, timeout=60): 1241 start = time.time() 1153 start = time.time() 1242 while (time.time() - start) < 1154 while (time.time() - start) < timeout: 1243 w = self.checkWifi(de 1155 w = self.checkWifi(dev) 1244 if w: 1156 if w: 1245 return '%s re 1157 return '%s reconnected %.2f' % \ 1246 (self 1158 (self.wifiDetails(dev), max(0, time.time() - start)) 1247 time.sleep(0.01) 1159 time.sleep(0.01) 1248 return '%s timeout %d' % (sel 1160 return '%s timeout %d' % (self.wifiDetails(dev), timeout) 1249 def errorSummary(self, errinfo, msg): 1161 def errorSummary(self, errinfo, msg): 1250 found = False 1162 found = False 1251 for entry in errinfo: 1163 for entry in errinfo: 1252 if re.match(entry['ma 1164 if re.match(entry['match'], msg): 1253 entry['count' 1165 entry['count'] += 1 1254 if self.hostn 1166 if self.hostname not in entry['urls']: 1255 entry 1167 entry['urls'][self.hostname] = [self.htmlfile] 1256 elif self.htm 1168 elif self.htmlfile not in entry['urls'][self.hostname]: 1257 entry 1169 entry['urls'][self.hostname].append(self.htmlfile) 1258 found = True 1170 found = True 1259 break 1171 break 1260 if found: 1172 if found: 1261 return 1173 return 1262 arr = msg.split() 1174 arr = msg.split() 1263 for j in range(len(arr)): 1175 for j in range(len(arr)): 1264 if re.match(r'^[0-9,\ !! 1176 if re.match('^[0-9,\-\.]*$', arr[j]): 1265 arr[j] = r'[0 !! 1177 arr[j] = '[0-9,\-\.]*' 1266 else: 1178 else: 1267 arr[j] = arr[ 1179 arr[j] = arr[j]\ 1268 .repl !! 1180 .replace('\\', '\\\\').replace(']', '\]').replace('[', '\[')\ 1269 .repl !! 1181 .replace('.', '\.').replace('+', '\+').replace('*', '\*')\ 1270 .repl !! 1182 .replace('(', '\(').replace(')', '\)').replace('}', '\}')\ 1271 .repl !! 1183 .replace('{', '\{') 1272 mstr = ' *'.join(arr) 1184 mstr = ' *'.join(arr) 1273 entry = { 1185 entry = { 1274 'line': msg, 1186 'line': msg, 1275 'match': mstr, 1187 'match': mstr, 1276 'count': 1, 1188 'count': 1, 1277 'urls': {self.hostnam 1189 'urls': {self.hostname: [self.htmlfile]} 1278 } 1190 } 1279 errinfo.append(entry) 1191 errinfo.append(entry) 1280 def multistat(self, start, idx, finis 1192 def multistat(self, start, idx, finish): 1281 if 'time' in self.multitest: 1193 if 'time' in self.multitest: 1282 id = '%d Duration=%dm 1194 id = '%d Duration=%dmin' % (idx+1, self.multitest['time']) 1283 else: 1195 else: 1284 id = '%d/%d' % (idx+1 1196 id = '%d/%d' % (idx+1, self.multitest['count']) 1285 t = time.time() 1197 t = time.time() 1286 if 'start' not in self.multit 1198 if 'start' not in self.multitest: 1287 self.multitest['start 1199 self.multitest['start'] = self.multitest['last'] = t 1288 self.multitest['total 1200 self.multitest['total'] = 0.0 1289 pprint('TEST (%s) STA 1201 pprint('TEST (%s) START' % id) 1290 return 1202 return 1291 dt = t - self.multitest['last 1203 dt = t - self.multitest['last'] 1292 if not start: 1204 if not start: 1293 if idx == 0 and self. 1205 if idx == 0 and self.multitest['delay'] > 0: 1294 self.multites 1206 self.multitest['total'] += self.multitest['delay'] 1295 pprint('TEST (%s) COM 1207 pprint('TEST (%s) COMPLETE -- Duration %.1fs' % (id, dt)) 1296 return 1208 return 1297 self.multitest['total'] += dt 1209 self.multitest['total'] += dt 1298 self.multitest['last'] = t 1210 self.multitest['last'] = t 1299 avg = self.multitest['total'] 1211 avg = self.multitest['total'] / idx 1300 if 'time' in self.multitest: 1212 if 'time' in self.multitest: 1301 left = finish - datet 1213 left = finish - datetime.now() 1302 left -= timedelta(mic 1214 left -= timedelta(microseconds=left.microseconds) 1303 else: 1215 else: 1304 left = timedelta(seco 1216 left = timedelta(seconds=((self.multitest['count'] - idx) * int(avg))) 1305 pprint('TEST (%s) START - Avg 1217 pprint('TEST (%s) START - Avg Duration %.1fs, Time left %s' % \ 1306 (id, avg, str(left))) 1218 (id, avg, str(left))) 1307 def multiinit(self, c, d): 1219 def multiinit(self, c, d): 1308 sz, unit = 'count', 'm' 1220 sz, unit = 'count', 'm' 1309 if c.endswith('d') or c.endsw 1221 if c.endswith('d') or c.endswith('h') or c.endswith('m'): 1310 sz, unit, c = 'time', 1222 sz, unit, c = 'time', c[-1], c[:-1] 1311 self.multitest['run'] = True 1223 self.multitest['run'] = True 1312 self.multitest[sz] = getArgIn 1224 self.multitest[sz] = getArgInt('multi: n d (exec count)', c, 1, 1000000, False) 1313 self.multitest['delay'] = get 1225 self.multitest['delay'] = getArgInt('multi: n d (delay between tests)', d, 0, 3600, False) 1314 if unit == 'd': 1226 if unit == 'd': 1315 self.multitest[sz] *= 1227 self.multitest[sz] *= 1440 1316 elif unit == 'h': 1228 elif unit == 'h': 1317 self.multitest[sz] *= 1229 self.multitest[sz] *= 60 1318 def displayControl(self, cmd): 1230 def displayControl(self, cmd): 1319 xset, ret = 'timeout 10 xset 1231 xset, ret = 'timeout 10 xset -d :0.0 {0}', 0 1320 if self.sudouser: 1232 if self.sudouser: 1321 xset = 'sudo -u %s %s 1233 xset = 'sudo -u %s %s' % (self.sudouser, xset) 1322 if cmd == 'init': 1234 if cmd == 'init': 1323 ret = call(xset.forma 1235 ret = call(xset.format('dpms 0 0 0'), shell=True) 1324 if not ret: 1236 if not ret: 1325 ret = call(xs 1237 ret = call(xset.format('s off'), shell=True) 1326 elif cmd == 'reset': 1238 elif cmd == 'reset': 1327 ret = call(xset.forma 1239 ret = call(xset.format('s reset'), shell=True) 1328 elif cmd in ['on', 'off', 'st 1240 elif cmd in ['on', 'off', 'standby', 'suspend']: 1329 b4 = self.displayCont 1241 b4 = self.displayControl('stat') 1330 ret = call(xset.forma 1242 ret = call(xset.format('dpms force %s' % cmd), shell=True) 1331 if not ret: 1243 if not ret: 1332 curr = self.d 1244 curr = self.displayControl('stat') 1333 self.vprint(' 1245 self.vprint('Display Switched: %s -> %s' % (b4, curr)) 1334 if curr != cm 1246 if curr != cmd: 1335 self. 1247 self.vprint('WARNING: Display failed to change to %s' % cmd) 1336 if ret: 1248 if ret: 1337 self.vprint(' 1249 self.vprint('WARNING: Display failed to change to %s with xset' % cmd) 1338 return ret 1250 return ret 1339 elif cmd == 'stat': 1251 elif cmd == 'stat': 1340 fp = Popen(xset.forma 1252 fp = Popen(xset.format('q').split(' '), stdout=PIPE).stdout 1341 ret = 'unknown' 1253 ret = 'unknown' 1342 for line in fp: 1254 for line in fp: 1343 m = re.match( !! 1255 m = re.match('[\s]*Monitor is (?P<m>.*)', ascii(line)) 1344 if(m and len( 1256 if(m and len(m.group('m')) >= 2): 1345 out = 1257 out = m.group('m').lower() 1346 ret = 1258 ret = out[3:] if out[0:2] == 'in' else out 1347 break 1259 break 1348 fp.close() 1260 fp.close() 1349 return ret 1261 return ret 1350 def setRuntimeSuspend(self, before=Tr 1262 def setRuntimeSuspend(self, before=True): 1351 if before: 1263 if before: 1352 # runtime suspend dis 1264 # runtime suspend disable or enable 1353 if self.rs > 0: 1265 if self.rs > 0: 1354 self.rstgt, s 1266 self.rstgt, self.rsval, self.rsdir = 'on', 'auto', 'enabled' 1355 else: 1267 else: 1356 self.rstgt, s 1268 self.rstgt, self.rsval, self.rsdir = 'auto', 'on', 'disabled' 1357 pprint('CONFIGURING R 1269 pprint('CONFIGURING RUNTIME SUSPEND...') 1358 self.rslist = deviceI 1270 self.rslist = deviceInfo(self.rstgt) 1359 for i in self.rslist: 1271 for i in self.rslist: 1360 self.setVal(s 1272 self.setVal(self.rsval, i) 1361 pprint('runtime suspe 1273 pprint('runtime suspend %s on all devices (%d changed)' % (self.rsdir, len(self.rslist))) 1362 pprint('waiting 5 sec 1274 pprint('waiting 5 seconds...') 1363 time.sleep(5) 1275 time.sleep(5) 1364 else: 1276 else: 1365 # runtime suspend re- 1277 # runtime suspend re-enable or re-disable 1366 for i in self.rslist: 1278 for i in self.rslist: 1367 self.setVal(s 1279 self.setVal(self.rstgt, i) 1368 pprint('runtime suspe 1280 pprint('runtime suspend settings restored on %d devices' % len(self.rslist)) 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 1281 1384 sysvals = SystemValues() 1282 sysvals = SystemValues() 1385 switchvalues = ['enable', 'disable', 'on', 'o 1283 switchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0'] 1386 switchoff = ['disable', 'off', 'false', '0'] 1284 switchoff = ['disable', 'off', 'false', '0'] 1387 suspendmodename = { 1285 suspendmodename = { 1388 'standby': 'standby (S1)', !! 1286 'freeze': 'Freeze (S0)', 1389 'freeze': 'freeze (S2idle)', !! 1287 'standby': 'Standby (S1)', 1390 'mem': 'suspend (S3)', !! 1288 'mem': 'Suspend (S3)', 1391 'disk': 'hibernate (S4)' !! 1289 'disk': 'Hibernate (S4)' 1392 } 1290 } 1393 1291 1394 # Class: DevProps 1292 # Class: DevProps 1395 # Description: 1293 # Description: 1396 # Simple class which holds property va 1294 # Simple class which holds property values collected 1397 # for all the devices used in the time 1295 # for all the devices used in the timeline. 1398 class DevProps: 1296 class DevProps: 1399 def __init__(self): 1297 def __init__(self): 1400 self.syspath = '' 1298 self.syspath = '' 1401 self.altname = '' 1299 self.altname = '' 1402 self.isasync = True 1300 self.isasync = True 1403 self.xtraclass = '' 1301 self.xtraclass = '' 1404 self.xtrainfo = '' 1302 self.xtrainfo = '' 1405 def out(self, dev): 1303 def out(self, dev): 1406 return '%s,%s,%d;' % (dev, se 1304 return '%s,%s,%d;' % (dev, self.altname, self.isasync) 1407 def debug(self, dev): 1305 def debug(self, dev): 1408 pprint('%s:\n\taltname = %s\n 1306 pprint('%s:\n\taltname = %s\n\t async = %s' % (dev, self.altname, self.isasync)) 1409 def altName(self, dev): 1307 def altName(self, dev): 1410 if not self.altname or self.a 1308 if not self.altname or self.altname == dev: 1411 return dev 1309 return dev 1412 return '%s [%s]' % (self.altn 1310 return '%s [%s]' % (self.altname, dev) 1413 def xtraClass(self): 1311 def xtraClass(self): 1414 if self.xtraclass: 1312 if self.xtraclass: 1415 return ' '+self.xtrac 1313 return ' '+self.xtraclass 1416 if not self.isasync: 1314 if not self.isasync: 1417 return ' sync' 1315 return ' sync' 1418 return '' 1316 return '' 1419 def xtraInfo(self): 1317 def xtraInfo(self): 1420 if self.xtraclass: 1318 if self.xtraclass: 1421 return ' '+self.xtrac 1319 return ' '+self.xtraclass 1422 if self.isasync: 1320 if self.isasync: 1423 return ' (async)' 1321 return ' (async)' 1424 return ' (sync)' 1322 return ' (sync)' 1425 1323 1426 # Class: DeviceNode 1324 # Class: DeviceNode 1427 # Description: 1325 # Description: 1428 # A container used to create a device 1326 # A container used to create a device hierachy, with a single root node 1429 # and a tree of child nodes. Used by D 1327 # and a tree of child nodes. Used by Data.deviceTopology() 1430 class DeviceNode: 1328 class DeviceNode: 1431 def __init__(self, nodename, nodedept 1329 def __init__(self, nodename, nodedepth): 1432 self.name = nodename 1330 self.name = nodename 1433 self.children = [] 1331 self.children = [] 1434 self.depth = nodedepth 1332 self.depth = nodedepth 1435 1333 1436 # Class: Data 1334 # Class: Data 1437 # Description: 1335 # Description: 1438 # The primary container for suspend/re 1336 # The primary container for suspend/resume test data. There is one for 1439 # each test run. The data is organized 1337 # each test run. The data is organized into a cronological hierarchy: 1440 # Data.dmesg { 1338 # Data.dmesg { 1441 # phases { 1339 # phases { 1442 # 10 sequential, non-ov 1340 # 10 sequential, non-overlapping phases of S/R 1443 # contents: times for p 1341 # contents: times for phase start/end, order/color data for html 1444 # devlist { 1342 # devlist { 1445 # device callba 1343 # device callback or action list for this phase 1446 # device { 1344 # device { 1447 # a sin 1345 # a single device callback or generic action 1448 # conte 1346 # contents: start/stop times, pid/cpu/driver info 1449 # 1347 # parents/children, html id for timeline/callgraph 1450 # 1348 # optionally includes an ftrace callgraph 1451 # 1349 # optionally includes dev/ps data 1452 # } 1350 # } 1453 # } 1351 # } 1454 # } 1352 # } 1455 # } 1353 # } 1456 # 1354 # 1457 class Data: 1355 class Data: 1458 phasedef = { 1356 phasedef = { 1459 'suspend_prepare': {'order': 1357 'suspend_prepare': {'order': 0, 'color': '#CCFFCC'}, 1460 'suspend': {'order': 1358 'suspend': {'order': 1, 'color': '#88FF88'}, 1461 'suspend_late': {'order': 1359 'suspend_late': {'order': 2, 'color': '#00AA00'}, 1462 'suspend_noirq': {'order': 1360 'suspend_noirq': {'order': 3, 'color': '#008888'}, 1463 'suspend_machine': {'order': 1361 'suspend_machine': {'order': 4, 'color': '#0000FF'}, 1464 'resume_machine': {'order': 1362 'resume_machine': {'order': 5, 'color': '#FF0000'}, 1465 'resume_noirq': {'order': 1363 'resume_noirq': {'order': 6, 'color': '#FF9900'}, 1466 'resume_early': {'order': 1364 'resume_early': {'order': 7, 'color': '#FFCC00'}, 1467 'resume': {'order': 1365 'resume': {'order': 8, 'color': '#FFFF88'}, 1468 'resume_complete': {'order': 1366 'resume_complete': {'order': 9, 'color': '#FFFFCC'}, 1469 } 1367 } 1470 errlist = { 1368 errlist = { 1471 'HWERROR' : r'.*\[ *Hardware 1369 'HWERROR' : r'.*\[ *Hardware Error *\].*', 1472 'FWBUG' : r'.*\[ *Firmware 1370 'FWBUG' : r'.*\[ *Firmware Bug *\].*', 1473 'TASKFAIL': r'.*Freezing .*af << 1474 'BUG' : r'(?i).*\bBUG\b.* 1371 'BUG' : r'(?i).*\bBUG\b.*', 1475 'ERROR' : r'(?i).*\bERROR\b 1372 'ERROR' : r'(?i).*\bERROR\b.*', 1476 'WARNING' : r'(?i).*\bWARNING 1373 'WARNING' : r'(?i).*\bWARNING\b.*', 1477 'FAULT' : r'(?i).*\bFAULT\b 1374 'FAULT' : r'(?i).*\bFAULT\b.*', 1478 'FAIL' : r'(?i).*\bFAILED\ 1375 'FAIL' : r'(?i).*\bFAILED\b.*', 1479 'INVALID' : r'(?i).*\bINVALID 1376 'INVALID' : r'(?i).*\bINVALID\b.*', 1480 'CRASH' : r'(?i).*\bCRASHED 1377 'CRASH' : r'(?i).*\bCRASHED\b.*', 1481 'TIMEOUT' : r'(?i).*\bTIMEOUT 1378 'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*', 1482 'ABORT' : r'(?i).*\bABORT\b << 1483 'IRQ' : r'.*\bgenirq: .*' 1379 'IRQ' : r'.*\bgenirq: .*', >> 1380 'TASKFAIL': r'.*Freezing of tasks *.*', 1484 'ACPI' : r'.*\bACPI *(?P<b 1381 'ACPI' : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*', 1485 'DISKFULL': r'.*\bNo space le 1382 'DISKFULL': r'.*\bNo space left on device.*', 1486 'USBERR' : r'.*usb .*device 1383 'USBERR' : r'.*usb .*device .*, error [0-9-]*', 1487 'ATAERR' : r' *ata[0-9\.]*: 1384 'ATAERR' : r' *ata[0-9\.]*: .*failed.*', 1488 'MEIERR' : r' *mei.*: .*fail 1385 'MEIERR' : r' *mei.*: .*failed.*', 1489 'TPMERR' : r'(?i) *tpm *tpm[ 1386 'TPMERR' : r'(?i) *tpm *tpm[0-9]*: .*error.*', 1490 } 1387 } 1491 def __init__(self, num): 1388 def __init__(self, num): 1492 idchar = 'abcdefghij' 1389 idchar = 'abcdefghij' 1493 self.start = 0.0 # test start 1390 self.start = 0.0 # test start 1494 self.end = 0.0 # test end 1391 self.end = 0.0 # test end 1495 self.hwstart = 0 # rtc test s 1392 self.hwstart = 0 # rtc test start 1496 self.hwend = 0 # rtc test e 1393 self.hwend = 0 # rtc test end 1497 self.tSuspended = 0.0 # low-l 1394 self.tSuspended = 0.0 # low-level suspend start 1498 self.tResumed = 0.0 # low-l 1395 self.tResumed = 0.0 # low-level resume start 1499 self.tKernSus = 0.0 # kerne 1396 self.tKernSus = 0.0 # kernel level suspend start 1500 self.tKernRes = 0.0 # kerne 1397 self.tKernRes = 0.0 # kernel level resume end 1501 self.fwValid = False # is fi 1398 self.fwValid = False # is firmware data available 1502 self.fwSuspend = 0 # time 1399 self.fwSuspend = 0 # time spent in firmware suspend 1503 self.fwResume = 0 # time 1400 self.fwResume = 0 # time spent in firmware resume 1504 self.html_device_id = 0 1401 self.html_device_id = 0 1505 self.stamp = 0 1402 self.stamp = 0 1506 self.outfile = '' 1403 self.outfile = '' 1507 self.kerror = False 1404 self.kerror = False 1508 self.wifi = dict() 1405 self.wifi = dict() 1509 self.turbostat = 0 1406 self.turbostat = 0 1510 self.enterfail = '' 1407 self.enterfail = '' 1511 self.currphase = '' 1408 self.currphase = '' 1512 self.pstl = dict() # proce 1409 self.pstl = dict() # process timeline 1513 self.testnumber = num 1410 self.testnumber = num 1514 self.idstr = idchar[num] 1411 self.idstr = idchar[num] 1515 self.dmesgtext = [] # dmesg 1412 self.dmesgtext = [] # dmesg text file in memory 1516 self.dmesg = dict() # root 1413 self.dmesg = dict() # root data structure 1517 self.errorinfo = {'suspend':[ 1414 self.errorinfo = {'suspend':[],'resume':[]} 1518 self.tLow = [] # time 1415 self.tLow = [] # time spent in low-level suspends (standby/freeze) 1519 self.devpids = [] 1416 self.devpids = [] 1520 self.devicegroups = 0 1417 self.devicegroups = 0 1521 def sortedPhases(self): 1418 def sortedPhases(self): 1522 return sorted(self.dmesg, key 1419 return sorted(self.dmesg, key=lambda k:self.dmesg[k]['order']) 1523 def initDevicegroups(self): 1420 def initDevicegroups(self): 1524 # called when phases are all 1421 # called when phases are all finished being added 1525 for phase in sorted(self.dmes 1422 for phase in sorted(self.dmesg.keys()): 1526 if '*' in phase: 1423 if '*' in phase: 1527 p = phase.spl 1424 p = phase.split('*') 1528 pnew = '%s%d' 1425 pnew = '%s%d' % (p[0], len(p)) 1529 self.dmesg[pn 1426 self.dmesg[pnew] = self.dmesg.pop(phase) 1530 self.devicegroups = [] 1427 self.devicegroups = [] 1531 for phase in self.sortedPhase 1428 for phase in self.sortedPhases(): 1532 self.devicegroups.app 1429 self.devicegroups.append([phase]) 1533 def nextPhase(self, phase, offset): 1430 def nextPhase(self, phase, offset): 1534 order = self.dmesg[phase]['or 1431 order = self.dmesg[phase]['order'] + offset 1535 for p in self.dmesg: 1432 for p in self.dmesg: 1536 if self.dmesg[p]['ord 1433 if self.dmesg[p]['order'] == order: 1537 return p 1434 return p 1538 return '' 1435 return '' 1539 def lastPhase(self, depth=1): 1436 def lastPhase(self, depth=1): 1540 plist = self.sortedPhases() 1437 plist = self.sortedPhases() 1541 if len(plist) < depth: 1438 if len(plist) < depth: 1542 return '' 1439 return '' 1543 return plist[-1*depth] 1440 return plist[-1*depth] 1544 def turbostatInfo(self): 1441 def turbostatInfo(self): 1545 tp = TestProps() 1442 tp = TestProps() 1546 out = {'syslpi':'N/A','pkgpc1 1443 out = {'syslpi':'N/A','pkgpc10':'N/A'} 1547 for line in self.dmesgtext: 1444 for line in self.dmesgtext: 1548 m = re.match(tp.tstat 1445 m = re.match(tp.tstatfmt, line) 1549 if not m: 1446 if not m: 1550 continue 1447 continue 1551 for i in m.group('t') 1448 for i in m.group('t').split('|'): 1552 if 'SYS%LPI' 1449 if 'SYS%LPI' in i: 1553 out[' 1450 out['syslpi'] = i.split('=')[-1]+'%' 1554 elif 'pc10' i 1451 elif 'pc10' in i: 1555 out[' 1452 out['pkgpc10'] = i.split('=')[-1]+'%' 1556 break 1453 break 1557 return out 1454 return out 1558 def extractErrorInfo(self): 1455 def extractErrorInfo(self): 1559 lf = self.dmesgtext 1456 lf = self.dmesgtext 1560 if len(self.dmesgtext) < 1 an 1457 if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 1561 lf = sysvals.openlog( 1458 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 1562 i = 0 1459 i = 0 1563 tp = TestProps() 1460 tp = TestProps() 1564 list = [] 1461 list = [] 1565 for line in lf: 1462 for line in lf: 1566 i += 1 1463 i += 1 1567 if tp.stampInfo(line, 1464 if tp.stampInfo(line, sysvals): 1568 continue 1465 continue 1569 m = re.match(r'[ \t]* !! 1466 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 1570 if not m: 1467 if not m: 1571 continue 1468 continue 1572 t = float(m.group('kt 1469 t = float(m.group('ktime')) 1573 if t < self.start or 1470 if t < self.start or t > self.end: 1574 continue 1471 continue 1575 dir = 'suspend' if t 1472 dir = 'suspend' if t < self.tSuspended else 'resume' 1576 msg = m.group('msg') 1473 msg = m.group('msg') 1577 if re.match(r'capabil !! 1474 if re.match('capability: warning: .*', msg): 1578 continue 1475 continue 1579 for err in self.errli 1476 for err in self.errlist: 1580 if re.match(s 1477 if re.match(self.errlist[err], msg): 1581 list. 1478 list.append((msg, err, dir, t, i, i)) 1582 self. 1479 self.kerror = True 1583 break 1480 break 1584 tp.msglist = [] 1481 tp.msglist = [] 1585 for msg, type, dir, t, idx1, 1482 for msg, type, dir, t, idx1, idx2 in list: 1586 tp.msglist.append(msg 1483 tp.msglist.append(msg) 1587 self.errorinfo[dir].a 1484 self.errorinfo[dir].append((type, t, idx1, idx2)) 1588 if self.kerror: 1485 if self.kerror: 1589 sysvals.dmesglog = Tr 1486 sysvals.dmesglog = True 1590 if len(self.dmesgtext) < 1 an 1487 if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 1591 lf.close() 1488 lf.close() 1592 return tp 1489 return tp 1593 def setStart(self, time, msg=''): 1490 def setStart(self, time, msg=''): 1594 self.start = time 1491 self.start = time 1595 if msg: 1492 if msg: 1596 try: 1493 try: 1597 self.hwstart 1494 self.hwstart = datetime.strptime(msg, sysvals.tmstart) 1598 except: 1495 except: 1599 self.hwstart 1496 self.hwstart = 0 1600 def setEnd(self, time, msg=''): 1497 def setEnd(self, time, msg=''): 1601 self.end = time 1498 self.end = time 1602 if msg: 1499 if msg: 1603 try: 1500 try: 1604 self.hwend = 1501 self.hwend = datetime.strptime(msg, sysvals.tmend) 1605 except: 1502 except: 1606 self.hwend = 1503 self.hwend = 0 1607 def isTraceEventOutsideDeviceCalls(se 1504 def isTraceEventOutsideDeviceCalls(self, pid, time): 1608 for phase in self.sortedPhase 1505 for phase in self.sortedPhases(): 1609 list = self.dmesg[pha 1506 list = self.dmesg[phase]['list'] 1610 for dev in list: 1507 for dev in list: 1611 d = list[dev] 1508 d = list[dev] 1612 if(d['pid'] = 1509 if(d['pid'] == pid and time >= d['start'] and 1613 time 1510 time < d['end']): 1614 retur 1511 return False 1615 return True 1512 return True 1616 def sourcePhase(self, start): 1513 def sourcePhase(self, start): 1617 for phase in self.sortedPhase 1514 for phase in self.sortedPhases(): 1618 if 'machine' in phase 1515 if 'machine' in phase: 1619 continue 1516 continue 1620 pend = self.dmesg[pha 1517 pend = self.dmesg[phase]['end'] 1621 if start <= pend: 1518 if start <= pend: 1622 return phase 1519 return phase 1623 return 'resume_complete' if ' !! 1520 return 'resume_complete' 1624 def sourceDevice(self, phaselist, sta 1521 def sourceDevice(self, phaselist, start, end, pid, type): 1625 tgtdev = '' 1522 tgtdev = '' 1626 for phase in phaselist: 1523 for phase in phaselist: 1627 list = self.dmesg[pha 1524 list = self.dmesg[phase]['list'] 1628 for devname in list: 1525 for devname in list: 1629 dev = list[de 1526 dev = list[devname] 1630 # pid must ma 1527 # pid must match 1631 if dev['pid'] 1528 if dev['pid'] != pid: 1632 conti 1529 continue 1633 devS = dev['s 1530 devS = dev['start'] 1634 devE = dev['e 1531 devE = dev['end'] 1635 if type == 'd 1532 if type == 'device': 1636 # dev 1533 # device target event is entirely inside the source boundary 1637 if(st 1534 if(start < devS or start >= devE or end <= devS or end > devE): 1638 1535 continue 1639 elif type == 1536 elif type == 'thread': 1640 # thr 1537 # thread target event will expand the source boundary 1641 if st 1538 if start < devS: 1642 1539 dev['start'] = start 1643 if en 1540 if end > devE: 1644 1541 dev['end'] = end 1645 tgtdev = dev 1542 tgtdev = dev 1646 break 1543 break 1647 return tgtdev 1544 return tgtdev 1648 def addDeviceFunctionCall(self, displ 1545 def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata): 1649 # try to place the call in a 1546 # try to place the call in a device 1650 phases = self.sortedPhases() 1547 phases = self.sortedPhases() 1651 tgtdev = self.sourceDevice(ph 1548 tgtdev = self.sourceDevice(phases, start, end, pid, 'device') 1652 # calls with device pids that 1549 # calls with device pids that occur outside device bounds are dropped 1653 # TODO: include these somehow 1550 # TODO: include these somehow 1654 if not tgtdev and pid in self 1551 if not tgtdev and pid in self.devpids: 1655 return False 1552 return False 1656 # try to place the call in a 1553 # try to place the call in a thread 1657 if not tgtdev: 1554 if not tgtdev: 1658 tgtdev = self.sourceD 1555 tgtdev = self.sourceDevice(phases, start, end, pid, 'thread') 1659 # create new thread blocks, e 1556 # create new thread blocks, expand as new calls are found 1660 if not tgtdev: 1557 if not tgtdev: 1661 if proc == '<...>': 1558 if proc == '<...>': 1662 threadname = 1559 threadname = 'kthread-%d' % (pid) 1663 else: 1560 else: 1664 threadname = 1561 threadname = '%s-%d' % (proc, pid) 1665 tgtphase = self.sourc 1562 tgtphase = self.sourcePhase(start) 1666 if not tgtphase: << 1667 return False << 1668 self.newAction(tgtpha 1563 self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '') 1669 return self.addDevice 1564 return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata) 1670 # this should not happen 1565 # this should not happen 1671 if not tgtdev: 1566 if not tgtdev: 1672 sysvals.vprint('[%f - 1567 sysvals.vprint('[%f - %f] %s-%d %s %s %s' % \ 1673 (start, end, 1568 (start, end, proc, pid, kprobename, cdata, rdata)) 1674 return False 1569 return False 1675 # place the call data inside 1570 # place the call data inside the src element of the tgtdev 1676 if('src' not in tgtdev): 1571 if('src' not in tgtdev): 1677 tgtdev['src'] = [] 1572 tgtdev['src'] = [] 1678 dtf = sysvals.dev_tracefuncs 1573 dtf = sysvals.dev_tracefuncs 1679 ubiquitous = False 1574 ubiquitous = False 1680 if kprobename in dtf and 'ub' 1575 if kprobename in dtf and 'ub' in dtf[kprobename]: 1681 ubiquitous = True 1576 ubiquitous = True 1682 mc = re.match(r'\(.*\) *(?P<a !! 1577 title = cdata+' '+rdata 1683 mr = re.match(r'\((?P<caller> !! 1578 mstr = '\(.*\) *(?P<args>.*) *\((?P<caller>.*)\+.* arg1=(?P<ret>.*)' 1684 if mc and mr: !! 1579 m = re.match(mstr, title) 1685 c = mr.group('caller' !! 1580 if m: 1686 a = mc.group('args'). !! 1581 c = m.group('caller') 1687 r = mr.group('ret') !! 1582 a = m.group('args').strip() >> 1583 r = m.group('ret') 1688 if len(r) > 6: 1584 if len(r) > 6: 1689 r = '' 1585 r = '' 1690 else: 1586 else: 1691 r = 'ret=%s ' 1587 r = 'ret=%s ' % r 1692 if ubiquitous and c i 1588 if ubiquitous and c in dtf and 'ub' in dtf[c]: 1693 return False 1589 return False 1694 else: << 1695 return False << 1696 color = sysvals.kprobeColor(k 1590 color = sysvals.kprobeColor(kprobename) 1697 e = DevFunction(displayname, 1591 e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color) 1698 tgtdev['src'].append(e) 1592 tgtdev['src'].append(e) 1699 return True 1593 return True 1700 def overflowDevices(self): 1594 def overflowDevices(self): 1701 # get a list of devices that 1595 # get a list of devices that extend beyond the end of this test run 1702 devlist = [] 1596 devlist = [] 1703 for phase in self.sortedPhase 1597 for phase in self.sortedPhases(): 1704 list = self.dmesg[pha 1598 list = self.dmesg[phase]['list'] 1705 for devname in list: 1599 for devname in list: 1706 dev = list[de 1600 dev = list[devname] 1707 if dev['end'] 1601 if dev['end'] > self.end: 1708 devli 1602 devlist.append(dev) 1709 return devlist 1603 return devlist 1710 def mergeOverlapDevices(self, devlist 1604 def mergeOverlapDevices(self, devlist): 1711 # merge any devices that over 1605 # merge any devices that overlap devlist 1712 for dev in devlist: 1606 for dev in devlist: 1713 devname = dev['name'] 1607 devname = dev['name'] 1714 for phase in self.sor 1608 for phase in self.sortedPhases(): 1715 list = self.d 1609 list = self.dmesg[phase]['list'] 1716 if devname no 1610 if devname not in list: 1717 conti 1611 continue 1718 tdev = list[d 1612 tdev = list[devname] 1719 o = min(dev[' 1613 o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start']) 1720 if o <= 0: 1614 if o <= 0: 1721 conti 1615 continue 1722 dev['end'] = 1616 dev['end'] = tdev['end'] 1723 if 'src' not 1617 if 'src' not in dev or 'src' not in tdev: 1724 conti 1618 continue 1725 dev['src'] += 1619 dev['src'] += tdev['src'] 1726 del list[devn 1620 del list[devname] 1727 def usurpTouchingThread(self, name, d 1621 def usurpTouchingThread(self, name, dev): 1728 # the caller test has priorit 1622 # the caller test has priority of this thread, give it to him 1729 for phase in self.sortedPhase 1623 for phase in self.sortedPhases(): 1730 list = self.dmesg[pha 1624 list = self.dmesg[phase]['list'] 1731 if name in list: 1625 if name in list: 1732 tdev = list[n 1626 tdev = list[name] 1733 if tdev['star 1627 if tdev['start'] - dev['end'] < 0.1: 1734 dev[' 1628 dev['end'] = tdev['end'] 1735 if 's 1629 if 'src' not in dev: 1736 1630 dev['src'] = [] 1737 if 's 1631 if 'src' in tdev: 1738 1632 dev['src'] += tdev['src'] 1739 del l 1633 del list[name] 1740 break 1634 break 1741 def stitchTouchingThreads(self, testl 1635 def stitchTouchingThreads(self, testlist): 1742 # merge any threads between t 1636 # merge any threads between tests that touch 1743 for phase in self.sortedPhase 1637 for phase in self.sortedPhases(): 1744 list = self.dmesg[pha 1638 list = self.dmesg[phase]['list'] 1745 for devname in list: 1639 for devname in list: 1746 dev = list[de 1640 dev = list[devname] 1747 if 'htmlclass 1641 if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']: 1748 conti 1642 continue 1749 for data in t 1643 for data in testlist: 1750 data. 1644 data.usurpTouchingThread(devname, dev) 1751 def optimizeDevSrc(self): 1645 def optimizeDevSrc(self): 1752 # merge any src call loops to 1646 # merge any src call loops to reduce timeline size 1753 for phase in self.sortedPhase 1647 for phase in self.sortedPhases(): 1754 list = self.dmesg[pha 1648 list = self.dmesg[phase]['list'] 1755 for dev in list: 1649 for dev in list: 1756 if 'src' not 1650 if 'src' not in list[dev]: 1757 conti 1651 continue 1758 src = list[de 1652 src = list[dev]['src'] 1759 p = 0 1653 p = 0 1760 for e in sort 1654 for e in sorted(src, key=lambda event: event.time): 1761 if no 1655 if not p or not e.repeat(p): 1762 1656 p = e 1763 1657 continue 1764 # e i 1658 # e is another iteration of p, move it into p 1765 p.end 1659 p.end = e.end 1766 p.len 1660 p.length = p.end - p.time 1767 p.cou 1661 p.count += 1 1768 src.r 1662 src.remove(e) 1769 def trimTimeVal(self, t, t0, dT, left 1663 def trimTimeVal(self, t, t0, dT, left): 1770 if left: 1664 if left: 1771 if(t > t0): 1665 if(t > t0): 1772 if(t - dT < t 1666 if(t - dT < t0): 1773 retur 1667 return t0 1774 return t - dT 1668 return t - dT 1775 else: 1669 else: 1776 return t 1670 return t 1777 else: 1671 else: 1778 if(t < t0 + dT): 1672 if(t < t0 + dT): 1779 if(t > t0): 1673 if(t > t0): 1780 retur 1674 return t0 + dT 1781 return t + dT 1675 return t + dT 1782 else: 1676 else: 1783 return t 1677 return t 1784 def trimTime(self, t0, dT, left): 1678 def trimTime(self, t0, dT, left): 1785 self.tSuspended = self.trimTi 1679 self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left) 1786 self.tResumed = self.trimTime 1680 self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left) 1787 self.start = self.trimTimeVal 1681 self.start = self.trimTimeVal(self.start, t0, dT, left) 1788 self.tKernSus = self.trimTime 1682 self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left) 1789 self.tKernRes = self.trimTime 1683 self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left) 1790 self.end = self.trimTimeVal(s 1684 self.end = self.trimTimeVal(self.end, t0, dT, left) 1791 for phase in self.sortedPhase 1685 for phase in self.sortedPhases(): 1792 p = self.dmesg[phase] 1686 p = self.dmesg[phase] 1793 p['start'] = self.tri 1687 p['start'] = self.trimTimeVal(p['start'], t0, dT, left) 1794 p['end'] = self.trimT 1688 p['end'] = self.trimTimeVal(p['end'], t0, dT, left) 1795 list = p['list'] 1689 list = p['list'] 1796 for name in list: 1690 for name in list: 1797 d = list[name 1691 d = list[name] 1798 d['start'] = 1692 d['start'] = self.trimTimeVal(d['start'], t0, dT, left) 1799 d['end'] = se 1693 d['end'] = self.trimTimeVal(d['end'], t0, dT, left) 1800 d['length'] = 1694 d['length'] = d['end'] - d['start'] 1801 if('ftrace' i 1695 if('ftrace' in d): 1802 cg = 1696 cg = d['ftrace'] 1803 cg.st 1697 cg.start = self.trimTimeVal(cg.start, t0, dT, left) 1804 cg.en 1698 cg.end = self.trimTimeVal(cg.end, t0, dT, left) 1805 for l 1699 for line in cg.list: 1806 1700 line.time = self.trimTimeVal(line.time, t0, dT, left) 1807 if('src' in d 1701 if('src' in d): 1808 for e 1702 for e in d['src']: 1809 1703 e.time = self.trimTimeVal(e.time, t0, dT, left) 1810 1704 e.end = self.trimTimeVal(e.end, t0, dT, left) 1811 1705 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 1706 for dir in ['suspend', 'resume']: 1821 list = [] 1707 list = [] 1822 for e in self.errorin 1708 for e in self.errorinfo[dir]: 1823 type, tm, idx 1709 type, tm, idx1, idx2 = e 1824 tm = self.tri 1710 tm = self.trimTimeVal(tm, t0, dT, left) 1825 list.append(( 1711 list.append((type, tm, idx1, idx2)) 1826 self.errorinfo[dir] = 1712 self.errorinfo[dir] = list 1827 def trimFreezeTime(self, tZero): 1713 def trimFreezeTime(self, tZero): 1828 # trim out any standby or fre 1714 # trim out any standby or freeze clock time 1829 lp = '' 1715 lp = '' 1830 for phase in self.sortedPhase 1716 for phase in self.sortedPhases(): 1831 if 'resume_machine' i 1717 if 'resume_machine' in phase and 'suspend_machine' in lp: 1832 tS, tR = self 1718 tS, tR = self.dmesg[lp]['end'], self.dmesg[phase]['start'] 1833 tL = tR - tS 1719 tL = tR - tS 1834 if tL <= 0: 1720 if tL <= 0: 1835 conti 1721 continue 1836 left = True i 1722 left = True if tR > tZero else False 1837 self.trimTime 1723 self.trimTime(tS, tL, left) 1838 if 'waking' i 1724 if 'waking' in self.dmesg[lp]: 1839 tCnt 1725 tCnt = self.dmesg[lp]['waking'][0] 1840 if se 1726 if self.dmesg[lp]['waking'][1] >= 0.001: 1841 !! 1727 tTry = '-%.0f' % (round(self.dmesg[lp]['waking'][1] * 1000)) 1842 else: 1728 else: 1843 !! 1729 tTry = '-%.3f' % (self.dmesg[lp]['waking'][1] * 1000) 1844 text 1730 text = '%.0f (%s ms waking %d times)' % (tL * 1000, tTry, tCnt) 1845 else: 1731 else: 1846 text 1732 text = '%.0f' % (tL * 1000) 1847 self.tLow.app 1733 self.tLow.append(text) 1848 lp = phase 1734 lp = phase 1849 def getMemTime(self): 1735 def getMemTime(self): 1850 if not self.hwstart or not se 1736 if not self.hwstart or not self.hwend: 1851 return 1737 return 1852 stime = (self.tSuspended - se 1738 stime = (self.tSuspended - self.start) * 1000000 1853 rtime = (self.end - self.tRes 1739 rtime = (self.end - self.tResumed) * 1000000 1854 hws = self.hwstart + timedelt 1740 hws = self.hwstart + timedelta(microseconds=stime) 1855 hwr = self.hwend - timedelta( 1741 hwr = self.hwend - timedelta(microseconds=rtime) 1856 self.tLow.append('%.0f'%((hwr 1742 self.tLow.append('%.0f'%((hwr - hws).total_seconds() * 1000)) 1857 def getTimeValues(self): 1743 def getTimeValues(self): 1858 s = (self.tSuspended - self.t !! 1744 sktime = (self.tSuspended - self.tKernSus) * 1000 1859 r = (self.tKernRes - self.tRe !! 1745 rktime = (self.tKernRes - self.tResumed) * 1000 1860 return (max(s, 0), max(r, 0)) !! 1746 return (sktime, rktime) 1861 def setPhase(self, phase, ktime, isbe 1747 def setPhase(self, phase, ktime, isbegin, order=-1): 1862 if(isbegin): 1748 if(isbegin): 1863 # phase start over cu 1749 # phase start over current phase 1864 if self.currphase: 1750 if self.currphase: 1865 if 'resume_ma 1751 if 'resume_machine' not in self.currphase: 1866 sysva 1752 sysvals.vprint('WARNING: phase %s failed to end' % self.currphase) 1867 self.dmesg[se 1753 self.dmesg[self.currphase]['end'] = ktime 1868 phases = self.dmesg.k 1754 phases = self.dmesg.keys() 1869 color = self.phasedef 1755 color = self.phasedef[phase]['color'] 1870 count = len(phases) i 1756 count = len(phases) if order < 0 else order 1871 # create unique name 1757 # create unique name for every new phase 1872 while phase in phases 1758 while phase in phases: 1873 phase += '*' 1759 phase += '*' 1874 self.dmesg[phase] = { 1760 self.dmesg[phase] = {'list': dict(), 'start': -1.0, 'end': -1.0, 1875 'row': 0, 'co 1761 'row': 0, 'color': color, 'order': count} 1876 self.dmesg[phase]['st 1762 self.dmesg[phase]['start'] = ktime 1877 self.currphase = phas 1763 self.currphase = phase 1878 else: 1764 else: 1879 # phase end without a 1765 # phase end without a start 1880 if phase not in self. 1766 if phase not in self.currphase: 1881 if self.currp 1767 if self.currphase: 1882 sysva 1768 sysvals.vprint('WARNING: %s ended instead of %s, ftrace corruption?' % (phase, self.currphase)) 1883 else: 1769 else: 1884 sysva 1770 sysvals.vprint('WARNING: %s ended without a start, ftrace corruption?' % phase) 1885 retur 1771 return phase 1886 phase = self.currphas 1772 phase = self.currphase 1887 self.dmesg[phase]['en 1773 self.dmesg[phase]['end'] = ktime 1888 self.currphase = '' 1774 self.currphase = '' 1889 return phase 1775 return phase 1890 def sortedDevices(self, phase): 1776 def sortedDevices(self, phase): 1891 list = self.dmesg[phase]['lis 1777 list = self.dmesg[phase]['list'] 1892 return sorted(list, key=lambd 1778 return sorted(list, key=lambda k:list[k]['start']) 1893 def fixupInitcalls(self, phase): 1779 def fixupInitcalls(self, phase): 1894 # if any calls never returned 1780 # if any calls never returned, clip them at system resume end 1895 phaselist = self.dmesg[phase] 1781 phaselist = self.dmesg[phase]['list'] 1896 for devname in phaselist: 1782 for devname in phaselist: 1897 dev = phaselist[devna 1783 dev = phaselist[devname] 1898 if(dev['end'] < 0): 1784 if(dev['end'] < 0): 1899 for p in self 1785 for p in self.sortedPhases(): 1900 if se 1786 if self.dmesg[p]['end'] > dev['start']: 1901 1787 dev['end'] = self.dmesg[p]['end'] 1902 1788 break 1903 sysvals.vprin 1789 sysvals.vprint('%s (%s): callback didnt return' % (devname, phase)) 1904 def deviceFilter(self, devicefilter): 1790 def deviceFilter(self, devicefilter): 1905 for phase in self.sortedPhase 1791 for phase in self.sortedPhases(): 1906 list = self.dmesg[pha 1792 list = self.dmesg[phase]['list'] 1907 rmlist = [] 1793 rmlist = [] 1908 for name in list: 1794 for name in list: 1909 keep = False 1795 keep = False 1910 for filter in 1796 for filter in devicefilter: 1911 if fi 1797 if filter in name or \ 1912 1798 ('drv' in list[name] and filter in list[name]['drv']): 1913 1799 keep = True 1914 if not keep: 1800 if not keep: 1915 rmlis 1801 rmlist.append(name) 1916 for name in rmlist: 1802 for name in rmlist: 1917 del list[name 1803 del list[name] 1918 def fixupInitcallsThatDidntReturn(sel 1804 def fixupInitcallsThatDidntReturn(self): 1919 # if any calls never returned 1805 # if any calls never returned, clip them at system resume end 1920 for phase in self.sortedPhase 1806 for phase in self.sortedPhases(): 1921 self.fixupInitcalls(p 1807 self.fixupInitcalls(phase) 1922 def phaseOverlap(self, phases): 1808 def phaseOverlap(self, phases): 1923 rmgroups = [] 1809 rmgroups = [] 1924 newgroup = [] 1810 newgroup = [] 1925 for group in self.devicegroup 1811 for group in self.devicegroups: 1926 for phase in phases: 1812 for phase in phases: 1927 if phase not 1813 if phase not in group: 1928 conti 1814 continue 1929 for p in grou 1815 for p in group: 1930 if p 1816 if p not in newgroup: 1931 1817 newgroup.append(p) 1932 if group not 1818 if group not in rmgroups: 1933 rmgro 1819 rmgroups.append(group) 1934 for group in rmgroups: 1820 for group in rmgroups: 1935 self.devicegroups.rem 1821 self.devicegroups.remove(group) 1936 self.devicegroups.append(newg 1822 self.devicegroups.append(newgroup) 1937 def newActionGlobal(self, name, start 1823 def newActionGlobal(self, name, start, end, pid=-1, color=''): 1938 # which phase is this device 1824 # which phase is this device callback or action in 1939 phases = self.sortedPhases() 1825 phases = self.sortedPhases() 1940 targetphase = 'none' 1826 targetphase = 'none' 1941 htmlclass = '' 1827 htmlclass = '' 1942 overlap = 0.0 1828 overlap = 0.0 1943 myphases = [] 1829 myphases = [] 1944 for phase in phases: 1830 for phase in phases: 1945 pstart = self.dmesg[p 1831 pstart = self.dmesg[phase]['start'] 1946 pend = self.dmesg[pha 1832 pend = self.dmesg[phase]['end'] 1947 # see if the action o 1833 # see if the action overlaps this phase 1948 o = max(0, min(end, p 1834 o = max(0, min(end, pend) - max(start, pstart)) 1949 if o > 0: 1835 if o > 0: 1950 myphases.appe 1836 myphases.append(phase) 1951 # set the target phas 1837 # set the target phase to the one that overlaps most 1952 if o > overlap: 1838 if o > overlap: 1953 if overlap > 1839 if overlap > 0 and phase == 'post_resume': 1954 conti 1840 continue 1955 targetphase = 1841 targetphase = phase 1956 overlap = o 1842 overlap = o 1957 # if no target phase was foun 1843 # if no target phase was found, pin it to the edge 1958 if targetphase == 'none': 1844 if targetphase == 'none': 1959 p0start = self.dmesg[ 1845 p0start = self.dmesg[phases[0]]['start'] 1960 if start <= p0start: 1846 if start <= p0start: 1961 targetphase = 1847 targetphase = phases[0] 1962 else: 1848 else: 1963 targetphase = 1849 targetphase = phases[-1] 1964 if pid == -2: 1850 if pid == -2: 1965 htmlclass = ' bg' 1851 htmlclass = ' bg' 1966 elif pid == -3: 1852 elif pid == -3: 1967 htmlclass = ' ps' 1853 htmlclass = ' ps' 1968 if len(myphases) > 1: 1854 if len(myphases) > 1: 1969 htmlclass = ' bg' 1855 htmlclass = ' bg' 1970 self.phaseOverlap(myp 1856 self.phaseOverlap(myphases) 1971 if targetphase in phases: 1857 if targetphase in phases: 1972 newname = self.newAct 1858 newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color) 1973 return (targetphase, 1859 return (targetphase, newname) 1974 return False 1860 return False 1975 def newAction(self, phase, name, pid, 1861 def newAction(self, phase, name, pid, parent, start, end, drv, htmlclass='', color=''): 1976 # new device callback for a s 1862 # new device callback for a specific phase 1977 self.html_device_id += 1 1863 self.html_device_id += 1 1978 devid = '%s%d' % (self.idstr, 1864 devid = '%s%d' % (self.idstr, self.html_device_id) 1979 list = self.dmesg[phase]['lis 1865 list = self.dmesg[phase]['list'] 1980 length = -1.0 1866 length = -1.0 1981 if(start >= 0 and end >= 0): 1867 if(start >= 0 and end >= 0): 1982 length = end - start 1868 length = end - start 1983 if pid == -2 or name not in s 1869 if pid == -2 or name not in sysvals.tracefuncs.keys(): 1984 i = 2 1870 i = 2 1985 origname = name 1871 origname = name 1986 while(name in list): 1872 while(name in list): 1987 name = '%s[%d 1873 name = '%s[%d]' % (origname, i) 1988 i += 1 1874 i += 1 1989 list[name] = {'name': name, ' 1875 list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid, 1990 'par': parent, 'lengt 1876 'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv } 1991 if htmlclass: 1877 if htmlclass: 1992 list[name]['htmlclass 1878 list[name]['htmlclass'] = htmlclass 1993 if color: 1879 if color: 1994 list[name]['color'] = 1880 list[name]['color'] = color 1995 return name 1881 return name 1996 def findDevice(self, phase, name): 1882 def findDevice(self, phase, name): 1997 list = self.dmesg[phase]['lis 1883 list = self.dmesg[phase]['list'] 1998 mydev = '' 1884 mydev = '' 1999 for devname in sorted(list): 1885 for devname in sorted(list): 2000 if name == devname or !! 1886 if name == devname or re.match('^%s\[(?P<num>[0-9]*)\]$' % name, devname): 2001 mydev = devna 1887 mydev = devname 2002 if mydev: 1888 if mydev: 2003 return list[mydev] 1889 return list[mydev] 2004 return False 1890 return False 2005 def deviceChildren(self, devname, pha 1891 def deviceChildren(self, devname, phase): 2006 devlist = [] 1892 devlist = [] 2007 list = self.dmesg[phase]['lis 1893 list = self.dmesg[phase]['list'] 2008 for child in list: 1894 for child in list: 2009 if(list[child]['par'] 1895 if(list[child]['par'] == devname): 2010 devlist.appen 1896 devlist.append(child) 2011 return devlist 1897 return devlist 2012 def maxDeviceNameSize(self, phase): 1898 def maxDeviceNameSize(self, phase): 2013 size = 0 1899 size = 0 2014 for name in self.dmesg[phase] 1900 for name in self.dmesg[phase]['list']: 2015 if len(name) > size: 1901 if len(name) > size: 2016 size = len(na 1902 size = len(name) 2017 return size 1903 return size 2018 def printDetails(self): 1904 def printDetails(self): 2019 sysvals.vprint('Timeline Deta 1905 sysvals.vprint('Timeline Details:') 2020 sysvals.vprint(' tes 1906 sysvals.vprint(' test start: %f' % self.start) 2021 sysvals.vprint('kernel suspen 1907 sysvals.vprint('kernel suspend start: %f' % self.tKernSus) 2022 tS = tR = False 1908 tS = tR = False 2023 for phase in self.sortedPhase 1909 for phase in self.sortedPhases(): 2024 devlist = self.dmesg[ 1910 devlist = self.dmesg[phase]['list'] 2025 dc, ps, pe = len(devl 1911 dc, ps, pe = len(devlist), self.dmesg[phase]['start'], self.dmesg[phase]['end'] 2026 if not tS and ps >= s 1912 if not tS and ps >= self.tSuspended: 2027 sysvals.vprin 1913 sysvals.vprint(' machine suspended: %f' % self.tSuspended) 2028 tS = True 1914 tS = True 2029 if not tR and ps >= s 1915 if not tR and ps >= self.tResumed: 2030 sysvals.vprin 1916 sysvals.vprint(' machine resumed: %f' % self.tResumed) 2031 tR = True 1917 tR = True 2032 sysvals.vprint('%20s: 1918 sysvals.vprint('%20s: %f - %f (%d devices)' % (phase, ps, pe, dc)) 2033 if sysvals.devdump: 1919 if sysvals.devdump: 2034 sysvals.vprin 1920 sysvals.vprint(''.join('-' for i in range(80))) 2035 maxname = '%d 1921 maxname = '%d' % self.maxDeviceNameSize(phase) 2036 fmt = '%3d) % 1922 fmt = '%3d) %'+maxname+'s - %f - %f' 2037 c = 1 1923 c = 1 2038 for name in s 1924 for name in sorted(devlist): 2039 s = d 1925 s = devlist[name]['start'] 2040 e = d 1926 e = devlist[name]['end'] 2041 sysva 1927 sysvals.vprint(fmt % (c, name, s, e)) 2042 c += 1928 c += 1 2043 sysvals.vprin 1929 sysvals.vprint(''.join('-' for i in range(80))) 2044 sysvals.vprint(' kernel res 1930 sysvals.vprint(' kernel resume end: %f' % self.tKernRes) 2045 sysvals.vprint(' t 1931 sysvals.vprint(' test end: %f' % self.end) 2046 def deviceChildrenAllPhases(self, dev 1932 def deviceChildrenAllPhases(self, devname): 2047 devlist = [] 1933 devlist = [] 2048 for phase in self.sortedPhase 1934 for phase in self.sortedPhases(): 2049 list = self.deviceChi 1935 list = self.deviceChildren(devname, phase) 2050 for dev in sorted(lis 1936 for dev in sorted(list): 2051 if dev not in 1937 if dev not in devlist: 2052 devli 1938 devlist.append(dev) 2053 return devlist 1939 return devlist 2054 def masterTopology(self, name, list, 1940 def masterTopology(self, name, list, depth): 2055 node = DeviceNode(name, depth 1941 node = DeviceNode(name, depth) 2056 for cname in list: 1942 for cname in list: 2057 # avoid recursions 1943 # avoid recursions 2058 if name == cname: 1944 if name == cname: 2059 continue 1945 continue 2060 clist = self.deviceCh 1946 clist = self.deviceChildrenAllPhases(cname) 2061 cnode = self.masterTo 1947 cnode = self.masterTopology(cname, clist, depth+1) 2062 node.children.append( 1948 node.children.append(cnode) 2063 return node 1949 return node 2064 def printTopology(self, node): 1950 def printTopology(self, node): 2065 html = '' 1951 html = '' 2066 if node.name: 1952 if node.name: 2067 info = '' 1953 info = '' 2068 drv = '' 1954 drv = '' 2069 for phase in self.sor 1955 for phase in self.sortedPhases(): 2070 list = self.d 1956 list = self.dmesg[phase]['list'] 2071 if node.name 1957 if node.name in list: 2072 s = l 1958 s = list[node.name]['start'] 2073 e = l 1959 e = list[node.name]['end'] 2074 if li 1960 if list[node.name]['drv']: 2075 1961 drv = ' {'+list[node.name]['drv']+'}' 2076 info 1962 info += ('<li>%s: %.3fms</li>' % (phase, (e-s)*1000)) 2077 html += '<li><b>'+nod 1963 html += '<li><b>'+node.name+drv+'</b>' 2078 if info: 1964 if info: 2079 html += '<ul> 1965 html += '<ul>'+info+'</ul>' 2080 html += '</li>' 1966 html += '</li>' 2081 if len(node.children) > 0: 1967 if len(node.children) > 0: 2082 html += '<ul>' 1968 html += '<ul>' 2083 for cnode in node.chi 1969 for cnode in node.children: 2084 html += self. 1970 html += self.printTopology(cnode) 2085 html += '</ul>' 1971 html += '</ul>' 2086 return html 1972 return html 2087 def rootDeviceList(self): 1973 def rootDeviceList(self): 2088 # list of devices graphed 1974 # list of devices graphed 2089 real = [] 1975 real = [] 2090 for phase in self.sortedPhase 1976 for phase in self.sortedPhases(): 2091 list = self.dmesg[pha 1977 list = self.dmesg[phase]['list'] 2092 for dev in sorted(lis 1978 for dev in sorted(list): 2093 if list[dev][ 1979 if list[dev]['pid'] >= 0 and dev not in real: 2094 real. 1980 real.append(dev) 2095 # list of top-most root devic 1981 # list of top-most root devices 2096 rootlist = [] 1982 rootlist = [] 2097 for phase in self.sortedPhase 1983 for phase in self.sortedPhases(): 2098 list = self.dmesg[pha 1984 list = self.dmesg[phase]['list'] 2099 for dev in sorted(lis 1985 for dev in sorted(list): 2100 pdev = list[d 1986 pdev = list[dev]['par'] 2101 pid = list[de 1987 pid = list[dev]['pid'] 2102 if(pid < 0 or !! 1988 if(pid < 0 or re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)): 2103 conti 1989 continue 2104 if pdev and p 1990 if pdev and pdev not in real and pdev not in rootlist: 2105 rootl 1991 rootlist.append(pdev) 2106 return rootlist 1992 return rootlist 2107 def deviceTopology(self): 1993 def deviceTopology(self): 2108 rootlist = self.rootDeviceLis 1994 rootlist = self.rootDeviceList() 2109 master = self.masterTopology( 1995 master = self.masterTopology('', rootlist, 0) 2110 return self.printTopology(mas 1996 return self.printTopology(master) 2111 def selectTimelineDevices(self, widfm 1997 def selectTimelineDevices(self, widfmt, tTotal, mindevlen): 2112 # only select devices that wi 1998 # only select devices that will actually show up in html 2113 self.tdevlist = dict() 1999 self.tdevlist = dict() 2114 for phase in self.dmesg: 2000 for phase in self.dmesg: 2115 devlist = [] 2001 devlist = [] 2116 list = self.dmesg[pha 2002 list = self.dmesg[phase]['list'] 2117 for dev in list: 2003 for dev in list: 2118 length = (lis 2004 length = (list[dev]['end'] - list[dev]['start']) * 1000 2119 width = widfm 2005 width = widfmt % (((list[dev]['end']-list[dev]['start'])*100)/tTotal) 2120 if length >= 2006 if length >= mindevlen: 2121 devli 2007 devlist.append(dev) 2122 self.tdevlist[phase] 2008 self.tdevlist[phase] = devlist 2123 def addHorizontalDivider(self, devnam 2009 def addHorizontalDivider(self, devname, devend): 2124 phase = 'suspend_prepare' 2010 phase = 'suspend_prepare' 2125 self.newAction(phase, devname 2011 self.newAction(phase, devname, -2, '', \ 2126 self.start, devend, ' 2012 self.start, devend, '', ' sec', '') 2127 if phase not in self.tdevlist 2013 if phase not in self.tdevlist: 2128 self.tdevlist[phase] 2014 self.tdevlist[phase] = [] 2129 self.tdevlist[phase].append(d 2015 self.tdevlist[phase].append(devname) 2130 d = DevItem(0, phase, self.dm 2016 d = DevItem(0, phase, self.dmesg[phase]['list'][devname]) 2131 return d 2017 return d 2132 def addProcessUsageEvent(self, name, 2018 def addProcessUsageEvent(self, name, times): 2133 # get the start and end times 2019 # get the start and end times for this process 2134 cpuexec = dict() !! 2020 maxC = 0 2135 tlast = start = end = -1 !! 2021 tlast = 0 >> 2022 start = -1 >> 2023 end = -1 2136 for t in sorted(times): 2024 for t in sorted(times): 2137 if tlast < 0: !! 2025 if tlast == 0: 2138 tlast = t 2026 tlast = t 2139 continue 2027 continue 2140 if name in self.pstl[ !! 2028 if name in self.pstl[t]: 2141 if start < 0: !! 2029 if start == -1 or tlast < start: 2142 start 2030 start = tlast 2143 end, key = t, !! 2031 if end == -1 or t > end: 2144 maxj = (t - t !! 2032 end = t 2145 cpuexec[key] << 2146 tlast = t 2033 tlast = t 2147 if start < 0 or end < 0: !! 2034 if start == -1 or end == -1: 2148 return !! 2035 return 0 2149 # add a new action for this p 2036 # add a new action for this process and get the object 2150 out = self.newActionGlobal(na 2037 out = self.newActionGlobal(name, start, end, -3) 2151 if out: !! 2038 if not out: 2152 phase, devname = out !! 2039 return 0 2153 dev = self.dmesg[phas !! 2040 phase, devname = out 2154 dev['cpuexec'] = cpue !! 2041 dev = self.dmesg[phase]['list'][devname] >> 2042 # get the cpu exec data >> 2043 tlast = 0 >> 2044 clast = 0 >> 2045 cpuexec = dict() >> 2046 for t in sorted(times): >> 2047 if tlast == 0 or t <= start or t > end: >> 2048 tlast = t >> 2049 continue >> 2050 list = self.pstl[t] >> 2051 c = 0 >> 2052 if name in list: >> 2053 c = list[name] >> 2054 if c > maxC: >> 2055 maxC = c >> 2056 if c != clast: >> 2057 key = (tlast, t) >> 2058 cpuexec[key] = c >> 2059 tlast = t >> 2060 clast = c >> 2061 dev['cpuexec'] = cpuexec >> 2062 return maxC 2155 def createProcessUsageEvents(self): 2063 def createProcessUsageEvents(self): 2156 # get an array of process nam !! 2064 # get an array of process names 2157 proclist = {'sus': dict(), 'r !! 2065 proclist = [] 2158 tdata = {'sus': [], 'res': [] !! 2066 for t in sorted(self.pstl): >> 2067 pslist = self.pstl[t] >> 2068 for ps in sorted(pslist): >> 2069 if ps not in proclist: >> 2070 proclist.append(ps) >> 2071 # get a list of data points for suspend and resume >> 2072 tsus = [] >> 2073 tres = [] 2159 for t in sorted(self.pstl): 2074 for t in sorted(self.pstl): 2160 dir = 'sus' if t < se !! 2075 if t < self.tSuspended: 2161 for ps in sorted(self !! 2076 tsus.append(t) 2162 if ps not in !! 2077 else: 2163 procl !! 2078 tres.append(t) 2164 tdata[dir].append(t) << 2165 # process the events for susp 2079 # process the events for suspend and resume 2166 if len(proclist['sus']) > 0 o !! 2080 if len(proclist) > 0: 2167 sysvals.vprint('Proce 2081 sysvals.vprint('Process Execution:') 2168 for dir in ['sus', 'res']: !! 2082 for ps in proclist: 2169 for ps in sorted(proc !! 2083 c = self.addProcessUsageEvent(ps, tsus) 2170 self.addProce !! 2084 if c > 0: >> 2085 sysvals.vprint('%25s (sus): %d' % (ps, c)) >> 2086 c = self.addProcessUsageEvent(ps, tres) >> 2087 if c > 0: >> 2088 sysvals.vprint('%25s (res): %d' % (ps, c)) 2171 def handleEndMarker(self, time, msg=' 2089 def handleEndMarker(self, time, msg=''): 2172 dm = self.dmesg 2090 dm = self.dmesg 2173 self.setEnd(time, msg) 2091 self.setEnd(time, msg) 2174 self.initDevicegroups() 2092 self.initDevicegroups() 2175 # give suspend_prepare an end 2093 # give suspend_prepare an end if needed 2176 if 'suspend_prepare' in dm an 2094 if 'suspend_prepare' in dm and dm['suspend_prepare']['end'] < 0: 2177 dm['suspend_prepare'] 2095 dm['suspend_prepare']['end'] = time 2178 # assume resume machine ends 2096 # assume resume machine ends at next phase start 2179 if 'resume_machine' in dm and 2097 if 'resume_machine' in dm and dm['resume_machine']['end'] < 0: 2180 np = self.nextPhase(' 2098 np = self.nextPhase('resume_machine', 1) 2181 if np: 2099 if np: 2182 dm['resume_ma 2100 dm['resume_machine']['end'] = dm[np]['start'] 2183 # if kernel resume end not fo 2101 # if kernel resume end not found, assume its the end marker 2184 if self.tKernRes == 0.0: 2102 if self.tKernRes == 0.0: 2185 self.tKernRes = time 2103 self.tKernRes = time 2186 # if kernel suspend start not 2104 # if kernel suspend start not found, assume its the end marker 2187 if self.tKernSus == 0.0: 2105 if self.tKernSus == 0.0: 2188 self.tKernSus = time 2106 self.tKernSus = time 2189 # set resume complete to end 2107 # set resume complete to end at end marker 2190 if 'resume_complete' in dm: 2108 if 'resume_complete' in dm: 2191 dm['resume_complete'] 2109 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): 2110 def debugPrint(self): 2217 for p in self.sortedPhases(): 2111 for p in self.sortedPhases(): 2218 list = self.dmesg[p][ 2112 list = self.dmesg[p]['list'] 2219 for devname in sorted 2113 for devname in sorted(list): 2220 dev = list[de 2114 dev = list[devname] 2221 if 'ftrace' i 2115 if 'ftrace' in dev: 2222 dev[' 2116 dev['ftrace'].debugPrint(' [%s]' % devname) 2223 2117 2224 # Class: DevFunction 2118 # Class: DevFunction 2225 # Description: 2119 # Description: 2226 # A container for kprobe function data 2120 # A container for kprobe function data we want in the dev timeline 2227 class DevFunction: 2121 class DevFunction: 2228 def __init__(self, name, args, caller 2122 def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color): 2229 self.row = 0 2123 self.row = 0 2230 self.count = 1 2124 self.count = 1 2231 self.name = name 2125 self.name = name 2232 self.args = args 2126 self.args = args 2233 self.caller = caller 2127 self.caller = caller 2234 self.ret = ret 2128 self.ret = ret 2235 self.time = start 2129 self.time = start 2236 self.length = end - start 2130 self.length = end - start 2237 self.end = end 2131 self.end = end 2238 self.ubiquitous = u 2132 self.ubiquitous = u 2239 self.proc = proc 2133 self.proc = proc 2240 self.pid = pid 2134 self.pid = pid 2241 self.color = color 2135 self.color = color 2242 def title(self): 2136 def title(self): 2243 cnt = '' 2137 cnt = '' 2244 if self.count > 1: 2138 if self.count > 1: 2245 cnt = '(x%d)' % self. 2139 cnt = '(x%d)' % self.count 2246 l = '%0.3fms' % (self.length 2140 l = '%0.3fms' % (self.length * 1000) 2247 if self.ubiquitous: 2141 if self.ubiquitous: 2248 title = '%s(%s)%s <- 2142 title = '%s(%s)%s <- %s, %s(%s)' % \ 2249 (self.name, s 2143 (self.name, self.args, cnt, self.caller, self.ret, l) 2250 else: 2144 else: 2251 title = '%s(%s) %s%s( 2145 title = '%s(%s) %s%s(%s)' % (self.name, self.args, self.ret, cnt, l) 2252 return title.replace('"', '') 2146 return title.replace('"', '') 2253 def text(self): 2147 def text(self): 2254 if self.count > 1: 2148 if self.count > 1: 2255 text = '%s(x%d)' % (s 2149 text = '%s(x%d)' % (self.name, self.count) 2256 else: 2150 else: 2257 text = self.name 2151 text = self.name 2258 return text 2152 return text 2259 def repeat(self, tgt): 2153 def repeat(self, tgt): 2260 # is the tgt call just a repe 2154 # is the tgt call just a repeat of this call (e.g. are we in a loop) 2261 dt = self.time - tgt.end 2155 dt = self.time - tgt.end 2262 # only combine calls if -all- 2156 # only combine calls if -all- attributes are identical 2263 if tgt.caller == self.caller 2157 if tgt.caller == self.caller and \ 2264 tgt.name == self.name 2158 tgt.name == self.name and tgt.args == self.args and \ 2265 tgt.proc == self.proc 2159 tgt.proc == self.proc and tgt.pid == self.pid and \ 2266 tgt.ret == self.ret a 2160 tgt.ret == self.ret and dt >= 0 and \ 2267 dt <= sysvals.callloo 2161 dt <= sysvals.callloopmaxgap and \ 2268 self.length < sysvals 2162 self.length < sysvals.callloopmaxlen: 2269 return True 2163 return True 2270 return False 2164 return False 2271 2165 2272 # Class: FTraceLine 2166 # Class: FTraceLine 2273 # Description: 2167 # Description: 2274 # A container for a single line of ftr 2168 # A container for a single line of ftrace data. There are six basic types: 2275 # callgraph line: 2169 # callgraph line: 2276 # call: " dpm_run_ca 2170 # call: " dpm_run_callback() {" 2277 # return: " }" 2171 # return: " }" 2278 # leaf: " dpm_run_cal 2172 # leaf: " dpm_run_callback();" 2279 # trace event: 2173 # trace event: 2280 # tracing_mark_write: 2174 # tracing_mark_write: SUSPEND START or RESUME COMPLETE 2281 # suspend_resume: phas 2175 # suspend_resume: phase or custom exec block data 2282 # device_pm_callback: 2176 # device_pm_callback: device callback info 2283 class FTraceLine: 2177 class FTraceLine: 2284 def __init__(self, t, m='', d=''): 2178 def __init__(self, t, m='', d=''): 2285 self.length = 0.0 2179 self.length = 0.0 2286 self.fcall = False 2180 self.fcall = False 2287 self.freturn = False 2181 self.freturn = False 2288 self.fevent = False 2182 self.fevent = False 2289 self.fkprobe = False 2183 self.fkprobe = False 2290 self.depth = 0 2184 self.depth = 0 2291 self.name = '' 2185 self.name = '' 2292 self.type = '' 2186 self.type = '' 2293 self.time = float(t) 2187 self.time = float(t) 2294 if not m and not d: 2188 if not m and not d: 2295 return 2189 return 2296 # is this a trace event 2190 # is this a trace event 2297 if(d == 'traceevent' or re.ma !! 2191 if(d == 'traceevent' or re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m)): 2298 if(d == 'traceevent') 2192 if(d == 'traceevent'): 2299 # nop format 2193 # nop format trace event 2300 msg = m 2194 msg = m 2301 else: 2195 else: 2302 # function_gr 2196 # function_graph format trace event 2303 em = re.match !! 2197 em = re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m) 2304 msg = em.grou 2198 msg = em.group('msg') 2305 2199 2306 emm = re.match(r'^(?P !! 2200 emm = re.match('^(?P<call>.*?): (?P<msg>.*)', msg) 2307 if(emm): 2201 if(emm): 2308 self.name = e 2202 self.name = emm.group('msg') 2309 self.type = e 2203 self.type = emm.group('call') 2310 else: 2204 else: 2311 self.name = m 2205 self.name = msg 2312 km = re.match(r'^(?P< !! 2206 km = re.match('^(?P<n>.*)_cal$', self.type) 2313 if km: 2207 if km: 2314 self.fcall = 2208 self.fcall = True 2315 self.fkprobe 2209 self.fkprobe = True 2316 self.type = k 2210 self.type = km.group('n') 2317 return 2211 return 2318 km = re.match(r'^(?P< !! 2212 km = re.match('^(?P<n>.*)_ret$', self.type) 2319 if km: 2213 if km: 2320 self.freturn 2214 self.freturn = True 2321 self.fkprobe 2215 self.fkprobe = True 2322 self.type = k 2216 self.type = km.group('n') 2323 return 2217 return 2324 self.fevent = True 2218 self.fevent = True 2325 return 2219 return 2326 # convert the duration to sec 2220 # convert the duration to seconds 2327 if(d): 2221 if(d): 2328 self.length = float(d 2222 self.length = float(d)/1000000 2329 # the indentation determines 2223 # the indentation determines the depth 2330 match = re.match(r'^(?P<d> *) !! 2224 match = re.match('^(?P<d> *)(?P<o>.*)$', m) 2331 if(not match): 2225 if(not match): 2332 return 2226 return 2333 self.depth = self.getDepth(ma 2227 self.depth = self.getDepth(match.group('d')) 2334 m = match.group('o') 2228 m = match.group('o') 2335 # function return 2229 # function return 2336 if(m[0] == '}'): 2230 if(m[0] == '}'): 2337 self.freturn = True 2231 self.freturn = True 2338 if(len(m) > 1): 2232 if(len(m) > 1): 2339 # includes co 2233 # includes comment with function name 2340 match = re.ma !! 2234 match = re.match('^} *\/\* *(?P<n>.*) *\*\/$', m) 2341 if(match): 2235 if(match): 2342 self. 2236 self.name = match.group('n').strip() 2343 # function call 2237 # function call 2344 else: 2238 else: 2345 self.fcall = True 2239 self.fcall = True 2346 # function call with 2240 # function call with children 2347 if(m[-1] == '{'): 2241 if(m[-1] == '{'): 2348 match = re.ma !! 2242 match = re.match('^(?P<n>.*) *\(.*', m) 2349 if(match): 2243 if(match): 2350 self. 2244 self.name = match.group('n').strip() 2351 # function call with 2245 # function call with no children (leaf) 2352 elif(m[-1] == ';'): 2246 elif(m[-1] == ';'): 2353 self.freturn 2247 self.freturn = True 2354 match = re.ma !! 2248 match = re.match('^(?P<n>.*) *\(.*', m) 2355 if(match): 2249 if(match): 2356 self. 2250 self.name = match.group('n').strip() 2357 # something else (pos 2251 # something else (possibly a trace marker) 2358 else: 2252 else: 2359 self.name = m 2253 self.name = m 2360 def isCall(self): 2254 def isCall(self): 2361 return self.fcall and not sel 2255 return self.fcall and not self.freturn 2362 def isReturn(self): 2256 def isReturn(self): 2363 return self.freturn and not s 2257 return self.freturn and not self.fcall 2364 def isLeaf(self): 2258 def isLeaf(self): 2365 return self.fcall and self.fr 2259 return self.fcall and self.freturn 2366 def getDepth(self, str): 2260 def getDepth(self, str): 2367 return len(str)/2 2261 return len(str)/2 2368 def debugPrint(self, info=''): 2262 def debugPrint(self, info=''): 2369 if self.isLeaf(): 2263 if self.isLeaf(): 2370 pprint(' -- %12.6f (d 2264 pprint(' -- %12.6f (depth=%02d): %s(); (%.3f us) %s' % (self.time, \ 2371 self.depth, s 2265 self.depth, self.name, self.length*1000000, info)) 2372 elif self.freturn: 2266 elif self.freturn: 2373 pprint(' -- %12.6f (d 2267 pprint(' -- %12.6f (depth=%02d): %s} (%.3f us) %s' % (self.time, \ 2374 self.depth, s 2268 self.depth, self.name, self.length*1000000, info)) 2375 else: 2269 else: 2376 pprint(' -- %12.6f (d 2270 pprint(' -- %12.6f (depth=%02d): %s() { (%.3f us) %s' % (self.time, \ 2377 self.depth, s 2271 self.depth, self.name, self.length*1000000, info)) 2378 def startMarker(self): 2272 def startMarker(self): 2379 # Is this the starting line o 2273 # Is this the starting line of a suspend? 2380 if not self.fevent: 2274 if not self.fevent: 2381 return False 2275 return False 2382 if sysvals.usetracemarkers: 2276 if sysvals.usetracemarkers: 2383 if(self.name.startswi 2277 if(self.name.startswith('SUSPEND START')): 2384 return True 2278 return True 2385 return False 2279 return False 2386 else: 2280 else: 2387 if(self.type == 'susp 2281 if(self.type == 'suspend_resume' and 2388 re.match(r'su !! 2282 re.match('suspend_enter\[.*\] begin', self.name)): 2389 return True 2283 return True 2390 return False 2284 return False 2391 def endMarker(self): 2285 def endMarker(self): 2392 # Is this the ending line of 2286 # Is this the ending line of a resume? 2393 if not self.fevent: 2287 if not self.fevent: 2394 return False 2288 return False 2395 if sysvals.usetracemarkers: 2289 if sysvals.usetracemarkers: 2396 if(self.name.startswi 2290 if(self.name.startswith('RESUME COMPLETE')): 2397 return True 2291 return True 2398 return False 2292 return False 2399 else: 2293 else: 2400 if(self.type == 'susp 2294 if(self.type == 'suspend_resume' and 2401 re.match(r'th !! 2295 re.match('thaw_processes\[.*\] end', self.name)): 2402 return True 2296 return True 2403 return False 2297 return False 2404 2298 2405 # Class: FTraceCallGraph 2299 # Class: FTraceCallGraph 2406 # Description: 2300 # Description: 2407 # A container for the ftrace callgraph 2301 # A container for the ftrace callgraph of a single recursive function. 2408 # This can be a dpm_run_callback, dpm_ 2302 # This can be a dpm_run_callback, dpm_prepare, or dpm_complete callgraph 2409 # Each instance is tied to a single de 2303 # Each instance is tied to a single device in a single phase, and is 2410 # comprised of an ordered list of FTra 2304 # comprised of an ordered list of FTraceLine objects 2411 class FTraceCallGraph: 2305 class FTraceCallGraph: 2412 vfname = 'missing_function_name' 2306 vfname = 'missing_function_name' 2413 def __init__(self, pid, sv): 2307 def __init__(self, pid, sv): 2414 self.id = '' 2308 self.id = '' 2415 self.invalid = False 2309 self.invalid = False 2416 self.name = '' 2310 self.name = '' 2417 self.partial = False 2311 self.partial = False 2418 self.ignore = False 2312 self.ignore = False 2419 self.start = -1.0 2313 self.start = -1.0 2420 self.end = -1.0 2314 self.end = -1.0 2421 self.list = [] 2315 self.list = [] 2422 self.depth = 0 2316 self.depth = 0 2423 self.pid = pid 2317 self.pid = pid 2424 self.sv = sv 2318 self.sv = sv 2425 def addLine(self, line): 2319 def addLine(self, line): 2426 # if this is already invalid, 2320 # if this is already invalid, just leave 2427 if(self.invalid): 2321 if(self.invalid): 2428 if(line.depth == 0 an 2322 if(line.depth == 0 and line.freturn): 2429 return 1 2323 return 1 2430 return 0 2324 return 0 2431 # invalidate on bad depth 2325 # invalidate on bad depth 2432 if(self.depth < 0): 2326 if(self.depth < 0): 2433 self.invalidate(line) 2327 self.invalidate(line) 2434 return 0 2328 return 0 2435 # ignore data til we return t 2329 # ignore data til we return to the current depth 2436 if self.ignore: 2330 if self.ignore: 2437 if line.depth > self. 2331 if line.depth > self.depth: 2438 return 0 2332 return 0 2439 else: 2333 else: 2440 self.list[-1] 2334 self.list[-1].freturn = True 2441 self.list[-1] 2335 self.list[-1].length = line.time - self.list[-1].time 2442 self.ignore = 2336 self.ignore = False 2443 # if this is 2337 # if this is a return at self.depth, no more work is needed 2444 if line.depth 2338 if line.depth == self.depth and line.isReturn(): 2445 if li 2339 if line.depth == 0: 2446 2340 self.end = line.time 2447 2341 return 1 2448 retur 2342 return 0 2449 # compare current depth with 2343 # compare current depth with this lines pre-call depth 2450 prelinedep = line.depth 2344 prelinedep = line.depth 2451 if line.isReturn(): 2345 if line.isReturn(): 2452 prelinedep += 1 2346 prelinedep += 1 2453 last = 0 2347 last = 0 2454 lasttime = line.time 2348 lasttime = line.time 2455 if len(self.list) > 0: 2349 if len(self.list) > 0: 2456 last = self.list[-1] 2350 last = self.list[-1] 2457 lasttime = last.time 2351 lasttime = last.time 2458 if last.isLeaf(): 2352 if last.isLeaf(): 2459 lasttime += l 2353 lasttime += last.length 2460 # handle low misalignments by 2354 # handle low misalignments by inserting returns 2461 mismatch = prelinedep - self. 2355 mismatch = prelinedep - self.depth 2462 warning = self.sv.verbose and 2356 warning = self.sv.verbose and abs(mismatch) > 1 2463 info = [] 2357 info = [] 2464 if mismatch < 0: 2358 if mismatch < 0: 2465 idx = 0 2359 idx = 0 2466 # add return calls to 2360 # add return calls to get the depth down 2467 while prelinedep < se 2361 while prelinedep < self.depth: 2468 self.depth -= 2362 self.depth -= 1 2469 if idx == 0 a 2363 if idx == 0 and last and last.isCall(): 2470 # spe 2364 # special case, turn last call into a leaf 2471 last. 2365 last.depth = self.depth 2472 last. 2366 last.freturn = True 2473 last. 2367 last.length = line.time - last.time 2474 if wa 2368 if warning: 2475 2369 info.append(('[make leaf]', last)) 2476 else: 2370 else: 2477 vline 2371 vline = FTraceLine(lasttime) 2478 vline 2372 vline.depth = self.depth 2479 vline 2373 vline.name = self.vfname 2480 vline 2374 vline.freturn = True 2481 self. 2375 self.list.append(vline) 2482 if wa 2376 if warning: 2483 2377 if idx == 0: 2484 2378 info.append(('', last)) 2485 2379 info.append(('[add return]', vline)) 2486 idx += 1 2380 idx += 1 2487 if warning: 2381 if warning: 2488 info.append(( 2382 info.append(('', line)) 2489 # handle high misalignments b 2383 # handle high misalignments by inserting calls 2490 elif mismatch > 0: 2384 elif mismatch > 0: 2491 idx = 0 2385 idx = 0 2492 if warning: 2386 if warning: 2493 info.append(( 2387 info.append(('', last)) 2494 # add calls to get th 2388 # add calls to get the depth up 2495 while prelinedep > se 2389 while prelinedep > self.depth: 2496 if idx == 0 a 2390 if idx == 0 and line.isReturn(): 2497 # spe 2391 # special case, turn this return into a leaf 2498 line. 2392 line.fcall = True 2499 preli 2393 prelinedep -= 1 2500 if wa 2394 if warning: 2501 2395 info.append(('[make leaf]', line)) 2502 else: 2396 else: 2503 vline 2397 vline = FTraceLine(lasttime) 2504 vline 2398 vline.depth = self.depth 2505 vline 2399 vline.name = self.vfname 2506 vline 2400 vline.fcall = True 2507 self. 2401 self.list.append(vline) 2508 self. 2402 self.depth += 1 2509 if no 2403 if not last: 2510 2404 self.start = vline.time 2511 if wa 2405 if warning: 2512 2406 info.append(('[add call]', vline)) 2513 idx += 1 2407 idx += 1 2514 if warning and ('[mak 2408 if warning and ('[make leaf]', line) not in info: 2515 info.append(( 2409 info.append(('', line)) 2516 if warning: 2410 if warning: 2517 pprint('WARNING: ftra 2411 pprint('WARNING: ftrace data missing, corrections made:') 2518 for i in info: 2412 for i in info: 2519 t, obj = i 2413 t, obj = i 2520 if obj: 2414 if obj: 2521 obj.d 2415 obj.debugPrint(t) 2522 # process the call and set th 2416 # process the call and set the new depth 2523 skipadd = False 2417 skipadd = False 2524 md = self.sv.max_graph_depth 2418 md = self.sv.max_graph_depth 2525 if line.isCall(): 2419 if line.isCall(): 2526 # ignore blacklisted/ 2420 # ignore blacklisted/overdepth funcs 2527 if (md and self.depth 2421 if (md and self.depth >= md - 1) or (line.name in self.sv.cgblacklist): 2528 self.ignore = 2422 self.ignore = True 2529 else: 2423 else: 2530 self.depth += 2424 self.depth += 1 2531 elif line.isReturn(): 2425 elif line.isReturn(): 2532 self.depth -= 1 2426 self.depth -= 1 2533 # remove blacklisted/ 2427 # remove blacklisted/overdepth/empty funcs that slipped through 2534 if (last and last.isC 2428 if (last and last.isCall() and last.depth == line.depth) or \ 2535 (md and last 2429 (md and last and last.depth >= md) or \ 2536 (line.name in 2430 (line.name in self.sv.cgblacklist): 2537 while len(sel 2431 while len(self.list) > 0 and self.list[-1].depth > line.depth: 2538 self. 2432 self.list.pop(-1) 2539 if len(self.l 2433 if len(self.list) == 0: 2540 self. 2434 self.invalid = True 2541 retur 2435 return 1 2542 self.list[-1] 2436 self.list[-1].freturn = True 2543 self.list[-1] 2437 self.list[-1].length = line.time - self.list[-1].time 2544 self.list[-1] 2438 self.list[-1].name = line.name 2545 skipadd = Tru 2439 skipadd = True 2546 if len(self.list) < 1: 2440 if len(self.list) < 1: 2547 self.start = line.tim 2441 self.start = line.time 2548 # check for a mismatch that r 2442 # check for a mismatch that returned all the way to callgraph end 2549 res = 1 2443 res = 1 2550 if mismatch < 0 and self.list 2444 if mismatch < 0 and self.list[-1].depth == 0 and self.list[-1].freturn: 2551 line = self.list[-1] 2445 line = self.list[-1] 2552 skipadd = True 2446 skipadd = True 2553 res = -1 2447 res = -1 2554 if not skipadd: 2448 if not skipadd: 2555 self.list.append(line 2449 self.list.append(line) 2556 if(line.depth == 0 and line.f 2450 if(line.depth == 0 and line.freturn): 2557 if(self.start < 0): 2451 if(self.start < 0): 2558 self.start = 2452 self.start = line.time 2559 self.end = line.time 2453 self.end = line.time 2560 if line.fcall: 2454 if line.fcall: 2561 self.end += l 2455 self.end += line.length 2562 if self.list[0].name 2456 if self.list[0].name == self.vfname: 2563 self.invalid 2457 self.invalid = True 2564 if res == -1: 2458 if res == -1: 2565 self.partial 2459 self.partial = True 2566 return res 2460 return res 2567 return 0 2461 return 0 2568 def invalidate(self, line): 2462 def invalidate(self, line): 2569 if(len(self.list) > 0): 2463 if(len(self.list) > 0): 2570 first = self.list[0] 2464 first = self.list[0] 2571 self.list = [] 2465 self.list = [] 2572 self.list.append(firs 2466 self.list.append(first) 2573 self.invalid = True 2467 self.invalid = True 2574 id = 'task %s' % (self.pid) 2468 id = 'task %s' % (self.pid) 2575 window = '(%f - %f)' % (self. 2469 window = '(%f - %f)' % (self.start, line.time) 2576 if(self.depth < 0): 2470 if(self.depth < 0): 2577 pprint('Data misalign 2471 pprint('Data misalignment for '+id+\ 2578 ' (buffer ove 2472 ' (buffer overflow), ignoring this callback') 2579 else: 2473 else: 2580 pprint('Too much data 2474 pprint('Too much data for '+id+\ 2581 ' '+window+', 2475 ' '+window+', ignoring this callback') 2582 def slice(self, dev): 2476 def slice(self, dev): 2583 minicg = FTraceCallGraph(dev[ 2477 minicg = FTraceCallGraph(dev['pid'], self.sv) 2584 minicg.name = self.name 2478 minicg.name = self.name 2585 mydepth = -1 2479 mydepth = -1 2586 good = False 2480 good = False 2587 for l in self.list: 2481 for l in self.list: 2588 if(l.time < dev['star 2482 if(l.time < dev['start'] or l.time > dev['end']): 2589 continue 2483 continue 2590 if mydepth < 0: 2484 if mydepth < 0: 2591 if l.name == 2485 if l.name == 'mutex_lock' and l.freturn: 2592 mydep 2486 mydepth = l.depth 2593 continue 2487 continue 2594 elif l.depth == mydep 2488 elif l.depth == mydepth and l.name == 'mutex_unlock' and l.fcall: 2595 good = True 2489 good = True 2596 break 2490 break 2597 l.depth -= mydepth 2491 l.depth -= mydepth 2598 minicg.addLine(l) 2492 minicg.addLine(l) 2599 if not good or len(minicg.lis 2493 if not good or len(minicg.list) < 1: 2600 return 0 2494 return 0 2601 return minicg 2495 return minicg 2602 def repair(self, enddepth): 2496 def repair(self, enddepth): 2603 # bring the depth back to 0 w 2497 # bring the depth back to 0 with additional returns 2604 fixed = False 2498 fixed = False 2605 last = self.list[-1] 2499 last = self.list[-1] 2606 for i in reversed(range(endde 2500 for i in reversed(range(enddepth)): 2607 t = FTraceLine(last.t 2501 t = FTraceLine(last.time) 2608 t.depth = i 2502 t.depth = i 2609 t.freturn = True 2503 t.freturn = True 2610 fixed = self.addLine( 2504 fixed = self.addLine(t) 2611 if fixed != 0: 2505 if fixed != 0: 2612 self.end = la 2506 self.end = last.time 2613 return True 2507 return True 2614 return False 2508 return False 2615 def postProcess(self): 2509 def postProcess(self): 2616 if len(self.list) > 0: 2510 if len(self.list) > 0: 2617 self.name = self.list 2511 self.name = self.list[0].name 2618 stack = dict() 2512 stack = dict() 2619 cnt = 0 2513 cnt = 0 2620 last = 0 2514 last = 0 2621 for l in self.list: 2515 for l in self.list: 2622 # ftrace bug: reporte 2516 # ftrace bug: reported duration is not reliable 2623 # check each leaf and 2517 # check each leaf and clip it at max possible length 2624 if last and last.isLe 2518 if last and last.isLeaf(): 2625 if last.lengt 2519 if last.length > l.time - last.time: 2626 last. 2520 last.length = l.time - last.time 2627 if l.isCall(): 2521 if l.isCall(): 2628 stack[l.depth 2522 stack[l.depth] = l 2629 cnt += 1 2523 cnt += 1 2630 elif l.isReturn(): 2524 elif l.isReturn(): 2631 if(l.depth no 2525 if(l.depth not in stack): 2632 if se 2526 if self.sv.verbose: 2633 2527 pprint('Post Process Error: Depth missing') 2634 2528 l.debugPrint() 2635 retur 2529 return False 2636 # calculate c 2530 # calculate call length from call/return lines 2637 cl = stack[l. 2531 cl = stack[l.depth] 2638 cl.length = l 2532 cl.length = l.time - cl.time 2639 if cl.name == 2533 if cl.name == self.vfname: 2640 cl.na 2534 cl.name = l.name 2641 stack.pop(l.d 2535 stack.pop(l.depth) 2642 l.length = 0 2536 l.length = 0 2643 cnt -= 1 2537 cnt -= 1 2644 last = l 2538 last = l 2645 if(cnt == 0): 2539 if(cnt == 0): 2646 # trace caught the wh 2540 # trace caught the whole call tree 2647 return True 2541 return True 2648 elif(cnt < 0): 2542 elif(cnt < 0): 2649 if self.sv.verbose: 2543 if self.sv.verbose: 2650 pprint('Post 2544 pprint('Post Process Error: Depth is less than 0') 2651 return False 2545 return False 2652 # trace ended before call tre 2546 # trace ended before call tree finished 2653 return self.repair(cnt) 2547 return self.repair(cnt) 2654 def deviceMatch(self, pid, data): 2548 def deviceMatch(self, pid, data): 2655 found = '' 2549 found = '' 2656 # add the callgraph data to t 2550 # add the callgraph data to the device hierarchy 2657 borderphase = { 2551 borderphase = { 2658 'dpm_prepare': 'suspe 2552 'dpm_prepare': 'suspend_prepare', 2659 'dpm_complete': 'resu 2553 'dpm_complete': 'resume_complete' 2660 } 2554 } 2661 if(self.name in borderphase): 2555 if(self.name in borderphase): 2662 p = borderphase[self. 2556 p = borderphase[self.name] 2663 list = data.dmesg[p][ 2557 list = data.dmesg[p]['list'] 2664 for devname in list: 2558 for devname in list: 2665 dev = list[de 2559 dev = list[devname] 2666 if(pid == dev 2560 if(pid == dev['pid'] and 2667 self. 2561 self.start <= dev['start'] and 2668 self. 2562 self.end >= dev['end']): 2669 cg = 2563 cg = self.slice(dev) 2670 if cg 2564 if cg: 2671 2565 dev['ftrace'] = cg 2672 found 2566 found = devname 2673 return found 2567 return found 2674 for p in data.sortedPhases(): 2568 for p in data.sortedPhases(): 2675 if(data.dmesg[p]['sta 2569 if(data.dmesg[p]['start'] <= self.start and 2676 self.start <= 2570 self.start <= data.dmesg[p]['end']): 2677 list = data.d 2571 list = data.dmesg[p]['list'] 2678 for devname i 2572 for devname in sorted(list, key=lambda k:list[k]['start']): 2679 dev = 2573 dev = list[devname] 2680 if(pi 2574 if(pid == dev['pid'] and 2681 2575 self.start <= dev['start'] and 2682 2576 self.end >= dev['end']): 2683 2577 dev['ftrace'] = self 2684 2578 found = devname 2685 2579 break 2686 break 2580 break 2687 return found 2581 return found 2688 def newActionFromFunction(self, data) 2582 def newActionFromFunction(self, data): 2689 name = self.name 2583 name = self.name 2690 if name in ['dpm_run_callback 2584 if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']: 2691 return 2585 return 2692 fs = self.start 2586 fs = self.start 2693 fe = self.end 2587 fe = self.end 2694 if fs < data.start or fe > da 2588 if fs < data.start or fe > data.end: 2695 return 2589 return 2696 phase = '' 2590 phase = '' 2697 for p in data.sortedPhases(): 2591 for p in data.sortedPhases(): 2698 if(data.dmesg[p]['sta 2592 if(data.dmesg[p]['start'] <= self.start and 2699 self.start < 2593 self.start < data.dmesg[p]['end']): 2700 phase = p 2594 phase = p 2701 break 2595 break 2702 if not phase: 2596 if not phase: 2703 return 2597 return 2704 out = data.newActionGlobal(na 2598 out = data.newActionGlobal(name, fs, fe, -2) 2705 if out: 2599 if out: 2706 phase, myname = out 2600 phase, myname = out 2707 data.dmesg[phase]['li 2601 data.dmesg[phase]['list'][myname]['ftrace'] = self 2708 def debugPrint(self, info=''): 2602 def debugPrint(self, info=''): 2709 pprint('%s pid=%d [%f - %f] % 2603 pprint('%s pid=%d [%f - %f] %.3f us' % \ 2710 (self.name, self.pid, 2604 (self.name, self.pid, self.start, self.end, 2711 (self.end - self.star 2605 (self.end - self.start)*1000000)) 2712 for l in self.list: 2606 for l in self.list: 2713 if l.isLeaf(): 2607 if l.isLeaf(): 2714 pprint('%f (% 2608 pprint('%f (%02d): %s(); (%.3f us)%s' % (l.time, \ 2715 l.dep 2609 l.depth, l.name, l.length*1000000, info)) 2716 elif l.freturn: 2610 elif l.freturn: 2717 pprint('%f (% 2611 pprint('%f (%02d): %s} (%.3f us)%s' % (l.time, \ 2718 l.dep 2612 l.depth, l.name, l.length*1000000, info)) 2719 else: 2613 else: 2720 pprint('%f (% 2614 pprint('%f (%02d): %s() { (%.3f us)%s' % (l.time, \ 2721 l.dep 2615 l.depth, l.name, l.length*1000000, info)) 2722 pprint(' ') 2616 pprint(' ') 2723 2617 2724 class DevItem: 2618 class DevItem: 2725 def __init__(self, test, phase, dev): 2619 def __init__(self, test, phase, dev): 2726 self.test = test 2620 self.test = test 2727 self.phase = phase 2621 self.phase = phase 2728 self.dev = dev 2622 self.dev = dev 2729 def isa(self, cls): 2623 def isa(self, cls): 2730 if 'htmlclass' in self.dev an 2624 if 'htmlclass' in self.dev and cls in self.dev['htmlclass']: 2731 return True 2625 return True 2732 return False 2626 return False 2733 2627 2734 # Class: Timeline 2628 # Class: Timeline 2735 # Description: 2629 # Description: 2736 # A container for a device timeline wh 2630 # A container for a device timeline which calculates 2737 # all the html properties to display i 2631 # all the html properties to display it correctly 2738 class Timeline: 2632 class Timeline: 2739 html_tblock = '<div id="block{0}" cla 2633 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="{ 2634 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 2635 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= 2636 html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' 2743 html_legend = '<div id="p{3}" class=" 2637 html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' 2744 def __init__(self, rowheight, scalehe 2638 def __init__(self, rowheight, scaleheight): 2745 self.html = '' 2639 self.html = '' 2746 self.height = 0 # total time 2640 self.height = 0 # total timeline height 2747 self.scaleH = scaleheight # t 2641 self.scaleH = scaleheight # timescale (top) row height 2748 self.rowH = rowheight # d 2642 self.rowH = rowheight # device row height 2749 self.bodyH = 0 # body heigh 2643 self.bodyH = 0 # body height 2750 self.rows = 0 # total time 2644 self.rows = 0 # total timeline rows 2751 self.rowlines = dict() 2645 self.rowlines = dict() 2752 self.rowheight = dict() 2646 self.rowheight = dict() 2753 def createHeader(self, sv, stamp): 2647 def createHeader(self, sv, stamp): 2754 if(not stamp['time']): 2648 if(not stamp['time']): 2755 return 2649 return 2756 self.html += '<div class="ver 2650 self.html += '<div class="version"><a href="https://01.org/pm-graph">%s v%s</a></div>' \ 2757 % (sv.title, sv.versi 2651 % (sv.title, sv.version) 2758 if sv.logmsg and sv.testlog: 2652 if sv.logmsg and sv.testlog: 2759 self.html += '<button 2653 self.html += '<button id="showtest" class="logbtn btnfmt">log</button>' 2760 if sv.dmesglog: 2654 if sv.dmesglog: 2761 self.html += '<button 2655 self.html += '<button id="showdmesg" class="logbtn btnfmt">dmesg</button>' 2762 if sv.ftracelog: 2656 if sv.ftracelog: 2763 self.html += '<button 2657 self.html += '<button id="showftrace" class="logbtn btnfmt">ftrace</button>' 2764 headline_stamp = '<div class= 2658 headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' 2765 self.html += headline_stamp.f 2659 self.html += headline_stamp.format(stamp['host'], stamp['kernel'], 2766 stamp['mode'], stamp[ 2660 stamp['mode'], stamp['time']) 2767 if 'man' in stamp and 'plat' 2661 if 'man' in stamp and 'plat' in stamp and 'cpu' in stamp and \ 2768 stamp['man'] and stam 2662 stamp['man'] and stamp['plat'] and stamp['cpu']: 2769 headline_sysinfo = '< 2663 headline_sysinfo = '<div class="stamp sysinfo">{0} {1} <i>with</i> {2}</div>\n' 2770 self.html += headline 2664 self.html += headline_sysinfo.format(stamp['man'], stamp['plat'], stamp['cpu']) 2771 2665 2772 # Function: getDeviceRows 2666 # Function: getDeviceRows 2773 # Description: 2667 # Description: 2774 # determine how may rows the devic 2668 # determine how may rows the device funcs will take 2775 # Arguments: 2669 # Arguments: 2776 # rawlist: the list of devices 2670 # rawlist: the list of devices/actions for a single phase 2777 # Output: 2671 # Output: 2778 # The total number of rows nee 2672 # The total number of rows needed to display this phase of the timeline 2779 def getDeviceRows(self, rawlist): 2673 def getDeviceRows(self, rawlist): 2780 # clear all rows and set them 2674 # clear all rows and set them to undefined 2781 sortdict = dict() 2675 sortdict = dict() 2782 for item in rawlist: 2676 for item in rawlist: 2783 item.row = -1 2677 item.row = -1 2784 sortdict[item] = item 2678 sortdict[item] = item.length 2785 sortlist = sorted(sortdict, k 2679 sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 2786 remaining = len(sortlist) 2680 remaining = len(sortlist) 2787 rowdata = dict() 2681 rowdata = dict() 2788 row = 1 2682 row = 1 2789 # try to pack each row with a 2683 # try to pack each row with as many ranges as possible 2790 while(remaining > 0): 2684 while(remaining > 0): 2791 if(row not in rowdata 2685 if(row not in rowdata): 2792 rowdata[row] 2686 rowdata[row] = [] 2793 for i in sortlist: 2687 for i in sortlist: 2794 if(i.row >= 0 2688 if(i.row >= 0): 2795 conti 2689 continue 2796 s = i.time 2690 s = i.time 2797 e = i.time + 2691 e = i.time + i.length 2798 valid = True 2692 valid = True 2799 for ritem in 2693 for ritem in rowdata[row]: 2800 rs = 2694 rs = ritem.time 2801 re = 2695 re = ritem.time + ritem.length 2802 if(no 2696 if(not (((s <= rs) and (e <= rs)) or 2803 2697 ((s >= re) and (e >= re)))): 2804 2698 valid = False 2805 2699 break 2806 if(valid): 2700 if(valid): 2807 rowda 2701 rowdata[row].append(i) 2808 i.row 2702 i.row = row 2809 remai 2703 remaining -= 1 2810 row += 1 2704 row += 1 2811 return row 2705 return row 2812 # Function: getPhaseRows 2706 # Function: getPhaseRows 2813 # Description: 2707 # Description: 2814 # Organize the timeline entrie 2708 # Organize the timeline entries into the smallest 2815 # number of rows possible, wit 2709 # number of rows possible, with no entry overlapping 2816 # Arguments: 2710 # Arguments: 2817 # devlist: the list of devices 2711 # devlist: the list of devices/actions in a group of contiguous phases 2818 # Output: 2712 # Output: 2819 # The total number of rows nee 2713 # The total number of rows needed to display this phase of the timeline 2820 def getPhaseRows(self, devlist, row=0 2714 def getPhaseRows(self, devlist, row=0, sortby='length'): 2821 # clear all rows and set them 2715 # clear all rows and set them to undefined 2822 remaining = len(devlist) 2716 remaining = len(devlist) 2823 rowdata = dict() 2717 rowdata = dict() 2824 sortdict = dict() 2718 sortdict = dict() 2825 myphases = [] 2719 myphases = [] 2826 # initialize all device rows 2720 # initialize all device rows to -1 and calculate devrows 2827 for item in devlist: 2721 for item in devlist: 2828 dev = item.dev 2722 dev = item.dev 2829 tp = (item.test, item 2723 tp = (item.test, item.phase) 2830 if tp not in myphases 2724 if tp not in myphases: 2831 myphases.appe 2725 myphases.append(tp) 2832 dev['row'] = -1 2726 dev['row'] = -1 2833 if sortby == 'start': 2727 if sortby == 'start': 2834 # sort by sta 2728 # sort by start 1st, then length 2nd 2835 sortdict[item 2729 sortdict[item] = (-1*float(dev['start']), float(dev['end']) - float(dev['start'])) 2836 else: 2730 else: 2837 # sort by len 2731 # sort by length 1st, then name 2nd 2838 sortdict[item 2732 sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) 2839 if 'src' in dev: 2733 if 'src' in dev: 2840 dev['devrows' 2734 dev['devrows'] = self.getDeviceRows(dev['src']) 2841 # sort the devlist by length 2735 # sort the devlist by length so that large items graph on top 2842 sortlist = sorted(sortdict, k 2736 sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 2843 orderedlist = [] 2737 orderedlist = [] 2844 for item in sortlist: 2738 for item in sortlist: 2845 if item.dev['pid'] == 2739 if item.dev['pid'] == -2: 2846 orderedlist.a 2740 orderedlist.append(item) 2847 for item in sortlist: 2741 for item in sortlist: 2848 if item not in ordere 2742 if item not in orderedlist: 2849 orderedlist.a 2743 orderedlist.append(item) 2850 # try to pack each row with a 2744 # try to pack each row with as many devices as possible 2851 while(remaining > 0): 2745 while(remaining > 0): 2852 rowheight = 1 2746 rowheight = 1 2853 if(row not in rowdata 2747 if(row not in rowdata): 2854 rowdata[row] 2748 rowdata[row] = [] 2855 for item in orderedli 2749 for item in orderedlist: 2856 dev = item.de 2750 dev = item.dev 2857 if(dev['row'] 2751 if(dev['row'] < 0): 2858 s = d 2752 s = dev['start'] 2859 e = d 2753 e = dev['end'] 2860 valid 2754 valid = True 2861 for r 2755 for ritem in rowdata[row]: 2862 2756 rs = ritem.dev['start'] 2863 2757 re = ritem.dev['end'] 2864 2758 if(not (((s <= rs) and (e <= rs)) or 2865 2759 ((s >= re) and (e >= re)))): 2866 2760 valid = False 2867 2761 break 2868 if(va 2762 if(valid): 2869 2763 rowdata[row].append(item) 2870 2764 dev['row'] = row 2871 2765 remaining -= 1 2872 2766 if 'devrows' in dev and dev['devrows'] > rowheight: 2873 2767 rowheight = dev['devrows'] 2874 for t, p in myphases: 2768 for t, p in myphases: 2875 if t not in s 2769 if t not in self.rowlines or t not in self.rowheight: 2876 self. 2770 self.rowlines[t] = dict() 2877 self. 2771 self.rowheight[t] = dict() 2878 if p not in s 2772 if p not in self.rowlines[t] or p not in self.rowheight[t]: 2879 self. 2773 self.rowlines[t][p] = dict() 2880 self. 2774 self.rowheight[t][p] = dict() 2881 rh = self.row 2775 rh = self.rowH 2882 # section hea 2776 # section headers should use a different row height 2883 if len(rowdat 2777 if len(rowdata[row]) == 1 and \ 2884 'html 2778 'htmlclass' in rowdata[row][0].dev and \ 2885 'sec' 2779 'sec' in rowdata[row][0].dev['htmlclass']: 2886 rh = 2780 rh = 15 2887 self.rowlines 2781 self.rowlines[t][p][row] = rowheight 2888 self.rowheigh 2782 self.rowheight[t][p][row] = rowheight * rh 2889 row += 1 2783 row += 1 2890 if(row > self.rows): 2784 if(row > self.rows): 2891 self.rows = int(row) 2785 self.rows = int(row) 2892 return row 2786 return row 2893 def phaseRowHeight(self, test, phase, 2787 def phaseRowHeight(self, test, phase, row): 2894 return self.rowheight[test][p 2788 return self.rowheight[test][phase][row] 2895 def phaseRowTop(self, test, phase, ro 2789 def phaseRowTop(self, test, phase, row): 2896 top = 0 2790 top = 0 2897 for i in sorted(self.rowheigh 2791 for i in sorted(self.rowheight[test][phase]): 2898 if i >= row: 2792 if i >= row: 2899 break 2793 break 2900 top += self.rowheight 2794 top += self.rowheight[test][phase][i] 2901 return top 2795 return top 2902 def calcTotalRows(self): 2796 def calcTotalRows(self): 2903 # Calculate the heights and o 2797 # Calculate the heights and offsets for the header and rows 2904 maxrows = 0 2798 maxrows = 0 2905 standardphases = [] 2799 standardphases = [] 2906 for t in self.rowlines: 2800 for t in self.rowlines: 2907 for p in self.rowline 2801 for p in self.rowlines[t]: 2908 total = 0 2802 total = 0 2909 for i in sort 2803 for i in sorted(self.rowlines[t][p]): 2910 total 2804 total += self.rowlines[t][p][i] 2911 if total > ma 2805 if total > maxrows: 2912 maxro 2806 maxrows = total 2913 if total == l 2807 if total == len(self.rowlines[t][p]): 2914 stand 2808 standardphases.append((t, p)) 2915 self.height = self.scaleH + ( 2809 self.height = self.scaleH + (maxrows*self.rowH) 2916 self.bodyH = self.height - se 2810 self.bodyH = self.height - self.scaleH 2917 # if there is 1 line per row, 2811 # if there is 1 line per row, draw them the standard way 2918 for t, p in standardphases: 2812 for t, p in standardphases: 2919 for i in sorted(self. 2813 for i in sorted(self.rowheight[t][p]): 2920 self.rowheigh 2814 self.rowheight[t][p][i] = float(self.bodyH)/len(self.rowlines[t][p]) 2921 def createZoomBox(self, mode='command 2815 def createZoomBox(self, mode='command', testcount=1): 2922 # Create bounding box, add bu 2816 # Create bounding box, add buttons 2923 html_zoombox = '<center><butt 2817 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 2818 html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' 2925 html_devlist1 = '<button id=" 2819 html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail{0}</button>' 2926 html_devlist2 = '<button id=" 2820 html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' 2927 if mode != 'command': 2821 if mode != 'command': 2928 if testcount > 1: 2822 if testcount > 1: 2929 self.html += 2823 self.html += html_devlist2 2930 self.html += 2824 self.html += html_devlist1.format('1') 2931 else: 2825 else: 2932 self.html += 2826 self.html += html_devlist1.format('') 2933 self.html += html_zoombox 2827 self.html += html_zoombox 2934 self.html += html_timeline.fo 2828 self.html += html_timeline.format('dmesg', self.height) 2935 # Function: createTimeScale 2829 # Function: createTimeScale 2936 # Description: 2830 # Description: 2937 # Create the timescale for a t 2831 # Create the timescale for a timeline block 2938 # Arguments: 2832 # Arguments: 2939 # m0: start time (mode begin) 2833 # m0: start time (mode begin) 2940 # mMax: end time (mode end) 2834 # mMax: end time (mode end) 2941 # tTotal: total timeline time 2835 # tTotal: total timeline time 2942 # mode: suspend or resume 2836 # mode: suspend or resume 2943 # Output: 2837 # Output: 2944 # The html code needed to disp 2838 # The html code needed to display the time scale 2945 def createTimeScale(self, m0, mMax, t 2839 def createTimeScale(self, m0, mMax, tTotal, mode): 2946 timescale = '<div class="t" s 2840 timescale = '<div class="t" style="right:{0}%">{1}</div>\n' 2947 rline = '<div class="t" style 2841 rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">{0}</div>\n' 2948 output = '<div class="timesca 2842 output = '<div class="timescale">\n' 2949 # set scale for timeline 2843 # set scale for timeline 2950 mTotal = mMax - m0 2844 mTotal = mMax - m0 2951 tS = 0.1 2845 tS = 0.1 2952 if(tTotal <= 0): 2846 if(tTotal <= 0): 2953 return output+'</div> 2847 return output+'</div>\n' 2954 if(tTotal > 4): 2848 if(tTotal > 4): 2955 tS = 1 2849 tS = 1 2956 divTotal = int(mTotal/tS) + 1 2850 divTotal = int(mTotal/tS) + 1 2957 divEdge = (mTotal - tS*(divTo 2851 divEdge = (mTotal - tS*(divTotal-1))*100/mTotal 2958 for i in range(divTotal): 2852 for i in range(divTotal): 2959 htmlline = '' 2853 htmlline = '' 2960 if(mode == 'suspend') 2854 if(mode == 'suspend'): 2961 pos = '%0.3f' 2855 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge) 2962 val = '%0.fms 2856 val = '%0.fms' % (float(i-divTotal+1)*tS*1000) 2963 if(i == divTo 2857 if(i == divTotal - 1): 2964 val = 2858 val = mode 2965 htmlline = ti 2859 htmlline = timescale.format(pos, val) 2966 else: 2860 else: 2967 pos = '%0.3f' 2861 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal)) 2968 val = '%0.fms 2862 val = '%0.fms' % (float(i)*tS*1000) 2969 htmlline = ti 2863 htmlline = timescale.format(pos, val) 2970 if(i == 0): 2864 if(i == 0): 2971 htmll 2865 htmlline = rline.format(mode) 2972 output += htmlline 2866 output += htmlline 2973 self.html += output+'</div>\n 2867 self.html += output+'</div>\n' 2974 2868 2975 # Class: TestProps 2869 # Class: TestProps 2976 # Description: 2870 # Description: 2977 # A list of values describing the prop 2871 # A list of values describing the properties of these test runs 2978 class TestProps: 2872 class TestProps: 2979 stampfmt = r'# [a-z]*-(?P<m>[0-9]{2}) !! 2873 stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ 2980 r'(?P<H>[0-9] !! 2874 '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ 2981 r' (?P<host>. !! 2875 ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' 2982 wififmt = r'^# wifi *(?P<d>\S*) *( !! 2876 wififmt = '^# wifi *(?P<d>\S*) *(?P<s>\S*) *(?P<t>[0-9\.]+).*' 2983 tstatfmt = r'^# turbostat (?P<t>\S* !! 2877 tstatfmt = '^# turbostat (?P<t>\S*)' 2984 testerrfmt = r'^# enter_sleep_error ( !! 2878 testerrfmt = '^# enter_sleep_error (?P<e>.*)' 2985 sysinfofmt = r'^# sysinfo .*' !! 2879 sysinfofmt = '^# sysinfo .*' 2986 cmdlinefmt = r'^# command \| (?P<cmd> !! 2880 cmdlinefmt = '^# command \| (?P<cmd>.*)' 2987 kparamsfmt = r'^# kparams \| (?P<kp>. !! 2881 kparamsfmt = '^# kparams \| (?P<kp>.*)' 2988 devpropfmt = r'# Device Properties: . !! 2882 devpropfmt = '# Device Properties: .*' 2989 pinfofmt = r'# platform-(?P<val>[a- !! 2883 pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)' 2990 tracertypefmt = r'# tracer: (?P<t>.*) !! 2884 tracertypefmt = '# tracer: (?P<t>.*)' 2991 firmwarefmt = r'# fwsuspend (?P<s>[0- !! 2885 firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' 2992 procexecfmt = r'ps - (?P<ps>.*)$' !! 2886 procexecfmt = 'ps - (?P<ps>.*)$' 2993 procmultifmt = r'@(?P<n>[0-9]*)\|(?P< << 2994 ftrace_line_fmt_fg = \ 2887 ftrace_line_fmt_fg = \ 2995 r'^ *(?P<time>[0-9\.]*) *\| * !! 2888 '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ 2996 r' *(?P<proc>.*)-(?P<pid>[0-9 !! 2889 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ 2997 r'[ +!#\*@$]*(?P<dur>[0-9\.]* !! 2890 '[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)' 2998 ftrace_line_fmt_nop = \ 2891 ftrace_line_fmt_nop = \ 2999 r' *(?P<proc>.*)-(?P<pid>[0-9 !! 2892 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\ 3000 r'(?P<flags>\S*) *(?P<time>[0 !! 2893 '(?P<flags>\S*) *(?P<time>[0-9\.]*): *'+\ 3001 r'(?P<msg>.*)' !! 2894 '(?P<msg>.*)' 3002 machinesuspend = r'machine_suspend\[. !! 2895 machinesuspend = 'machine_suspend\[.*' 3003 multiproclist = dict() << 3004 multiproctime = 0.0 << 3005 multiproccnt = 0 << 3006 def __init__(self): 2896 def __init__(self): 3007 self.stamp = '' 2897 self.stamp = '' 3008 self.sysinfo = '' 2898 self.sysinfo = '' 3009 self.cmdline = '' 2899 self.cmdline = '' 3010 self.testerror = [] 2900 self.testerror = [] 3011 self.turbostat = [] 2901 self.turbostat = [] 3012 self.wifi = [] 2902 self.wifi = [] 3013 self.fwdata = [] 2903 self.fwdata = [] 3014 self.ftrace_line_fmt = self.f 2904 self.ftrace_line_fmt = self.ftrace_line_fmt_nop 3015 self.cgformat = False 2905 self.cgformat = False 3016 self.data = 0 2906 self.data = 0 3017 self.ktemp = dict() 2907 self.ktemp = dict() 3018 def setTracerType(self, tracer): 2908 def setTracerType(self, tracer): 3019 if(tracer == 'function_graph' 2909 if(tracer == 'function_graph'): 3020 self.cgformat = True 2910 self.cgformat = True 3021 self.ftrace_line_fmt 2911 self.ftrace_line_fmt = self.ftrace_line_fmt_fg 3022 elif(tracer == 'nop'): 2912 elif(tracer == 'nop'): 3023 self.ftrace_line_fmt 2913 self.ftrace_line_fmt = self.ftrace_line_fmt_nop 3024 else: 2914 else: 3025 doError('Invalid trac 2915 doError('Invalid tracer format: [%s]' % tracer) 3026 def stampInfo(self, line, sv): 2916 def stampInfo(self, line, sv): 3027 if re.match(self.stampfmt, li 2917 if re.match(self.stampfmt, line): 3028 self.stamp = line 2918 self.stamp = line 3029 return True 2919 return True 3030 elif re.match(self.sysinfofmt 2920 elif re.match(self.sysinfofmt, line): 3031 self.sysinfo = line 2921 self.sysinfo = line 3032 return True 2922 return True 3033 elif re.match(self.tstatfmt, 2923 elif re.match(self.tstatfmt, line): 3034 self.turbostat.append 2924 self.turbostat.append(line) 3035 return True 2925 return True 3036 elif re.match(self.wififmt, l 2926 elif re.match(self.wififmt, line): 3037 self.wifi.append(line 2927 self.wifi.append(line) 3038 return True 2928 return True 3039 elif re.match(self.testerrfmt 2929 elif re.match(self.testerrfmt, line): 3040 self.testerror.append 2930 self.testerror.append(line) 3041 return True 2931 return True 3042 elif re.match(self.firmwarefm 2932 elif re.match(self.firmwarefmt, line): 3043 self.fwdata.append(li 2933 self.fwdata.append(line) 3044 return True 2934 return True 3045 elif(re.match(self.devpropfmt 2935 elif(re.match(self.devpropfmt, line)): 3046 self.parseDevprops(li 2936 self.parseDevprops(line, sv) 3047 return True 2937 return True 3048 elif(re.match(self.pinfofmt, 2938 elif(re.match(self.pinfofmt, line)): 3049 self.parsePlatformInf 2939 self.parsePlatformInfo(line, sv) 3050 return True 2940 return True 3051 m = re.match(self.cmdlinefmt, 2941 m = re.match(self.cmdlinefmt, line) 3052 if m: 2942 if m: 3053 self.cmdline = m.grou 2943 self.cmdline = m.group('cmd') 3054 return True 2944 return True 3055 m = re.match(self.tracertypef 2945 m = re.match(self.tracertypefmt, line) 3056 if(m): 2946 if(m): 3057 self.setTracerType(m. 2947 self.setTracerType(m.group('t')) 3058 return True 2948 return True 3059 return False 2949 return False 3060 def parseStamp(self, data, sv): 2950 def parseStamp(self, data, sv): 3061 # global test data 2951 # global test data 3062 m = re.match(self.stampfmt, s 2952 m = re.match(self.stampfmt, self.stamp) 3063 if not self.stamp or not m: 2953 if not self.stamp or not m: 3064 doError('data does no 2954 doError('data does not include the expected stamp') 3065 data.stamp = {'time': '', 'ho 2955 data.stamp = {'time': '', 'host': '', 'mode': ''} 3066 dt = datetime(int(m.group('y' 2956 dt = datetime(int(m.group('y'))+2000, int(m.group('m')), 3067 int(m.group('d')), in 2957 int(m.group('d')), int(m.group('H')), int(m.group('M')), 3068 int(m.group('S'))) 2958 int(m.group('S'))) 3069 data.stamp['time'] = dt.strft 2959 data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') 3070 data.stamp['host'] = m.group( 2960 data.stamp['host'] = m.group('host') 3071 data.stamp['mode'] = m.group( 2961 data.stamp['mode'] = m.group('mode') 3072 data.stamp['kernel'] = m.grou 2962 data.stamp['kernel'] = m.group('kernel') 3073 if re.match(self.sysinfofmt, 2963 if re.match(self.sysinfofmt, self.sysinfo): 3074 for f in self.sysinfo 2964 for f in self.sysinfo.split('|'): 3075 if '#' in f: 2965 if '#' in f: 3076 conti 2966 continue 3077 tmp = f.strip 2967 tmp = f.strip().split(':', 1) 3078 key = tmp[0] 2968 key = tmp[0] 3079 val = tmp[1] 2969 val = tmp[1] 3080 data.stamp[ke 2970 data.stamp[key] = val 3081 sv.hostname = data.stamp['hos 2971 sv.hostname = data.stamp['host'] 3082 sv.suspendmode = data.stamp[' 2972 sv.suspendmode = data.stamp['mode'] 3083 if sv.suspendmode == 'freeze' 2973 if sv.suspendmode == 'freeze': 3084 self.machinesuspend = !! 2974 self.machinesuspend = 'timekeeping_freeze\[.*' 3085 else: 2975 else: 3086 self.machinesuspend = !! 2976 self.machinesuspend = 'machine_suspend\[.*' 3087 if sv.suspendmode == 'command 2977 if sv.suspendmode == 'command' and sv.ftracefile != '': 3088 modes = ['on', 'freez 2978 modes = ['on', 'freeze', 'standby', 'mem', 'disk'] 3089 fp = sv.openlog(sv.ft 2979 fp = sv.openlog(sv.ftracefile, 'r') 3090 for line in fp: 2980 for line in fp: 3091 m = re.match( !! 2981 m = re.match('.* machine_suspend\[(?P<mode>.*)\]', line) 3092 if m and m.gr 2982 if m and m.group('mode') in ['1', '2', '3', '4']: 3093 sv.su 2983 sv.suspendmode = modes[int(m.group('mode'))] 3094 data. 2984 data.stamp['mode'] = sv.suspendmode 3095 break 2985 break 3096 fp.close() 2986 fp.close() 3097 sv.cmdline = self.cmdline 2987 sv.cmdline = self.cmdline 3098 if not sv.stamp: 2988 if not sv.stamp: 3099 sv.stamp = data.stamp 2989 sv.stamp = data.stamp 3100 # firmware data 2990 # firmware data 3101 if sv.suspendmode == 'mem' an 2991 if sv.suspendmode == 'mem' and len(self.fwdata) > data.testnumber: 3102 m = re.match(self.fir 2992 m = re.match(self.firmwarefmt, self.fwdata[data.testnumber]) 3103 if m: 2993 if m: 3104 data.fwSuspen 2994 data.fwSuspend, data.fwResume = int(m.group('s')), int(m.group('r')) 3105 if(data.fwSus 2995 if(data.fwSuspend > 0 or data.fwResume > 0): 3106 data. 2996 data.fwValid = True 3107 # turbostat data 2997 # turbostat data 3108 if len(self.turbostat) > data 2998 if len(self.turbostat) > data.testnumber: 3109 m = re.match(self.tst 2999 m = re.match(self.tstatfmt, self.turbostat[data.testnumber]) 3110 if m: 3000 if m: 3111 data.turbosta 3001 data.turbostat = m.group('t') 3112 # wifi data 3002 # wifi data 3113 if len(self.wifi) > data.test 3003 if len(self.wifi) > data.testnumber: 3114 m = re.match(self.wif 3004 m = re.match(self.wififmt, self.wifi[data.testnumber]) 3115 if m: 3005 if m: 3116 data.wifi = { 3006 data.wifi = {'dev': m.group('d'), 'stat': m.group('s'), 3117 'time 3007 'time': float(m.group('t'))} 3118 data.stamp['w 3008 data.stamp['wifi'] = m.group('d') 3119 # sleep mode enter errors 3009 # sleep mode enter errors 3120 if len(self.testerror) > data 3010 if len(self.testerror) > data.testnumber: 3121 m = re.match(self.tes 3011 m = re.match(self.testerrfmt, self.testerror[data.testnumber]) 3122 if m: 3012 if m: 3123 data.enterfai 3013 data.enterfail = m.group('e') 3124 def devprops(self, data): 3014 def devprops(self, data): 3125 props = dict() 3015 props = dict() 3126 devlist = data.split(';') 3016 devlist = data.split(';') 3127 for dev in devlist: 3017 for dev in devlist: 3128 f = dev.split(',') 3018 f = dev.split(',') 3129 if len(f) < 3: 3019 if len(f) < 3: 3130 continue 3020 continue 3131 dev = f[0] 3021 dev = f[0] 3132 props[dev] = DevProps 3022 props[dev] = DevProps() 3133 props[dev].altname = 3023 props[dev].altname = f[1] 3134 if int(f[2]): 3024 if int(f[2]): 3135 props[dev].is 3025 props[dev].isasync = True 3136 else: 3026 else: 3137 props[dev].is 3027 props[dev].isasync = False 3138 return props 3028 return props 3139 def parseDevprops(self, line, sv): 3029 def parseDevprops(self, line, sv): 3140 idx = line.index(': ') + 2 3030 idx = line.index(': ') + 2 3141 if idx >= len(line): 3031 if idx >= len(line): 3142 return 3032 return 3143 props = self.devprops(line[id 3033 props = self.devprops(line[idx:]) 3144 if sv.suspendmode == 'command 3034 if sv.suspendmode == 'command' and 'testcommandstring' in props: 3145 sv.testcommand = prop 3035 sv.testcommand = props['testcommandstring'].altname 3146 sv.devprops = props 3036 sv.devprops = props 3147 def parsePlatformInfo(self, line, sv) 3037 def parsePlatformInfo(self, line, sv): 3148 m = re.match(self.pinfofmt, l 3038 m = re.match(self.pinfofmt, line) 3149 if not m: 3039 if not m: 3150 return 3040 return 3151 name, info = m.group('val'), 3041 name, info = m.group('val'), m.group('info') 3152 if name == 'devinfo': 3042 if name == 'devinfo': 3153 sv.devprops = self.de 3043 sv.devprops = self.devprops(sv.b64unzip(info)) 3154 return 3044 return 3155 elif name == 'testcmd': 3045 elif name == 'testcmd': 3156 sv.testcommand = info 3046 sv.testcommand = info 3157 return 3047 return 3158 field = info.split('|') 3048 field = info.split('|') 3159 if len(field) < 2: 3049 if len(field) < 2: 3160 return 3050 return 3161 cmdline = field[0].strip() 3051 cmdline = field[0].strip() 3162 output = sv.b64unzip(field[1] 3052 output = sv.b64unzip(field[1].strip()) 3163 sv.platinfo.append([name, cmd 3053 sv.platinfo.append([name, cmdline, output]) 3164 3054 3165 # Class: TestRun 3055 # Class: TestRun 3166 # Description: 3056 # Description: 3167 # A container for a suspend/resume tes 3057 # A container for a suspend/resume test run. This is necessary as 3168 # there could be more than one, and th 3058 # there could be more than one, and they need to be separate. 3169 class TestRun: 3059 class TestRun: 3170 def __init__(self, dataobj): 3060 def __init__(self, dataobj): 3171 self.data = dataobj 3061 self.data = dataobj 3172 self.ftemp = dict() 3062 self.ftemp = dict() 3173 self.ttemp = dict() 3063 self.ttemp = dict() 3174 3064 3175 class ProcessMonitor: 3065 class ProcessMonitor: 3176 maxchars = 512 << 3177 def __init__(self): 3066 def __init__(self): 3178 self.proclist = dict() 3067 self.proclist = dict() 3179 self.running = False 3068 self.running = False 3180 def procstat(self): 3069 def procstat(self): 3181 c = ['cat /proc/[1-9]*/stat 2 3070 c = ['cat /proc/[1-9]*/stat 2>/dev/null'] 3182 process = Popen(c, shell=True 3071 process = Popen(c, shell=True, stdout=PIPE) 3183 running = dict() 3072 running = dict() 3184 for line in process.stdout: 3073 for line in process.stdout: 3185 data = ascii(line).sp 3074 data = ascii(line).split() 3186 pid = data[0] 3075 pid = data[0] 3187 name = re.sub('[()]', 3076 name = re.sub('[()]', '', data[1]) 3188 user = int(data[13]) 3077 user = int(data[13]) 3189 kern = int(data[14]) 3078 kern = int(data[14]) 3190 kjiff = ujiff = 0 3079 kjiff = ujiff = 0 3191 if pid not in self.pr 3080 if pid not in self.proclist: 3192 self.proclist 3081 self.proclist[pid] = {'name' : name, 'user' : user, 'kern' : kern} 3193 else: 3082 else: 3194 val = self.pr 3083 val = self.proclist[pid] 3195 ujiff = user 3084 ujiff = user - val['user'] 3196 kjiff = kern 3085 kjiff = kern - val['kern'] 3197 val['user'] = 3086 val['user'] = user 3198 val['kern'] = 3087 val['kern'] = kern 3199 if ujiff > 0 or kjiff 3088 if ujiff > 0 or kjiff > 0: 3200 running[pid] 3089 running[pid] = ujiff + kjiff 3201 process.wait() 3090 process.wait() 3202 out = [''] !! 3091 out = '' 3203 for pid in running: 3092 for pid in running: 3204 jiffies = running[pid 3093 jiffies = running[pid] 3205 val = self.proclist[p 3094 val = self.proclist[pid] 3206 if len(out[-1]) > sel !! 3095 if out: 3207 out.append('' !! 3096 out += ',' 3208 elif len(out[-1]) > 0 !! 3097 out += '%s-%s %d' % (val['name'], pid, jiffies) 3209 out[-1] += ', !! 3098 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): 3099 def processMonitor(self, tid): 3217 while self.running: 3100 while self.running: 3218 self.procstat() !! 3101 out = self.procstat() >> 3102 if out: >> 3103 sysvals.fsetVal(out, 'trace_marker') 3219 def start(self): 3104 def start(self): 3220 self.thread = Thread(target=s 3105 self.thread = Thread(target=self.processMonitor, args=(0,)) 3221 self.running = True 3106 self.running = True 3222 self.thread.start() 3107 self.thread.start() 3223 def stop(self): 3108 def stop(self): 3224 self.running = False 3109 self.running = False 3225 3110 3226 # ----------------- FUNCTIONS --------------- 3111 # ----------------- FUNCTIONS -------------------- 3227 3112 3228 # Function: doesTraceLogHaveTraceEvents 3113 # Function: doesTraceLogHaveTraceEvents 3229 # Description: 3114 # Description: 3230 # Quickly determine if the ftrace log 3115 # Quickly determine if the ftrace log has all of the trace events, 3231 # markers, and/or kprobes required for 3116 # markers, and/or kprobes required for primary parsing. 3232 def doesTraceLogHaveTraceEvents(): 3117 def doesTraceLogHaveTraceEvents(): 3233 kpcheck = ['_cal: (', '_ret: ('] 3118 kpcheck = ['_cal: (', '_ret: ('] 3234 techeck = ['suspend_resume', 'device_ !! 3119 techeck = ['suspend_resume', 'device_pm_callback'] 3235 tmcheck = ['SUSPEND START', 'RESUME C 3120 tmcheck = ['SUSPEND START', 'RESUME COMPLETE'] 3236 sysvals.usekprobes = False 3121 sysvals.usekprobes = False 3237 fp = sysvals.openlog(sysvals.ftracefi 3122 fp = sysvals.openlog(sysvals.ftracefile, 'r') 3238 for line in fp: 3123 for line in fp: 3239 # check for kprobes 3124 # check for kprobes 3240 if not sysvals.usekprobes: 3125 if not sysvals.usekprobes: 3241 for i in kpcheck: 3126 for i in kpcheck: 3242 if i in line: 3127 if i in line: 3243 sysva 3128 sysvals.usekprobes = True 3244 # check for all necessary tra 3129 # check for all necessary trace events 3245 check = techeck[:] 3130 check = techeck[:] 3246 for i in techeck: 3131 for i in techeck: 3247 if i in line: 3132 if i in line: 3248 check.remove( 3133 check.remove(i) 3249 techeck = check 3134 techeck = check 3250 # check for all necessary tra 3135 # check for all necessary trace markers 3251 check = tmcheck[:] 3136 check = tmcheck[:] 3252 for i in tmcheck: 3137 for i in tmcheck: 3253 if i in line: 3138 if i in line: 3254 check.remove( 3139 check.remove(i) 3255 tmcheck = check 3140 tmcheck = check 3256 fp.close() 3141 fp.close() 3257 sysvals.usetraceevents = True if len( !! 3142 sysvals.usetraceevents = True if len(techeck) < 2 else False 3258 sysvals.usetracemarkers = True if len 3143 sysvals.usetracemarkers = True if len(tmcheck) == 0 else False 3259 3144 3260 # Function: appendIncompleteTraceLog 3145 # Function: appendIncompleteTraceLog 3261 # Description: 3146 # Description: >> 3147 # [deprecated for kernel 3.15 or newer] 3262 # Adds callgraph data which lacks trac 3148 # Adds callgraph data which lacks trace event data. This is only 3263 # for timelines generated from 3.15 or 3149 # for timelines generated from 3.15 or older 3264 # Arguments: 3150 # Arguments: 3265 # testruns: the array of Data objects 3151 # testruns: the array of Data objects obtained from parseKernelLog 3266 def appendIncompleteTraceLog(testruns): 3152 def appendIncompleteTraceLog(testruns): 3267 # create TestRun vessels for ftrace p 3153 # create TestRun vessels for ftrace parsing 3268 testcnt = len(testruns) 3154 testcnt = len(testruns) 3269 testidx = 0 3155 testidx = 0 3270 testrun = [] 3156 testrun = [] 3271 for data in testruns: 3157 for data in testruns: 3272 testrun.append(TestRun(data)) 3158 testrun.append(TestRun(data)) 3273 3159 3274 # extract the callgraph and traceeven 3160 # extract the callgraph and traceevent data 3275 sysvals.vprint('Analyzing the ftrace 3161 sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 3276 os.path.basename(sysvals.ftra 3162 os.path.basename(sysvals.ftracefile)) 3277 tp = TestProps() 3163 tp = TestProps() 3278 tf = sysvals.openlog(sysvals.ftracefi 3164 tf = sysvals.openlog(sysvals.ftracefile, 'r') 3279 data = 0 3165 data = 0 3280 for line in tf: 3166 for line in tf: 3281 # remove any latent carriage 3167 # remove any latent carriage returns 3282 line = line.replace('\r\n', ' 3168 line = line.replace('\r\n', '') 3283 if tp.stampInfo(line, sysvals 3169 if tp.stampInfo(line, sysvals): 3284 continue 3170 continue 3285 # parse only valid lines, if 3171 # parse only valid lines, if this is not one move on 3286 m = re.match(tp.ftrace_line_f 3172 m = re.match(tp.ftrace_line_fmt, line) 3287 if(not m): 3173 if(not m): 3288 continue 3174 continue 3289 # gather the basic message da 3175 # gather the basic message data from the line 3290 m_time = m.group('time') 3176 m_time = m.group('time') 3291 m_pid = m.group('pid') 3177 m_pid = m.group('pid') 3292 m_msg = m.group('msg') 3178 m_msg = m.group('msg') 3293 if(tp.cgformat): 3179 if(tp.cgformat): 3294 m_param3 = m.group('d 3180 m_param3 = m.group('dur') 3295 else: 3181 else: 3296 m_param3 = 'traceeven 3182 m_param3 = 'traceevent' 3297 if(m_time and m_pid and m_msg 3183 if(m_time and m_pid and m_msg): 3298 t = FTraceLine(m_time 3184 t = FTraceLine(m_time, m_msg, m_param3) 3299 pid = int(m_pid) 3185 pid = int(m_pid) 3300 else: 3186 else: 3301 continue 3187 continue 3302 # the line should be a call, 3188 # the line should be a call, return, or event 3303 if(not t.fcall and not t.fret 3189 if(not t.fcall and not t.freturn and not t.fevent): 3304 continue 3190 continue 3305 # look for the suspend start 3191 # look for the suspend start marker 3306 if(t.startMarker()): 3192 if(t.startMarker()): 3307 data = testrun[testid 3193 data = testrun[testidx].data 3308 tp.parseStamp(data, s 3194 tp.parseStamp(data, sysvals) 3309 data.setStart(t.time, 3195 data.setStart(t.time, t.name) 3310 continue 3196 continue 3311 if(not data): 3197 if(not data): 3312 continue 3198 continue 3313 # find the end of resume 3199 # find the end of resume 3314 if(t.endMarker()): 3200 if(t.endMarker()): 3315 data.setEnd(t.time, t 3201 data.setEnd(t.time, t.name) 3316 testidx += 1 3202 testidx += 1 3317 if(testidx >= testcnt 3203 if(testidx >= testcnt): 3318 break 3204 break 3319 continue 3205 continue 3320 # trace event processing 3206 # trace event processing 3321 if(t.fevent): 3207 if(t.fevent): 3322 continue 3208 continue 3323 # call/return processing 3209 # call/return processing 3324 elif sysvals.usecallgraph: 3210 elif sysvals.usecallgraph: 3325 # create a callgraph 3211 # create a callgraph object for the data 3326 if(pid not in testrun 3212 if(pid not in testrun[testidx].ftemp): 3327 testrun[testi 3213 testrun[testidx].ftemp[pid] = [] 3328 testrun[testi 3214 testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 3329 # when the call is fi 3215 # when the call is finished, see which device matches it 3330 cg = testrun[testidx] 3216 cg = testrun[testidx].ftemp[pid][-1] 3331 res = cg.addLine(t) 3217 res = cg.addLine(t) 3332 if(res != 0): 3218 if(res != 0): 3333 testrun[testi 3219 testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 3334 if(res == -1): 3220 if(res == -1): 3335 testrun[testi 3221 testrun[testidx].ftemp[pid][-1].addLine(t) 3336 tf.close() 3222 tf.close() 3337 3223 3338 for test in testrun: 3224 for test in testrun: 3339 # add the callgraph data to t 3225 # add the callgraph data to the device hierarchy 3340 for pid in test.ftemp: 3226 for pid in test.ftemp: 3341 for cg in test.ftemp[ 3227 for cg in test.ftemp[pid]: 3342 if len(cg.lis 3228 if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 3343 conti 3229 continue 3344 if(not cg.pos 3230 if(not cg.postProcess()): 3345 id = 3231 id = 'task %s cpu %s' % (pid, m.group('cpu')) 3346 sysva 3232 sysvals.vprint('Sanity check failed for '+\ 3347 3233 id+', ignoring this callback') 3348 conti 3234 continue 3349 callstart = c 3235 callstart = cg.start 3350 callend = cg. 3236 callend = cg.end 3351 for p in test 3237 for p in test.data.sortedPhases(): 3352 if(te 3238 if(test.data.dmesg[p]['start'] <= callstart and 3353 3239 callstart <= test.data.dmesg[p]['end']): 3354 3240 list = test.data.dmesg[p]['list'] 3355 3241 for devname in list: 3356 3242 dev = list[devname] 3357 3243 if(pid == dev['pid'] and 3358 3244 callstart <= dev['start'] and 3359 3245 callend >= dev['end']): 3360 3246 dev['ftrace'] = cg 3361 3247 break 3362 3248 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 3249 # Function: parseTraceLog 3419 # Description: 3250 # Description: 3420 # Analyze an ftrace log output file ge 3251 # Analyze an ftrace log output file generated from this app during 3421 # the execution phase. Used when the f 3252 # the execution phase. Used when the ftrace log is the primary data source 3422 # and includes the suspend_resume and 3253 # and includes the suspend_resume and device_pm_callback trace events 3423 # The ftrace filename is taken from sy 3254 # The ftrace filename is taken from sysvals 3424 # Output: 3255 # Output: 3425 # An array of Data objects 3256 # An array of Data objects 3426 def parseTraceLog(live=False): 3257 def parseTraceLog(live=False): 3427 sysvals.vprint('Analyzing the ftrace 3258 sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 3428 os.path.basename(sysvals.ftra 3259 os.path.basename(sysvals.ftracefile)) 3429 if(os.path.exists(sysvals.ftracefile) 3260 if(os.path.exists(sysvals.ftracefile) == False): 3430 doError('%s does not exist' % 3261 doError('%s does not exist' % sysvals.ftracefile) 3431 if not live: 3262 if not live: 3432 sysvals.setupAllKprobes() 3263 sysvals.setupAllKprobes() 3433 ksuscalls = ['ksys_sync', 'pm_prepare 3264 ksuscalls = ['ksys_sync', 'pm_prepare_console'] 3434 krescalls = ['pm_restore_console'] 3265 krescalls = ['pm_restore_console'] 3435 tracewatch = ['irq_wakeup'] 3266 tracewatch = ['irq_wakeup'] 3436 if sysvals.usekprobes: 3267 if sysvals.usekprobes: 3437 tracewatch += ['sync_filesyst 3268 tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend', 3438 'syscore_resume', 're 3269 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 3439 'CPU_OFF', 'acpi_susp 3270 'CPU_OFF', 'acpi_suspend'] 3440 3271 3441 # extract the callgraph and traceeven 3272 # extract the callgraph and traceevent data 3442 s2idle_enter = hwsus = False 3273 s2idle_enter = hwsus = False >> 3274 tp = TestProps() 3443 testruns, testdata = [], [] 3275 testruns, testdata = [], [] 3444 testrun, data, limbo = 0, 0, True 3276 testrun, data, limbo = 0, 0, True >> 3277 tf = sysvals.openlog(sysvals.ftracefile, 'r') 3445 phase = 'suspend_prepare' 3278 phase = 'suspend_prepare' 3446 tp, tf = loadTraceLog() !! 3279 for line in tf: 3447 for m_time, m_proc, m_pid, m_msg, m_p !! 3280 # remove any latent carriage returns >> 3281 line = line.replace('\r\n', '') >> 3282 if tp.stampInfo(line, sysvals): >> 3283 continue >> 3284 # ignore all other commented lines >> 3285 if line[0] == '#': >> 3286 continue >> 3287 # ftrace line: parse only valid lines >> 3288 m = re.match(tp.ftrace_line_fmt, line) >> 3289 if(not m): >> 3290 continue 3448 # gather the basic message da 3291 # gather the basic message data from the line >> 3292 m_time = m.group('time') >> 3293 m_proc = m.group('proc') >> 3294 m_pid = m.group('pid') >> 3295 m_msg = m.group('msg') >> 3296 if(tp.cgformat): >> 3297 m_param3 = m.group('dur') >> 3298 else: >> 3299 m_param3 = 'traceevent' 3449 if(m_time and m_pid and m_msg 3300 if(m_time and m_pid and m_msg): 3450 t = FTraceLine(m_time 3301 t = FTraceLine(m_time, m_msg, m_param3) 3451 pid = int(m_pid) 3302 pid = int(m_pid) 3452 else: 3303 else: 3453 continue 3304 continue 3454 # the line should be a call, 3305 # the line should be a call, return, or event 3455 if(not t.fcall and not t.fret 3306 if(not t.fcall and not t.freturn and not t.fevent): 3456 continue 3307 continue 3457 # find the start of suspend 3308 # find the start of suspend 3458 if(t.startMarker()): 3309 if(t.startMarker()): 3459 data, limbo = Data(le 3310 data, limbo = Data(len(testdata)), False 3460 testdata.append(data) 3311 testdata.append(data) 3461 testrun = TestRun(dat 3312 testrun = TestRun(data) 3462 testruns.append(testr 3313 testruns.append(testrun) 3463 tp.parseStamp(data, s 3314 tp.parseStamp(data, sysvals) 3464 data.setStart(t.time, 3315 data.setStart(t.time, t.name) 3465 data.first_suspend_pr 3316 data.first_suspend_prepare = True 3466 phase = data.setPhase 3317 phase = data.setPhase('suspend_prepare', t.time, True) 3467 continue 3318 continue 3468 if(not data or limbo): 3319 if(not data or limbo): 3469 continue 3320 continue 3470 # process cpu exec line 3321 # process cpu exec line 3471 if t.type == 'tracing_mark_wr 3322 if t.type == 'tracing_mark_write': 3472 if t.name == 'CMD COM << 3473 data.tKernRes << 3474 m = re.match(tp.proce 3323 m = re.match(tp.procexecfmt, t.name) 3475 if(m): 3324 if(m): 3476 parts, msg = !! 3325 proclist = dict() 3477 m = re.match( !! 3326 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 = 3327 val = ps.split() 3490 if no !! 3328 if not val: 3491 3329 continue 3492 name 3330 name = val[0].replace('--', '-') 3493 procl 3331 proclist[name] = int(val[1]) 3494 if parts == 1 !! 3332 data.pstl[t.time] = proclist 3495 data. << 3496 elif parts == << 3497 data. << 3498 tp.mu << 3499 continue 3333 continue 3500 # find the end of resume 3334 # find the end of resume 3501 if(t.endMarker()): 3335 if(t.endMarker()): 3502 if data.tKernRes == 0 3336 if data.tKernRes == 0: 3503 data.tKernRes 3337 data.tKernRes = t.time 3504 data.handleEndMarker( 3338 data.handleEndMarker(t.time, t.name) 3505 if(not sysvals.usetra 3339 if(not sysvals.usetracemarkers): 3506 # no trace ma 3340 # no trace markers? then quit and be sure to finish recording 3507 # the event w 3341 # the event we used to trigger resume end 3508 if('thaw_proc 3342 if('thaw_processes' in testrun.ttemp and len(testrun.ttemp['thaw_processes']) > 0): 3509 # if 3343 # if an entry exists, assume this is its end 3510 testr 3344 testrun.ttemp['thaw_processes'][-1]['end'] = t.time 3511 limbo = True 3345 limbo = True 3512 continue 3346 continue 3513 # trace event processing 3347 # trace event processing 3514 if(t.fevent): 3348 if(t.fevent): 3515 if(t.type == 'suspend 3349 if(t.type == 'suspend_resume'): 3516 # suspend_res 3350 # suspend_resume trace events have two types, begin and end 3517 if(re.match(r !! 3351 if(re.match('(?P<name>.*) begin$', t.name)): 3518 isbeg 3352 isbegin = True 3519 elif(re.match !! 3353 elif(re.match('(?P<name>.*) end$', t.name)): 3520 isbeg 3354 isbegin = False 3521 else: 3355 else: 3522 conti 3356 continue 3523 if '[' in t.n 3357 if '[' in t.name: 3524 m = r !! 3358 m = re.match('(?P<name>.*)\[.*', t.name) 3525 else: 3359 else: 3526 m = r !! 3360 m = re.match('(?P<name>.*) .*', t.name) 3527 name = m.grou 3361 name = m.group('name') 3528 # ignore thes 3362 # ignore these events 3529 if(name.split 3363 if(name.split('[')[0] in tracewatch): 3530 conti 3364 continue 3531 # -- phase ch 3365 # -- phase changes -- 3532 # start of ke 3366 # start of kernel suspend 3533 if(re.match(r !! 3367 if(re.match('suspend_enter\[.*', t.name)): 3534 if(is 3368 if(isbegin and data.tKernSus == 0): 3535 3369 data.tKernSus = t.time 3536 conti 3370 continue 3537 # suspend_pre 3371 # suspend_prepare start 3538 elif(re.match !! 3372 elif(re.match('dpm_prepare\[.*', t.name)): 3539 if is 3373 if isbegin and data.first_suspend_prepare: 3540 3374 data.first_suspend_prepare = False 3541 3375 if data.tKernSus == 0: 3542 3376 data.tKernSus = t.time 3543 3377 continue 3544 phase 3378 phase = data.setPhase('suspend_prepare', t.time, isbegin) 3545 conti 3379 continue 3546 # suspend sta 3380 # suspend start 3547 elif(re.match !! 3381 elif(re.match('dpm_suspend\[.*', t.name)): 3548 phase 3382 phase = data.setPhase('suspend', t.time, isbegin) 3549 conti 3383 continue 3550 # suspend_lat 3384 # suspend_late start 3551 elif(re.match !! 3385 elif(re.match('dpm_suspend_late\[.*', t.name)): 3552 phase 3386 phase = data.setPhase('suspend_late', t.time, isbegin) 3553 conti 3387 continue 3554 # suspend_noi 3388 # suspend_noirq start 3555 elif(re.match !! 3389 elif(re.match('dpm_suspend_noirq\[.*', t.name)): 3556 phase 3390 phase = data.setPhase('suspend_noirq', t.time, isbegin) 3557 conti 3391 continue 3558 # suspend_mac 3392 # suspend_machine/resume_machine 3559 elif(re.match 3393 elif(re.match(tp.machinesuspend, t.name)): 3560 lp = 3394 lp = data.lastPhase() 3561 if(is 3395 if(isbegin): 3562 3396 hwsus = True 3563 3397 if lp.startswith('resume_machine'): 3564 3398 # trim out s2idle loops, track time trying to freeze 3565 3399 llp = data.lastPhase(2) 3566 3400 if llp.startswith('suspend_machine'): 3567 3401 if 'waking' not in data.dmesg[llp]: 3568 3402 data.dmesg[llp]['waking'] = [0, 0.0] 3569 3403 data.dmesg[llp]['waking'][0] += 1 3570 3404 data.dmesg[llp]['waking'][1] += \ 3571 3405 t.time - data.dmesg[lp]['start'] 3572 3406 data.currphase = '' 3573 3407 del data.dmesg[lp] 3574 3408 continue 3575 3409 phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True) 3576 3410 data.setPhase(phase, t.time, False) 3577 3411 if data.tSuspended == 0: 3578 3412 data.tSuspended = t.time 3579 else: 3413 else: 3580 3414 if lp.startswith('resume_machine'): 3581 3415 data.dmesg[lp]['end'] = t.time 3582 3416 continue 3583 3417 phase = data.setPhase('resume_machine', t.time, True) 3584 3418 if(sysvals.suspendmode in ['mem', 'disk']): 3585 3419 susp = phase.replace('resume', 'suspend') 3586 3420 if susp in data.dmesg: 3587 3421 data.dmesg[susp]['end'] = t.time 3588 3422 data.tSuspended = t.time 3589 3423 data.tResumed = t.time 3590 conti 3424 continue 3591 # resume_noir 3425 # resume_noirq start 3592 elif(re.match !! 3426 elif(re.match('dpm_resume_noirq\[.*', t.name)): 3593 phase 3427 phase = data.setPhase('resume_noirq', t.time, isbegin) 3594 conti 3428 continue 3595 # resume_earl 3429 # resume_early start 3596 elif(re.match !! 3430 elif(re.match('dpm_resume_early\[.*', t.name)): 3597 phase 3431 phase = data.setPhase('resume_early', t.time, isbegin) 3598 conti 3432 continue 3599 # resume star 3433 # resume start 3600 elif(re.match !! 3434 elif(re.match('dpm_resume\[.*', t.name)): 3601 phase 3435 phase = data.setPhase('resume', t.time, isbegin) 3602 conti 3436 continue 3603 # resume comp 3437 # resume complete start 3604 elif(re.match !! 3438 elif(re.match('dpm_complete\[.*', t.name)): 3605 phase 3439 phase = data.setPhase('resume_complete', t.time, isbegin) 3606 conti 3440 continue 3607 # skip trace 3441 # skip trace events inside devices calls 3608 if(not data.i 3442 if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)): 3609 conti 3443 continue 3610 # global even 3444 # global events (outside device calls) are graphed 3611 if(name not i 3445 if(name not in testrun.ttemp): 3612 testr 3446 testrun.ttemp[name] = [] 3613 # special han 3447 # special handling for s2idle_enter 3614 if name == 'm 3448 if name == 'machine_suspend': 3615 if hw 3449 if hwsus: 3616 3450 s2idle_enter = hwsus = False 3617 elif 3451 elif s2idle_enter and not isbegin: 3618 3452 if(len(testrun.ttemp[name]) > 0): 3619 3453 testrun.ttemp[name][-1]['end'] = t.time 3620 3454 testrun.ttemp[name][-1]['loop'] += 1 3621 elif 3455 elif not s2idle_enter and isbegin: 3622 3456 s2idle_enter = True 3623 3457 testrun.ttemp[name].append({'begin': t.time, 3624 3458 'end': t.time, 'pid': pid, 'loop': 0}) 3625 conti 3459 continue 3626 if(isbegin): 3460 if(isbegin): 3627 # cre 3461 # create a new list entry 3628 testr 3462 testrun.ttemp[name].append(\ 3629 3463 {'begin': t.time, 'end': t.time, 'pid': pid}) 3630 else: 3464 else: 3631 if(le 3465 if(len(testrun.ttemp[name]) > 0): 3632 3466 # if an entry exists, assume this is its end 3633 3467 testrun.ttemp[name][-1]['end'] = t.time 3634 # device callback sta 3468 # device callback start 3635 elif(t.type == 'devic 3469 elif(t.type == 'device_pm_callback_start'): 3636 if phase not 3470 if phase not in data.dmesg: 3637 conti 3471 continue 3638 m = re.match( !! 3472 m = re.match('(?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*',\ 3639 t.nam 3473 t.name); 3640 if(not m): 3474 if(not m): 3641 conti 3475 continue 3642 drv = m.group 3476 drv = m.group('drv') 3643 n = m.group(' 3477 n = m.group('d') 3644 p = m.group(' 3478 p = m.group('p') 3645 if(n and p): 3479 if(n and p): 3646 data. 3480 data.newAction(phase, n, pid, p, t.time, -1, drv) 3647 if pi 3481 if pid not in data.devpids: 3648 3482 data.devpids.append(pid) 3649 # device callback fin 3483 # device callback finish 3650 elif(t.type == 'devic 3484 elif(t.type == 'device_pm_callback_end'): 3651 if phase not 3485 if phase not in data.dmesg: 3652 conti 3486 continue 3653 m = re.match( !! 3487 m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name); 3654 if(not m): 3488 if(not m): 3655 conti 3489 continue 3656 n = m.group(' 3490 n = m.group('d') 3657 dev = data.fi 3491 dev = data.findDevice(phase, n) 3658 if dev: 3492 if dev: 3659 dev[' 3493 dev['length'] = t.time - dev['start'] 3660 dev[' 3494 dev['end'] = t.time 3661 # kprobe event processing 3495 # kprobe event processing 3662 elif(t.fkprobe): 3496 elif(t.fkprobe): 3663 kprobename = t.type 3497 kprobename = t.type 3664 kprobedata = t.name 3498 kprobedata = t.name 3665 key = (kprobename, pi 3499 key = (kprobename, pid) 3666 # displayname is gene 3500 # displayname is generated from kprobe data 3667 displayname = '' 3501 displayname = '' 3668 if(t.fcall): 3502 if(t.fcall): 3669 displayname = 3503 displayname = sysvals.kprobeDisplayName(kprobename, kprobedata) 3670 if not displa 3504 if not displayname: 3671 conti 3505 continue 3672 if(key not in 3506 if(key not in tp.ktemp): 3673 tp.kt 3507 tp.ktemp[key] = [] 3674 tp.ktemp[key] 3508 tp.ktemp[key].append({ 3675 'pid' 3509 'pid': pid, 3676 'begi 3510 'begin': t.time, 3677 'end' 3511 'end': -1, 3678 'name 3512 'name': displayname, 3679 'cdat 3513 'cdata': kprobedata, 3680 'proc 3514 'proc': m_proc, 3681 }) 3515 }) 3682 # start of ke 3516 # start of kernel resume 3683 if(data.tKern 3517 if(data.tKernSus == 0 and phase == 'suspend_prepare' \ 3684 and k 3518 and kprobename in ksuscalls): 3685 data. 3519 data.tKernSus = t.time 3686 elif(t.freturn): 3520 elif(t.freturn): 3687 if(key not in 3521 if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1: 3688 conti 3522 continue 3689 e = next((x f 3523 e = next((x for x in reversed(tp.ktemp[key]) if x['end'] < 0), 0) 3690 if not e: 3524 if not e: 3691 conti 3525 continue 3692 if (t.time - << 3693 tp.kt << 3694 conti << 3695 e['end'] = t. 3526 e['end'] = t.time 3696 e['rdata'] = 3527 e['rdata'] = kprobedata 3697 # end of kern 3528 # end of kernel resume 3698 if(phase != ' 3529 if(phase != 'suspend_prepare' and kprobename in krescalls): 3699 if ph 3530 if phase in data.dmesg: 3700 3531 data.dmesg[phase]['end'] = t.time 3701 data. 3532 data.tKernRes = t.time 3702 3533 3703 # callgraph processing 3534 # callgraph processing 3704 elif sysvals.usecallgraph: 3535 elif sysvals.usecallgraph: 3705 # create a callgraph 3536 # create a callgraph object for the data 3706 key = (m_proc, pid) 3537 key = (m_proc, pid) 3707 if(key not in testrun 3538 if(key not in testrun.ftemp): 3708 testrun.ftemp 3539 testrun.ftemp[key] = [] 3709 testrun.ftemp 3540 testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 3710 # when the call is fi 3541 # when the call is finished, see which device matches it 3711 cg = testrun.ftemp[ke 3542 cg = testrun.ftemp[key][-1] 3712 res = cg.addLine(t) 3543 res = cg.addLine(t) 3713 if(res != 0): 3544 if(res != 0): 3714 testrun.ftemp 3545 testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 3715 if(res == -1): 3546 if(res == -1): 3716 testrun.ftemp 3547 testrun.ftemp[key][-1].addLine(t) >> 3548 tf.close() 3717 if len(testdata) < 1: 3549 if len(testdata) < 1: 3718 sysvals.vprint('WARNING: ftra 3550 sysvals.vprint('WARNING: ftrace start marker is missing') 3719 if data and not data.devicegroups: 3551 if data and not data.devicegroups: 3720 sysvals.vprint('WARNING: ftra 3552 sysvals.vprint('WARNING: ftrace end marker is missing') 3721 data.handleEndMarker(t.time, 3553 data.handleEndMarker(t.time, t.name) 3722 3554 3723 if sysvals.suspendmode == 'command': 3555 if sysvals.suspendmode == 'command': 3724 for test in testruns: 3556 for test in testruns: 3725 for p in test.data.so 3557 for p in test.data.sortedPhases(): 3726 if p == 'susp 3558 if p == 'suspend_prepare': 3727 test. 3559 test.data.dmesg[p]['start'] = test.data.start 3728 test. 3560 test.data.dmesg[p]['end'] = test.data.end 3729 else: 3561 else: 3730 test. 3562 test.data.dmesg[p]['start'] = test.data.end 3731 test. 3563 test.data.dmesg[p]['end'] = test.data.end 3732 test.data.tSuspended 3564 test.data.tSuspended = test.data.end 3733 test.data.tResumed = 3565 test.data.tResumed = test.data.end 3734 test.data.fwValid = F 3566 test.data.fwValid = False 3735 3567 3736 # dev source and procmon events can b 3568 # dev source and procmon events can be unreadable with mixed phase height 3737 if sysvals.usedevsrc or sysvals.usepr 3569 if sysvals.usedevsrc or sysvals.useprocmon: 3738 sysvals.mixedphaseheight = Fa 3570 sysvals.mixedphaseheight = False 3739 3571 3740 # expand phase boundaries so there ar 3572 # expand phase boundaries so there are no gaps 3741 for data in testdata: 3573 for data in testdata: 3742 lp = data.sortedPhases()[0] 3574 lp = data.sortedPhases()[0] 3743 for p in data.sortedPhases(): 3575 for p in data.sortedPhases(): 3744 if(p != lp and not (' 3576 if(p != lp and not ('machine' in p and 'machine' in lp)): 3745 data.dmesg[lp 3577 data.dmesg[lp]['end'] = data.dmesg[p]['start'] 3746 lp = p 3578 lp = p 3747 3579 3748 for i in range(len(testruns)): 3580 for i in range(len(testruns)): 3749 test = testruns[i] 3581 test = testruns[i] 3750 data = test.data 3582 data = test.data 3751 # find the total time range f 3583 # find the total time range for this test (begin, end) 3752 tlb, tle = data.start, data.e 3584 tlb, tle = data.start, data.end 3753 if i < len(testruns) - 1: 3585 if i < len(testruns) - 1: 3754 tle = testruns[i+1].d 3586 tle = testruns[i+1].data.start 3755 # add the process usage data 3587 # add the process usage data to the timeline 3756 if sysvals.useprocmon: 3588 if sysvals.useprocmon: 3757 data.createProcessUsa 3589 data.createProcessUsageEvents() 3758 # add the traceevent data to 3590 # add the traceevent data to the device hierarchy 3759 if(sysvals.usetraceevents): 3591 if(sysvals.usetraceevents): 3760 # add actual trace fu 3592 # add actual trace funcs 3761 for name in sorted(te 3593 for name in sorted(test.ttemp): 3762 for event in 3594 for event in test.ttemp[name]: 3763 if ev 3595 if event['end'] - event['begin'] <= 0: 3764 3596 continue 3765 title 3597 title = name 3766 if na 3598 if name == 'machine_suspend' and 'loop' in event: 3767 3599 title = 's2idle_enter_%dx' % event['loop'] 3768 data. 3600 data.newActionGlobal(title, event['begin'], event['end'], event['pid']) 3769 # add the kprobe base 3601 # add the kprobe based virtual tracefuncs as actual devices 3770 for key in sorted(tp. 3602 for key in sorted(tp.ktemp): 3771 name, pid = k 3603 name, pid = key 3772 if name not i 3604 if name not in sysvals.tracefuncs: 3773 conti 3605 continue 3774 if pid not in 3606 if pid not in data.devpids: 3775 data. 3607 data.devpids.append(pid) 3776 for e in tp.k 3608 for e in tp.ktemp[key]: 3777 kb, k 3609 kb, ke = e['begin'], e['end'] 3778 if ke 3610 if ke - kb < 0.000001 or tlb > kb or tle <= kb: 3779 3611 continue 3780 color 3612 color = sysvals.kprobeColor(name) 3781 data. 3613 data.newActionGlobal(e['name'], kb, ke, pid, color) 3782 # add config base kpr 3614 # add config base kprobes and dev kprobes 3783 if sysvals.usedevsrc: 3615 if sysvals.usedevsrc: 3784 for key in so 3616 for key in sorted(tp.ktemp): 3785 name, 3617 name, pid = key 3786 if na 3618 if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs: 3787 3619 continue 3788 for e 3620 for e in tp.ktemp[key]: 3789 3621 kb, ke = e['begin'], e['end'] 3790 3622 if ke - kb < 0.000001 or tlb > kb or tle <= kb: 3791 3623 continue 3792 3624 data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb, 3793 3625 ke, e['cdata'], e['rdata']) 3794 if sysvals.usecallgraph: 3626 if sysvals.usecallgraph: 3795 # add the callgraph d 3627 # add the callgraph data to the device hierarchy 3796 sortlist = dict() 3628 sortlist = dict() 3797 for key in sorted(tes 3629 for key in sorted(test.ftemp): 3798 proc, pid = k 3630 proc, pid = key 3799 for cg in tes 3631 for cg in test.ftemp[key]: 3800 if le 3632 if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 3801 3633 continue 3802 if(no 3634 if(not cg.postProcess()): 3803 3635 id = 'task %s' % (pid) 3804 3636 sysvals.vprint('Sanity check failed for '+\ 3805 3637 id+', ignoring this callback') 3806 3638 continue 3807 # mat 3639 # match cg data to devices 3808 devna 3640 devname = '' 3809 if sy 3641 if sysvals.suspendmode != 'command': 3810 3642 devname = cg.deviceMatch(pid, data) 3811 if no 3643 if not devname: 3812 3644 sortkey = '%f%f%d' % (cg.start, cg.end, pid) 3813 3645 sortlist[sortkey] = cg 3814 elif 3646 elif len(cg.list) > 1000000 and cg.name != sysvals.ftopfunc: 3815 3647 sysvals.vprint('WARNING: the callgraph for %s is massive (%d lines)' %\ 3816 3648 (devname, len(cg.list))) 3817 # create blocks for o 3649 # create blocks for orphan cg data 3818 for sortkey in sorted 3650 for sortkey in sorted(sortlist): 3819 cg = sortlist 3651 cg = sortlist[sortkey] 3820 name = cg.nam 3652 name = cg.name 3821 if sysvals.is 3653 if sysvals.isCallgraphFunc(name): 3822 sysva 3654 sysvals.vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name)) 3823 cg.ne 3655 cg.newActionFromFunction(data) 3824 if sysvals.suspendmode == 'command': 3656 if sysvals.suspendmode == 'command': 3825 return (testdata, '') 3657 return (testdata, '') 3826 3658 3827 # fill in any missing phases 3659 # fill in any missing phases 3828 error = [] 3660 error = [] 3829 for data in testdata: 3661 for data in testdata: 3830 tn = '' if len(testdata) == 1 3662 tn = '' if len(testdata) == 1 else ('%d' % (data.testnumber + 1)) 3831 terr = '' 3663 terr = '' 3832 phasedef = data.phasedef 3664 phasedef = data.phasedef 3833 lp = 'suspend_prepare' 3665 lp = 'suspend_prepare' 3834 for p in sorted(phasedef, key 3666 for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 3835 if p not in data.dmes 3667 if p not in data.dmesg: 3836 if not terr: 3668 if not terr: 3837 ph = 3669 ph = p if 'machine' in p else lp 3838 if p !! 3670 terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph) 3839 << 3840 << 3841 << 3842 << 3843 else: << 3844 << 3845 pprin 3671 pprint('TEST%s FAILED: %s' % (tn, terr)) 3846 error 3672 error.append(terr) 3847 if da 3673 if data.tSuspended == 0: 3848 3674 data.tSuspended = data.dmesg[lp]['end'] 3849 if da 3675 if data.tResumed == 0: 3850 3676 data.tResumed = data.dmesg[lp]['end'] 3851 data. 3677 data.fwValid = False 3852 sysvals.vprin 3678 sysvals.vprint('WARNING: phase "%s" is missing!' % p) 3853 lp = p 3679 lp = p 3854 if not terr and 'dev' in data 3680 if not terr and 'dev' in data.wifi and data.wifi['stat'] == 'timeout': 3855 terr = '%s%s failed i 3681 terr = '%s%s failed in wifi_resume <i>(%s %.0fs timeout)</i>' % \ 3856 (sysvals.susp 3682 (sysvals.suspendmode, tn, data.wifi['dev'], data.wifi['time']) 3857 error.append(terr) 3683 error.append(terr) 3858 if not terr and data.enterfai 3684 if not terr and data.enterfail: 3859 pprint('test%s FAILED 3685 pprint('test%s FAILED: enter %s failed with %s' % (tn, sysvals.suspendmode, data.enterfail)) 3860 terr = 'test%s failed 3686 terr = 'test%s failed to enter %s mode' % (tn, sysvals.suspendmode) 3861 error.append(terr) 3687 error.append(terr) 3862 if data.tSuspended == 0: 3688 if data.tSuspended == 0: 3863 data.tSuspended = dat 3689 data.tSuspended = data.tKernRes 3864 if data.tResumed == 0: 3690 if data.tResumed == 0: 3865 data.tResumed = data. 3691 data.tResumed = data.tSuspended 3866 3692 3867 if(len(sysvals.devicefilter) 3693 if(len(sysvals.devicefilter) > 0): 3868 data.deviceFilter(sys 3694 data.deviceFilter(sysvals.devicefilter) 3869 data.fixupInitcallsThatDidntR 3695 data.fixupInitcallsThatDidntReturn() 3870 if sysvals.usedevsrc: 3696 if sysvals.usedevsrc: 3871 data.optimizeDevSrc() 3697 data.optimizeDevSrc() 3872 3698 3873 # x2: merge any overlapping devices b 3699 # x2: merge any overlapping devices between test runs 3874 if sysvals.usedevsrc and len(testdata 3700 if sysvals.usedevsrc and len(testdata) > 1: 3875 tc = len(testdata) 3701 tc = len(testdata) 3876 for i in range(tc - 1): 3702 for i in range(tc - 1): 3877 devlist = testdata[i] 3703 devlist = testdata[i].overflowDevices() 3878 for j in range(i + 1, 3704 for j in range(i + 1, tc): 3879 testdata[j].m 3705 testdata[j].mergeOverlapDevices(devlist) 3880 testdata[0].stitchTouchingThr 3706 testdata[0].stitchTouchingThreads(testdata[1:]) 3881 return (testdata, ', '.join(error)) 3707 return (testdata, ', '.join(error)) 3882 3708 3883 # Function: loadKernelLog 3709 # Function: loadKernelLog 3884 # Description: 3710 # Description: >> 3711 # [deprecated for kernel 3.15.0 or newer] 3885 # load the dmesg file into memory and 3712 # load the dmesg file into memory and fix up any ordering issues >> 3713 # The dmesg filename is taken from sysvals 3886 # Output: 3714 # Output: 3887 # An array of empty Data objects with 3715 # An array of empty Data objects with only their dmesgtext attributes set 3888 def loadKernelLog(): 3716 def loadKernelLog(): 3889 sysvals.vprint('Analyzing the dmesg d 3717 sysvals.vprint('Analyzing the dmesg data (%s)...' % \ 3890 os.path.basename(sysvals.dmes 3718 os.path.basename(sysvals.dmesgfile)) 3891 if(os.path.exists(sysvals.dmesgfile) 3719 if(os.path.exists(sysvals.dmesgfile) == False): 3892 doError('%s does not exist' % 3720 doError('%s does not exist' % sysvals.dmesgfile) 3893 3721 3894 # there can be multiple test runs in 3722 # there can be multiple test runs in a single file 3895 tp = TestProps() 3723 tp = TestProps() 3896 tp.stamp = datetime.now().strftime('# 3724 tp.stamp = datetime.now().strftime('# suspend-%m%d%y-%H%M%S localhost mem unknown') 3897 testruns = [] 3725 testruns = [] 3898 data = 0 3726 data = 0 3899 lf = sysvals.openlog(sysvals.dmesgfil 3727 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 3900 for line in lf: 3728 for line in lf: 3901 line = line.replace('\r\n', ' 3729 line = line.replace('\r\n', '') 3902 idx = line.find('[') 3730 idx = line.find('[') 3903 if idx > 1: 3731 if idx > 1: 3904 line = line[idx:] 3732 line = line[idx:] 3905 if tp.stampInfo(line, sysvals 3733 if tp.stampInfo(line, sysvals): 3906 continue 3734 continue 3907 m = re.match(r'[ \t]*(\[ *)(? !! 3735 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 3908 if(not m): 3736 if(not m): 3909 continue 3737 continue 3910 msg = m.group("msg") 3738 msg = m.group("msg") 3911 if re.match(r'PM: Syncing fil !! 3739 if(re.match('PM: Syncing filesystems.*', msg)): 3912 re.match(r'PM: suspen << 3913 if(data): 3740 if(data): 3914 testruns.appe 3741 testruns.append(data) 3915 data = Data(len(testr 3742 data = Data(len(testruns)) 3916 tp.parseStamp(data, s 3743 tp.parseStamp(data, sysvals) 3917 if(not data): 3744 if(not data): 3918 continue 3745 continue 3919 m = re.match(r'.* *(?P<k>[0-9 !! 3746 m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg) 3920 if(m): 3747 if(m): 3921 sysvals.stamp['kernel 3748 sysvals.stamp['kernel'] = m.group('k') 3922 m = re.match(r'PM: Preparing !! 3749 m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg) 3923 if not m: !! 3750 if(m): 3924 m = re.match(r'PM: Pr << 3925 if m: << 3926 sysvals.stamp['mode'] 3751 sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m') 3927 data.dmesgtext.append(line) 3752 data.dmesgtext.append(line) 3928 lf.close() 3753 lf.close() 3929 3754 3930 if sysvals.suspendmode == 's2idle': << 3931 sysvals.suspendmode = 'freeze << 3932 elif sysvals.suspendmode == 'deep': << 3933 sysvals.suspendmode = 'mem' << 3934 if data: 3755 if data: 3935 testruns.append(data) 3756 testruns.append(data) 3936 if len(testruns) < 1: 3757 if len(testruns) < 1: 3937 doError('dmesg log has no sus 3758 doError('dmesg log has no suspend/resume data: %s' \ 3938 % sysvals.dmesgfile) 3759 % sysvals.dmesgfile) 3939 3760 3940 # fix lines with same timestamp/funct 3761 # fix lines with same timestamp/function with the call and return swapped 3941 for data in testruns: 3762 for data in testruns: 3942 last = '' 3763 last = '' 3943 for line in data.dmesgtext: 3764 for line in data.dmesgtext: 3944 ct, cf, n, p = data.i !! 3765 mc = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling '+\ 3945 rt, rf, l = data.init !! 3766 '(?P<f>.*)\+ @ .*, parent: .*', line) 3946 if ct and rt and ct = !! 3767 mr = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\ >> 3768 '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', last) >> 3769 if(mc and mr and (mc.group('t') == mr.group('t')) and >> 3770 (mc.group('f') == mr.group('f'))): 3947 i = data.dmes 3771 i = data.dmesgtext.index(last) 3948 j = data.dmes 3772 j = data.dmesgtext.index(line) 3949 data.dmesgtex 3773 data.dmesgtext[i] = line 3950 data.dmesgtex 3774 data.dmesgtext[j] = last 3951 last = line 3775 last = line 3952 return testruns 3776 return testruns 3953 3777 3954 # Function: parseKernelLog 3778 # Function: parseKernelLog 3955 # Description: 3779 # Description: >> 3780 # [deprecated for kernel 3.15.0 or newer] 3956 # Analyse a dmesg log output file gene 3781 # Analyse a dmesg log output file generated from this app during 3957 # the execution phase. Create a set of 3782 # the execution phase. Create a set of device structures in memory 3958 # for subsequent formatting in the htm 3783 # for subsequent formatting in the html output file 3959 # This call is only for legacy support 3784 # This call is only for legacy support on kernels where the ftrace 3960 # data lacks the suspend_resume or dev 3785 # data lacks the suspend_resume or device_pm_callbacks trace events. 3961 # Arguments: 3786 # Arguments: 3962 # data: an empty Data object (with dme 3787 # data: an empty Data object (with dmesgtext) obtained from loadKernelLog 3963 # Output: 3788 # Output: 3964 # The filled Data object 3789 # The filled Data object 3965 def parseKernelLog(data): 3790 def parseKernelLog(data): 3966 phase = 'suspend_runtime' 3791 phase = 'suspend_runtime' 3967 3792 3968 if(data.fwValid): 3793 if(data.fwValid): 3969 sysvals.vprint('Firmware Susp 3794 sysvals.vprint('Firmware Suspend = %u ns, Firmware Resume = %u ns' % \ 3970 (data.fwSuspend, data 3795 (data.fwSuspend, data.fwResume)) 3971 3796 3972 # dmesg phase match table 3797 # dmesg phase match table 3973 dm = { 3798 dm = { 3974 'suspend_prepare': ['PM: Sync !! 3799 'suspend_prepare': ['PM: Syncing filesystems.*'], 3975 'suspend': ['PM: Ente !! 3800 'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*'], 3976 'PM: Susp !! 3801 'suspend_late': ['PM: suspend of devices complete after.*'], 3977 'suspend_late': ['PM: susp !! 3802 'suspend_noirq': ['PM: late suspend of devices complete after.*'], 3978 !! 3803 'suspend_machine': ['PM: noirq suspend of devices complete after.*'], 3979 'suspend_noirq': ['PM: late !! 3804 'resume_machine': ['ACPI: Low-level resume complete.*'], 3980 !! 3805 'resume_noirq': ['ACPI: Waking up from system sleep state.*'], 3981 'suspend_machine': ['PM: susp !! 3806 'resume_early': ['PM: noirq resume of devices complete after.*'], 3982 !! 3807 'resume': ['PM: early resume of devices complete after.*'], 3983 !! 3808 'resume_complete': ['PM: resume of devices complete after.*'], 3984 'resume_machine': ['[PM: ]*T !! 3809 '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 } 3810 } >> 3811 if(sysvals.suspendmode == 'standby'): >> 3812 dm['resume_machine'] = ['PM: Restoring platform NVS memory'] >> 3813 elif(sysvals.suspendmode == 'disk'): >> 3814 dm['suspend_late'] = ['PM: freeze of devices complete after.*'] >> 3815 dm['suspend_noirq'] = ['PM: late freeze of devices complete after.*'] >> 3816 dm['suspend_machine'] = ['PM: noirq freeze of devices complete after.*'] >> 3817 dm['resume_machine'] = ['PM: Restoring platform NVS memory'] >> 3818 dm['resume_early'] = ['PM: noirq restore of devices complete after.*'] >> 3819 dm['resume'] = ['PM: early restore of devices complete after.*'] >> 3820 dm['resume_complete'] = ['PM: restore of devices complete after.*'] >> 3821 elif(sysvals.suspendmode == 'freeze'): >> 3822 dm['resume_machine'] = ['ACPI: resume from mwait'] 3998 3823 3999 # action table (expected events that 3824 # action table (expected events that occur and show up in dmesg) 4000 at = { 3825 at = { 4001 'sync_filesystems': { 3826 'sync_filesystems': { 4002 'smsg': '.*[Ff]+ilesy !! 3827 'smsg': 'PM: Syncing filesystems.*', 4003 'emsg': 'PM: Preparin !! 3828 'emsg': 'PM: Preparing system for mem sleep.*' }, 4004 'freeze_user_processes': { 3829 'freeze_user_processes': { 4005 'smsg': 'Freezing use !! 3830 'smsg': 'Freezing user space processes .*', 4006 'emsg': 'Freezing rem 3831 'emsg': 'Freezing remaining freezable tasks.*' }, 4007 'freeze_tasks': { 3832 'freeze_tasks': { 4008 'smsg': 'Freezing rem 3833 'smsg': 'Freezing remaining freezable tasks.*', 4009 'emsg': 'PM: Suspendi !! 3834 'emsg': 'PM: Entering (?P<mode>[a-z,A-Z]*) sleep.*' }, 4010 'ACPI prepare': { 3835 'ACPI prepare': { 4011 'smsg': 'ACPI: Prepar 3836 'smsg': 'ACPI: Preparing to enter system sleep state.*', 4012 'emsg': 'PM: Saving p 3837 'emsg': 'PM: Saving platform NVS memory.*' }, 4013 'PM vns': { 3838 'PM vns': { 4014 'smsg': 'PM: Saving p 3839 'smsg': 'PM: Saving platform NVS memory.*', 4015 'emsg': 'Disabling no 3840 'emsg': 'Disabling non-boot CPUs .*' }, 4016 } 3841 } 4017 3842 4018 t0 = -1.0 3843 t0 = -1.0 4019 cpu_start = -1.0 3844 cpu_start = -1.0 4020 prevktime = -1.0 3845 prevktime = -1.0 4021 actions = dict() 3846 actions = dict() 4022 for line in data.dmesgtext: 3847 for line in data.dmesgtext: 4023 # parse each dmesg line into 3848 # parse each dmesg line into the time and message 4024 m = re.match(r'[ \t]*(\[ *)(? !! 3849 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 4025 if(m): 3850 if(m): 4026 val = m.group('ktime' 3851 val = m.group('ktime') 4027 try: 3852 try: 4028 ktime = float 3853 ktime = float(val) 4029 except: 3854 except: 4030 continue 3855 continue 4031 msg = m.group('msg') 3856 msg = m.group('msg') 4032 # initialize data sta 3857 # initialize data start to first line time 4033 if t0 < 0: 3858 if t0 < 0: 4034 data.setStart 3859 data.setStart(ktime) 4035 t0 = ktime 3860 t0 = ktime 4036 else: 3861 else: 4037 continue 3862 continue 4038 3863 4039 # check for a phase change li 3864 # check for a phase change line 4040 phasechange = False 3865 phasechange = False 4041 for p in dm: 3866 for p in dm: 4042 for s in dm[p]: 3867 for s in dm[p]: 4043 if(re.match(s 3868 if(re.match(s, msg)): 4044 phase 3869 phasechange, phase = True, p 4045 dm[p] << 4046 break 3870 break 4047 3871 4048 # hack for determining resume 3872 # hack for determining resume_machine end for freeze 4049 if(not sysvals.usetraceevents 3873 if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \ 4050 and phase == 'resume_ 3874 and phase == 'resume_machine' and \ 4051 data.initcall_debug_c !! 3875 re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): 4052 data.setPhase(phase, 3876 data.setPhase(phase, ktime, False) 4053 phase = 'resume_noirq 3877 phase = 'resume_noirq' 4054 data.setPhase(phase, 3878 data.setPhase(phase, ktime, True) 4055 3879 4056 if phasechange: 3880 if phasechange: 4057 if phase == 'suspend_ 3881 if phase == 'suspend_prepare': 4058 data.setPhase 3882 data.setPhase(phase, ktime, True) 4059 data.setStart 3883 data.setStart(ktime) 4060 data.tKernSus 3884 data.tKernSus = ktime 4061 elif phase == 'suspen 3885 elif phase == 'suspend': 4062 lp = data.las 3886 lp = data.lastPhase() 4063 if lp: 3887 if lp: 4064 data. 3888 data.setPhase(lp, ktime, False) 4065 data.setPhase 3889 data.setPhase(phase, ktime, True) 4066 elif phase == 'suspen 3890 elif phase == 'suspend_late': 4067 lp = data.las 3891 lp = data.lastPhase() 4068 if lp: 3892 if lp: 4069 data. 3893 data.setPhase(lp, ktime, False) 4070 data.setPhase 3894 data.setPhase(phase, ktime, True) 4071 elif phase == 'suspen 3895 elif phase == 'suspend_noirq': 4072 lp = data.las 3896 lp = data.lastPhase() 4073 if lp: 3897 if lp: 4074 data. 3898 data.setPhase(lp, ktime, False) 4075 data.setPhase 3899 data.setPhase(phase, ktime, True) 4076 elif phase == 'suspen 3900 elif phase == 'suspend_machine': 4077 lp = data.las 3901 lp = data.lastPhase() 4078 if lp: 3902 if lp: 4079 data. 3903 data.setPhase(lp, ktime, False) 4080 data.setPhase 3904 data.setPhase(phase, ktime, True) 4081 elif phase == 'resume 3905 elif phase == 'resume_machine': 4082 lp = data.las 3906 lp = data.lastPhase() 4083 if(sysvals.su 3907 if(sysvals.suspendmode in ['freeze', 'standby']): 4084 data. 3908 data.tSuspended = prevktime 4085 if lp 3909 if lp: 4086 3910 data.setPhase(lp, prevktime, False) 4087 else: 3911 else: 4088 data. 3912 data.tSuspended = ktime 4089 if lp 3913 if lp: 4090 3914 data.setPhase(lp, prevktime, False) 4091 data.tResumed 3915 data.tResumed = ktime 4092 data.setPhase 3916 data.setPhase(phase, ktime, True) 4093 elif phase == 'resume 3917 elif phase == 'resume_noirq': 4094 lp = data.las 3918 lp = data.lastPhase() 4095 if lp: 3919 if lp: 4096 data. 3920 data.setPhase(lp, ktime, False) 4097 data.setPhase 3921 data.setPhase(phase, ktime, True) 4098 elif phase == 'resume 3922 elif phase == 'resume_early': 4099 lp = data.las 3923 lp = data.lastPhase() 4100 if lp: 3924 if lp: 4101 data. 3925 data.setPhase(lp, ktime, False) 4102 data.setPhase 3926 data.setPhase(phase, ktime, True) 4103 elif phase == 'resume 3927 elif phase == 'resume': 4104 lp = data.las 3928 lp = data.lastPhase() 4105 if lp: 3929 if lp: 4106 data. 3930 data.setPhase(lp, ktime, False) 4107 data.setPhase 3931 data.setPhase(phase, ktime, True) 4108 elif phase == 'resume 3932 elif phase == 'resume_complete': 4109 lp = data.las 3933 lp = data.lastPhase() 4110 if lp: 3934 if lp: 4111 data. 3935 data.setPhase(lp, ktime, False) 4112 data.setPhase 3936 data.setPhase(phase, ktime, True) 4113 elif phase == 'post_r 3937 elif phase == 'post_resume': 4114 lp = data.las 3938 lp = data.lastPhase() 4115 if lp: 3939 if lp: 4116 data. 3940 data.setPhase(lp, ktime, False) 4117 data.setEnd(k 3941 data.setEnd(ktime) 4118 data.tKernRes 3942 data.tKernRes = ktime 4119 break 3943 break 4120 3944 4121 # -- device callbacks -- 3945 # -- device callbacks -- 4122 if(phase in data.sortedPhases 3946 if(phase in data.sortedPhases()): 4123 # device init call 3947 # device init call 4124 t, f, n, p = data.ini !! 3948 if(re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): 4125 if t and f and n and !! 3949 sm = re.match('calling (?P<f>.*)\+ @ '+\ 4126 data.newActio !! 3950 '(?P<n>.*), parent: (?P<p>.*)', msg); 4127 else: !! 3951 f = sm.group('f') 4128 # device init !! 3952 n = sm.group('n') 4129 t, f, l = dat !! 3953 p = sm.group('p') 4130 if t and f an !! 3954 if(f and n and p): 4131 list !! 3955 data.newAction(phase, f, int(n), p, ktime, -1, '') 4132 if(f !! 3956 # device init return 4133 !! 3957 elif(re.match('call (?P<f>.*)\+ returned .* after '+\ 4134 !! 3958 '(?P<t>.*) usecs', msg)): 4135 !! 3959 sm = re.match('call (?P<f>.*)\+ returned .* after '+\ >> 3960 '(?P<t>.*) usecs(?P<a>.*)', msg); >> 3961 f = sm.group('f') >> 3962 t = sm.group('t') >> 3963 list = data.dmesg[phase]['list'] >> 3964 if(f in list): >> 3965 dev = list[f] >> 3966 dev['length'] = int(t) >> 3967 dev['end'] = ktime 4136 3968 4137 # if trace events are not ava 3969 # if trace events are not available, these are better than nothing 4138 if(not sysvals.usetraceevents 3970 if(not sysvals.usetraceevents): 4139 # look for known acti 3971 # look for known actions 4140 for a in sorted(at): 3972 for a in sorted(at): 4141 if(re.match(a 3973 if(re.match(at[a]['smsg'], msg)): 4142 if(a 3974 if(a not in actions): 4143 !! 3975 actions[a] = [] >> 3976 actions[a].append({'begin': ktime, 'end': ktime}) 4144 if(re.match(a 3977 if(re.match(at[a]['emsg'], msg)): 4145 if(a !! 3978 if(a in actions): 4146 3979 actions[a][-1]['end'] = ktime 4147 # now look for CPU on 3980 # now look for CPU on/off events 4148 if(re.match(r'Disabli !! 3981 if(re.match('Disabling non-boot CPUs .*', msg)): 4149 # start of fi 3982 # start of first cpu suspend 4150 cpu_start = k 3983 cpu_start = ktime 4151 elif(re.match(r'Enabl !! 3984 elif(re.match('Enabling non-boot CPUs .*', msg)): 4152 # start of fi 3985 # start of first cpu resume 4153 cpu_start = k 3986 cpu_start = ktime 4154 elif(re.match(r'smpbo !! 3987 elif(re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg)): 4155 or re.match(r << 4156 # end of a cp 3988 # end of a cpu suspend, start of the next 4157 m = re.match( !! 3989 m = re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg) 4158 if(not m): << 4159 m = r << 4160 cpu = 'CPU'+m 3990 cpu = 'CPU'+m.group('cpu') 4161 if(cpu not in 3991 if(cpu not in actions): 4162 actio 3992 actions[cpu] = [] 4163 actions[cpu]. 3993 actions[cpu].append({'begin': cpu_start, 'end': ktime}) 4164 cpu_start = k 3994 cpu_start = ktime 4165 elif(re.match(r'CPU(? !! 3995 elif(re.match('CPU(?P<cpu>[0-9]*) is up', msg)): 4166 # end of a cp 3996 # end of a cpu resume, start of the next 4167 m = re.match( !! 3997 m = re.match('CPU(?P<cpu>[0-9]*) is up', msg) 4168 cpu = 'CPU'+m 3998 cpu = 'CPU'+m.group('cpu') 4169 if(cpu not in 3999 if(cpu not in actions): 4170 actio 4000 actions[cpu] = [] 4171 actions[cpu]. 4001 actions[cpu].append({'begin': cpu_start, 'end': ktime}) 4172 cpu_start = k 4002 cpu_start = ktime 4173 prevktime = ktime 4003 prevktime = ktime 4174 data.initDevicegroups() 4004 data.initDevicegroups() 4175 4005 4176 # fill in any missing phases 4006 # fill in any missing phases 4177 phasedef = data.phasedef 4007 phasedef = data.phasedef 4178 terr, lp = '', 'suspend_prepare' 4008 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 4009 for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 4182 if p not in data.dmesg: 4010 if p not in data.dmesg: 4183 if not terr: 4011 if not terr: 4184 pprint('TEST 4012 pprint('TEST FAILED: %s failed in %s phase' % (sysvals.suspendmode, lp)) 4185 terr = '%s fa 4013 terr = '%s failed in %s phase' % (sysvals.suspendmode, lp) 4186 if data.tSusp 4014 if data.tSuspended == 0: 4187 data. 4015 data.tSuspended = data.dmesg[lp]['end'] 4188 if data.tResu 4016 if data.tResumed == 0: 4189 data. 4017 data.tResumed = data.dmesg[lp]['end'] 4190 sysvals.vprint('WARNI 4018 sysvals.vprint('WARNING: phase "%s" is missing!' % p) 4191 lp = p 4019 lp = p 4192 lp = data.sortedPhases()[0] 4020 lp = data.sortedPhases()[0] 4193 for p in data.sortedPhases(): 4021 for p in data.sortedPhases(): 4194 if(p != lp and not ('machine' 4022 if(p != lp and not ('machine' in p and 'machine' in lp)): 4195 data.dmesg[lp]['end'] 4023 data.dmesg[lp]['end'] = data.dmesg[p]['start'] 4196 lp = p 4024 lp = p 4197 if data.tSuspended == 0: 4025 if data.tSuspended == 0: 4198 data.tSuspended = data.tKernR 4026 data.tSuspended = data.tKernRes 4199 if data.tResumed == 0: 4027 if data.tResumed == 0: 4200 data.tResumed = data.tSuspend 4028 data.tResumed = data.tSuspended 4201 4029 4202 # fill in any actions we've found 4030 # fill in any actions we've found 4203 for name in sorted(actions): 4031 for name in sorted(actions): 4204 for event in actions[name]: 4032 for event in actions[name]: 4205 data.newActionGlobal( 4033 data.newActionGlobal(name, event['begin'], event['end']) 4206 4034 4207 if(len(sysvals.devicefilter) > 0): 4035 if(len(sysvals.devicefilter) > 0): 4208 data.deviceFilter(sysvals.dev 4036 data.deviceFilter(sysvals.devicefilter) 4209 data.fixupInitcallsThatDidntReturn() 4037 data.fixupInitcallsThatDidntReturn() 4210 return True 4038 return True 4211 4039 4212 def callgraphHTML(sv, hf, num, cg, title, col 4040 def callgraphHTML(sv, hf, num, cg, title, color, devid): 4213 html_func_top = '<article id="{0}" cl 4041 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 4042 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' 4043 html_func_end = '</article>\n' 4216 html_func_leaf = '<article>{0} {1}</a 4044 html_func_leaf = '<article>{0} {1}</article>\n' 4217 4045 4218 cgid = devid 4046 cgid = devid 4219 if cg.id: 4047 if cg.id: 4220 cgid += cg.id 4048 cgid += cg.id 4221 cglen = (cg.end - cg.start) * 1000 4049 cglen = (cg.end - cg.start) * 1000 4222 if cglen < sv.mincglen: 4050 if cglen < sv.mincglen: 4223 return num 4051 return num 4224 4052 4225 fmt = '<r>(%.3f ms @ '+sv.timeformat+' 4053 fmt = '<r>(%.3f ms @ '+sv.timeformat+' to '+sv.timeformat+')</r>' 4226 flen = fmt % (cglen, cg.start, cg.end 4054 flen = fmt % (cglen, cg.start, cg.end) 4227 hf.write(html_func_top.format(cgid, c 4055 hf.write(html_func_top.format(cgid, color, num, title, flen)) 4228 num += 1 4056 num += 1 4229 for line in cg.list: 4057 for line in cg.list: 4230 if(line.length < 0.000000001) 4058 if(line.length < 0.000000001): 4231 flen = '' 4059 flen = '' 4232 else: 4060 else: 4233 fmt = '<n>(%.3f ms @ ' 4061 fmt = '<n>(%.3f ms @ '+sv.timeformat+')</n>' 4234 flen = fmt % (line.le 4062 flen = fmt % (line.length*1000, line.time) 4235 if line.isLeaf(): 4063 if line.isLeaf(): 4236 if line.length * 1000 << 4237 continue << 4238 hf.write(html_func_le 4064 hf.write(html_func_leaf.format(line.name, flen)) 4239 elif line.freturn: 4065 elif line.freturn: 4240 hf.write(html_func_en 4066 hf.write(html_func_end) 4241 else: 4067 else: 4242 hf.write(html_func_st 4068 hf.write(html_func_start.format(num, line.name, flen)) 4243 num += 1 4069 num += 1 4244 hf.write(html_func_end) 4070 hf.write(html_func_end) 4245 return num 4071 return num 4246 4072 4247 def addCallgraphs(sv, hf, data): 4073 def addCallgraphs(sv, hf, data): 4248 hf.write('<section id="callgraphs" cl 4074 hf.write('<section id="callgraphs" class="callgraph">\n') 4249 # write out the ftrace data converted 4075 # write out the ftrace data converted to html 4250 num = 0 4076 num = 0 4251 for p in data.sortedPhases(): 4077 for p in data.sortedPhases(): 4252 if sv.cgphase and p != sv.cgp 4078 if sv.cgphase and p != sv.cgphase: 4253 continue 4079 continue 4254 list = data.dmesg[p]['list'] 4080 list = data.dmesg[p]['list'] 4255 for d in data.sortedDevices(p 4081 for d in data.sortedDevices(p): 4256 if len(sv.cgfilter) > 4082 if len(sv.cgfilter) > 0 and d not in sv.cgfilter: 4257 continue 4083 continue 4258 dev = list[d] 4084 dev = list[d] 4259 color = 'white' 4085 color = 'white' 4260 if 'color' in data.dm 4086 if 'color' in data.dmesg[p]: 4261 color = data. 4087 color = data.dmesg[p]['color'] 4262 if 'color' in dev: 4088 if 'color' in dev: 4263 color = dev[' 4089 color = dev['color'] 4264 name = d if '[' not i 4090 name = d if '[' not in d else d.split('[')[0] 4265 if(d in sv.devprops): 4091 if(d in sv.devprops): 4266 name = sv.dev 4092 name = sv.devprops[d].altName(d) 4267 if 'drv' in dev and d 4093 if 'drv' in dev and dev['drv']: 4268 name += ' {%s 4094 name += ' {%s}' % dev['drv'] 4269 if sv.suspendmode in 4095 if sv.suspendmode in suspendmodename: 4270 name += ' '+p 4096 name += ' '+p 4271 if('ftrace' in dev): 4097 if('ftrace' in dev): 4272 cg = dev['ftr 4098 cg = dev['ftrace'] 4273 if cg.name == 4099 if cg.name == sv.ftopfunc: 4274 name 4100 name = 'top level suspend/resume call' 4275 num = callgra 4101 num = callgraphHTML(sv, hf, num, cg, 4276 name, 4102 name, color, dev['id']) 4277 if('ftraces' in dev): 4103 if('ftraces' in dev): 4278 for cg in dev 4104 for cg in dev['ftraces']: 4279 num = 4105 num = callgraphHTML(sv, hf, num, cg, 4280 4106 name+' → '+cg.name, color, dev['id']) 4281 hf.write('\n\n </section>\n') 4107 hf.write('\n\n </section>\n') 4282 4108 4283 def summaryCSS(title, center=True): 4109 def summaryCSS(title, center=True): 4284 tdcenter = 'text-align:center;' if ce 4110 tdcenter = 'text-align:center;' if center else '' 4285 out = '<!DOCTYPE html>\n<html>\n<head 4111 out = '<!DOCTYPE html>\n<html>\n<head>\n\ 4286 <meta http-equiv="content-type" conte 4112 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 4287 <title>'+title+'</title>\n\ 4113 <title>'+title+'</title>\n\ 4288 <style type=\'text/css\'>\n\ 4114 <style type=\'text/css\'>\n\ 4289 .stamp {width: 100%;text-alig 4115 .stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\ 4290 table {width:100%;border-coll 4116 table {width:100%;border-collapse: collapse;border:1px solid;}\n\ 4291 th {border: 1px solid black;b 4117 th {border: 1px solid black;background:#222;color:white;}\n\ 4292 td {font: 14px "Times New Rom 4118 td {font: 14px "Times New Roman";'+tdcenter+'}\n\ 4293 tr.head td {border: 1px solid 4119 tr.head td {border: 1px solid black;background:#aaa;}\n\ 4294 tr.alt {background-color:#ddd 4120 tr.alt {background-color:#ddd;}\n\ 4295 tr.notice {color:red;}\n\ 4121 tr.notice {color:red;}\n\ 4296 .minval {background-color:#BB 4122 .minval {background-color:#BBFFBB;}\n\ 4297 .medval {background-color:#BB 4123 .medval {background-color:#BBBBFF;}\n\ 4298 .maxval {background-color:#FF 4124 .maxval {background-color:#FFBBBB;}\n\ 4299 .head a {color:#000;text-deco 4125 .head a {color:#000;text-decoration: none;}\n\ 4300 </style>\n</head>\n<body>\n' 4126 </style>\n</head>\n<body>\n' 4301 return out 4127 return out 4302 4128 4303 # Function: createHTMLSummarySimple 4129 # Function: createHTMLSummarySimple 4304 # Description: 4130 # Description: 4305 # Create summary html file for a serie 4131 # Create summary html file for a series of tests 4306 # Arguments: 4132 # Arguments: 4307 # testruns: array of Data objects from 4133 # testruns: array of Data objects from parseTraceLog 4308 def createHTMLSummarySimple(testruns, htmlfil 4134 def createHTMLSummarySimple(testruns, htmlfile, title): 4309 # write the html header first (html h 4135 # write the html header first (html head, css code, up to body start) 4310 html = summaryCSS('Summary - SleepGra 4136 html = summaryCSS('Summary - SleepGraph') 4311 4137 4312 # extract the test data into list 4138 # extract the test data into list 4313 list = dict() 4139 list = dict() 4314 tAvg, tMin, tMax, tMed = [0.0, 0.0], 4140 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 4141 iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 4316 num = 0 4142 num = 0 4317 useturbo = usewifi = False 4143 useturbo = usewifi = False 4318 lastmode = '' 4144 lastmode = '' 4319 cnt = dict() 4145 cnt = dict() 4320 for data in sorted(testruns, key=lamb 4146 for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])): 4321 mode = data['mode'] 4147 mode = data['mode'] 4322 if mode not in list: 4148 if mode not in list: 4323 list[mode] = {'data': 4149 list[mode] = {'data': [], 'avg': [0,0], 'min': [0,0], 'max': [0,0], 'med': [0,0]} 4324 if lastmode and lastmode != m 4150 if lastmode and lastmode != mode and num > 0: 4325 for i in range(2): 4151 for i in range(2): 4326 s = sorted(tM 4152 s = sorted(tMed[i]) 4327 list[lastmode 4153 list[lastmode]['med'][i] = s[int(len(s)//2)] 4328 iMed[i] = tMe 4154 iMed[i] = tMed[i][list[lastmode]['med'][i]] 4329 list[lastmode]['avg'] 4155 list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 4330 list[lastmode]['min'] 4156 list[lastmode]['min'] = tMin 4331 list[lastmode]['max'] 4157 list[lastmode]['max'] = tMax 4332 list[lastmode]['idx'] 4158 list[lastmode]['idx'] = (iMin, iMed, iMax) 4333 tAvg, tMin, tMax, tMe 4159 tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 4334 iMin, iMed, iMax = [0 4160 iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 4335 num = 0 4161 num = 0 4336 pkgpc10 = syslpi = wifi = '' 4162 pkgpc10 = syslpi = wifi = '' 4337 if 'pkgpc10' in data and 'sys 4163 if 'pkgpc10' in data and 'syslpi' in data: 4338 pkgpc10, syslpi, uset 4164 pkgpc10, syslpi, useturbo = data['pkgpc10'], data['syslpi'], True 4339 if 'wifi' in data: 4165 if 'wifi' in data: 4340 wifi, usewifi = data[ 4166 wifi, usewifi = data['wifi'], True 4341 res = data['result'] 4167 res = data['result'] 4342 tVal = [float(data['suspend'] 4168 tVal = [float(data['suspend']), float(data['resume'])] 4343 list[mode]['data'].append([da 4169 list[mode]['data'].append([data['host'], data['kernel'], 4344 data['time'], tVal[0] 4170 data['time'], tVal[0], tVal[1], data['url'], res, 4345 data['issues'], data[ 4171 data['issues'], data['sus_worst'], data['sus_worsttime'], 4346 data['res_worst'], da !! 4172 data['res_worst'], data['res_worsttime'], pkgpc10, syslpi, wifi]) 4347 (data['fullmode'] if << 4348 idx = len(list[mode]['data']) 4173 idx = len(list[mode]['data']) - 1 4349 if res.startswith('fail in'): 4174 if res.startswith('fail in'): 4350 res = 'fail' 4175 res = 'fail' 4351 if res not in cnt: 4176 if res not in cnt: 4352 cnt[res] = 1 4177 cnt[res] = 1 4353 else: 4178 else: 4354 cnt[res] += 1 4179 cnt[res] += 1 4355 if res == 'pass': 4180 if res == 'pass': 4356 for i in range(2): 4181 for i in range(2): 4357 tMed[i][tVal[ 4182 tMed[i][tVal[i]] = idx 4358 tAvg[i] += tV 4183 tAvg[i] += tVal[i] 4359 if tMin[i] == 4184 if tMin[i] == 0 or tVal[i] < tMin[i]: 4360 iMin[ 4185 iMin[i] = idx 4361 tMin[ 4186 tMin[i] = tVal[i] 4362 if tMax[i] == 4187 if tMax[i] == 0 or tVal[i] > tMax[i]: 4363 iMax[ 4188 iMax[i] = idx 4364 tMax[ 4189 tMax[i] = tVal[i] 4365 num += 1 4190 num += 1 4366 lastmode = mode 4191 lastmode = mode 4367 if lastmode and num > 0: 4192 if lastmode and num > 0: 4368 for i in range(2): 4193 for i in range(2): 4369 s = sorted(tMed[i]) 4194 s = sorted(tMed[i]) 4370 list[lastmode]['med'] 4195 list[lastmode]['med'][i] = s[int(len(s)//2)] 4371 iMed[i] = tMed[i][lis 4196 iMed[i] = tMed[i][list[lastmode]['med'][i]] 4372 list[lastmode]['avg'] = [tAvg 4197 list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 4373 list[lastmode]['min'] = tMin 4198 list[lastmode]['min'] = tMin 4374 list[lastmode]['max'] = tMax 4199 list[lastmode]['max'] = tMax 4375 list[lastmode]['idx'] = (iMin 4200 list[lastmode]['idx'] = (iMin, iMed, iMax) 4376 4201 4377 # group test header 4202 # group test header 4378 desc = [] 4203 desc = [] 4379 for ilk in sorted(cnt, reverse=True): 4204 for ilk in sorted(cnt, reverse=True): 4380 if cnt[ilk] > 0: 4205 if cnt[ilk] > 0: 4381 desc.append('%d %s' % 4206 desc.append('%d %s' % (cnt[ilk], ilk)) 4382 html += '<div class="stamp">%s (%d te 4207 html += '<div class="stamp">%s (%d tests: %s)</div>\n' % (title, len(testruns), ', '.join(desc)) 4383 th = '\t<th>{0}</th>\n' 4208 th = '\t<th>{0}</th>\n' 4384 td = '\t<td>{0}</td>\n' 4209 td = '\t<td>{0}</td>\n' 4385 tdh = '\t<td{1}>{0}</td>\n' 4210 tdh = '\t<td{1}>{0}</td>\n' 4386 tdlink = '\t<td><a href="{0}">html</a 4211 tdlink = '\t<td><a href="{0}">html</a></td>\n' 4387 cols = 12 4212 cols = 12 4388 if useturbo: 4213 if useturbo: 4389 cols += 2 4214 cols += 2 4390 if usewifi: 4215 if usewifi: 4391 cols += 1 4216 cols += 1 4392 colspan = '%d' % cols 4217 colspan = '%d' % cols 4393 4218 4394 # table header 4219 # table header 4395 html += '<table>\n<tr>\n' + th.format 4220 html += '<table>\n<tr>\n' + th.format('#') +\ 4396 th.format('Mode') + th.format 4221 th.format('Mode') + th.format('Host') + th.format('Kernel') +\ 4397 th.format('Test Time') + th.f 4222 th.format('Test Time') + th.format('Result') + th.format('Issues') +\ 4398 th.format('Suspend') + th.for 4223 th.format('Suspend') + th.format('Resume') +\ 4399 th.format('Worst Suspend Devi 4224 th.format('Worst Suspend Device') + th.format('SD Time') +\ 4400 th.format('Worst Resume Devic 4225 th.format('Worst Resume Device') + th.format('RD Time') 4401 if useturbo: 4226 if useturbo: 4402 html += th.format('PkgPC10') 4227 html += th.format('PkgPC10') + th.format('SysLPI') 4403 if usewifi: 4228 if usewifi: 4404 html += th.format('Wifi') 4229 html += th.format('Wifi') 4405 html += th.format('Detail')+'</tr>\n' 4230 html += th.format('Detail')+'</tr>\n' 4406 # export list into html 4231 # export list into html 4407 head = '<tr class="head"><td>{0}</td> 4232 head = '<tr class="head"><td>{0}</td><td>{1}</td>'+\ 4408 '<td colspan='+colspan+' clas 4233 '<td colspan='+colspan+' class="sus">Suspend Avg={2} '+\ 4409 '<span class=minval><a href=" 4234 '<span class=minval><a href="#s{10}min">Min={3}</a></span> '+\ 4410 '<span class=medval><a href=" 4235 '<span class=medval><a href="#s{10}med">Med={4}</a></span> '+\ 4411 '<span class=maxval><a href=" 4236 '<span class=maxval><a href="#s{10}max">Max={5}</a></span> '+\ 4412 'Resume Avg={6} '+\ 4237 'Resume Avg={6} '+\ 4413 '<span class=minval><a href=" 4238 '<span class=minval><a href="#r{10}min">Min={7}</a></span> '+\ 4414 '<span class=medval><a href=" 4239 '<span class=medval><a href="#r{10}med">Med={8}</a></span> '+\ 4415 '<span class=maxval><a href=" 4240 '<span class=maxval><a href="#r{10}max">Max={9}</a></span></td>'+\ 4416 '</tr>\n' 4241 '</tr>\n' 4417 headnone = '<tr class="head"><td>{0}< 4242 headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan='+\ 4418 colspan+'></td></tr>\n' 4243 colspan+'></td></tr>\n' 4419 for mode in sorted(list): 4244 for mode in sorted(list): 4420 # header line for each suspen 4245 # header line for each suspend mode 4421 num = 0 4246 num = 0 4422 tAvg, tMin, tMax, tMed = list 4247 tAvg, tMin, tMax, tMed = list[mode]['avg'], list[mode]['min'],\ 4423 list[mode]['max'], li 4248 list[mode]['max'], list[mode]['med'] 4424 count = len(list[mode]['data' 4249 count = len(list[mode]['data']) 4425 if 'idx' in list[mode]: 4250 if 'idx' in list[mode]: 4426 iMin, iMed, iMax = li 4251 iMin, iMed, iMax = list[mode]['idx'] 4427 html += head.format(' 4252 html += head.format('%d' % count, mode.upper(), 4428 '%.3f' % tAvg 4253 '%.3f' % tAvg[0], '%.3f' % tMin[0], '%.3f' % tMed[0], '%.3f' % tMax[0], 4429 '%.3f' % tAvg 4254 '%.3f' % tAvg[1], '%.3f' % tMin[1], '%.3f' % tMed[1], '%.3f' % tMax[1], 4430 mode.lower() 4255 mode.lower() 4431 ) 4256 ) 4432 else: 4257 else: 4433 iMin = iMed = iMax = 4258 iMin = iMed = iMax = [-1, -1, -1] 4434 html += headnone.form 4259 html += headnone.format('%d' % count, mode.upper()) 4435 for d in list[mode]['data']: 4260 for d in list[mode]['data']: 4436 # row classes - alter 4261 # row classes - alternate row color 4437 rcls = ['alt'] if num 4262 rcls = ['alt'] if num % 2 == 1 else [] 4438 if d[6] != 'pass': 4263 if d[6] != 'pass': 4439 rcls.append(' 4264 rcls.append('notice') 4440 html += '<tr class="' 4265 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4441 # figure out if the l 4266 # figure out if the line has sus or res highlighted 4442 idx = list[mode]['dat 4267 idx = list[mode]['data'].index(d) 4443 tHigh = ['', ''] 4268 tHigh = ['', ''] 4444 for i in range(2): 4269 for i in range(2): 4445 tag = 's%s' % 4270 tag = 's%s' % mode if i == 0 else 'r%s' % mode 4446 if idx == iMi 4271 if idx == iMin[i]: 4447 tHigh 4272 tHigh[i] = ' id="%smin" class=minval title="Minimum"' % tag 4448 elif idx == i 4273 elif idx == iMax[i]: 4449 tHigh 4274 tHigh[i] = ' id="%smax" class=maxval title="Maximum"' % tag 4450 elif idx == i 4275 elif idx == iMed[i]: 4451 tHigh 4276 tHigh[i] = ' id="%smed" class=medval title="Median"' % tag 4452 html += td.format("%d 4277 html += td.format("%d" % (list[mode]['data'].index(d) + 1)) # row 4453 html += td.format(d[1 !! 4278 html += td.format(mode) # mode 4454 html += td.format(d[0 4279 html += td.format(d[0]) # host 4455 html += td.format(d[1 4280 html += td.format(d[1]) # kernel 4456 html += td.format(d[2 4281 html += td.format(d[2]) # time 4457 html += td.format(d[6 4282 html += td.format(d[6]) # result 4458 html += td.format(d[7 4283 html += td.format(d[7]) # issues 4459 html += tdh.format('% 4284 html += tdh.format('%.3f ms' % d[3], tHigh[0]) if d[3] else td.format('') # suspend 4460 html += tdh.format('% 4285 html += tdh.format('%.3f ms' % d[4], tHigh[1]) if d[4] else td.format('') # resume 4461 html += td.format(d[8 4286 html += td.format(d[8]) # sus_worst 4462 html += td.format('%. 4287 html += td.format('%.3f ms' % d[9]) if d[9] else td.format('') # sus_worst time 4463 html += td.format(d[1 4288 html += td.format(d[10]) # res_worst 4464 html += td.format('%. 4289 html += td.format('%.3f ms' % d[11]) if d[11] else td.format('') # res_worst time 4465 if useturbo: 4290 if useturbo: 4466 html += td.fo 4291 html += td.format(d[12]) # pkg_pc10 4467 html += td.fo 4292 html += td.format(d[13]) # syslpi 4468 if usewifi: 4293 if usewifi: 4469 html += td.fo 4294 html += td.format(d[14]) # wifi 4470 html += tdlink.format 4295 html += tdlink.format(d[5]) if d[5] else td.format('') # url 4471 html += '</tr>\n' 4296 html += '</tr>\n' 4472 num += 1 4297 num += 1 4473 4298 4474 # flush the data to file 4299 # flush the data to file 4475 hf = open(htmlfile, 'w') 4300 hf = open(htmlfile, 'w') 4476 hf.write(html+'</table>\n</body>\n</h 4301 hf.write(html+'</table>\n</body>\n</html>\n') 4477 hf.close() 4302 hf.close() 4478 4303 4479 def createHTMLDeviceSummary(testruns, htmlfil 4304 def createHTMLDeviceSummary(testruns, htmlfile, title): 4480 html = summaryCSS('Device Summary - S 4305 html = summaryCSS('Device Summary - SleepGraph', False) 4481 4306 4482 # create global device list from all 4307 # create global device list from all tests 4483 devall = dict() 4308 devall = dict() 4484 for data in testruns: 4309 for data in testruns: 4485 host, url, devlist = data['ho 4310 host, url, devlist = data['host'], data['url'], data['devlist'] 4486 for type in devlist: 4311 for type in devlist: 4487 if type not in devall 4312 if type not in devall: 4488 devall[type] 4313 devall[type] = dict() 4489 mdevlist, devlist = d 4314 mdevlist, devlist = devall[type], data['devlist'][type] 4490 for name in devlist: 4315 for name in devlist: 4491 length = devl 4316 length = devlist[name] 4492 if name not i 4317 if name not in mdevlist: 4493 mdevl 4318 mdevlist[name] = {'name': name, 'host': host, 4494 4319 'worst': length, 'total': length, 'count': 1, 4495 4320 'url': url} 4496 else: 4321 else: 4497 if le 4322 if length > mdevlist[name]['worst']: 4498 4323 mdevlist[name]['worst'] = length 4499 4324 mdevlist[name]['url'] = url 4500 4325 mdevlist[name]['host'] = host 4501 mdevl 4326 mdevlist[name]['total'] += length 4502 mdevl 4327 mdevlist[name]['count'] += 1 4503 4328 4504 # generate the html 4329 # generate the html 4505 th = '\t<th>{0}</th>\n' 4330 th = '\t<th>{0}</th>\n' 4506 td = '\t<td align=center>{0}</td>\n' 4331 td = '\t<td align=center>{0}</td>\n' 4507 tdr = '\t<td align=right>{0}</td>\n' 4332 tdr = '\t<td align=right>{0}</td>\n' 4508 tdlink = '\t<td align=center><a href= 4333 tdlink = '\t<td align=center><a href="{0}">html</a></td>\n' 4509 limit = 1 4334 limit = 1 4510 for type in sorted(devall, reverse=Tr 4335 for type in sorted(devall, reverse=True): 4511 num = 0 4336 num = 0 4512 devlist = devall[type] 4337 devlist = devall[type] 4513 # table header 4338 # table header 4514 html += '<div class="stamp">% 4339 html += '<div class="stamp">%s (%s devices > %d ms)</div><table>\n' % \ 4515 (title, type.upper(), 4340 (title, type.upper(), limit) 4516 html += '<tr>\n' + '<th align 4341 html += '<tr>\n' + '<th align=right>Device Name</th>' +\ 4517 th.format('Average Ti 4342 th.format('Average Time') + th.format('Count') +\ 4518 th.format('Worst Time 4343 th.format('Worst Time') + th.format('Host (worst time)') +\ 4519 th.format('Link (wors 4344 th.format('Link (worst time)') + '</tr>\n' 4520 for name in sorted(devlist, k 4345 for name in sorted(devlist, key=lambda k:(devlist[k]['worst'], \ 4521 devlist[k]['total'], 4346 devlist[k]['total'], devlist[k]['name']), reverse=True): 4522 data = devall[type][n 4347 data = devall[type][name] 4523 data['average'] = dat 4348 data['average'] = data['total'] / data['count'] 4524 if data['average'] < 4349 if data['average'] < limit: 4525 continue 4350 continue 4526 # row classes - alter 4351 # row classes - alternate row color 4527 rcls = ['alt'] if num 4352 rcls = ['alt'] if num % 2 == 1 else [] 4528 html += '<tr class="' 4353 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4529 html += tdr.format(da 4354 html += tdr.format(data['name']) # name 4530 html += td.format('%. 4355 html += td.format('%.3f ms' % data['average']) # average 4531 html += td.format(dat 4356 html += td.format(data['count']) # count 4532 html += td.format('%. 4357 html += td.format('%.3f ms' % data['worst']) # worst 4533 html += td.format(dat 4358 html += td.format(data['host']) # host 4534 html += tdlink.format 4359 html += tdlink.format(data['url']) # url 4535 html += '</tr>\n' 4360 html += '</tr>\n' 4536 num += 1 4361 num += 1 4537 html += '</table>\n' 4362 html += '</table>\n' 4538 4363 4539 # flush the data to file 4364 # flush the data to file 4540 hf = open(htmlfile, 'w') 4365 hf = open(htmlfile, 'w') 4541 hf.write(html+'</body>\n</html>\n') 4366 hf.write(html+'</body>\n</html>\n') 4542 hf.close() 4367 hf.close() 4543 return devall 4368 return devall 4544 4369 4545 def createHTMLIssuesSummary(testruns, issues, 4370 def createHTMLIssuesSummary(testruns, issues, htmlfile, title, extra=''): 4546 multihost = len([e for e in issues if 4371 multihost = len([e for e in issues if len(e['urls']) > 1]) > 0 4547 html = summaryCSS('Issues Summary - S 4372 html = summaryCSS('Issues Summary - SleepGraph', False) 4548 total = len(testruns) 4373 total = len(testruns) 4549 4374 4550 # generate the html 4375 # generate the html 4551 th = '\t<th>{0}</th>\n' 4376 th = '\t<th>{0}</th>\n' 4552 td = '\t<td align={0}>{1}</td>\n' 4377 td = '\t<td align={0}>{1}</td>\n' 4553 tdlink = '<a href="{1}">{0}</a>' 4378 tdlink = '<a href="{1}">{0}</a>' 4554 subtitle = '%d issues' % len(issues) 4379 subtitle = '%d issues' % len(issues) if len(issues) > 0 else 'no issues' 4555 html += '<div class="stamp">%s (%s)</ 4380 html += '<div class="stamp">%s (%s)</div><table>\n' % (title, subtitle) 4556 html += '<tr>\n' + th.format('Issue') 4381 html += '<tr>\n' + th.format('Issue') + th.format('Count') 4557 if multihost: 4382 if multihost: 4558 html += th.format('Hosts') 4383 html += th.format('Hosts') 4559 html += th.format('Tests') + th.forma 4384 html += th.format('Tests') + th.format('Fail Rate') +\ 4560 th.format('First Instance') + 4385 th.format('First Instance') + '</tr>\n' 4561 4386 4562 num = 0 4387 num = 0 4563 for e in sorted(issues, key=lambda v: 4388 for e in sorted(issues, key=lambda v:v['count'], reverse=True): 4564 testtotal = 0 4389 testtotal = 0 4565 links = [] 4390 links = [] 4566 for host in sorted(e['urls']) 4391 for host in sorted(e['urls']): 4567 links.append(tdlink.f 4392 links.append(tdlink.format(host, e['urls'][host][0])) 4568 testtotal += len(e['u 4393 testtotal += len(e['urls'][host]) 4569 rate = '%d/%d (%.2f%%)' % (te 4394 rate = '%d/%d (%.2f%%)' % (testtotal, total, 100*float(testtotal)/float(total)) 4570 # row classes - alternate row 4395 # row classes - alternate row color 4571 rcls = ['alt'] if num % 2 == 4396 rcls = ['alt'] if num % 2 == 1 else [] 4572 html += '<tr class="'+(' '.jo 4397 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4573 html += td.format('left', e[' 4398 html += td.format('left', e['line']) # issue 4574 html += td.format('center', e 4399 html += td.format('center', e['count']) # count 4575 if multihost: 4400 if multihost: 4576 html += td.format('ce 4401 html += td.format('center', len(e['urls'])) # hosts 4577 html += td.format('center', t 4402 html += td.format('center', testtotal) # test count 4578 html += td.format('center', r 4403 html += td.format('center', rate) # test rate 4579 html += td.format('center now 4404 html += td.format('center nowrap', '<br>'.join(links)) # links 4580 html += '</tr>\n' 4405 html += '</tr>\n' 4581 num += 1 4406 num += 1 4582 4407 4583 # flush the data to file 4408 # flush the data to file 4584 hf = open(htmlfile, 'w') 4409 hf = open(htmlfile, 'w') 4585 hf.write(html+'</table>\n'+extra+'</b 4410 hf.write(html+'</table>\n'+extra+'</body>\n</html>\n') 4586 hf.close() 4411 hf.close() 4587 return issues 4412 return issues 4588 4413 4589 def ordinal(value): 4414 def ordinal(value): 4590 suffix = 'th' 4415 suffix = 'th' 4591 if value < 10 or value > 19: 4416 if value < 10 or value > 19: 4592 if value % 10 == 1: 4417 if value % 10 == 1: 4593 suffix = 'st' 4418 suffix = 'st' 4594 elif value % 10 == 2: 4419 elif value % 10 == 2: 4595 suffix = 'nd' 4420 suffix = 'nd' 4596 elif value % 10 == 3: 4421 elif value % 10 == 3: 4597 suffix = 'rd' 4422 suffix = 'rd' 4598 return '%d%s' % (value, suffix) 4423 return '%d%s' % (value, suffix) 4599 4424 4600 # Function: createHTML 4425 # Function: createHTML 4601 # Description: 4426 # Description: 4602 # Create the output html file from the 4427 # Create the output html file from the resident test data 4603 # Arguments: 4428 # Arguments: 4604 # testruns: array of Data objects from 4429 # testruns: array of Data objects from parseKernelLog or parseTraceLog 4605 # Output: 4430 # Output: 4606 # True if the html file was created, f 4431 # True if the html file was created, false if it failed 4607 def createHTML(testruns, testfail): 4432 def createHTML(testruns, testfail): 4608 if len(testruns) < 1: 4433 if len(testruns) < 1: 4609 pprint('ERROR: Not enough tes 4434 pprint('ERROR: Not enough test data to build a timeline') 4610 return 4435 return 4611 4436 4612 kerror = False 4437 kerror = False 4613 for data in testruns: 4438 for data in testruns: 4614 if data.kerror: 4439 if data.kerror: 4615 kerror = True 4440 kerror = True 4616 if(sysvals.suspendmode in ['f 4441 if(sysvals.suspendmode in ['freeze', 'standby']): 4617 data.trimFreezeTime(t 4442 data.trimFreezeTime(testruns[-1].tSuspended) 4618 else: 4443 else: 4619 data.getMemTime() 4444 data.getMemTime() 4620 4445 4621 # html function templates 4446 # html function templates 4622 html_error = '<div id="{1}" title="ke 4447 html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">{2}→</div>\n' 4623 html_traceevent = '<div title="{0}" c 4448 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 4449 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 4450 html_timetotal = '<table class="time1">\n<tr>'\ 4626 '<td class="green" title="{3} 4451 '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ 4627 '<td class="yellow" title="{4 4452 '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ 4628 '</tr>\n</table>\n' 4453 '</tr>\n</table>\n' 4629 html_timetotal2 = '<table class="time 4454 html_timetotal2 = '<table class="time1">\n<tr>'\ 4630 '<td class="green" title="{4} 4455 '<td class="green" title="{4}">{3} Suspend Time: <b>{0} ms</b></td>'\ 4631 '<td class="gray" title="time 4456 '<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 4457 '<td class="yellow" title="{5}">{3} Resume Time: <b>{2} ms</b></td>'\ 4633 '</tr>\n</table>\n' 4458 '</tr>\n</table>\n' 4634 html_timetotal3 = '<table class="time 4459 html_timetotal3 = '<table class="time1">\n<tr>'\ 4635 '<td class="green">Execution 4460 '<td class="green">Execution Time: <b>{0} ms</b></td>'\ 4636 '<td class="yellow">Command: 4461 '<td class="yellow">Command: <b>{1}</b></td>'\ 4637 '</tr>\n</table>\n' 4462 '</tr>\n</table>\n' 4638 html_fail = '<table class="testfail"> 4463 html_fail = '<table class="testfail"><tr><td>{0}</td></tr></table>\n' 4639 html_kdesc = '<td class="{3}" title=" 4464 html_kdesc = '<td class="{3}" title="time spent in kernel execution">{0}Kernel {2}: {1} ms</td>' 4640 html_fwdesc = '<td class="{3}" title= 4465 html_fwdesc = '<td class="{3}" title="time spent in firmware">{0}Firmware {2}: {1} ms</td>' 4641 html_wifdesc = '<td class="yellow" ti 4466 html_wifdesc = '<td class="yellow" title="time for wifi to reconnect after resume complete ({2})">{0}Wifi Resume: {1}</td>' 4642 4467 4643 # html format variables 4468 # html format variables 4644 scaleH = 20 4469 scaleH = 20 4645 if kerror: 4470 if kerror: 4646 scaleH = 40 4471 scaleH = 40 4647 4472 4648 # device timeline 4473 # device timeline 4649 devtl = Timeline(30, scaleH) 4474 devtl = Timeline(30, scaleH) 4650 4475 4651 # write the test title and general in 4476 # write the test title and general info header 4652 devtl.createHeader(sysvals, testruns[ 4477 devtl.createHeader(sysvals, testruns[0].stamp) 4653 4478 4654 # Generate the header for this timeli 4479 # Generate the header for this timeline 4655 for data in testruns: 4480 for data in testruns: 4656 tTotal = data.end - data.star 4481 tTotal = data.end - data.start 4657 if(tTotal == 0): 4482 if(tTotal == 0): 4658 doError('No timeline 4483 doError('No timeline data') 4659 if sysvals.suspendmode == 'co 4484 if sysvals.suspendmode == 'command': 4660 run_time = '%.0f' % ( 4485 run_time = '%.0f' % (tTotal * 1000) 4661 if sysvals.testcomman 4486 if sysvals.testcommand: 4662 testdesc = sy 4487 testdesc = sysvals.testcommand 4663 else: 4488 else: 4664 testdesc = 'u 4489 testdesc = 'unknown' 4665 if(len(testruns) > 1) 4490 if(len(testruns) > 1): 4666 testdesc = or 4491 testdesc = ordinal(data.testnumber+1)+' '+testdesc 4667 thtml = html_timetota 4492 thtml = html_timetotal3.format(run_time, testdesc) 4668 devtl.html += thtml 4493 devtl.html += thtml 4669 continue 4494 continue 4670 # typical full suspend/resume 4495 # typical full suspend/resume header 4671 stot, rtot = sktime, rktime = 4496 stot, rtot = sktime, rktime = data.getTimeValues() 4672 ssrc, rsrc, testdesc, testdes 4497 ssrc, rsrc, testdesc, testdesc2 = ['kernel'], ['kernel'], 'Kernel', '' 4673 if data.fwValid: 4498 if data.fwValid: 4674 stot += (data.fwSuspe 4499 stot += (data.fwSuspend/1000000.0) 4675 rtot += (data.fwResum 4500 rtot += (data.fwResume/1000000.0) 4676 ssrc.append('firmware 4501 ssrc.append('firmware') 4677 rsrc.append('firmware 4502 rsrc.append('firmware') 4678 testdesc = 'Total' 4503 testdesc = 'Total' 4679 if 'time' in data.wifi and da 4504 if 'time' in data.wifi and data.wifi['stat'] != 'timeout': 4680 rtot += data.end - da 4505 rtot += data.end - data.tKernRes + (data.wifi['time'] * 1000.0) 4681 rsrc.append('wifi') 4506 rsrc.append('wifi') 4682 testdesc = 'Total' 4507 testdesc = 'Total' 4683 suspend_time, resume_time = ' 4508 suspend_time, resume_time = '%.3f' % stot, '%.3f' % rtot 4684 stitle = 'time from kernel su 4509 stitle = 'time from kernel suspend start to %s mode [%s time]' % \ 4685 (sysvals.suspendmode, 4510 (sysvals.suspendmode, ' & '.join(ssrc)) 4686 rtitle = 'time from %s mode t 4511 rtitle = 'time from %s mode to kernel resume complete [%s time]' % \ 4687 (sysvals.suspendmode, 4512 (sysvals.suspendmode, ' & '.join(rsrc)) 4688 if(len(testruns) > 1): 4513 if(len(testruns) > 1): 4689 testdesc = testdesc2 4514 testdesc = testdesc2 = ordinal(data.testnumber+1) 4690 testdesc2 += ' ' 4515 testdesc2 += ' ' 4691 if(len(data.tLow) == 0): 4516 if(len(data.tLow) == 0): 4692 thtml = html_timetota 4517 thtml = html_timetotal.format(suspend_time, \ 4693 resume_time, 4518 resume_time, testdesc, stitle, rtitle) 4694 else: 4519 else: 4695 low_time = '+'.join(d 4520 low_time = '+'.join(data.tLow) 4696 thtml = html_timetota 4521 thtml = html_timetotal2.format(suspend_time, low_time, \ 4697 resume_time, 4522 resume_time, testdesc, stitle, rtitle) 4698 devtl.html += thtml 4523 devtl.html += thtml 4699 if not data.fwValid and 'dev' 4524 if not data.fwValid and 'dev' not in data.wifi: 4700 continue 4525 continue 4701 # extra detail when the times 4526 # extra detail when the times come from multiple sources 4702 thtml = '<table class="time2" 4527 thtml = '<table class="time2">\n<tr>' 4703 thtml += html_kdesc.format(te 4528 thtml += html_kdesc.format(testdesc2, '%.3f'%sktime, 'Suspend', 'green') 4704 if data.fwValid: 4529 if data.fwValid: 4705 sftime = '%.3f'%(data 4530 sftime = '%.3f'%(data.fwSuspend / 1000000.0) 4706 rftime = '%.3f'%(data 4531 rftime = '%.3f'%(data.fwResume / 1000000.0) 4707 thtml += html_fwdesc. 4532 thtml += html_fwdesc.format(testdesc2, sftime, 'Suspend', 'green') 4708 thtml += html_fwdesc. 4533 thtml += html_fwdesc.format(testdesc2, rftime, 'Resume', 'yellow') 4709 thtml += html_kdesc.format(te 4534 thtml += html_kdesc.format(testdesc2, '%.3f'%rktime, 'Resume', 'yellow') 4710 if 'time' in data.wifi: 4535 if 'time' in data.wifi: 4711 if data.wifi['stat'] 4536 if data.wifi['stat'] != 'timeout': 4712 wtime = '%.0f 4537 wtime = '%.0f ms'%(data.end - data.tKernRes + (data.wifi['time'] * 1000.0)) 4713 else: 4538 else: 4714 wtime = 'TIME 4539 wtime = 'TIMEOUT' 4715 thtml += html_wifdesc 4540 thtml += html_wifdesc.format(testdesc2, wtime, data.wifi['dev']) 4716 thtml += '</tr>\n</table>\n' 4541 thtml += '</tr>\n</table>\n' 4717 devtl.html += thtml 4542 devtl.html += thtml 4718 if testfail: 4543 if testfail: 4719 devtl.html += html_fail.forma 4544 devtl.html += html_fail.format(testfail) 4720 4545 4721 # time scale for potentially multiple 4546 # time scale for potentially multiple datasets 4722 t0 = testruns[0].start 4547 t0 = testruns[0].start 4723 tMax = testruns[-1].end 4548 tMax = testruns[-1].end 4724 tTotal = tMax - t0 4549 tTotal = tMax - t0 4725 4550 4726 # determine the maximum number of row 4551 # determine the maximum number of rows we need to draw 4727 fulllist = [] 4552 fulllist = [] 4728 threadlist = [] 4553 threadlist = [] 4729 pscnt = 0 4554 pscnt = 0 4730 devcnt = 0 4555 devcnt = 0 4731 for data in testruns: 4556 for data in testruns: 4732 data.selectTimelineDevices('% 4557 data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen) 4733 for group in data.devicegroup 4558 for group in data.devicegroups: 4734 devlist = [] 4559 devlist = [] 4735 for phase in group: 4560 for phase in group: 4736 for devname i 4561 for devname in sorted(data.tdevlist[phase]): 4737 d = D 4562 d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname]) 4738 devli 4563 devlist.append(d) 4739 if d. 4564 if d.isa('kth'): 4740 4565 threadlist.append(d) 4741 else: 4566 else: 4742 4567 if d.isa('ps'): 4743 4568 pscnt += 1 4744 4569 else: 4745 4570 devcnt += 1 4746 4571 fulllist.append(d) 4747 if sysvals.mixedphase 4572 if sysvals.mixedphaseheight: 4748 devtl.getPhas 4573 devtl.getPhaseRows(devlist) 4749 if not sysvals.mixedphaseheight: 4574 if not sysvals.mixedphaseheight: 4750 if len(threadlist) > 0 and le 4575 if len(threadlist) > 0 and len(fulllist) > 0: 4751 if pscnt > 0 and devc 4576 if pscnt > 0 and devcnt > 0: 4752 msg = 'user p 4577 msg = 'user processes & device pm callbacks' 4753 elif pscnt > 0: 4578 elif pscnt > 0: 4754 msg = 'user p 4579 msg = 'user processes' 4755 else: 4580 else: 4756 msg = 'device 4581 msg = 'device pm callbacks' 4757 d = testruns[0].addHo 4582 d = testruns[0].addHorizontalDivider(msg, testruns[-1].end) 4758 fulllist.insert(0, d) 4583 fulllist.insert(0, d) 4759 devtl.getPhaseRows(fulllist) 4584 devtl.getPhaseRows(fulllist) 4760 if len(threadlist) > 0: 4585 if len(threadlist) > 0: 4761 d = testruns[0].addHo 4586 d = testruns[0].addHorizontalDivider('asynchronous kernel threads', testruns[-1].end) 4762 threadlist.insert(0, 4587 threadlist.insert(0, d) 4763 devtl.getPhaseRows(th 4588 devtl.getPhaseRows(threadlist, devtl.rows) 4764 devtl.calcTotalRows() 4589 devtl.calcTotalRows() 4765 4590 4766 # draw the full timeline 4591 # draw the full timeline 4767 devtl.createZoomBox(sysvals.suspendmo 4592 devtl.createZoomBox(sysvals.suspendmode, len(testruns)) 4768 for data in testruns: 4593 for data in testruns: 4769 # draw each test run and bloc 4594 # draw each test run and block chronologically 4770 phases = {'suspend':[],'resum 4595 phases = {'suspend':[],'resume':[]} 4771 for phase in data.sortedPhase 4596 for phase in data.sortedPhases(): 4772 if data.dmesg[phase][ 4597 if data.dmesg[phase]['start'] >= data.tSuspended: 4773 phases['resum 4598 phases['resume'].append(phase) 4774 else: 4599 else: 4775 phases['suspe 4600 phases['suspend'].append(phase) 4776 # now draw the actual timelin 4601 # now draw the actual timeline blocks 4777 for dir in phases: 4602 for dir in phases: 4778 # draw suspend and re 4603 # draw suspend and resume blocks separately 4779 bname = '%s%d' % (dir 4604 bname = '%s%d' % (dir[0], data.testnumber) 4780 if dir == 'suspend': 4605 if dir == 'suspend': 4781 m0 = data.sta 4606 m0 = data.start 4782 mMax = data.t 4607 mMax = data.tSuspended 4783 left = '%f' % 4608 left = '%f' % (((m0-t0)*100.0)/tTotal) 4784 else: 4609 else: 4785 m0 = data.tSu 4610 m0 = data.tSuspended 4786 mMax = data.e 4611 mMax = data.end 4787 # in an x2 ru 4612 # in an x2 run, remove any gap between blocks 4788 if len(testru 4613 if len(testruns) > 1 and data.testnumber == 0: 4789 mMax 4614 mMax = testruns[1].start 4790 left = '%f' % 4615 left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal) 4791 mTotal = mMax - m0 4616 mTotal = mMax - m0 4792 # if a timeline block 4617 # if a timeline block is 0 length, skip altogether 4793 if mTotal == 0: 4618 if mTotal == 0: 4794 continue 4619 continue 4795 width = '%f' % (((mTo 4620 width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal) 4796 devtl.html += devtl.h 4621 devtl.html += devtl.html_tblock.format(bname, left, width, devtl.scaleH) 4797 for b in phases[dir]: 4622 for b in phases[dir]: 4798 # draw the ph 4623 # draw the phase color background 4799 phase = data. 4624 phase = data.dmesg[b] 4800 length = phas 4625 length = phase['end']-phase['start'] 4801 left = '%f' % 4626 left = '%f' % (((phase['start']-m0)*100.0)/mTotal) 4802 width = '%f' 4627 width = '%f' % ((length*100.0)/mTotal) 4803 devtl.html += 4628 devtl.html += devtl.html_phase.format(left, width, \ 4804 '%.3f 4629 '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ 4805 data. 4630 data.dmesg[b]['color'], '') 4806 for e in data.errorin 4631 for e in data.errorinfo[dir]: 4807 # draw red li 4632 # draw red lines for any kernel errors found 4808 type, t, idx1 4633 type, t, idx1, idx2 = e 4809 id = '%d_%d' 4634 id = '%d_%d' % (idx1, idx2) 4810 right = '%f' 4635 right = '%f' % (((mMax-t)*100.0)/mTotal) 4811 devtl.html += 4636 devtl.html += html_error.format(right, id, type) 4812 for b in phases[dir]: 4637 for b in phases[dir]: 4813 # draw the de 4638 # draw the devices for this phase 4814 phaselist = d 4639 phaselist = data.dmesg[b]['list'] 4815 for d in sort 4640 for d in sorted(data.tdevlist[b]): 4816 dname 4641 dname = d if ('[' not in d or 'CPU' in d) else d.split('[')[0] 4817 name, 4642 name, dev = dname, phaselist[d] 4818 drv = 4643 drv = xtraclass = xtrainfo = xtrastyle = '' 4819 if 'h 4644 if 'htmlclass' in dev: 4820 4645 xtraclass = dev['htmlclass'] 4821 if 'c 4646 if 'color' in dev: 4822 4647 xtrastyle = 'background:%s;' % dev['color'] 4823 if(d 4648 if(d in sysvals.devprops): 4824 4649 name = sysvals.devprops[d].altName(d) 4825 4650 xtraclass = sysvals.devprops[d].xtraClass() 4826 4651 xtrainfo = sysvals.devprops[d].xtraInfo() 4827 elif 4652 elif xtraclass == ' kth': 4828 4653 xtrainfo = ' kernel_thread' 4829 if('d 4654 if('drv' in dev and dev['drv']): 4830 4655 drv = ' {%s}' % dev['drv'] 4831 rowhe 4656 rowheight = devtl.phaseRowHeight(data.testnumber, b, dev['row']) 4832 rowto 4657 rowtop = devtl.phaseRowTop(data.testnumber, b, dev['row']) 4833 top = 4658 top = '%.3f' % (rowtop + devtl.scaleH) 4834 left 4659 left = '%f' % (((dev['start']-m0)*100)/mTotal) 4835 width 4660 width = '%f' % (((dev['end']-dev['start'])*100)/mTotal) 4836 lengt 4661 length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) 4837 title 4662 title = name+drv+xtrainfo+length 4838 if sy 4663 if sysvals.suspendmode == 'command': 4839 4664 title += sysvals.testcommand 4840 elif 4665 elif xtraclass == ' ps': 4841 4666 if 'suspend' in b: 4842 4667 title += 'pre_suspend_process' 4843 4668 else: 4844 4669 title += 'post_resume_process' 4845 else: 4670 else: 4846 4671 title += b 4847 devtl 4672 devtl.html += devtl.html_device.format(dev['id'], \ 4848 4673 title, left, top, '%.3f'%rowheight, width, \ 4849 4674 dname+drv, xtraclass, xtrastyle) 4850 if('c 4675 if('cpuexec' in dev): 4851 4676 for t in sorted(dev['cpuexec']): 4852 4677 start, end = t >> 4678 j = float(dev['cpuexec'][t]) / 5 >> 4679 if j > 1.0: >> 4680 j = 1.0 4853 4681 height = '%.3f' % (rowheight/3) 4854 4682 top = '%.3f' % (rowtop + devtl.scaleH + 2*rowheight/3) 4855 4683 left = '%f' % (((start-m0)*100)/mTotal) 4856 4684 width = '%f' % ((end-start)*100/mTotal) 4857 !! 4685 color = 'rgba(255, 0, 0, %f)' % j 4858 4686 devtl.html += \ 4859 4687 html_cpuexec.format(left, top, height, width, color) 4860 if('s 4688 if('src' not in dev): 4861 4689 continue 4862 # dra 4690 # draw any trace events for this device 4863 for e 4691 for e in dev['src']: 4864 4692 if e.length == 0: 4865 4693 continue 4866 4694 height = '%.3f' % devtl.rowH 4867 4695 top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH)) 4868 4696 left = '%f' % (((e.time-m0)*100)/mTotal) 4869 4697 width = '%f' % (e.length*100/mTotal) 4870 4698 xtrastyle = '' 4871 4699 if e.color: 4872 4700 xtrastyle = 'background:%s;' % e.color 4873 4701 devtl.html += \ 4874 4702 html_traceevent.format(e.title(), \ 4875 4703 left, top, height, width, e.text(), '', xtrastyle) 4876 # draw the time scale 4704 # draw the time scale, try to make the number of labels readable 4877 devtl.createTimeScale 4705 devtl.createTimeScale(m0, mMax, tTotal, dir) 4878 devtl.html += '</div> 4706 devtl.html += '</div>\n' 4879 4707 4880 # timeline is finished 4708 # timeline is finished 4881 devtl.html += '</div>\n</div>\n' 4709 devtl.html += '</div>\n</div>\n' 4882 4710 4883 # draw a legend which describes the p 4711 # draw a legend which describes the phases by color 4884 if sysvals.suspendmode != 'command': 4712 if sysvals.suspendmode != 'command': 4885 phasedef = testruns[-1].phase 4713 phasedef = testruns[-1].phasedef 4886 devtl.html += '<div class="le 4714 devtl.html += '<div class="legend">\n' 4887 pdelta = 100.0/len(phasedef.k 4715 pdelta = 100.0/len(phasedef.keys()) 4888 pmargin = pdelta / 4.0 4716 pmargin = pdelta / 4.0 4889 for phase in sorted(phasedef, 4717 for phase in sorted(phasedef, key=lambda k:phasedef[k]['order']): 4890 id, p = '', phasedef[ 4718 id, p = '', phasedef[phase] 4891 for word in phase.spl 4719 for word in phase.split('_'): 4892 id += word[0] 4720 id += word[0] 4893 order = '%.2f' % ((p[ 4721 order = '%.2f' % ((p['order'] * pdelta) + pmargin) 4894 name = phase.replace( 4722 name = phase.replace('_', ' ') 4895 devtl.html += devtl.h 4723 devtl.html += devtl.html_legend.format(order, p['color'], name, id) 4896 devtl.html += '</div>\n' 4724 devtl.html += '</div>\n' 4897 4725 4898 hf = open(sysvals.htmlfile, 'w') 4726 hf = open(sysvals.htmlfile, 'w') 4899 addCSS(hf, sysvals, len(testruns), ke 4727 addCSS(hf, sysvals, len(testruns), kerror) 4900 4728 4901 # write the device timeline 4729 # write the device timeline 4902 hf.write(devtl.html) 4730 hf.write(devtl.html) 4903 hf.write('<div id="devicedetailtitle" 4731 hf.write('<div id="devicedetailtitle"></div>\n') 4904 hf.write('<div id="devicedetail" styl 4732 hf.write('<div id="devicedetail" style="display:none;">\n') 4905 # draw the colored boxes for the devi 4733 # draw the colored boxes for the device detail section 4906 for data in testruns: 4734 for data in testruns: 4907 hf.write('<div id="devicedeta 4735 hf.write('<div id="devicedetail%d">\n' % data.testnumber) 4908 pscolor = 'linear-gradient(to 4736 pscolor = 'linear-gradient(to top left, #ccc, #eee)' 4909 hf.write(devtl.html_phaselet. 4737 hf.write(devtl.html_phaselet.format('pre_suspend_process', \ 4910 '0', '0', pscolor)) 4738 '0', '0', pscolor)) 4911 for b in data.sortedPhases(): 4739 for b in data.sortedPhases(): 4912 phase = data.dmesg[b] 4740 phase = data.dmesg[b] 4913 length = phase['end'] 4741 length = phase['end']-phase['start'] 4914 left = '%.3f' % (((ph 4742 left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) 4915 width = '%.3f' % ((le 4743 width = '%.3f' % ((length*100.0)/tTotal) 4916 hf.write(devtl.html_p 4744 hf.write(devtl.html_phaselet.format(b, left, width, \ 4917 data.dmesg[b] 4745 data.dmesg[b]['color'])) 4918 hf.write(devtl.html_phaselet. 4746 hf.write(devtl.html_phaselet.format('post_resume_process', \ 4919 '0', '0', pscolor)) 4747 '0', '0', pscolor)) 4920 if sysvals.suspendmode == 'co 4748 if sysvals.suspendmode == 'command': 4921 hf.write(devtl.html_p 4749 hf.write(devtl.html_phaselet.format('cmdexec', '0', '0', pscolor)) 4922 hf.write('</div>\n') 4750 hf.write('</div>\n') 4923 hf.write('</div>\n') 4751 hf.write('</div>\n') 4924 4752 4925 # write the ftrace data (callgraph) 4753 # write the ftrace data (callgraph) 4926 if sysvals.cgtest >= 0 and len(testru 4754 if sysvals.cgtest >= 0 and len(testruns) > sysvals.cgtest: 4927 data = testruns[sysvals.cgtes 4755 data = testruns[sysvals.cgtest] 4928 else: 4756 else: 4929 data = testruns[-1] 4757 data = testruns[-1] 4930 if sysvals.usecallgraph: 4758 if sysvals.usecallgraph: 4931 addCallgraphs(sysvals, hf, da 4759 addCallgraphs(sysvals, hf, data) 4932 4760 4933 # add the test log as a hidden div 4761 # add the test log as a hidden div 4934 if sysvals.testlog and sysvals.logmsg 4762 if sysvals.testlog and sysvals.logmsg: 4935 hf.write('<div id="testlog" s 4763 hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') 4936 # add the dmesg log as a hidden div 4764 # add the dmesg log as a hidden div 4937 if sysvals.dmesglog and sysvals.dmesg 4765 if sysvals.dmesglog and sysvals.dmesgfile: 4938 hf.write('<div id="dmesglog" 4766 hf.write('<div id="dmesglog" style="display:none;">\n') 4939 lf = sysvals.openlog(sysvals. 4767 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 4940 for line in lf: 4768 for line in lf: 4941 line = line.replace(' 4769 line = line.replace('<', '<').replace('>', '>') 4942 hf.write(line) 4770 hf.write(line) 4943 lf.close() 4771 lf.close() 4944 hf.write('</div>\n') 4772 hf.write('</div>\n') 4945 # add the ftrace log as a hidden div 4773 # add the ftrace log as a hidden div 4946 if sysvals.ftracelog and sysvals.ftra 4774 if sysvals.ftracelog and sysvals.ftracefile: 4947 hf.write('<div id="ftracelog" 4775 hf.write('<div id="ftracelog" style="display:none;">\n') 4948 lf = sysvals.openlog(sysvals. 4776 lf = sysvals.openlog(sysvals.ftracefile, 'r') 4949 for line in lf: 4777 for line in lf: 4950 hf.write(line) 4778 hf.write(line) 4951 lf.close() 4779 lf.close() 4952 hf.write('</div>\n') 4780 hf.write('</div>\n') 4953 4781 4954 # write the footer and close 4782 # write the footer and close 4955 addScriptCode(hf, testruns) 4783 addScriptCode(hf, testruns) 4956 hf.write('</body>\n</html>\n') 4784 hf.write('</body>\n</html>\n') 4957 hf.close() 4785 hf.close() 4958 return True 4786 return True 4959 4787 4960 def addCSS(hf, sv, testcount=1, kerror=False, 4788 def addCSS(hf, sv, testcount=1, kerror=False, extra=''): 4961 kernel = sv.stamp['kernel'] 4789 kernel = sv.stamp['kernel'] 4962 host = sv.hostname[0].upper()+sv.host 4790 host = sv.hostname[0].upper()+sv.hostname[1:] 4963 mode = sv.suspendmode 4791 mode = sv.suspendmode 4964 if sv.suspendmode in suspendmodename: 4792 if sv.suspendmode in suspendmodename: 4965 mode = suspendmodename[sv.sus 4793 mode = suspendmodename[sv.suspendmode] 4966 title = host+' '+mode+' '+kernel 4794 title = host+' '+mode+' '+kernel 4967 4795 4968 # various format changes by flags 4796 # various format changes by flags 4969 cgchk = 'checked' 4797 cgchk = 'checked' 4970 cgnchk = 'not(:checked)' 4798 cgnchk = 'not(:checked)' 4971 if sv.cgexp: 4799 if sv.cgexp: 4972 cgchk = 'not(:checked)' 4800 cgchk = 'not(:checked)' 4973 cgnchk = 'checked' 4801 cgnchk = 'checked' 4974 4802 4975 hoverZ = 'z-index:8;' 4803 hoverZ = 'z-index:8;' 4976 if sv.usedevsrc: 4804 if sv.usedevsrc: 4977 hoverZ = '' 4805 hoverZ = '' 4978 4806 4979 devlistpos = 'absolute' 4807 devlistpos = 'absolute' 4980 if testcount > 1: 4808 if testcount > 1: 4981 devlistpos = 'relative' 4809 devlistpos = 'relative' 4982 4810 4983 scaleTH = 20 4811 scaleTH = 20 4984 if kerror: 4812 if kerror: 4985 scaleTH = 60 4813 scaleTH = 60 4986 4814 4987 # write the html header first (html h 4815 # write the html header first (html head, css code, up to body start) 4988 html_header = '<!DOCTYPE html>\n<html 4816 html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ 4989 <meta http-equiv="content-type" conte 4817 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 4990 <title>'+title+'</title>\n\ 4818 <title>'+title+'</title>\n\ 4991 <style type=\'text/css\'>\n\ 4819 <style type=\'text/css\'>\n\ 4992 body {overflow-y:scroll;}\n\ 4820 body {overflow-y:scroll;}\n\ 4993 .stamp {width:100%;text-align 4821 .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ 4994 .stamp.sysinfo {font:10px Ari 4822 .stamp.sysinfo {font:10px Arial;}\n\ 4995 .callgraph {margin-top:30px;b 4823 .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ 4996 .callgraph article * {padding 4824 .callgraph article * {padding-left:28px;}\n\ 4997 h1 {color:black;font:bold 30p 4825 h1 {color:black;font:bold 30px Times;}\n\ 4998 t0 {color:black;font:bold 30p 4826 t0 {color:black;font:bold 30px Times;}\n\ 4999 t1 {color:black;font:30px Tim 4827 t1 {color:black;font:30px Times;}\n\ 5000 t2 {color:black;font:25px Tim 4828 t2 {color:black;font:25px Times;}\n\ 5001 t3 {color:black;font:20px Tim 4829 t3 {color:black;font:20px Times;white-space:nowrap;}\n\ 5002 t4 {color:black;font:bold 30p 4830 t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ 5003 cS {font:bold 13px Times;}\n\ 4831 cS {font:bold 13px Times;}\n\ 5004 table {width:100%;}\n\ 4832 table {width:100%;}\n\ 5005 .gray {background:rgba(80,80, 4833 .gray {background:rgba(80,80,80,0.1);}\n\ 5006 .green {background:rgba(204,2 4834 .green {background:rgba(204,255,204,0.4);}\n\ 5007 .purple {background:rgba(128, 4835 .purple {background:rgba(128,0,128,0.2);}\n\ 5008 .yellow {background:rgba(255, 4836 .yellow {background:rgba(255,255,204,0.4);}\n\ 5009 .blue {background:rgba(169,20 4837 .blue {background:rgba(169,208,245,0.4);}\n\ 5010 .time1 {font:22px Arial;borde 4838 .time1 {font:22px Arial;border:1px solid;}\n\ 5011 .time2 {font:15px Arial;borde 4839 .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ 5012 .testfail {font:bold 22px Ari 4840 .testfail {font:bold 22px Arial;color:red;border:1px dashed;}\n\ 5013 td {text-align:center;}\n\ 4841 td {text-align:center;}\n\ 5014 r {color:#500000;font:15px Ta 4842 r {color:#500000;font:15px Tahoma;}\n\ 5015 n {color:#505050;font:15px Ta 4843 n {color:#505050;font:15px Tahoma;}\n\ 5016 .tdhl {color:red;}\n\ 4844 .tdhl {color:red;}\n\ 5017 .hide {display:none;}\n\ 4845 .hide {display:none;}\n\ 5018 .pf {display:none;}\n\ 4846 .pf {display:none;}\n\ 5019 .pf:'+cgchk+' + label {backgr 4847 .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 4848 .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 4849 .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ 5022 .zoombox {position:relative;w 4850 .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ 5023 .timeline {position:relative; 4851 .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ 5024 .thread {position:absolute;he 4852 .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 4853 .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ 5026 .thread:hover {background:whi 4854 .thread:hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 5027 .thread.sec,.thread.sec:hover 4855 .thread.sec,.thread.sec:hover {background:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ 5028 .hover {background:white;bord 4856 .hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 5029 .hover.sync {background:white 4857 .hover.sync {background:white;}\n\ 5030 .hover.bg,.hover.kth,.hover.s 4858 .hover.bg,.hover.kth,.hover.sync,.hover.ps {background:white;}\n\ 5031 .jiffie {position:absolute;po 4859 .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ 5032 .traceevent {position:absolut 4860 .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 4861 .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ 5034 .phase {position:absolute;ove 4862 .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ 5035 .phaselet {float:left;overflo 4863 .phaselet {float:left;overflow:hidden;border:0px;text-align:center;min-height:100px;font-size:24px;}\n\ 5036 .t {position:absolute;line-he 4864 .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 4865 .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 4866 .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ 5039 .legend .square {position:abs 4867 .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 4868 button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ 5041 .btnfmt {position:relative;fl 4869 .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 4870 .devlist {position:'+devlistpos+';width:190px;}\n\ 5043 a:link {color:white;text-deco 4871 a:link {color:white;text-decoration:none;}\n\ 5044 a:visited {color:white;}\n\ 4872 a:visited {color:white;}\n\ 5045 a:hover {color:white;}\n\ 4873 a:hover {color:white;}\n\ 5046 a:active {color:white;}\n\ 4874 a:active {color:white;}\n\ 5047 .version {position:relative;f 4875 .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ 5048 #devicedetail {min-height:100 4876 #devicedetail {min-height:100px;box-shadow:5px 5px 20px black;}\n\ 5049 .tblock {position:absolute;he 4877 .tblock {position:absolute;height:100%;background:#ddd;}\n\ 5050 .tback {position:absolute;wid 4878 .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ 5051 .bg {z-index:1;}\n\ 4879 .bg {z-index:1;}\n\ 5052 '+extra+'\ 4880 '+extra+'\ 5053 </style>\n</head>\n<body>\n' 4881 </style>\n</head>\n<body>\n' 5054 hf.write(html_header) 4882 hf.write(html_header) 5055 4883 5056 # Function: addScriptCode 4884 # Function: addScriptCode 5057 # Description: 4885 # Description: 5058 # Adds the javascript code to the outp 4886 # Adds the javascript code to the output html 5059 # Arguments: 4887 # Arguments: 5060 # hf: the open html file pointer 4888 # hf: the open html file pointer 5061 # testruns: array of Data objects from 4889 # testruns: array of Data objects from parseKernelLog or parseTraceLog 5062 def addScriptCode(hf, testruns): 4890 def addScriptCode(hf, testruns): 5063 t0 = testruns[0].start * 1000 4891 t0 = testruns[0].start * 1000 5064 tMax = testruns[-1].end * 1000 4892 tMax = testruns[-1].end * 1000 5065 hf.write('<script type="text/javascri << 5066 # create an array in javascript memor 4893 # create an array in javascript memory with the device details 5067 detail = ' var devtable = [];\n' 4894 detail = ' var devtable = [];\n' 5068 for data in testruns: 4895 for data in testruns: 5069 topo = data.deviceTopology() 4896 topo = data.deviceTopology() 5070 detail += ' devtable[%d] 4897 detail += ' devtable[%d] = "%s";\n' % (data.testnumber, topo) 5071 detail += ' var bounds = [%f,%f]; 4898 detail += ' var bounds = [%f,%f];\n' % (t0, tMax) 5072 # add the code which will manipulate 4899 # add the code which will manipulate the data in the browser 5073 hf.write(detail); !! 4900 script_code = \ 5074 script_code = r""" var resolutio !! 4901 '<script type="text/javascript">\n'+detail+\ 5075 var dragval = [0, 0]; !! 4902 ' var resolution = -1;\n'\ 5076 function redrawTimescale(t0, tMax, tS !! 4903 ' var dragval = [0, 0];\n'\ 5077 var rline = '<div class="t" s !! 4904 ' function redrawTimescale(t0, tMax, tS) {\n'\ 5078 var tTotal = tMax - t0; !! 4905 ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;">\';\n'\ 5079 var list = document.getElemen !! 4906 ' var tTotal = tMax - t0;\n'\ 5080 for (var i = 0; i < list.leng !! 4907 ' var list = document.getElementsByClassName("tblock");\n'\ 5081 var timescale = list[ !! 4908 ' for (var i = 0; i < list.length; i++) {\n'\ 5082 var m0 = t0 + (tTotal !! 4909 ' var timescale = list[i].getElementsByClassName("timescale")[0];\n'\ 5083 var mTotal = tTotal*p !! 4910 ' var m0 = t0 + (tTotal*parseFloat(list[i].style.left)/100);\n'\ 5084 var mMax = m0 + mTota !! 4911 ' var mTotal = tTotal*parseFloat(list[i].style.width)/100;\n'\ 5085 var html = ""; !! 4912 ' var mMax = m0 + mTotal;\n'\ 5086 var divTotal = Math.f !! 4913 ' var html = "";\n'\ 5087 if(divTotal > 1000) c !! 4914 ' var divTotal = Math.floor(mTotal/tS) + 1;\n'\ 5088 var divEdge = (mTotal !! 4915 ' if(divTotal > 1000) continue;\n'\ 5089 var pos = 0.0, val = !! 4916 ' var divEdge = (mTotal - tS*(divTotal-1))*100/mTotal;\n'\ 5090 for (var j = 0; j < d !! 4917 ' var pos = 0.0, val = 0.0;\n'\ 5091 var htmlline !! 4918 ' for (var j = 0; j < divTotal; j++) {\n'\ 5092 var mode = li !! 4919 ' var htmlline = "";\n'\ 5093 if(mode == "s !! 4920 ' var mode = list[i].id[5];\n'\ 5094 pos = !! 4921 ' if(mode == "s") {\n'\ 5095 val = !! 4922 ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\ 5096 if(j !! 4923 ' val = (j-divTotal+1)*tS;\n'\ 5097 !! 4924 ' if(j == divTotal - 1)\n'\ 5098 else !! 4925 ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S→</cS></div>\';\n'\ 5099 !! 4926 ' else\n'\ 5100 } else { !! 4927 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 5101 pos = !! 4928 ' } else {\n'\ 5102 val = !! 4929 ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ 5103 htmll !! 4930 ' val = (j)*tS;\n'\ 5104 if(j !! 4931 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 5105 !! 4932 ' if(j == 0)\n'\ 5106 !! 4933 ' if(mode == "r")\n'\ 5107 !! 4934 ' htmlline = rline+"<cS>←R</cS></div>";\n'\ 5108 !! 4935 ' else\n'\ 5109 } !! 4936 ' htmlline = rline+"<cS>0ms</div>";\n'\ 5110 html += htmll !! 4937 ' }\n'\ 5111 } !! 4938 ' html += htmlline;\n'\ 5112 timescale.innerHTML = !! 4939 ' }\n'\ 5113 } !! 4940 ' timescale.innerHTML = html;\n'\ 5114 } !! 4941 ' }\n'\ 5115 function zoomTimeline() { !! 4942 ' }\n'\ 5116 var dmesg = document.getEleme !! 4943 ' function zoomTimeline() {\n'\ 5117 var zoombox = document.getEle !! 4944 ' var dmesg = document.getElementById("dmesg");\n'\ 5118 var left = zoombox.scrollLeft !! 4945 ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 5119 var val = parseFloat(dmesg.st !! 4946 ' var left = zoombox.scrollLeft;\n'\ 5120 var newval = 100; !! 4947 ' var val = parseFloat(dmesg.style.width);\n'\ 5121 var sh = window.outerWidth / !! 4948 ' var newval = 100;\n'\ 5122 if(this.id == "zoomin") { !! 4949 ' var sh = window.outerWidth / 2;\n'\ 5123 newval = val * 1.2; !! 4950 ' if(this.id == "zoomin") {\n'\ 5124 if(newval > 910034) n !! 4951 ' newval = val * 1.2;\n'\ 5125 dmesg.style.width = n !! 4952 ' if(newval > 910034) newval = 910034;\n'\ 5126 zoombox.scrollLeft = !! 4953 ' dmesg.style.width = newval+"%";\n'\ 5127 } else if (this.id == "zoomou !! 4954 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 5128 newval = val / 1.2; !! 4955 ' } else if (this.id == "zoomout") {\n'\ 5129 if(newval < 100) newv !! 4956 ' newval = val / 1.2;\n'\ 5130 dmesg.style.width = n !! 4957 ' if(newval < 100) newval = 100;\n'\ 5131 zoombox.scrollLeft = !! 4958 ' dmesg.style.width = newval+"%";\n'\ 5132 } else { !! 4959 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 5133 zoombox.scrollLeft = !! 4960 ' } else {\n'\ 5134 dmesg.style.width = " !! 4961 ' zoombox.scrollLeft = 0;\n'\ 5135 } !! 4962 ' dmesg.style.width = "100%";\n'\ 5136 var tS = [10000, 5000, 2000, !! 4963 ' }\n'\ 5137 var t0 = bounds[0]; !! 4964 ' var tS = [10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1];\n'\ 5138 var tMax = bounds[1]; !! 4965 ' var t0 = bounds[0];\n'\ 5139 var tTotal = tMax - t0; !! 4966 ' var tMax = bounds[1];\n'\ 5140 var wTotal = tTotal * 100.0 / !! 4967 ' var tTotal = tMax - t0;\n'\ 5141 var idx = 7*window.innerWidth !! 4968 ' var wTotal = tTotal * 100.0 / newval;\n'\ 5142 for(var i = 0; (i < tS.length !! 4969 ' var idx = 7*window.innerWidth/1100;\n'\ 5143 if(i >= tS.length) i = tS.len !! 4970 ' for(var i = 0; (i < tS.length)&&((wTotal / tS[i]) < idx); i++);\n'\ 5144 if(tS[i] == resolution) retur !! 4971 ' if(i >= tS.length) i = tS.length - 1;\n'\ 5145 resolution = tS[i]; !! 4972 ' if(tS[i] == resolution) return;\n'\ 5146 redrawTimescale(t0, tMax, tS[ !! 4973 ' resolution = tS[i];\n'\ 5147 } !! 4974 ' redrawTimescale(t0, tMax, tS[i]);\n'\ 5148 function deviceName(title) { !! 4975 ' }\n'\ 5149 var name = title.slice(0, tit !! 4976 ' function deviceName(title) {\n'\ 5150 return name; !! 4977 ' var name = title.slice(0, title.indexOf(" ("));\n'\ 5151 } !! 4978 ' return name;\n'\ 5152 function deviceHover() { !! 4979 ' }\n'\ 5153 var name = deviceName(this.ti !! 4980 ' function deviceHover() {\n'\ 5154 var dmesg = document.getEleme !! 4981 ' var name = deviceName(this.title);\n'\ 5155 var dev = dmesg.getElementsBy !! 4982 ' var dmesg = document.getElementById("dmesg");\n'\ 5156 var cpu = -1; !! 4983 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5157 if(name.match("CPU_ON\[[0-9]* !! 4984 ' var cpu = -1;\n'\ 5158 cpu = parseInt(name.s !! 4985 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 5159 else if(name.match("CPU_OFF\[ !! 4986 ' cpu = parseInt(name.slice(7));\n'\ 5160 cpu = parseInt(name.s !! 4987 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 5161 for (var i = 0; i < dev.lengt !! 4988 ' cpu = parseInt(name.slice(8));\n'\ 5162 dname = deviceName(de !! 4989 ' for (var i = 0; i < dev.length; i++) {\n'\ 5163 var cname = dev[i].cl !! 4990 ' dname = deviceName(dev[i].title);\n'\ 5164 if((cpu >= 0 && dname !! 4991 ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 5165 (name == dnam !! 4992 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 5166 { !! 4993 ' (name == dname))\n'\ 5167 dev[i].classN !! 4994 ' {\n'\ 5168 } else { !! 4995 ' dev[i].className = "hover "+cname;\n'\ 5169 dev[i].classN !! 4996 ' } else {\n'\ 5170 } !! 4997 ' dev[i].className = cname;\n'\ 5171 } !! 4998 ' }\n'\ 5172 } !! 4999 ' }\n'\ 5173 function deviceUnhover() { !! 5000 ' }\n'\ 5174 var dmesg = document.getEleme !! 5001 ' function deviceUnhover() {\n'\ 5175 var dev = dmesg.getElementsBy !! 5002 ' var dmesg = document.getElementById("dmesg");\n'\ 5176 for (var i = 0; i < dev.lengt !! 5003 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5177 dev[i].className = de !! 5004 ' for (var i = 0; i < dev.length; i++) {\n'\ 5178 } !! 5005 ' dev[i].className = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 5179 } !! 5006 ' }\n'\ 5180 function deviceTitle(title, total, cp !! 5007 ' }\n'\ 5181 var prefix = "Total"; !! 5008 ' function deviceTitle(title, total, cpu) {\n'\ 5182 if(total.length > 3) { !! 5009 ' var prefix = "Total";\n'\ 5183 prefix = "Average"; !! 5010 ' if(total.length > 3) {\n'\ 5184 total[1] = (total[1]+ !! 5011 ' prefix = "Average";\n'\ 5185 total[2] = (total[2]+ !! 5012 ' total[1] = (total[1]+total[3])/2;\n'\ 5186 } !! 5013 ' total[2] = (total[2]+total[4])/2;\n'\ 5187 var devtitle = document.getEl !! 5014 ' }\n'\ 5188 var name = deviceName(title); !! 5015 ' var devtitle = document.getElementById("devicedetailtitle");\n'\ 5189 if(cpu >= 0) name = "CPU"+cpu !! 5016 ' var name = deviceName(title);\n'\ 5190 var driver = ""; !! 5017 ' if(cpu >= 0) name = "CPU"+cpu;\n'\ 5191 var tS = "<t2>(</t2>"; !! 5018 ' var driver = "";\n'\ 5192 var tR = "<t2>)</t2>"; !! 5019 ' var tS = "<t2>(</t2>";\n'\ 5193 if(total[1] > 0) !! 5020 ' var tR = "<t2>)</t2>";\n'\ 5194 tS = "<t2>("+prefix+" !! 5021 ' if(total[1] > 0)\n'\ 5195 if(total[2] > 0) !! 5022 ' tS = "<t2>("+prefix+" Suspend:</t2><t0> "+total[1].toFixed(3)+" ms</t0> ";\n'\ 5196 tR = " <t2>"+prefix+" !! 5023 ' if(total[2] > 0)\n'\ 5197 var s = title.indexOf("{"); !! 5024 ' tR = " <t2>"+prefix+" Resume:</t2><t0> "+total[2].toFixed(3)+" ms<t2>)</t2></t0>";\n'\ 5198 var e = title.indexOf("}"); !! 5025 ' var s = title.indexOf("{");\n'\ 5199 if((s >= 0) && (e >= 0)) !! 5026 ' var e = title.indexOf("}");\n'\ 5200 driver = title.slice(< !! 5027 ' if((s >= 0) && (e >= 0))\n'\ 5201 if(total[1] > 0 && total[2] > !! 5028 ' driver = title.slice(s+1, e) + " <t1>@</t1> ";\n'\ 5202 devtitle.innerHTML = !! 5029 ' if(total[1] > 0 && total[2] > 0)\n'\ 5203 else !! 5030 ' devtitle.innerHTML = "<t0>"+driver+name+"</t0> "+tS+tR;\n'\ 5204 devtitle.innerHTML = !! 5031 ' else\n'\ 5205 return name; !! 5032 ' devtitle.innerHTML = "<t0>"+title+"</t0>";\n'\ 5206 } !! 5033 ' return name;\n'\ 5207 function deviceDetail() { !! 5034 ' }\n'\ 5208 var devinfo = document.getEle !! 5035 ' function deviceDetail() {\n'\ 5209 devinfo.style.display = "bloc !! 5036 ' var devinfo = document.getElementById("devicedetail");\n'\ 5210 var name = deviceName(this.ti !! 5037 ' devinfo.style.display = "block";\n'\ 5211 var cpu = -1; !! 5038 ' var name = deviceName(this.title);\n'\ 5212 if(name.match("CPU_ON\[[0-9]* !! 5039 ' var cpu = -1;\n'\ 5213 cpu = parseInt(name.s !! 5040 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 5214 else if(name.match("CPU_OFF\[ !! 5041 ' cpu = parseInt(name.slice(7));\n'\ 5215 cpu = parseInt(name.s !! 5042 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 5216 var dmesg = document.getEleme !! 5043 ' cpu = parseInt(name.slice(8));\n'\ 5217 var dev = dmesg.getElementsBy !! 5044 ' var dmesg = document.getElementById("dmesg");\n'\ 5218 var idlist = []; !! 5045 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5219 var pdata = [[]]; !! 5046 ' var idlist = [];\n'\ 5220 if(document.getElementById("d !! 5047 ' var pdata = [[]];\n'\ 5221 pdata = [[], []]; !! 5048 ' if(document.getElementById("devicedetail1"))\n'\ 5222 var pd = pdata[0]; !! 5049 ' pdata = [[], []];\n'\ 5223 var total = [0.0, 0.0, 0.0]; !! 5050 ' var pd = pdata[0];\n'\ 5224 for (var i = 0; i < dev.lengt !! 5051 ' var total = [0.0, 0.0, 0.0];\n'\ 5225 dname = deviceName(de !! 5052 ' for (var i = 0; i < dev.length; i++) {\n'\ 5226 if((cpu >= 0 && dname !! 5053 ' dname = deviceName(dev[i].title);\n'\ 5227 (name == dnam !! 5054 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 5228 { !! 5055 ' (name == dname))\n'\ 5229 idlist[idlist !! 5056 ' {\n'\ 5230 var tidx = 1; !! 5057 ' idlist[idlist.length] = dev[i].id;\n'\ 5231 if(dev[i].id[ !! 5058 ' var tidx = 1;\n'\ 5232 pd = !! 5059 ' if(dev[i].id[0] == "a") {\n'\ 5233 } else { !! 5060 ' pd = pdata[0];\n'\ 5234 if(pd !! 5061 ' } else {\n'\ 5235 if(to !! 5062 ' if(pdata.length == 1) pdata[1] = [];\n'\ 5236 pd = !! 5063 ' if(total.length == 3) total[3]=total[4]=0.0;\n'\ 5237 tidx !! 5064 ' pd = pdata[1];\n'\ 5238 } !! 5065 ' tidx = 3;\n'\ 5239 var info = de !! 5066 ' }\n'\ 5240 var pname = i !! 5067 ' var info = dev[i].title.split(" ");\n'\ 5241 pd[pname] = p !! 5068 ' var pname = info[info.length-1];\n'\ 5242 total[0] += p !! 5069 ' pd[pname] = parseFloat(info[info.length-3].slice(1));\n'\ 5243 if(pname.inde !! 5070 ' total[0] += pd[pname];\n'\ 5244 total !! 5071 ' if(pname.indexOf("suspend") >= 0)\n'\ 5245 else !! 5072 ' total[tidx] += pd[pname];\n'\ 5246 total !! 5073 ' else\n'\ 5247 } !! 5074 ' total[tidx+1] += pd[pname];\n'\ 5248 } !! 5075 ' }\n'\ 5249 var devname = deviceTitle(thi !! 5076 ' }\n'\ 5250 var left = 0.0; !! 5077 ' var devname = deviceTitle(this.title, total, cpu);\n'\ 5251 for (var t = 0; t < pdata.len !! 5078 ' var left = 0.0;\n'\ 5252 pd = pdata[t]; !! 5079 ' for (var t = 0; t < pdata.length; t++) {\n'\ 5253 devinfo = document.ge !! 5080 ' pd = pdata[t];\n'\ 5254 var phases = devinfo. !! 5081 ' devinfo = document.getElementById("devicedetail"+t);\n'\ 5255 for (var i = 0; i < p !! 5082 ' var phases = devinfo.getElementsByClassName("phaselet");\n'\ 5256 if(phases[i]. !! 5083 ' for (var i = 0; i < phases.length; i++) {\n'\ 5257 var w !! 5084 ' if(phases[i].id in pd) {\n'\ 5258 var f !! 5085 ' var w = 100.0*pd[phases[i].id]/total[0];\n'\ 5259 if(w !! 5086 ' var fs = 32;\n'\ 5260 var f !! 5087 ' if(w < 8) fs = 4*w | 0;\n'\ 5261 phase !! 5088 ' var fs2 = fs*3/4;\n'\ 5262 phase !! 5089 ' phases[i].style.width = w+"%";\n'\ 5263 phase !! 5090 ' phases[i].style.left = left+"%";\n'\ 5264 left !! 5091 ' phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\ 5265 var t !! 5092 ' left += w;\n'\ 5266 var p !! 5093 ' var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\ 5267 phase !! 5094 ' var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";\n'\ 5268 } else { !! 5095 ' phases[i].innerHTML = time+pname;\n'\ 5269 phase !! 5096 ' } else {\n'\ 5270 phase !! 5097 ' phases[i].style.width = "0%";\n'\ 5271 } !! 5098 ' phases[i].style.left = left+"%";\n'\ 5272 } !! 5099 ' }\n'\ 5273 } !! 5100 ' }\n'\ 5274 if(typeof devstats !== 'undef !! 5101 ' }\n'\ 5275 callDetail(this.id, t !! 5102 ' if(typeof devstats !== \'undefined\')\n'\ 5276 var cglist = document.getElem !! 5103 ' callDetail(this.id, this.title);\n'\ 5277 if(!cglist) return; !! 5104 ' var cglist = document.getElementById("callgraphs");\n'\ 5278 var cg = cglist.getElementsBy !! 5105 ' if(!cglist) return;\n'\ 5279 if(cg.length < 10) return; !! 5106 ' var cg = cglist.getElementsByClassName("atop");\n'\ 5280 for (var i = 0; i < cg.length !! 5107 ' if(cg.length < 10) return;\n'\ 5281 cgid = cg[i].id.split !! 5108 ' for (var i = 0; i < cg.length; i++) {\n'\ 5282 if(idlist.indexOf(cgi !! 5109 ' cgid = cg[i].id.split("x")[0]\n'\ 5283 cg[i].style.d !! 5110 ' if(idlist.indexOf(cgid) >= 0) {\n'\ 5284 } else { !! 5111 ' cg[i].style.display = "block";\n'\ 5285 cg[i].style.d !! 5112 ' } else {\n'\ 5286 } !! 5113 ' cg[i].style.display = "none";\n'\ 5287 } !! 5114 ' }\n'\ 5288 } !! 5115 ' }\n'\ 5289 function callDetail(devid, devtitle) !! 5116 ' }\n'\ 5290 if(!(devid in devstats) || de !! 5117 ' function callDetail(devid, devtitle) {\n'\ 5291 return; !! 5118 ' if(!(devid in devstats) || devstats[devid].length < 1)\n'\ 5292 var list = devstats[devid]; !! 5119 ' return;\n'\ 5293 var tmp = devtitle.split(" ") !! 5120 ' var list = devstats[devid];\n'\ 5294 var name = tmp[0], phase = tm !! 5121 ' var tmp = devtitle.split(" ");\n'\ 5295 var dd = document.getElementB !! 5122 ' var name = tmp[0], phase = tmp[tmp.length-1];\n'\ 5296 var total = parseFloat(tmp[1] !! 5123 ' var dd = document.getElementById(phase);\n'\ 5297 var mlist = []; !! 5124 ' var total = parseFloat(tmp[1].slice(1));\n'\ 5298 var maxlen = 0; !! 5125 ' var mlist = [];\n'\ 5299 var info = [] !! 5126 ' var maxlen = 0;\n'\ 5300 for(var i in list) { !! 5127 ' var info = []\n'\ 5301 if(list[i][0] == "@") !! 5128 ' for(var i in list) {\n'\ 5302 info = list[i !! 5129 ' if(list[i][0] == "@") {\n'\ 5303 continue; !! 5130 ' info = list[i].split("|");\n'\ 5304 } !! 5131 ' continue;\n'\ 5305 var tmp = list[i].spl !! 5132 ' }\n'\ 5306 var t = parseFloat(tm !! 5133 ' var tmp = list[i].split("|");\n'\ 5307 var p = (t*100.0/tota !! 5134 ' var t = parseFloat(tmp[0]), f = tmp[1], c = parseInt(tmp[2]);\n'\ 5308 mlist[mlist.length] = !! 5135 ' var p = (t*100.0/total).toFixed(2);\n'\ 5309 if(f.length > maxlen) !! 5136 ' mlist[mlist.length] = [f, c, t.toFixed(2), p+"%"];\n'\ 5310 maxlen = f.le !! 5137 ' if(f.length > maxlen)\n'\ 5311 } !! 5138 ' maxlen = f.length;\n'\ 5312 var pad = 5; !! 5139 ' }\n'\ 5313 if(mlist.length == 0) pad = 3 !! 5140 ' var pad = 5;\n'\ 5314 var html = '<div style="paddi !! 5141 ' if(mlist.length == 0) pad = 30;\n'\ 5315 if(info.length > 2) !! 5142 ' var html = \'<div style="padding-top:\'+pad+\'px"><t3> <b>\'+name+\':</b>\';\n'\ 5316 html += " start=<b>"+ !! 5143 ' if(info.length > 2)\n'\ 5317 if(info.length > 3) !! 5144 ' html += " start=<b>"+info[1]+"</b>, end=<b>"+info[2]+"</b>";\n'\ 5318 html += ", length<i>( !! 5145 ' if(info.length > 3)\n'\ 5319 if(info.length > 4) !! 5146 ' html += ", length<i>(w/o overhead)</i>=<b>"+info[3]+" ms</b>";\n'\ 5320 html += ", return=<b> !! 5147 ' if(info.length > 4)\n'\ 5321 html += "</t3></div>"; !! 5148 ' html += ", return=<b>"+info[4]+"</b>";\n'\ 5322 if(mlist.length > 0) { !! 5149 ' html += "</t3></div>";\n'\ 5323 html += '<table class !! 5150 ' if(mlist.length > 0) {\n'\ 5324 for(var i in mlist) !! 5151 ' html += \'<table class=fstat style="padding-top:\'+(maxlen*5)+\'px;"><tr><th>Function</th>\';\n'\ 5325 html += "<td !! 5152 ' for(var i in mlist)\n'\ 5326 html += "</tr><tr><th !! 5153 ' html += "<td class=vt>"+mlist[i][0]+"</td>";\n'\ 5327 for(var i in mlist) !! 5154 ' html += "</tr><tr><th>Calls</th>";\n'\ 5328 html += "<td> !! 5155 ' for(var i in mlist)\n'\ 5329 html += "</tr><tr><th !! 5156 ' html += "<td>"+mlist[i][1]+"</td>";\n'\ 5330 for(var i in mlist) !! 5157 ' html += "</tr><tr><th>Time(ms)</th>";\n'\ 5331 html += "<td> !! 5158 ' for(var i in mlist)\n'\ 5332 html += "</tr><tr><th !! 5159 ' html += "<td>"+mlist[i][2]+"</td>";\n'\ 5333 for(var i in mlist) !! 5160 ' html += "</tr><tr><th>Percent</th>";\n'\ 5334 html += "<td> !! 5161 ' for(var i in mlist)\n'\ 5335 html += "</tr></table !! 5162 ' html += "<td>"+mlist[i][3]+"</td>";\n'\ 5336 } !! 5163 ' html += "</tr></table>";\n'\ 5337 dd.innerHTML = html; !! 5164 ' }\n'\ 5338 var height = (maxlen*5)+100; !! 5165 ' dd.innerHTML = html;\n'\ 5339 dd.style.height = height+"px" !! 5166 ' var height = (maxlen*5)+100;\n'\ 5340 document.getElementById("devi !! 5167 ' dd.style.height = height+"px";\n'\ 5341 } !! 5168 ' document.getElementById("devicedetail").style.height = height+"px";\n'\ 5342 function callSelect() { !! 5169 ' }\n'\ 5343 var cglist = document.getElem !! 5170 ' function callSelect() {\n'\ 5344 if(!cglist) return; !! 5171 ' var cglist = document.getElementById("callgraphs");\n'\ 5345 var cg = cglist.getElementsBy !! 5172 ' if(!cglist) return;\n'\ 5346 for (var i = 0; i < cg.length !! 5173 ' var cg = cglist.getElementsByClassName("atop");\n'\ 5347 if(this.id == cg[i].i !! 5174 ' for (var i = 0; i < cg.length; i++) {\n'\ 5348 cg[i].style.d !! 5175 ' if(this.id == cg[i].id) {\n'\ 5349 } else { !! 5176 ' cg[i].style.display = "block";\n'\ 5350 cg[i].style.d !! 5177 ' } else {\n'\ 5351 } !! 5178 ' cg[i].style.display = "none";\n'\ 5352 } !! 5179 ' }\n'\ 5353 } !! 5180 ' }\n'\ 5354 function devListWindow(e) { !! 5181 ' }\n'\ 5355 var win = window.open(); !! 5182 ' function devListWindow(e) {\n'\ 5356 var html = "<title>"+e.target !! 5183 ' var win = window.open();\n'\ 5357 "<style type=\"text/c !! 5184 ' var html = "<title>"+e.target.innerHTML+"</title>"+\n'\ 5358 " ul {list-style-ty !! 5185 ' "<style type=\\"text/css\\">"+\n'\ 5359 "</style>" !! 5186 ' " ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\ 5360 var dt = devtable[0]; !! 5187 ' "</style>"\n'\ 5361 if(e.target.id != "devlist1") !! 5188 ' var dt = devtable[0];\n'\ 5362 dt = devtable[1]; !! 5189 ' if(e.target.id != "devlist1")\n'\ 5363 win.document.write(html+dt); !! 5190 ' dt = devtable[1];\n'\ 5364 } !! 5191 ' win.document.write(html+dt);\n'\ 5365 function errWindow() { !! 5192 ' }\n'\ 5366 var range = this.id.split("_" !! 5193 ' function errWindow() {\n'\ 5367 var idx1 = parseInt(range[0]) !! 5194 ' var range = this.id.split("_");\n'\ 5368 var idx2 = parseInt(range[1]) !! 5195 ' var idx1 = parseInt(range[0]);\n'\ 5369 var win = window.open(); !! 5196 ' var idx2 = parseInt(range[1]);\n'\ 5370 var log = document.getElement !! 5197 ' var win = window.open();\n'\ 5371 var title = "<title>dmesg log !! 5198 ' var log = document.getElementById("dmesglog");\n'\ 5372 var text = log.innerHTML.spli !! 5199 ' var title = "<title>dmesg log</title>";\n'\ 5373 var html = ""; !! 5200 ' var text = log.innerHTML.split("\\n");\n'\ 5374 for(var i = 0; i < text.lengt !! 5201 ' var html = "";\n'\ 5375 if(i == idx1) { !! 5202 ' for(var i = 0; i < text.length; i++) {\n'\ 5376 html += "<e i !! 5203 ' if(i == idx1) {\n'\ 5377 } else if(i > idx1 && !! 5204 ' html += "<e id=target>"+text[i]+"</e>\\n";\n'\ 5378 html += "<e>" !! 5205 ' } else if(i > idx1 && i <= idx2) {\n'\ 5379 } else { !! 5206 ' html += "<e>"+text[i]+"</e>\\n";\n'\ 5380 html += text[ !! 5207 ' } else {\n'\ 5381 } !! 5208 ' html += text[i]+"\\n";\n'\ 5382 } !! 5209 ' }\n'\ 5383 win.document.write("<style>e{ !! 5210 ' }\n'\ 5384 win.location.hash = "#target" !! 5211 ' win.document.write("<style>e{color:red}</style>"+title+"<pre>"+html+"</pre>");\n'\ 5385 win.document.close(); !! 5212 ' win.location.hash = "#target";\n'\ 5386 } !! 5213 ' win.document.close();\n'\ 5387 function logWindow(e) { !! 5214 ' }\n'\ 5388 var name = e.target.id.slice( !! 5215 ' function logWindow(e) {\n'\ 5389 var win = window.open(); !! 5216 ' var name = e.target.id.slice(4);\n'\ 5390 var log = document.getElement !! 5217 ' var win = window.open();\n'\ 5391 var title = "<title>"+documen !! 5218 ' var log = document.getElementById(name+"log");\n'\ 5392 win.document.write(title+"<pr !! 5219 ' var title = "<title>"+document.title.split(" ")[0]+" "+name+" log</title>";\n'\ 5393 win.document.close(); !! 5220 ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ 5394 } !! 5221 ' win.document.close();\n'\ 5395 function onMouseDown(e) { !! 5222 ' }\n'\ 5396 dragval[0] = e.clientX; !! 5223 ' function onMouseDown(e) {\n'\ 5397 dragval[1] = document.getElem !! 5224 ' dragval[0] = e.clientX;\n'\ 5398 document.onmousemove = onMous !! 5225 ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ 5399 } !! 5226 ' document.onmousemove = onMouseMove;\n'\ 5400 function onMouseMove(e) { !! 5227 ' }\n'\ 5401 var zoombox = document.getEle !! 5228 ' function onMouseMove(e) {\n'\ 5402 zoombox.scrollLeft = dragval[ !! 5229 ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 5403 } !! 5230 ' zoombox.scrollLeft = dragval[1] + dragval[0] - e.clientX;\n'\ 5404 function onMouseUp(e) { !! 5231 ' }\n'\ 5405 document.onmousemove = null; !! 5232 ' function onMouseUp(e) {\n'\ 5406 } !! 5233 ' document.onmousemove = null;\n'\ 5407 function onKeyPress(e) { !! 5234 ' }\n'\ 5408 var c = e.charCode; !! 5235 ' function onKeyPress(e) {\n'\ 5409 if(c != 42 && c != 43 && c != !! 5236 ' var c = e.charCode;\n'\ 5410 var click = document.createEv !! 5237 ' if(c != 42 && c != 43 && c != 45) return;\n'\ 5411 click.initEvent("click", true !! 5238 ' var click = document.createEvent("Events");\n'\ 5412 if(c == 43) !! 5239 ' click.initEvent("click", true, false);\n'\ 5413 document.getElementBy !! 5240 ' if(c == 43) \n'\ 5414 else if(c == 45) !! 5241 ' document.getElementById("zoomin").dispatchEvent(click);\n'\ 5415 document.getElementBy !! 5242 ' else if(c == 45)\n'\ 5416 else if(c == 42) !! 5243 ' document.getElementById("zoomout").dispatchEvent(click);\n'\ 5417 document.getElementBy !! 5244 ' else if(c == 42)\n'\ 5418 } !! 5245 ' document.getElementById("zoomdef").dispatchEvent(click);\n'\ 5419 window.addEventListener("resize", fun !! 5246 ' }\n'\ 5420 window.addEventListener("load", funct !! 5247 ' window.addEventListener("resize", function () {zoomTimeline();});\n'\ 5421 var dmesg = document.getEleme !! 5248 ' window.addEventListener("load", function () {\n'\ 5422 dmesg.style.width = "100%" !! 5249 ' var dmesg = document.getElementById("dmesg");\n'\ 5423 dmesg.onmousedown = onMouseDo !! 5250 ' dmesg.style.width = "100%"\n'\ 5424 document.onmouseup = onMouseU !! 5251 ' dmesg.onmousedown = onMouseDown;\n'\ 5425 document.onkeypress = onKeyPr !! 5252 ' document.onmouseup = onMouseUp;\n'\ 5426 document.getElementById("zoom !! 5253 ' document.onkeypress = onKeyPress;\n'\ 5427 document.getElementById("zoom !! 5254 ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ 5428 document.getElementById("zoom !! 5255 ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ 5429 var list = document.getElemen !! 5256 ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ 5430 for (var i = 0; i < list.leng !! 5257 ' var list = document.getElementsByClassName("err");\n'\ 5431 list[i].onclick = err !! 5258 ' for (var i = 0; i < list.length; i++)\n'\ 5432 var list = document.getElemen !! 5259 ' list[i].onclick = errWindow;\n'\ 5433 for (var i = 0; i < list.leng !! 5260 ' var list = document.getElementsByClassName("logbtn");\n'\ 5434 list[i].onclick = log !! 5261 ' for (var i = 0; i < list.length; i++)\n'\ 5435 list = document.getElementsBy !! 5262 ' list[i].onclick = logWindow;\n'\ 5436 for (var i = 0; i < list.leng !! 5263 ' list = document.getElementsByClassName("devlist");\n'\ 5437 list[i].onclick = dev !! 5264 ' for (var i = 0; i < list.length; i++)\n'\ 5438 var dev = dmesg.getElementsBy !! 5265 ' list[i].onclick = devListWindow;\n'\ 5439 for (var i = 0; i < dev.lengt !! 5266 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5440 dev[i].onclick = devi !! 5267 ' for (var i = 0; i < dev.length; i++) {\n'\ 5441 dev[i].onmouseover = !! 5268 ' dev[i].onclick = deviceDetail;\n'\ 5442 dev[i].onmouseout = d !! 5269 ' dev[i].onmouseover = deviceHover;\n'\ 5443 } !! 5270 ' dev[i].onmouseout = deviceUnhover;\n'\ 5444 var dev = dmesg.getElementsBy !! 5271 ' }\n'\ 5445 for (var i = 0; i < dev.lengt !! 5272 ' var dev = dmesg.getElementsByClassName("srccall");\n'\ 5446 dev[i].onclick = call !! 5273 ' for (var i = 0; i < dev.length; i++)\n'\ 5447 zoomTimeline(); !! 5274 ' dev[i].onclick = callSelect;\n'\ 5448 }); !! 5275 ' zoomTimeline();\n'\ 5449 </script> """ !! 5276 ' });\n'\ >> 5277 '</script>\n' 5450 hf.write(script_code); 5278 hf.write(script_code); 5451 5279 5452 # Function: executeSuspend 5280 # Function: executeSuspend 5453 # Description: 5281 # Description: 5454 # Execute system suspend through the s 5282 # Execute system suspend through the sysfs interface, then copy the output 5455 # dmesg and ftrace files to the test o 5283 # dmesg and ftrace files to the test output directory. 5456 def executeSuspend(quiet=False): 5284 def executeSuspend(quiet=False): 5457 sv, tp, pm = sysvals, sysvals.tpath, 5285 sv, tp, pm = sysvals, sysvals.tpath, ProcessMonitor() 5458 if sv.wifi: 5286 if sv.wifi: 5459 wifi = sv.checkWifi() 5287 wifi = sv.checkWifi() 5460 sv.dlog('wifi check, connecte 5288 sv.dlog('wifi check, connected device is "%s"' % wifi) 5461 testdata = [] 5289 testdata = [] 5462 # run these commands to prepare the s 5290 # run these commands to prepare the system for suspend 5463 if sv.display: 5291 if sv.display: 5464 if not quiet: 5292 if not quiet: 5465 pprint('SET DISPLAY T 5293 pprint('SET DISPLAY TO %s' % sv.display.upper()) 5466 ret = sv.displayControl(sv.di 5294 ret = sv.displayControl(sv.display) 5467 sv.dlog('xset display %s, ret 5295 sv.dlog('xset display %s, ret = %d' % (sv.display, ret)) 5468 time.sleep(1) 5296 time.sleep(1) 5469 if sv.sync: 5297 if sv.sync: 5470 if not quiet: 5298 if not quiet: 5471 pprint('SYNCING FILES 5299 pprint('SYNCING FILESYSTEMS') 5472 sv.dlog('syncing filesystems' 5300 sv.dlog('syncing filesystems') 5473 call('sync', shell=True) 5301 call('sync', shell=True) 5474 sv.dlog('read dmesg') 5302 sv.dlog('read dmesg') 5475 sv.initdmesg() 5303 sv.initdmesg() 5476 sv.dlog('cmdinfo before') !! 5304 # start ftrace >> 5305 if(sv.usecallgraph or sv.usetraceevents): >> 5306 if not quiet: >> 5307 pprint('START TRACING') >> 5308 sv.dlog('start ftrace tracing') >> 5309 sv.fsetVal('1', 'tracing_on') >> 5310 if sv.useprocmon: >> 5311 sv.dlog('start the process monitor') >> 5312 pm.start() >> 5313 sv.dlog('run the cmdinfo list before') 5477 sv.cmdinfo(True) 5314 sv.cmdinfo(True) 5478 sv.start(pm) << 5479 # execute however many s/r runs reque 5315 # execute however many s/r runs requested 5480 for count in range(1,sv.execcount+1): 5316 for count in range(1,sv.execcount+1): 5481 # x2delay in between test run 5317 # x2delay in between test runs 5482 if(count > 1 and sv.x2delay > 5318 if(count > 1 and sv.x2delay > 0): 5483 sv.fsetVal('WAIT %d' 5319 sv.fsetVal('WAIT %d' % sv.x2delay, 'trace_marker') 5484 time.sleep(sv.x2delay 5320 time.sleep(sv.x2delay/1000.0) 5485 sv.fsetVal('WAIT END' 5321 sv.fsetVal('WAIT END', 'trace_marker') 5486 # start message 5322 # start message 5487 if sv.testcommand != '': 5323 if sv.testcommand != '': 5488 pprint('COMMAND START 5324 pprint('COMMAND START') 5489 else: 5325 else: 5490 if(sv.rtcwake): 5326 if(sv.rtcwake): 5491 pprint('SUSPE 5327 pprint('SUSPEND START') 5492 else: 5328 else: 5493 pprint('SUSPE 5329 pprint('SUSPEND START (press a key to resume)') 5494 # set rtcwake 5330 # set rtcwake 5495 if(sv.rtcwake): 5331 if(sv.rtcwake): 5496 if not quiet: 5332 if not quiet: 5497 pprint('will 5333 pprint('will issue an rtcwake in %d seconds' % sv.rtcwaketime) 5498 sv.dlog('enable RTC w 5334 sv.dlog('enable RTC wake alarm') 5499 sv.rtcWakeAlarmOn() 5335 sv.rtcWakeAlarmOn() 5500 # start of suspend trace mark 5336 # start of suspend trace marker 5501 sv.fsetVal(datetime.now().str !! 5337 if(sv.usecallgraph or sv.usetraceevents): >> 5338 sv.fsetVal(datetime.now().strftime(sv.tmstart), 'trace_marker') 5502 # predelay delay 5339 # predelay delay 5503 if(count == 1 and sv.predelay 5340 if(count == 1 and sv.predelay > 0): 5504 sv.fsetVal('WAIT %d' 5341 sv.fsetVal('WAIT %d' % sv.predelay, 'trace_marker') 5505 time.sleep(sv.predela 5342 time.sleep(sv.predelay/1000.0) 5506 sv.fsetVal('WAIT END' 5343 sv.fsetVal('WAIT END', 'trace_marker') 5507 # initiate suspend or command 5344 # initiate suspend or command 5508 sv.dlog('system executing a s 5345 sv.dlog('system executing a suspend') 5509 tdata = {'error': ''} 5346 tdata = {'error': ''} 5510 if sv.testcommand != '': 5347 if sv.testcommand != '': 5511 res = call(sv.testcom 5348 res = call(sv.testcommand+' 2>&1', shell=True); 5512 if res != 0: 5349 if res != 0: 5513 tdata['error' 5350 tdata['error'] = 'cmd returned %d' % res 5514 else: 5351 else: 5515 s0ixready = sv.s0ixSu << 5516 mode = sv.suspendmode 5352 mode = sv.suspendmode 5517 if sv.memmode and os. 5353 if sv.memmode and os.path.exists(sv.mempowerfile): 5518 mode = 'mem' 5354 mode = 'mem' 5519 sv.testVal(sv 5355 sv.testVal(sv.mempowerfile, 'radio', sv.memmode) 5520 if sv.diskmode and os 5356 if sv.diskmode and os.path.exists(sv.diskpowerfile): 5521 mode = 'disk' 5357 mode = 'disk' 5522 sv.testVal(sv 5358 sv.testVal(sv.diskpowerfile, 'radio', sv.diskmode) 5523 if sv.acpidebug: 5359 if sv.acpidebug: 5524 sv.testVal(sv 5360 sv.testVal(sv.acpipath, 'acpi', '0xe') 5525 if ((mode == 'freeze' !! 5361 if mode == 'freeze' and sv.haveTurbostat(): 5526 and sv.haveTu << 5527 # execution w 5362 # execution will pause here 5528 retval, turbo !! 5363 turbo = sv.turbostat() 5529 if retval != << 5530 tdata << 5531 if turbo: 5364 if turbo: 5532 tdata 5365 tdata['turbo'] = turbo 5533 else: 5366 else: 5534 pf = open(sv. 5367 pf = open(sv.powerfile, 'w') 5535 pf.write(mode 5368 pf.write(mode) 5536 # execution w 5369 # execution will pause here 5537 try: 5370 try: 5538 pf.fl << 5539 pf.cl 5371 pf.close() 5540 except Except 5372 except Exception as e: 5541 tdata 5373 tdata['error'] = str(e) 5542 sv.fsetVal('CMD COMPLETE', 't !! 5374 sv.dlog('system returned from resume') 5543 sv.dlog('system returned') << 5544 # reset everything 5375 # reset everything 5545 sv.testVal('restoreall') 5376 sv.testVal('restoreall') 5546 if(sv.rtcwake): 5377 if(sv.rtcwake): 5547 sv.dlog('disable RTC 5378 sv.dlog('disable RTC wake alarm') 5548 sv.rtcWakeAlarmOff() 5379 sv.rtcWakeAlarmOff() 5549 # postdelay delay 5380 # postdelay delay 5550 if(count == sv.execcount and 5381 if(count == sv.execcount and sv.postdelay > 0): 5551 sv.fsetVal('WAIT %d' 5382 sv.fsetVal('WAIT %d' % sv.postdelay, 'trace_marker') 5552 time.sleep(sv.postdel 5383 time.sleep(sv.postdelay/1000.0) 5553 sv.fsetVal('WAIT END' 5384 sv.fsetVal('WAIT END', 'trace_marker') 5554 # return from suspend 5385 # return from suspend 5555 pprint('RESUME COMPLETE') 5386 pprint('RESUME COMPLETE') 5556 if(count < sv.execcount): !! 5387 if(sv.usecallgraph or sv.usetraceevents): 5557 sv.fsetVal(datetime.n << 5558 elif(not sv.wifitrace): << 5559 sv.fsetVal(datetime.n 5388 sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker') 5560 sv.stop(pm) << 5561 if sv.wifi and wifi: 5389 if sv.wifi and wifi: 5562 tdata['wifi'] = sv.po 5390 tdata['wifi'] = sv.pollWifi(wifi) 5563 sv.dlog('wifi check, 5391 sv.dlog('wifi check, %s' % tdata['wifi']) 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 5392 if(sv.suspendmode == 'mem' or sv.suspendmode == 'command'): 5571 sv.dlog('read the ACP 5393 sv.dlog('read the ACPI FPDT') 5572 tdata['fw'] = getFPDT 5394 tdata['fw'] = getFPDT(False) 5573 testdata.append(tdata) 5395 testdata.append(tdata) 5574 sv.dlog('cmdinfo after') !! 5396 sv.dlog('run the cmdinfo list after') 5575 cmdafter = sv.cmdinfo(False) 5397 cmdafter = sv.cmdinfo(False) >> 5398 # stop ftrace >> 5399 if(sv.usecallgraph or sv.usetraceevents): >> 5400 if sv.useprocmon: >> 5401 sv.dlog('stop the process monitor') >> 5402 pm.stop() >> 5403 sv.fsetVal('0', 'tracing_on') 5576 # grab a copy of the dmesg output 5404 # grab a copy of the dmesg output 5577 if not quiet: 5405 if not quiet: 5578 pprint('CAPTURING DMESG') 5406 pprint('CAPTURING DMESG') >> 5407 sysvals.dlog('EXECUTION TRACE END') 5579 sv.getdmesg(testdata) 5408 sv.getdmesg(testdata) 5580 # grab a copy of the ftrace output 5409 # grab a copy of the ftrace output 5581 if sv.useftrace: !! 5410 if(sv.usecallgraph or sv.usetraceevents): 5582 if not quiet: 5411 if not quiet: 5583 pprint('CAPTURING TRA 5412 pprint('CAPTURING TRACE') 5584 op = sv.writeDatafileHeader(s 5413 op = sv.writeDatafileHeader(sv.ftracefile, testdata) 5585 fp = open(tp+'trace', 'rb') !! 5414 fp = open(tp+'trace', 'r') 5586 op.write(ascii(fp.read())) !! 5415 for line in fp: >> 5416 op.write(line) 5587 op.close() 5417 op.close() 5588 sv.fsetVal('', 'trace') 5418 sv.fsetVal('', 'trace') 5589 sv.platforminfo(cmdafter) 5419 sv.platforminfo(cmdafter) 5590 5420 5591 def readFile(file): 5421 def readFile(file): 5592 if os.path.islink(file): 5422 if os.path.islink(file): 5593 return os.readlink(file).spli 5423 return os.readlink(file).split('/')[-1] 5594 else: 5424 else: 5595 return sysvals.getVal(file).s 5425 return sysvals.getVal(file).strip() 5596 5426 5597 # Function: ms2nice 5427 # Function: ms2nice 5598 # Description: 5428 # Description: 5599 # Print out a very concise time string 5429 # Print out a very concise time string in minutes and seconds 5600 # Output: 5430 # Output: 5601 # The time string, e.g. "1901m16s" 5431 # The time string, e.g. "1901m16s" 5602 def ms2nice(val): 5432 def ms2nice(val): 5603 val = int(val) 5433 val = int(val) 5604 h = val // 3600000 5434 h = val // 3600000 5605 m = (val // 60000) % 60 5435 m = (val // 60000) % 60 5606 s = (val // 1000) % 60 5436 s = (val // 1000) % 60 5607 if h > 0: 5437 if h > 0: 5608 return '%d:%02d:%02d' % (h, m 5438 return '%d:%02d:%02d' % (h, m, s) 5609 if m > 0: 5439 if m > 0: 5610 return '%02d:%02d' % (m, s) 5440 return '%02d:%02d' % (m, s) 5611 return '%ds' % s 5441 return '%ds' % s 5612 5442 5613 def yesno(val): 5443 def yesno(val): 5614 list = {'enabled':'A', 'disabled':'S' 5444 list = {'enabled':'A', 'disabled':'S', 'auto':'E', 'on':'D', 5615 'active':'A', 'suspended':'S' 5445 'active':'A', 'suspended':'S', 'suspending':'S'} 5616 if val not in list: 5446 if val not in list: 5617 return ' ' 5447 return ' ' 5618 return list[val] 5448 return list[val] 5619 5449 5620 # Function: deviceInfo 5450 # Function: deviceInfo 5621 # Description: 5451 # Description: 5622 # Detect all the USB hosts and devices 5452 # Detect all the USB hosts and devices currently connected and add 5623 # a list of USB device names to sysval 5453 # a list of USB device names to sysvals for better timeline readability 5624 def deviceInfo(output=''): 5454 def deviceInfo(output=''): 5625 if not output: 5455 if not output: 5626 pprint('LEGEND\n'\ 5456 pprint('LEGEND\n'\ 5627 '---------------------------- 5457 '---------------------------------------------------------------------------------------------\n'\ 5628 ' A = async/sync PM queue (A 5458 ' A = async/sync PM queue (A/S) C = runtime active children\n'\ 5629 ' R = runtime suspend enable 5459 ' R = runtime suspend enabled/disabled (E/D) rACTIVE = runtime active (min/sec)\n'\ 5630 ' S = runtime status active/ 5460 ' S = runtime status active/suspended (A/S) rSUSPEND = runtime suspend (min/sec)\n'\ 5631 ' U = runtime usage count\n' 5461 ' U = runtime usage count\n'\ 5632 '---------------------------- 5462 '---------------------------------------------------------------------------------------------\n'\ 5633 'DEVICE N 5463 'DEVICE NAME A R S U C rACTIVE rSUSPEND\n'\ 5634 '---------------------------- 5464 '---------------------------------------------------------------------------------------------') 5635 5465 5636 res = [] 5466 res = [] 5637 tgtval = 'runtime_status' 5467 tgtval = 'runtime_status' 5638 lines = dict() 5468 lines = dict() 5639 for dirname, dirnames, filenames in o 5469 for dirname, dirnames, filenames in os.walk('/sys/devices'): 5640 if(not re.match(r'.*/power', !! 5470 if(not re.match('.*/power', dirname) or 5641 'control' not in file 5471 'control' not in filenames or 5642 tgtval not in filenam 5472 tgtval not in filenames): 5643 continue 5473 continue 5644 name = '' 5474 name = '' 5645 dirname = dirname[:-6] 5475 dirname = dirname[:-6] 5646 device = dirname.split('/')[- 5476 device = dirname.split('/')[-1] 5647 power = dict() 5477 power = dict() 5648 power[tgtval] = readFile('%s/ 5478 power[tgtval] = readFile('%s/power/%s' % (dirname, tgtval)) 5649 # only list devices which sup 5479 # only list devices which support runtime suspend 5650 if power[tgtval] not in ['act 5480 if power[tgtval] not in ['active', 'suspended', 'suspending']: 5651 continue 5481 continue 5652 for i in ['product', 'driver' 5482 for i in ['product', 'driver', 'subsystem']: 5653 file = '%s/%s' % (dir 5483 file = '%s/%s' % (dirname, i) 5654 if os.path.exists(fil 5484 if os.path.exists(file): 5655 name = readFi 5485 name = readFile(file) 5656 break 5486 break 5657 for i in ['async', 'control', 5487 for i in ['async', 'control', 'runtime_status', 'runtime_usage', 5658 'runtime_active_kids' 5488 'runtime_active_kids', 'runtime_active_time', 5659 'runtime_suspended_ti 5489 'runtime_suspended_time']: 5660 if i in filenames: 5490 if i in filenames: 5661 power[i] = re 5491 power[i] = readFile('%s/power/%s' % (dirname, i)) 5662 if output: 5492 if output: 5663 if power['control'] = 5493 if power['control'] == output: 5664 res.append('% 5494 res.append('%s/power/control' % dirname) 5665 continue 5495 continue 5666 lines[dirname] = '%-26s %-26s 5496 lines[dirname] = '%-26s %-26s %1s %1s %1s %1s %1s %10s %10s' % \ 5667 (device[:26], name[:2 5497 (device[:26], name[:26], 5668 yesno(power['async']) 5498 yesno(power['async']), \ 5669 yesno(power['control' 5499 yesno(power['control']), \ 5670 yesno(power['runtime_ 5500 yesno(power['runtime_status']), \ 5671 power['runtime_usage' 5501 power['runtime_usage'], \ 5672 power['runtime_active 5502 power['runtime_active_kids'], \ 5673 ms2nice(power['runtim 5503 ms2nice(power['runtime_active_time']), \ 5674 ms2nice(power['runtim 5504 ms2nice(power['runtime_suspended_time'])) 5675 for i in sorted(lines): 5505 for i in sorted(lines): 5676 print(lines[i]) 5506 print(lines[i]) 5677 return res 5507 return res 5678 5508 5679 # Function: getModes 5509 # Function: getModes 5680 # Description: 5510 # Description: 5681 # Determine the supported power modes 5511 # Determine the supported power modes on this system 5682 # Output: 5512 # Output: 5683 # A string list of the available modes 5513 # A string list of the available modes 5684 def getModes(): 5514 def getModes(): 5685 modes = [] 5515 modes = [] 5686 if(os.path.exists(sysvals.powerfile)) 5516 if(os.path.exists(sysvals.powerfile)): 5687 fp = open(sysvals.powerfile, 5517 fp = open(sysvals.powerfile, 'r') 5688 modes = fp.read().split() 5518 modes = fp.read().split() 5689 fp.close() 5519 fp.close() 5690 if(os.path.exists(sysvals.mempowerfil 5520 if(os.path.exists(sysvals.mempowerfile)): 5691 deep = False 5521 deep = False 5692 fp = open(sysvals.mempowerfil 5522 fp = open(sysvals.mempowerfile, 'r') 5693 for m in fp.read().split(): 5523 for m in fp.read().split(): 5694 memmode = m.strip('[] 5524 memmode = m.strip('[]') 5695 if memmode == 'deep': 5525 if memmode == 'deep': 5696 deep = True 5526 deep = True 5697 else: 5527 else: 5698 modes.append( 5528 modes.append('mem-%s' % memmode) 5699 fp.close() 5529 fp.close() 5700 if 'mem' in modes and not dee 5530 if 'mem' in modes and not deep: 5701 modes.remove('mem') 5531 modes.remove('mem') 5702 if('disk' in modes and os.path.exists 5532 if('disk' in modes and os.path.exists(sysvals.diskpowerfile)): 5703 fp = open(sysvals.diskpowerfi 5533 fp = open(sysvals.diskpowerfile, 'r') 5704 for m in fp.read().split(): 5534 for m in fp.read().split(): 5705 modes.append('disk-%s 5535 modes.append('disk-%s' % m.strip('[]')) 5706 fp.close() 5536 fp.close() 5707 return modes 5537 return modes 5708 5538 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 5539 # Function: dmidecode 5744 # Description: 5540 # Description: 5745 # Read the bios tables and pull out sy 5541 # Read the bios tables and pull out system info 5746 # Arguments: 5542 # Arguments: 5747 # mempath: /dev/mem or custom mem path 5543 # mempath: /dev/mem or custom mem path 5748 # fatal: True to exit on error, False 5544 # fatal: True to exit on error, False to return empty dict 5749 # Output: 5545 # Output: 5750 # A dict object with all available key 5546 # A dict object with all available key/values 5751 def dmidecode(mempath, fatal=False): 5547 def dmidecode(mempath, fatal=False): 5752 out = dict() 5548 out = dict() 5753 if(not (os.path.exists(mempath) and o << 5754 return dmidecode_backup(out, << 5755 5549 5756 # the list of values to retrieve, wit 5550 # the list of values to retrieve, with hardcoded (type, idx) 5757 info = { 5551 info = { 5758 'bios-vendor': (0, 4), 5552 'bios-vendor': (0, 4), 5759 'bios-version': (0, 5), 5553 'bios-version': (0, 5), 5760 'bios-release-date': (0, 8), 5554 'bios-release-date': (0, 8), 5761 'system-manufacturer': (1, 4) 5555 'system-manufacturer': (1, 4), 5762 'system-product-name': (1, 5) 5556 'system-product-name': (1, 5), 5763 'system-version': (1, 6), 5557 'system-version': (1, 6), 5764 'system-serial-number': (1, 7 5558 'system-serial-number': (1, 7), 5765 'baseboard-manufacturer': (2, 5559 'baseboard-manufacturer': (2, 4), 5766 'baseboard-product-name': (2, 5560 'baseboard-product-name': (2, 5), 5767 'baseboard-version': (2, 6), 5561 'baseboard-version': (2, 6), 5768 'baseboard-serial-number': (2 5562 'baseboard-serial-number': (2, 7), 5769 'chassis-manufacturer': (3, 4 5563 'chassis-manufacturer': (3, 4), >> 5564 'chassis-type': (3, 5), 5770 'chassis-version': (3, 6), 5565 'chassis-version': (3, 6), 5771 'chassis-serial-number': (3, 5566 'chassis-serial-number': (3, 7), 5772 'processor-manufacturer': (4, 5567 'processor-manufacturer': (4, 7), 5773 'processor-version': (4, 16), 5568 'processor-version': (4, 16), 5774 } 5569 } >> 5570 if(not os.path.exists(mempath)): >> 5571 if(fatal): >> 5572 doError('file does not exist: %s' % mempath) >> 5573 return out >> 5574 if(not os.access(mempath, os.R_OK)): >> 5575 if(fatal): >> 5576 doError('file is not readable: %s' % mempath) >> 5577 return out 5775 5578 5776 # by default use legacy scan, but try 5579 # by default use legacy scan, but try to use EFI first 5777 memaddr, memsize = 0xf0000, 0x10000 !! 5580 memaddr = 0xf0000 >> 5581 memsize = 0x10000 5778 for ep in ['/sys/firmware/efi/systab' 5582 for ep in ['/sys/firmware/efi/systab', '/proc/efi/systab']: 5779 if not os.path.exists(ep) or 5583 if not os.path.exists(ep) or not os.access(ep, os.R_OK): 5780 continue 5584 continue 5781 fp = open(ep, 'r') 5585 fp = open(ep, 'r') 5782 buf = fp.read() 5586 buf = fp.read() 5783 fp.close() 5587 fp.close() 5784 i = buf.find('SMBIOS=') 5588 i = buf.find('SMBIOS=') 5785 if i >= 0: 5589 if i >= 0: 5786 try: 5590 try: 5787 memaddr = int 5591 memaddr = int(buf[i+7:], 16) 5788 memsize = 0x2 5592 memsize = 0x20 5789 except: 5593 except: 5790 continue 5594 continue 5791 5595 5792 # read in the memory for scanning 5596 # read in the memory for scanning 5793 try: 5597 try: 5794 fp = open(mempath, 'rb') 5598 fp = open(mempath, 'rb') 5795 fp.seek(memaddr) 5599 fp.seek(memaddr) 5796 buf = fp.read(memsize) 5600 buf = fp.read(memsize) 5797 except: 5601 except: 5798 return dmidecode_backup(out, !! 5602 if(fatal): >> 5603 doError('DMI table is unreachable, sorry') >> 5604 else: >> 5605 pprint('WARNING: /dev/mem is not readable, ignoring DMI data') >> 5606 return out 5799 fp.close() 5607 fp.close() 5800 5608 5801 # search for either an SM table or DM 5609 # search for either an SM table or DMI table 5802 i = base = length = num = 0 5610 i = base = length = num = 0 5803 while(i < memsize): 5611 while(i < memsize): 5804 if buf[i:i+4] == b'_SM_' and 5612 if buf[i:i+4] == b'_SM_' and i < memsize - 16: 5805 length = struct.unpac 5613 length = struct.unpack('H', buf[i+22:i+24])[0] 5806 base, num = struct.un 5614 base, num = struct.unpack('IH', buf[i+24:i+30]) 5807 break 5615 break 5808 elif buf[i:i+5] == b'_DMI_': 5616 elif buf[i:i+5] == b'_DMI_': 5809 length = struct.unpac 5617 length = struct.unpack('H', buf[i+6:i+8])[0] 5810 base, num = struct.un 5618 base, num = struct.unpack('IH', buf[i+8:i+14]) 5811 break 5619 break 5812 i += 16 5620 i += 16 5813 if base == 0 and length == 0 and num 5621 if base == 0 and length == 0 and num == 0: 5814 return dmidecode_backup(out, !! 5622 if(fatal): >> 5623 doError('Neither SMBIOS nor DMI were found') >> 5624 else: >> 5625 return out 5815 5626 5816 # read in the SM or DMI table 5627 # read in the SM or DMI table 5817 try: 5628 try: 5818 fp = open(mempath, 'rb') 5629 fp = open(mempath, 'rb') 5819 fp.seek(base) 5630 fp.seek(base) 5820 buf = fp.read(length) 5631 buf = fp.read(length) 5821 except: 5632 except: 5822 return dmidecode_backup(out, !! 5633 if(fatal): >> 5634 doError('DMI table is unreachable, sorry') >> 5635 else: >> 5636 pprint('WARNING: /dev/mem is not readable, ignoring DMI data') >> 5637 return out 5823 fp.close() 5638 fp.close() 5824 5639 5825 # scan the table for the values we wa 5640 # scan the table for the values we want 5826 count = i = 0 5641 count = i = 0 5827 while(count < num and i <= len(buf) - 5642 while(count < num and i <= len(buf) - 4): 5828 type, size, handle = struct.u 5643 type, size, handle = struct.unpack('BBH', buf[i:i+4]) 5829 n = i + size 5644 n = i + size 5830 while n < len(buf) - 1: 5645 while n < len(buf) - 1: 5831 if 0 == struct.unpack 5646 if 0 == struct.unpack('H', buf[n:n+2])[0]: 5832 break 5647 break 5833 n += 1 5648 n += 1 5834 data = buf[i+size:n+2].split( 5649 data = buf[i+size:n+2].split(b'\0') 5835 for name in info: 5650 for name in info: 5836 itype, idxadr = info[ 5651 itype, idxadr = info[name] 5837 if itype == type: 5652 if itype == type: 5838 idx = struct. 5653 idx = struct.unpack('B', buf[i+idxadr:i+idxadr+1])[0] 5839 if idx > 0 an 5654 if idx > 0 and idx < len(data) - 1: 5840 s = d 5655 s = data[idx-1].decode('utf-8') 5841 if s. 5656 if s.strip() and s.strip().lower() != 'to be filled by o.e.m.': 5842 5657 out[name] = s 5843 i = n + 2 5658 i = n + 2 5844 count += 1 5659 count += 1 5845 return out 5660 return out 5846 5661 5847 # Function: getFPDT 5662 # Function: getFPDT 5848 # Description: 5663 # Description: 5849 # Read the acpi bios tables and pull o 5664 # Read the acpi bios tables and pull out FPDT, the firmware data 5850 # Arguments: 5665 # Arguments: 5851 # output: True to output the info to s 5666 # output: True to output the info to stdout, False otherwise 5852 def getFPDT(output): 5667 def getFPDT(output): 5853 rectype = {} 5668 rectype = {} 5854 rectype[0] = 'Firmware Basic Boot Per 5669 rectype[0] = 'Firmware Basic Boot Performance Record' 5855 rectype[1] = 'S3 Performance Table Re 5670 rectype[1] = 'S3 Performance Table Record' 5856 prectype = {} 5671 prectype = {} 5857 prectype[0] = 'Basic S3 Resume Perfor 5672 prectype[0] = 'Basic S3 Resume Performance Record' 5858 prectype[1] = 'Basic S3 Suspend Perfo 5673 prectype[1] = 'Basic S3 Suspend Performance Record' 5859 5674 5860 sysvals.rootCheck(True) 5675 sysvals.rootCheck(True) 5861 if(not os.path.exists(sysvals.fpdtpat 5676 if(not os.path.exists(sysvals.fpdtpath)): 5862 if(output): 5677 if(output): 5863 doError('file does no 5678 doError('file does not exist: %s' % sysvals.fpdtpath) 5864 return False 5679 return False 5865 if(not os.access(sysvals.fpdtpath, os 5680 if(not os.access(sysvals.fpdtpath, os.R_OK)): 5866 if(output): 5681 if(output): 5867 doError('file is not 5682 doError('file is not readable: %s' % sysvals.fpdtpath) 5868 return False 5683 return False 5869 if(not os.path.exists(sysvals.mempath 5684 if(not os.path.exists(sysvals.mempath)): 5870 if(output): 5685 if(output): 5871 doError('file does no 5686 doError('file does not exist: %s' % sysvals.mempath) 5872 return False 5687 return False 5873 if(not os.access(sysvals.mempath, os. 5688 if(not os.access(sysvals.mempath, os.R_OK)): 5874 if(output): 5689 if(output): 5875 doError('file is not 5690 doError('file is not readable: %s' % sysvals.mempath) 5876 return False 5691 return False 5877 5692 5878 fp = open(sysvals.fpdtpath, 'rb') 5693 fp = open(sysvals.fpdtpath, 'rb') 5879 buf = fp.read() 5694 buf = fp.read() 5880 fp.close() 5695 fp.close() 5881 5696 5882 if(len(buf) < 36): 5697 if(len(buf) < 36): 5883 if(output): 5698 if(output): 5884 doError('Invalid FPDT 5699 doError('Invalid FPDT table data, should '+\ 5885 'be at least 5700 'be at least 36 bytes') 5886 return False 5701 return False 5887 5702 5888 table = struct.unpack('4sIBB6s8sI4sI' 5703 table = struct.unpack('4sIBB6s8sI4sI', buf[0:36]) 5889 if(output): 5704 if(output): 5890 pprint('\n'\ 5705 pprint('\n'\ 5891 'Firmware Performance Data Ta 5706 'Firmware Performance Data Table (%s)\n'\ 5892 ' Signature 5707 ' Signature : %s\n'\ 5893 ' Table Length 5708 ' Table Length : %u\n'\ 5894 ' Revision 5709 ' Revision : %u\n'\ 5895 ' Checksum 5710 ' Checksum : 0x%x\n'\ 5896 ' OEM ID 5711 ' OEM ID : %s\n'\ 5897 ' OEM Table ID 5712 ' OEM Table ID : %s\n'\ 5898 ' OEM Revision 5713 ' OEM Revision : %u\n'\ 5899 ' Creator ID 5714 ' Creator ID : %s\n'\ 5900 ' Creator Revision 5715 ' Creator Revision : 0x%x\n'\ 5901 '' % (ascii(table[0]), ascii( 5716 '' % (ascii(table[0]), ascii(table[0]), table[1], table[2], 5902 table[3], ascii(table 5717 table[3], ascii(table[4]), ascii(table[5]), table[6], 5903 ascii(table[7]), tabl 5718 ascii(table[7]), table[8])) 5904 5719 5905 if(table[0] != b'FPDT'): 5720 if(table[0] != b'FPDT'): 5906 if(output): 5721 if(output): 5907 doError('Invalid FPDT 5722 doError('Invalid FPDT table') 5908 return False 5723 return False 5909 if(len(buf) <= 36): 5724 if(len(buf) <= 36): 5910 return False 5725 return False 5911 i = 0 5726 i = 0 5912 fwData = [0, 0] 5727 fwData = [0, 0] 5913 records = buf[36:] 5728 records = buf[36:] 5914 try: 5729 try: 5915 fp = open(sysvals.mempath, 'r 5730 fp = open(sysvals.mempath, 'rb') 5916 except: 5731 except: 5917 pprint('WARNING: /dev/mem is 5732 pprint('WARNING: /dev/mem is not readable, ignoring the FPDT data') 5918 return False 5733 return False 5919 while(i < len(records)): 5734 while(i < len(records)): 5920 header = struct.unpack('HBB', 5735 header = struct.unpack('HBB', records[i:i+4]) 5921 if(header[0] not in rectype): 5736 if(header[0] not in rectype): 5922 i += header[1] 5737 i += header[1] 5923 continue 5738 continue 5924 if(header[1] != 16): 5739 if(header[1] != 16): 5925 i += header[1] 5740 i += header[1] 5926 continue 5741 continue 5927 addr = struct.unpack('Q', rec 5742 addr = struct.unpack('Q', records[i+8:i+16])[0] 5928 try: 5743 try: 5929 fp.seek(addr) 5744 fp.seek(addr) 5930 first = fp.read(8) 5745 first = fp.read(8) 5931 except: 5746 except: 5932 if(output): 5747 if(output): 5933 pprint('Bad a 5748 pprint('Bad address 0x%x in %s' % (addr, sysvals.mempath)) 5934 return [0, 0] 5749 return [0, 0] 5935 rechead = struct.unpack('4sI' 5750 rechead = struct.unpack('4sI', first) 5936 recdata = fp.read(rechead[1]- 5751 recdata = fp.read(rechead[1]-8) 5937 if(rechead[0] == b'FBPT'): 5752 if(rechead[0] == b'FBPT'): 5938 record = struct.unpac 5753 record = struct.unpack('HBBIQQQQQ', recdata[:48]) 5939 if(output): 5754 if(output): 5940 pprint('%s (% 5755 pprint('%s (%s)\n'\ 5941 ' 5756 ' Reset END : %u ns\n'\ 5942 ' OS Loader 5757 ' OS Loader LoadImage Start : %u ns\n'\ 5943 ' OS Loader S 5758 ' OS Loader StartImage Start : %u ns\n'\ 5944 ' ExitBoo 5759 ' ExitBootServices Entry : %u ns\n'\ 5945 ' ExitBo 5760 ' ExitBootServices Exit : %u ns'\ 5946 '' % (rectype 5761 '' % (rectype[header[0]], ascii(rechead[0]), record[4], record[5], 5947 recor 5762 record[6], record[7], record[8])) 5948 elif(rechead[0] == b'S3PT'): 5763 elif(rechead[0] == b'S3PT'): 5949 if(output): 5764 if(output): 5950 pprint('%s (% 5765 pprint('%s (%s)' % (rectype[header[0]], ascii(rechead[0]))) 5951 j = 0 5766 j = 0 5952 while(j < len(recdata 5767 while(j < len(recdata)): 5953 prechead = st 5768 prechead = struct.unpack('HBB', recdata[j:j+4]) 5954 if(prechead[0 5769 if(prechead[0] not in prectype): 5955 conti 5770 continue 5956 if(prechead[0 5771 if(prechead[0] == 0): 5957 recor 5772 record = struct.unpack('IIQQ', recdata[j:j+prechead[1]]) 5958 fwDat 5773 fwData[1] = record[2] 5959 if(ou 5774 if(output): 5960 5775 pprint(' %s\n'\ 5961 5776 ' Resume Count : %u\n'\ 5962 5777 ' FullResume : %u ns\n'\ 5963 5778 ' AverageResume : %u ns'\ 5964 5779 '' % (prectype[prechead[0]], record[1], 5965 5780 record[2], record[3])) 5966 elif(prechead 5781 elif(prechead[0] == 1): 5967 recor 5782 record = struct.unpack('QQ', recdata[j+4:j+prechead[1]]) 5968 fwDat 5783 fwData[0] = record[1] - record[0] 5969 if(ou 5784 if(output): 5970 5785 pprint(' %s\n'\ 5971 5786 ' SuspendStart : %u ns\n'\ 5972 5787 ' SuspendEnd : %u ns\n'\ 5973 5788 ' SuspendTime : %u ns'\ 5974 5789 '' % (prectype[prechead[0]], record[0], 5975 5790 record[1], fwData[0])) 5976 5791 5977 j += prechead 5792 j += prechead[1] 5978 if(output): 5793 if(output): 5979 pprint('') 5794 pprint('') 5980 i += header[1] 5795 i += header[1] 5981 fp.close() 5796 fp.close() 5982 return fwData 5797 return fwData 5983 5798 5984 # Function: statusCheck 5799 # Function: statusCheck 5985 # Description: 5800 # Description: 5986 # Verify that the requested command an 5801 # Verify that the requested command and options will work, and 5987 # print the results to the terminal 5802 # print the results to the terminal 5988 # Output: 5803 # Output: 5989 # True if the test will work, False if 5804 # True if the test will work, False if not 5990 def statusCheck(probecheck=False): 5805 def statusCheck(probecheck=False): 5991 status = '' 5806 status = '' 5992 5807 5993 pprint('Checking this system (%s)...' 5808 pprint('Checking this system (%s)...' % platform.node()) 5994 5809 5995 # check we have root access 5810 # check we have root access 5996 res = sysvals.colorText('NO (No featu 5811 res = sysvals.colorText('NO (No features of this tool will work!)') 5997 if(sysvals.rootCheck(False)): 5812 if(sysvals.rootCheck(False)): 5998 res = 'YES' 5813 res = 'YES' 5999 pprint(' have root access: %s' % r 5814 pprint(' have root access: %s' % res) 6000 if(res != 'YES'): 5815 if(res != 'YES'): 6001 pprint(' Try running this 5816 pprint(' Try running this script with sudo') 6002 return 'missing root access' 5817 return 'missing root access' 6003 5818 6004 # check sysfs is mounted 5819 # check sysfs is mounted 6005 res = sysvals.colorText('NO (No featu 5820 res = sysvals.colorText('NO (No features of this tool will work!)') 6006 if(os.path.exists(sysvals.powerfile)) 5821 if(os.path.exists(sysvals.powerfile)): 6007 res = 'YES' 5822 res = 'YES' 6008 pprint(' is sysfs mounted: %s' % r 5823 pprint(' is sysfs mounted: %s' % res) 6009 if(res != 'YES'): 5824 if(res != 'YES'): 6010 return 'sysfs is missing' 5825 return 'sysfs is missing' 6011 5826 6012 # check target mode is a valid mode 5827 # check target mode is a valid mode 6013 if sysvals.suspendmode != 'command': 5828 if sysvals.suspendmode != 'command': 6014 res = sysvals.colorText('NO') 5829 res = sysvals.colorText('NO') 6015 modes = getModes() 5830 modes = getModes() 6016 if(sysvals.suspendmode in mod 5831 if(sysvals.suspendmode in modes): 6017 res = 'YES' 5832 res = 'YES' 6018 else: 5833 else: 6019 status = '%s mode is 5834 status = '%s mode is not supported' % sysvals.suspendmode 6020 pprint(' is "%s" a valid p 5835 pprint(' is "%s" a valid power mode: %s' % (sysvals.suspendmode, res)) 6021 if(res == 'NO'): 5836 if(res == 'NO'): 6022 pprint(' valid p 5837 pprint(' valid power modes are: %s' % modes) 6023 pprint(' please 5838 pprint(' please choose one with -m') 6024 5839 6025 # check if ftrace is available 5840 # check if ftrace is available 6026 if sysvals.useftrace: !! 5841 res = sysvals.colorText('NO') 6027 res = sysvals.colorText('NO') !! 5842 ftgood = sysvals.verifyFtrace() 6028 sysvals.useftrace = sysvals.v !! 5843 if(ftgood): 6029 efmt = '"{0}" uses ftrace, an !! 5844 res = 'YES' 6030 if sysvals.useftrace: !! 5845 elif(sysvals.usecallgraph): 6031 res = 'YES' !! 5846 status = 'ftrace is not properly supported' 6032 elif sysvals.usecallgraph: !! 5847 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 5848 6040 # check if kprobes are available 5849 # check if kprobes are available 6041 if sysvals.usekprobes: 5850 if sysvals.usekprobes: 6042 res = sysvals.colorText('NO') 5851 res = sysvals.colorText('NO') 6043 sysvals.usekprobes = sysvals. 5852 sysvals.usekprobes = sysvals.verifyKprobes() 6044 if(sysvals.usekprobes): 5853 if(sysvals.usekprobes): 6045 res = 'YES' 5854 res = 'YES' 6046 else: 5855 else: 6047 sysvals.usedevsrc = F 5856 sysvals.usedevsrc = False 6048 pprint(' are kprobes suppo 5857 pprint(' are kprobes supported: %s' % res) 6049 5858 6050 # what data source are we using 5859 # what data source are we using 6051 res = 'DMESG (very limited, ftrace is !! 5860 res = 'DMESG' 6052 if sysvals.useftrace: !! 5861 if(ftgood): 6053 sysvals.usetraceevents = True 5862 sysvals.usetraceevents = True 6054 for e in sysvals.traceevents: 5863 for e in sysvals.traceevents: 6055 if not os.path.exists 5864 if not os.path.exists(sysvals.epath+e): 6056 sysvals.usetr 5865 sysvals.usetraceevents = False 6057 if(sysvals.usetraceevents): 5866 if(sysvals.usetraceevents): 6058 res = 'FTRACE (all tr 5867 res = 'FTRACE (all trace events found)' 6059 pprint(' timeline data source: %s' 5868 pprint(' timeline data source: %s' % res) 6060 5869 6061 # check if rtcwake 5870 # check if rtcwake 6062 res = sysvals.colorText('NO') 5871 res = sysvals.colorText('NO') 6063 if(sysvals.rtcpath != ''): 5872 if(sysvals.rtcpath != ''): 6064 res = 'YES' 5873 res = 'YES' 6065 elif(sysvals.rtcwake): 5874 elif(sysvals.rtcwake): 6066 status = 'rtcwake is not prop 5875 status = 'rtcwake is not properly supported' 6067 pprint(' is rtcwake supported: %s' 5876 pprint(' is rtcwake supported: %s' % res) 6068 5877 6069 # check info commands 5878 # check info commands 6070 pprint(' optional commands this to 5879 pprint(' optional commands this tool may use for info:') 6071 no = sysvals.colorText('MISSING') 5880 no = sysvals.colorText('MISSING') 6072 yes = sysvals.colorText('FOUND', 32) 5881 yes = sysvals.colorText('FOUND', 32) 6073 for c in ['turbostat', 'mcelog', 'lsp !! 5882 for c in ['turbostat', 'mcelog', 'lspci', 'lsusb']: 6074 if c == 'turbostat': 5883 if c == 'turbostat': 6075 res = yes if sysvals. 5884 res = yes if sysvals.haveTurbostat() else no 6076 else: 5885 else: 6077 res = yes if sysvals. 5886 res = yes if sysvals.getExec(c) else no 6078 pprint(' %s: %s' % (c, 5887 pprint(' %s: %s' % (c, res)) 6079 5888 6080 if not probecheck: 5889 if not probecheck: 6081 return status 5890 return status 6082 5891 6083 # verify kprobes 5892 # verify kprobes 6084 if sysvals.usekprobes: 5893 if sysvals.usekprobes: 6085 for name in sysvals.tracefunc 5894 for name in sysvals.tracefuncs: 6086 sysvals.defaultKprobe 5895 sysvals.defaultKprobe(name, sysvals.tracefuncs[name]) 6087 if sysvals.usedevsrc: 5896 if sysvals.usedevsrc: 6088 for name in sysvals.d 5897 for name in sysvals.dev_tracefuncs: 6089 sysvals.defau 5898 sysvals.defaultKprobe(name, sysvals.dev_tracefuncs[name]) 6090 sysvals.addKprobes(True) 5899 sysvals.addKprobes(True) 6091 5900 6092 return status 5901 return status 6093 5902 6094 # Function: doError 5903 # Function: doError 6095 # Description: 5904 # Description: 6096 # generic error function for catastrph 5905 # generic error function for catastrphic failures 6097 # Arguments: 5906 # Arguments: 6098 # msg: the error message to print 5907 # msg: the error message to print 6099 # help: True if printHelp should be ca 5908 # help: True if printHelp should be called after, False otherwise 6100 def doError(msg, help=False): 5909 def doError(msg, help=False): 6101 if(help == True): 5910 if(help == True): 6102 printHelp() 5911 printHelp() 6103 pprint('ERROR: %s\n' % msg) 5912 pprint('ERROR: %s\n' % msg) 6104 sysvals.outputResult({'error':msg}) 5913 sysvals.outputResult({'error':msg}) 6105 sys.exit(1) 5914 sys.exit(1) 6106 5915 6107 # Function: getArgInt 5916 # Function: getArgInt 6108 # Description: 5917 # Description: 6109 # pull out an integer argument from th 5918 # pull out an integer argument from the command line with checks 6110 def getArgInt(name, args, min, max, main=True 5919 def getArgInt(name, args, min, max, main=True): 6111 if main: 5920 if main: 6112 try: 5921 try: 6113 arg = next(args) 5922 arg = next(args) 6114 except: 5923 except: 6115 doError(name+': no ar 5924 doError(name+': no argument supplied', True) 6116 else: 5925 else: 6117 arg = args 5926 arg = args 6118 try: 5927 try: 6119 val = int(arg) 5928 val = int(arg) 6120 except: 5929 except: 6121 doError(name+': non-integer v 5930 doError(name+': non-integer value given', True) 6122 if(val < min or val > max): 5931 if(val < min or val > max): 6123 doError(name+': value should 5932 doError(name+': value should be between %d and %d' % (min, max), True) 6124 return val 5933 return val 6125 5934 6126 # Function: getArgFloat 5935 # Function: getArgFloat 6127 # Description: 5936 # Description: 6128 # pull out a float argument from the c 5937 # pull out a float argument from the command line with checks 6129 def getArgFloat(name, args, min, max, main=Tr 5938 def getArgFloat(name, args, min, max, main=True): 6130 if main: 5939 if main: 6131 try: 5940 try: 6132 arg = next(args) 5941 arg = next(args) 6133 except: 5942 except: 6134 doError(name+': no ar 5943 doError(name+': no argument supplied', True) 6135 else: 5944 else: 6136 arg = args 5945 arg = args 6137 try: 5946 try: 6138 val = float(arg) 5947 val = float(arg) 6139 except: 5948 except: 6140 doError(name+': non-numerical 5949 doError(name+': non-numerical value given', True) 6141 if(val < min or val > max): 5950 if(val < min or val > max): 6142 doError(name+': value should 5951 doError(name+': value should be between %f and %f' % (min, max), True) 6143 return val 5952 return val 6144 5953 6145 def processData(live=False, quiet=False): 5954 def processData(live=False, quiet=False): 6146 if not quiet: 5955 if not quiet: 6147 pprint('PROCESSING: %s' % sys 5956 pprint('PROCESSING: %s' % sysvals.htmlfile) 6148 sysvals.vprint('usetraceevents=%s, us 5957 sysvals.vprint('usetraceevents=%s, usetracemarkers=%s, usekprobes=%s' % \ 6149 (sysvals.usetraceevents, sysv 5958 (sysvals.usetraceevents, sysvals.usetracemarkers, sysvals.usekprobes)) 6150 error = '' 5959 error = '' 6151 if(sysvals.usetraceevents): 5960 if(sysvals.usetraceevents): 6152 testruns, error = parseTraceL 5961 testruns, error = parseTraceLog(live) 6153 if sysvals.dmesgfile: 5962 if sysvals.dmesgfile: 6154 for data in testruns: 5963 for data in testruns: 6155 data.extractE 5964 data.extractErrorInfo() 6156 else: 5965 else: 6157 testruns = loadKernelLog() 5966 testruns = loadKernelLog() 6158 for data in testruns: 5967 for data in testruns: 6159 parseKernelLog(data) 5968 parseKernelLog(data) 6160 if(sysvals.ftracefile and (sy 5969 if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): 6161 appendIncompleteTrace 5970 appendIncompleteTraceLog(testruns) 6162 if not sysvals.stamp: 5971 if not sysvals.stamp: 6163 pprint('ERROR: data does not 5972 pprint('ERROR: data does not include the expected stamp') 6164 return (testruns, {'error': ' 5973 return (testruns, {'error': 'timeline generation failed'}) 6165 shown = ['os', 'bios', 'biosdate', 'c !! 5974 shown = ['bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr', 6166 'memsz', 'mode', 'num 5975 'memsz', 'mode', 'numcpu', 'plat', 'time', 'wifi'] 6167 sysvals.vprint('System Info:') 5976 sysvals.vprint('System Info:') 6168 for key in sorted(sysvals.stamp): 5977 for key in sorted(sysvals.stamp): 6169 if key in shown: 5978 if key in shown: 6170 sysvals.vprint(' % 5979 sysvals.vprint(' %-8s : %s' % (key.upper(), sysvals.stamp[key])) 6171 sysvals.vprint('Command:\n %s' % s 5980 sysvals.vprint('Command:\n %s' % sysvals.cmdline) 6172 for data in testruns: 5981 for data in testruns: 6173 if data.turbostat: 5982 if data.turbostat: 6174 idx, s = 0, 'Turbosta 5983 idx, s = 0, 'Turbostat:\n ' 6175 for val in data.turbo 5984 for val in data.turbostat.split('|'): 6176 idx += len(va 5985 idx += len(val) + 1 6177 if idx >= 80: 5986 if idx >= 80: 6178 idx = 5987 idx = 0 6179 s += 5988 s += '\n ' 6180 s += val + ' 5989 s += val + ' ' 6181 sysvals.vprint(s) 5990 sysvals.vprint(s) 6182 data.printDetails() 5991 data.printDetails() 6183 if len(sysvals.platinfo) > 0: 5992 if len(sysvals.platinfo) > 0: 6184 sysvals.vprint('\nPlatform In 5993 sysvals.vprint('\nPlatform Info:') 6185 for info in sysvals.platinfo: 5994 for info in sysvals.platinfo: 6186 sysvals.vprint('[%s - 5995 sysvals.vprint('[%s - %s]' % (info[0], info[1])) 6187 sysvals.vprint(info[2 5996 sysvals.vprint(info[2]) 6188 sysvals.vprint('') 5997 sysvals.vprint('') 6189 if sysvals.cgdump: 5998 if sysvals.cgdump: 6190 for data in testruns: 5999 for data in testruns: 6191 data.debugPrint() 6000 data.debugPrint() 6192 sys.exit(0) 6001 sys.exit(0) 6193 if len(testruns) < 1: 6002 if len(testruns) < 1: 6194 pprint('ERROR: Not enough tes 6003 pprint('ERROR: Not enough test data to build a timeline') 6195 return (testruns, {'error': ' 6004 return (testruns, {'error': 'timeline generation failed'}) 6196 sysvals.vprint('Creating the html tim 6005 sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile) 6197 createHTML(testruns, error) 6006 createHTML(testruns, error) 6198 if not quiet: 6007 if not quiet: 6199 pprint('DONE: %s' % sys 6008 pprint('DONE: %s' % sysvals.htmlfile) 6200 data = testruns[0] 6009 data = testruns[0] 6201 stamp = data.stamp 6010 stamp = data.stamp 6202 stamp['suspend'], stamp['resume'] = d 6011 stamp['suspend'], stamp['resume'] = data.getTimeValues() 6203 if data.fwValid: 6012 if data.fwValid: 6204 stamp['fwsuspend'], stamp['fw 6013 stamp['fwsuspend'], stamp['fwresume'] = data.fwSuspend, data.fwResume 6205 if error: 6014 if error: 6206 stamp['error'] = error 6015 stamp['error'] = error 6207 return (testruns, stamp) 6016 return (testruns, stamp) 6208 6017 6209 # Function: rerunTest 6018 # Function: rerunTest 6210 # Description: 6019 # Description: 6211 # generate an output from an existing 6020 # generate an output from an existing set of ftrace/dmesg logs 6212 def rerunTest(htmlfile=''): 6021 def rerunTest(htmlfile=''): 6213 if sysvals.ftracefile: 6022 if sysvals.ftracefile: 6214 doesTraceLogHaveTraceEvents() 6023 doesTraceLogHaveTraceEvents() 6215 if not sysvals.dmesgfile and not sysv 6024 if not sysvals.dmesgfile and not sysvals.usetraceevents: 6216 doError('recreating this html 6025 doError('recreating this html output requires a dmesg file') 6217 if htmlfile: 6026 if htmlfile: 6218 sysvals.htmlfile = htmlfile 6027 sysvals.htmlfile = htmlfile 6219 else: 6028 else: 6220 sysvals.setOutputFile() 6029 sysvals.setOutputFile() 6221 if os.path.exists(sysvals.htmlfile): 6030 if os.path.exists(sysvals.htmlfile): 6222 if not os.path.isfile(sysvals 6031 if not os.path.isfile(sysvals.htmlfile): 6223 doError('a directory 6032 doError('a directory already exists with this name: %s' % sysvals.htmlfile) 6224 elif not os.access(sysvals.ht 6033 elif not os.access(sysvals.htmlfile, os.W_OK): 6225 doError('missing perm 6034 doError('missing permission to write to %s' % sysvals.htmlfile) 6226 testruns, stamp = processData() 6035 testruns, stamp = processData() 6227 sysvals.resetlog() 6036 sysvals.resetlog() 6228 return stamp 6037 return stamp 6229 6038 6230 # Function: runTest 6039 # Function: runTest 6231 # Description: 6040 # Description: 6232 # execute a suspend/resume, gather the 6041 # execute a suspend/resume, gather the logs, and generate the output 6233 def runTest(n=0, quiet=False): 6042 def runTest(n=0, quiet=False): 6234 # prepare for the test 6043 # prepare for the test 6235 sysvals.initTestOutput('suspend') 6044 sysvals.initTestOutput('suspend') 6236 op = sysvals.writeDatafileHeader(sysv 6045 op = sysvals.writeDatafileHeader(sysvals.dmesgfile, []) 6237 op.write('# EXECUTION TRACE START\n') 6046 op.write('# EXECUTION TRACE START\n') 6238 op.close() 6047 op.close() 6239 if n <= 1: 6048 if n <= 1: 6240 if sysvals.rs != 0: 6049 if sysvals.rs != 0: 6241 sysvals.dlog('%sablin 6050 sysvals.dlog('%sabling runtime suspend' % ('en' if sysvals.rs > 0 else 'dis')) 6242 sysvals.setRuntimeSus 6051 sysvals.setRuntimeSuspend(True) 6243 if sysvals.display: 6052 if sysvals.display: 6244 ret = sysvals.display 6053 ret = sysvals.displayControl('init') 6245 sysvals.dlog('xset di 6054 sysvals.dlog('xset display init, ret = %d' % ret) 6246 sysvals.testVal(sysvals.pmdpath, 'bas << 6247 sysvals.testVal(sysvals.s0ixpath, 'ba << 6248 sysvals.dlog('initialize ftrace') 6055 sysvals.dlog('initialize ftrace') 6249 sysvals.initFtrace(quiet) 6056 sysvals.initFtrace(quiet) 6250 6057 6251 # execute the test 6058 # execute the test 6252 executeSuspend(quiet) 6059 executeSuspend(quiet) 6253 sysvals.cleanupFtrace() 6060 sysvals.cleanupFtrace() 6254 if sysvals.skiphtml: 6061 if sysvals.skiphtml: 6255 sysvals.outputResult({}, n) 6062 sysvals.outputResult({}, n) 6256 sysvals.sudoUserchown(sysvals 6063 sysvals.sudoUserchown(sysvals.testdir) 6257 return 6064 return 6258 testruns, stamp = processData(True, q 6065 testruns, stamp = processData(True, quiet) 6259 for data in testruns: 6066 for data in testruns: 6260 del data 6067 del data 6261 sysvals.sudoUserchown(sysvals.testdir 6068 sysvals.sudoUserchown(sysvals.testdir) 6262 sysvals.outputResult(stamp, n) 6069 sysvals.outputResult(stamp, n) 6263 if 'error' in stamp: 6070 if 'error' in stamp: 6264 return 2 6071 return 2 6265 return 0 6072 return 0 6266 6073 6267 def find_in_html(html, start, end, firstonly= 6074 def find_in_html(html, start, end, firstonly=True): 6268 cnt, out, list = len(html), [], [] 6075 cnt, out, list = len(html), [], [] 6269 if firstonly: 6076 if firstonly: 6270 m = re.search(start, html) 6077 m = re.search(start, html) 6271 if m: 6078 if m: 6272 list.append(m) 6079 list.append(m) 6273 else: 6080 else: 6274 list = re.finditer(start, htm 6081 list = re.finditer(start, html) 6275 for match in list: 6082 for match in list: 6276 s = match.end() 6083 s = match.end() 6277 e = cnt if (len(out) < 1 or s 6084 e = cnt if (len(out) < 1 or s + 10000 > cnt) else s + 10000 6278 m = re.search(end, html[s:e]) 6085 m = re.search(end, html[s:e]) 6279 if not m: 6086 if not m: 6280 break 6087 break 6281 e = s + m.start() 6088 e = s + m.start() 6282 str = html[s:e] 6089 str = html[s:e] 6283 if end == 'ms': 6090 if end == 'ms': 6284 num = re.search(r'[-+ 6091 num = re.search(r'[-+]?\d*\.\d+|\d+', str) 6285 str = num.group() if 6092 str = num.group() if num else 'NaN' 6286 if firstonly: 6093 if firstonly: 6287 return str 6094 return str 6288 out.append(str) 6095 out.append(str) 6289 if firstonly: 6096 if firstonly: 6290 return '' 6097 return '' 6291 return out 6098 return out 6292 6099 6293 def data_from_html(file, outpath, issues, ful 6100 def data_from_html(file, outpath, issues, fulldetail=False): 6294 try: !! 6101 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 6102 sysvals.htmlfile = os.path.relpath(file, outpath) 6299 # extract general info 6103 # extract general info 6300 suspend = find_in_html(html, 'Kernel 6104 suspend = find_in_html(html, 'Kernel Suspend', 'ms') 6301 resume = find_in_html(html, 'Kernel R 6105 resume = find_in_html(html, 'Kernel Resume', 'ms') 6302 sysinfo = find_in_html(html, '<div cl 6106 sysinfo = find_in_html(html, '<div class="stamp sysinfo">', '</div>') 6303 line = find_in_html(html, '<div class 6107 line = find_in_html(html, '<div class="stamp">', '</div>') 6304 stmp = line.split() 6108 stmp = line.split() 6305 if not suspend or not resume or len(s 6109 if not suspend or not resume or len(stmp) != 8: 6306 return False 6110 return False 6307 try: 6111 try: 6308 dt = datetime.strptime(' '.jo 6112 dt = datetime.strptime(' '.join(stmp[3:]), '%B %d %Y, %I:%M:%S %p') 6309 except: 6113 except: 6310 return False 6114 return False 6311 sysvals.hostname = stmp[0] 6115 sysvals.hostname = stmp[0] 6312 tstr = dt.strftime('%Y/%m/%d %H:%M:%S 6116 tstr = dt.strftime('%Y/%m/%d %H:%M:%S') 6313 error = find_in_html(html, '<table cl 6117 error = find_in_html(html, '<table class="testfail"><tr><td>', '</td>') 6314 if error: 6118 if error: 6315 m = re.match(r'[a-z0-9]* fail !! 6119 m = re.match('[a-z0-9]* failed in (?P<p>\S*).*', error) 6316 if m: 6120 if m: 6317 result = 'fail in %s' 6121 result = 'fail in %s' % m.group('p') 6318 else: 6122 else: 6319 result = 'fail' 6123 result = 'fail' 6320 else: 6124 else: 6321 result = 'pass' 6125 result = 'pass' 6322 # extract error info 6126 # extract error info 6323 tp, ilist = False, [] 6127 tp, ilist = False, [] 6324 extra = dict() 6128 extra = dict() 6325 log = find_in_html(html, '<div id="dm 6129 log = find_in_html(html, '<div id="dmesglog" style="display:none;">', 6326 '</div>').strip() 6130 '</div>').strip() 6327 if log: 6131 if log: 6328 d = Data(0) 6132 d = Data(0) 6329 d.end = 999999999 6133 d.end = 999999999 6330 d.dmesgtext = log.split('\n') 6134 d.dmesgtext = log.split('\n') 6331 tp = d.extractErrorInfo() 6135 tp = d.extractErrorInfo() 6332 if len(issues) < 100: !! 6136 for msg in tp.msglist: 6333 for msg in tp.msglist !! 6137 sysvals.errorSummary(issues, msg) 6334 sysvals.error << 6335 if stmp[2] == 'freeze': 6138 if stmp[2] == 'freeze': 6336 extra = d.turbostatIn 6139 extra = d.turbostatInfo() 6337 elist = dict() 6140 elist = dict() 6338 for dir in d.errorinfo: 6141 for dir in d.errorinfo: 6339 for err in d.errorinf 6142 for err in d.errorinfo[dir]: 6340 if err[0] not 6143 if err[0] not in elist: 6341 elist 6144 elist[err[0]] = 0 6342 elist[err[0]] 6145 elist[err[0]] += 1 6343 for i in elist: 6146 for i in elist: 6344 ilist.append('%sx%d' 6147 ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i) 6345 line = find_in_html(log, '# w !! 6148 wifi = find_in_html(html, 'Wifi Resume: ', '</td>') 6346 if line: !! 6149 if wifi: 6347 extra['wifi'] = line !! 6150 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 6151 low = find_in_html(html, 'freeze time: <b>', ' ms</b>') 6357 for lowstr in ['waking', '+']: 6152 for lowstr in ['waking', '+']: 6358 if not low: 6153 if not low: 6359 break 6154 break 6360 if lowstr not in low: 6155 if lowstr not in low: 6361 continue 6156 continue 6362 if lowstr == '+': 6157 if lowstr == '+': 6363 issue = 'S2LOOPx%d' % 6158 issue = 'S2LOOPx%d' % len(low.split('+')) 6364 else: 6159 else: 6365 m = re.match(r'.*waki !! 6160 m = re.match('.*waking *(?P<n>[0-9]*) *times.*', low) 6366 issue = 'S2WAKEx%s' % 6161 issue = 'S2WAKEx%s' % m.group('n') if m else 'S2WAKExNaN' 6367 match = [i for i in issues if 6162 match = [i for i in issues if i['match'] == issue] 6368 if len(match) > 0: 6163 if len(match) > 0: 6369 match[0]['count'] += 6164 match[0]['count'] += 1 6370 if sysvals.hostname n 6165 if sysvals.hostname not in match[0]['urls']: 6371 match[0]['url 6166 match[0]['urls'][sysvals.hostname] = [sysvals.htmlfile] 6372 elif sysvals.htmlfile 6167 elif sysvals.htmlfile not in match[0]['urls'][sysvals.hostname]: 6373 match[0]['url 6168 match[0]['urls'][sysvals.hostname].append(sysvals.htmlfile) 6374 else: 6169 else: 6375 issues.append({ 6170 issues.append({ 6376 'match': issu 6171 'match': issue, 'count': 1, 'line': issue, 6377 'urls': {sysv 6172 'urls': {sysvals.hostname: [sysvals.htmlfile]}, 6378 }) 6173 }) 6379 ilist.append(issue) 6174 ilist.append(issue) 6380 # extract device info 6175 # extract device info 6381 devices = dict() 6176 devices = dict() 6382 for line in html.split('\n'): 6177 for line in html.split('\n'): 6383 m = re.match(r' *<div id=\"[a !! 6178 m = re.match(' *<div id=\"[a,0-9]*\" *title=\"(?P<title>.*)\" class=\"thread.*', line) 6384 if not m or 'thread kth' in l 6179 if not m or 'thread kth' in line or 'thread sec' in line: 6385 continue 6180 continue 6386 m = re.match(r'(?P<n>.*) \((? !! 6181 m = re.match('(?P<n>.*) \((?P<t>[0-9,\.]*) ms\) (?P<p>.*)', m.group('title')) 6387 if not m: 6182 if not m: 6388 continue 6183 continue 6389 name, time, phase = m.group(' 6184 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 6185 if ' async' in name or ' sync' in name: 6393 name = ' '.join(name. 6186 name = ' '.join(name.split(' ')[:-1]) 6394 if phase.startswith('suspend' 6187 if phase.startswith('suspend'): 6395 d = 'suspend' 6188 d = 'suspend' 6396 elif phase.startswith('resume 6189 elif phase.startswith('resume'): 6397 d = 'resume' 6190 d = 'resume' 6398 else: 6191 else: 6399 continue 6192 continue 6400 if d not in devices: 6193 if d not in devices: 6401 devices[d] = dict() 6194 devices[d] = dict() 6402 if name not in devices[d]: 6195 if name not in devices[d]: 6403 devices[d][name] = 0. 6196 devices[d][name] = 0.0 6404 devices[d][name] += float(tim 6197 devices[d][name] += float(time) 6405 # create worst device info 6198 # create worst device info 6406 worst = dict() 6199 worst = dict() 6407 for d in ['suspend', 'resume']: 6200 for d in ['suspend', 'resume']: 6408 worst[d] = {'name':'', 'time' 6201 worst[d] = {'name':'', 'time': 0.0} 6409 dev = devices[d] if d in devi 6202 dev = devices[d] if d in devices else 0 6410 if dev and len(dev.keys()) > 6203 if dev and len(dev.keys()) > 0: 6411 n = sorted(dev, key=l 6204 n = sorted(dev, key=lambda k:(dev[k], k), reverse=True)[0] 6412 worst[d]['name'], wor 6205 worst[d]['name'], worst[d]['time'] = n, dev[n] 6413 data = { 6206 data = { 6414 'mode': stmp[2], 6207 'mode': stmp[2], 6415 'host': stmp[0], 6208 'host': stmp[0], 6416 'kernel': stmp[1], 6209 'kernel': stmp[1], 6417 'sysinfo': sysinfo, 6210 'sysinfo': sysinfo, 6418 'time': tstr, 6211 'time': tstr, 6419 'result': result, 6212 'result': result, 6420 'issues': ' '.join(ilist), 6213 'issues': ' '.join(ilist), 6421 'suspend': suspend, 6214 'suspend': suspend, 6422 'resume': resume, 6215 'resume': resume, 6423 'devlist': devices, 6216 'devlist': devices, 6424 'sus_worst': worst['suspend'] 6217 'sus_worst': worst['suspend']['name'], 6425 'sus_worsttime': worst['suspe 6218 'sus_worsttime': worst['suspend']['time'], 6426 'res_worst': worst['resume'][ 6219 'res_worst': worst['resume']['name'], 6427 'res_worsttime': worst['resum 6220 'res_worsttime': worst['resume']['time'], 6428 'url': sysvals.htmlfile, 6221 'url': sysvals.htmlfile, 6429 } 6222 } 6430 for key in extra: 6223 for key in extra: 6431 data[key] = extra[key] 6224 data[key] = extra[key] 6432 if fulldetail: 6225 if fulldetail: 6433 data['funclist'] = find_in_ht 6226 data['funclist'] = find_in_html(html, '<div title="', '" class="traceevent"', False) 6434 if tp: 6227 if tp: 6435 for arg in ['-multi ', '-info 6228 for arg in ['-multi ', '-info ']: 6436 if arg in tp.cmdline: 6229 if arg in tp.cmdline: 6437 data['target' 6230 data['target'] = tp.cmdline[tp.cmdline.find(arg):].split()[1] 6438 break 6231 break 6439 return data 6232 return data 6440 6233 6441 def genHtml(subdir, force=False): 6234 def genHtml(subdir, force=False): 6442 for dirname, dirnames, filenames in o 6235 for dirname, dirnames, filenames in os.walk(subdir): 6443 sysvals.dmesgfile = sysvals.f 6236 sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = '' 6444 for filename in filenames: 6237 for filename in filenames: 6445 file = os.path.join(d 6238 file = os.path.join(dirname, filename) 6446 if sysvals.usable(fil 6239 if sysvals.usable(file): 6447 if(re.match(r !! 6240 if(re.match('.*_dmesg.txt', filename)): 6448 sysva 6241 sysvals.dmesgfile = file 6449 elif(re.match !! 6242 elif(re.match('.*_ftrace.txt', filename)): 6450 sysva 6243 sysvals.ftracefile = file 6451 sysvals.setOutputFile() 6244 sysvals.setOutputFile() 6452 if (sysvals.dmesgfile or sysv 6245 if (sysvals.dmesgfile or sysvals.ftracefile) and sysvals.htmlfile and \ 6453 (force or not sysvals !! 6246 (force or not sysvals.usable(sysvals.htmlfile)): 6454 pprint('FTRACE: %s' % 6247 pprint('FTRACE: %s' % sysvals.ftracefile) 6455 if sysvals.dmesgfile: 6248 if sysvals.dmesgfile: 6456 pprint('DMESG 6249 pprint('DMESG : %s' % sysvals.dmesgfile) 6457 rerunTest() 6250 rerunTest() 6458 6251 6459 # Function: runSummary 6252 # Function: runSummary 6460 # Description: 6253 # Description: 6461 # create a summary of tests in a sub-d 6254 # create a summary of tests in a sub-directory 6462 def runSummary(subdir, local=True, genhtml=Fa 6255 def runSummary(subdir, local=True, genhtml=False): 6463 inpath = os.path.abspath(subdir) 6256 inpath = os.path.abspath(subdir) 6464 outpath = os.path.abspath('.') if loc 6257 outpath = os.path.abspath('.') if local else inpath 6465 pprint('Generating a summary of folde 6258 pprint('Generating a summary of folder:\n %s' % inpath) 6466 if genhtml: 6259 if genhtml: 6467 genHtml(subdir) 6260 genHtml(subdir) 6468 target, issues, testruns = '', [], [] 6261 target, issues, testruns = '', [], [] 6469 desc = {'host':[],'mode':[],'kernel': 6262 desc = {'host':[],'mode':[],'kernel':[]} 6470 for dirname, dirnames, filenames in o 6263 for dirname, dirnames, filenames in os.walk(subdir): 6471 for filename in filenames: 6264 for filename in filenames: 6472 if(not re.match(r'.*. !! 6265 if(not re.match('.*.html', filename)): 6473 continue 6266 continue 6474 data = data_from_html 6267 data = data_from_html(os.path.join(dirname, filename), outpath, issues) 6475 if(not data): 6268 if(not data): 6476 continue 6269 continue 6477 if 'target' in data: 6270 if 'target' in data: 6478 target = data 6271 target = data['target'] 6479 testruns.append(data) 6272 testruns.append(data) 6480 for key in desc: 6273 for key in desc: 6481 if data[key] 6274 if data[key] not in desc[key]: 6482 desc[ 6275 desc[key].append(data[key]) 6483 pprint('Summary files:') 6276 pprint('Summary files:') 6484 if len(desc['host']) == len(desc['mod 6277 if len(desc['host']) == len(desc['mode']) == len(desc['kernel']) == 1: 6485 title = '%s %s %s' % (desc['h 6278 title = '%s %s %s' % (desc['host'][0], desc['kernel'][0], desc['mode'][0]) 6486 if target: 6279 if target: 6487 title += ' %s' % targ 6280 title += ' %s' % target 6488 else: 6281 else: 6489 title = inpath 6282 title = inpath 6490 createHTMLSummarySimple(testruns, os. 6283 createHTMLSummarySimple(testruns, os.path.join(outpath, 'summary.html'), title) 6491 pprint(' summary.html - tab 6284 pprint(' summary.html - tabular list of test data found') 6492 createHTMLDeviceSummary(testruns, os. 6285 createHTMLDeviceSummary(testruns, os.path.join(outpath, 'summary-devices.html'), title) 6493 pprint(' summary-devices.html - ker 6286 pprint(' summary-devices.html - kernel device list sorted by total execution time') 6494 createHTMLIssuesSummary(testruns, iss 6287 createHTMLIssuesSummary(testruns, issues, os.path.join(outpath, 'summary-issues.html'), title) 6495 pprint(' summary-issues.html - ker 6288 pprint(' summary-issues.html - kernel issues found sorted by frequency') 6496 6289 6497 # Function: checkArgBool 6290 # Function: checkArgBool 6498 # Description: 6291 # Description: 6499 # check if a boolean string value is t 6292 # check if a boolean string value is true or false 6500 def checkArgBool(name, value): 6293 def checkArgBool(name, value): 6501 if value in switchvalues: 6294 if value in switchvalues: 6502 if value in switchoff: 6295 if value in switchoff: 6503 return False 6296 return False 6504 return True 6297 return True 6505 doError('invalid boolean --> (%s: %s) 6298 doError('invalid boolean --> (%s: %s), use "true/false" or "1/0"' % (name, value), True) 6506 return False 6299 return False 6507 6300 6508 # Function: configFromFile 6301 # Function: configFromFile 6509 # Description: 6302 # Description: 6510 # Configure the script via the info in 6303 # Configure the script via the info in a config file 6511 def configFromFile(file): 6304 def configFromFile(file): 6512 Config = configparser.ConfigParser() 6305 Config = configparser.ConfigParser() 6513 6306 6514 Config.read(file) 6307 Config.read(file) 6515 sections = Config.sections() 6308 sections = Config.sections() 6516 overridekprobes = False 6309 overridekprobes = False 6517 overridedevkprobes = False 6310 overridedevkprobes = False 6518 if 'Settings' in sections: 6311 if 'Settings' in sections: 6519 for opt in Config.options('Se 6312 for opt in Config.options('Settings'): 6520 value = Config.get('S 6313 value = Config.get('Settings', opt).lower() 6521 option = opt.lower() 6314 option = opt.lower() 6522 if(option == 'verbose 6315 if(option == 'verbose'): 6523 sysvals.verbo 6316 sysvals.verbose = checkArgBool(option, value) 6524 elif(option == 'addlo 6317 elif(option == 'addlogs'): 6525 sysvals.dmesg 6318 sysvals.dmesglog = sysvals.ftracelog = checkArgBool(option, value) 6526 elif(option == 'dev') 6319 elif(option == 'dev'): 6527 sysvals.usede 6320 sysvals.usedevsrc = checkArgBool(option, value) 6528 elif(option == 'proc' 6321 elif(option == 'proc'): 6529 sysvals.usepr 6322 sysvals.useprocmon = checkArgBool(option, value) 6530 elif(option == 'x2'): 6323 elif(option == 'x2'): 6531 if checkArgBo 6324 if checkArgBool(option, value): 6532 sysva 6325 sysvals.execcount = 2 6533 elif(option == 'callg 6326 elif(option == 'callgraph'): 6534 sysvals.useca 6327 sysvals.usecallgraph = checkArgBool(option, value) 6535 elif(option == 'overr 6328 elif(option == 'override-timeline-functions'): 6536 overridekprob 6329 overridekprobes = checkArgBool(option, value) 6537 elif(option == 'overr 6330 elif(option == 'override-dev-timeline-functions'): 6538 overridedevkp 6331 overridedevkprobes = checkArgBool(option, value) 6539 elif(option == 'skiph 6332 elif(option == 'skiphtml'): 6540 sysvals.skiph 6333 sysvals.skiphtml = checkArgBool(option, value) 6541 elif(option == 'sync' 6334 elif(option == 'sync'): 6542 sysvals.sync 6335 sysvals.sync = checkArgBool(option, value) 6543 elif(option == 'rs' o 6336 elif(option == 'rs' or option == 'runtimesuspend'): 6544 if value in s 6337 if value in switchvalues: 6545 if va 6338 if value in switchoff: 6546 6339 sysvals.rs = -1 6547 else: 6340 else: 6548 6341 sysvals.rs = 1 6549 else: 6342 else: 6550 doErr 6343 doError('invalid value --> (%s: %s), use "enable/disable"' % (option, value), True) 6551 elif(option == 'displ 6344 elif(option == 'display'): 6552 disopt = ['on 6345 disopt = ['on', 'off', 'standby', 'suspend'] 6553 if value not 6346 if value not in disopt: 6554 doErr 6347 doError('invalid value --> (%s: %s), use %s' % (option, value, disopt), True) 6555 sysvals.displ 6348 sysvals.display = value 6556 elif(option == 'gzip' 6349 elif(option == 'gzip'): 6557 sysvals.gzip 6350 sysvals.gzip = checkArgBool(option, value) 6558 elif(option == 'cgfil 6351 elif(option == 'cgfilter'): 6559 sysvals.setCa 6352 sysvals.setCallgraphFilter(value) 6560 elif(option == 'cgski 6353 elif(option == 'cgskip'): 6561 if value in s 6354 if value in switchoff: 6562 sysva 6355 sysvals.cgskip = '' 6563 else: 6356 else: 6564 sysva 6357 sysvals.cgskip = sysvals.configFile(val) 6565 if(no 6358 if(not sysvals.cgskip): 6566 6359 doError('%s does not exist' % sysvals.cgskip) 6567 elif(option == 'cgtes 6360 elif(option == 'cgtest'): 6568 sysvals.cgtes 6361 sysvals.cgtest = getArgInt('cgtest', value, 0, 1, False) 6569 elif(option == 'cgpha 6362 elif(option == 'cgphase'): 6570 d = Data(0) 6363 d = Data(0) 6571 if value not 6364 if value not in d.phasedef: 6572 doErr 6365 doError('invalid phase --> (%s: %s), valid phases are %s'\ 6573 6366 % (option, value, d.phasedef.keys()), True) 6574 sysvals.cgpha 6367 sysvals.cgphase = value 6575 elif(option == 'fadd' 6368 elif(option == 'fadd'): 6576 file = sysval 6369 file = sysvals.configFile(value) 6577 if(not file): 6370 if(not file): 6578 doErr 6371 doError('%s does not exist' % value) 6579 sysvals.addFt 6372 sysvals.addFtraceFilterFunctions(file) 6580 elif(option == 'resul 6373 elif(option == 'result'): 6581 sysvals.resul 6374 sysvals.result = value 6582 elif(option == 'multi 6375 elif(option == 'multi'): 6583 nums = value. 6376 nums = value.split() 6584 if len(nums) 6377 if len(nums) != 2: 6585 doErr 6378 doError('multi requires 2 integers (exec_count and delay)', True) 6586 sysvals.multi 6379 sysvals.multiinit(nums[0], nums[1]) 6587 elif(option == 'devic 6380 elif(option == 'devicefilter'): 6588 sysvals.setDe 6381 sysvals.setDeviceFilter(value) 6589 elif(option == 'expan 6382 elif(option == 'expandcg'): 6590 sysvals.cgexp 6383 sysvals.cgexp = checkArgBool(option, value) 6591 elif(option == 'srgap 6384 elif(option == 'srgap'): 6592 if checkArgBo 6385 if checkArgBool(option, value): 6593 sysva 6386 sysvals.srgap = 5 6594 elif(option == 'mode' 6387 elif(option == 'mode'): 6595 sysvals.suspe 6388 sysvals.suspendmode = value 6596 elif(option == 'comma 6389 elif(option == 'command' or option == 'cmd'): 6597 sysvals.testc 6390 sysvals.testcommand = value 6598 elif(option == 'x2del 6391 elif(option == 'x2delay'): 6599 sysvals.x2del 6392 sysvals.x2delay = getArgInt('x2delay', value, 0, 60000, False) 6600 elif(option == 'prede 6393 elif(option == 'predelay'): 6601 sysvals.prede 6394 sysvals.predelay = getArgInt('predelay', value, 0, 60000, False) 6602 elif(option == 'postd 6395 elif(option == 'postdelay'): 6603 sysvals.postd 6396 sysvals.postdelay = getArgInt('postdelay', value, 0, 60000, False) 6604 elif(option == 'maxde 6397 elif(option == 'maxdepth'): 6605 sysvals.max_g 6398 sysvals.max_graph_depth = getArgInt('maxdepth', value, 0, 1000, False) 6606 elif(option == 'rtcwa 6399 elif(option == 'rtcwake'): 6607 if value in s 6400 if value in switchoff: 6608 sysva 6401 sysvals.rtcwake = False 6609 else: 6402 else: 6610 sysva 6403 sysvals.rtcwake = True 6611 sysva 6404 sysvals.rtcwaketime = getArgInt('rtcwake', value, 0, 3600, False) 6612 elif(option == 'timep 6405 elif(option == 'timeprec'): 6613 sysvals.setPr 6406 sysvals.setPrecision(getArgInt('timeprec', value, 0, 6, False)) 6614 elif(option == 'minde 6407 elif(option == 'mindev'): 6615 sysvals.minde 6408 sysvals.mindevlen = getArgFloat('mindev', value, 0.0, 10000.0, False) 6616 elif(option == 'calll 6409 elif(option == 'callloop-maxgap'): 6617 sysvals.calll 6410 sysvals.callloopmaxgap = getArgFloat('callloop-maxgap', value, 0.0, 1.0, False) 6618 elif(option == 'calll 6411 elif(option == 'callloop-maxlen'): 6619 sysvals.calll 6412 sysvals.callloopmaxgap = getArgFloat('callloop-maxlen', value, 0.0, 1.0, False) 6620 elif(option == 'mincg 6413 elif(option == 'mincg'): 6621 sysvals.mincg 6414 sysvals.mincglen = getArgFloat('mincg', value, 0.0, 10000.0, False) 6622 elif(option == 'bufsi 6415 elif(option == 'bufsize'): 6623 sysvals.bufsi 6416 sysvals.bufsize = getArgInt('bufsize', value, 1, 1024*1024*8, False) 6624 elif(option == 'outpu 6417 elif(option == 'output-dir'): 6625 sysvals.outdi 6418 sysvals.outdir = sysvals.setOutputFolder(value) 6626 6419 6627 if sysvals.suspendmode == 'command' a 6420 if sysvals.suspendmode == 'command' and not sysvals.testcommand: 6628 doError('No command supplied 6421 doError('No command supplied for mode "command"') 6629 6422 6630 # compatibility errors 6423 # compatibility errors 6631 if sysvals.usedevsrc and sysvals.usec 6424 if sysvals.usedevsrc and sysvals.usecallgraph: 6632 doError('-dev is not compatib 6425 doError('-dev is not compatible with -f') 6633 if sysvals.usecallgraph and sysvals.u 6426 if sysvals.usecallgraph and sysvals.useprocmon: 6634 doError('-proc is not compati 6427 doError('-proc is not compatible with -f') 6635 6428 6636 if overridekprobes: 6429 if overridekprobes: 6637 sysvals.tracefuncs = dict() 6430 sysvals.tracefuncs = dict() 6638 if overridedevkprobes: 6431 if overridedevkprobes: 6639 sysvals.dev_tracefuncs = dict 6432 sysvals.dev_tracefuncs = dict() 6640 6433 6641 kprobes = dict() 6434 kprobes = dict() 6642 kprobesec = 'dev_timeline_functions_' 6435 kprobesec = 'dev_timeline_functions_'+platform.machine() 6643 if kprobesec in sections: 6436 if kprobesec in sections: 6644 for name in Config.options(kp 6437 for name in Config.options(kprobesec): 6645 text = Config.get(kpr 6438 text = Config.get(kprobesec, name) 6646 kprobes[name] = (text 6439 kprobes[name] = (text, True) 6647 kprobesec = 'timeline_functions_'+pla 6440 kprobesec = 'timeline_functions_'+platform.machine() 6648 if kprobesec in sections: 6441 if kprobesec in sections: 6649 for name in Config.options(kp 6442 for name in Config.options(kprobesec): 6650 if name in kprobes: 6443 if name in kprobes: 6651 doError('Dupl 6444 doError('Duplicate timeline function found "%s"' % (name)) 6652 text = Config.get(kpr 6445 text = Config.get(kprobesec, name) 6653 kprobes[name] = (text 6446 kprobes[name] = (text, False) 6654 6447 6655 for name in kprobes: 6448 for name in kprobes: 6656 function = name 6449 function = name 6657 format = name 6450 format = name 6658 color = '' 6451 color = '' 6659 args = dict() 6452 args = dict() 6660 text, dev = kprobes[name] 6453 text, dev = kprobes[name] 6661 data = text.split() 6454 data = text.split() 6662 i = 0 6455 i = 0 6663 for val in data: 6456 for val in data: 6664 # bracketted strings 6457 # bracketted strings are special formatting, read them separately 6665 if val[0] == '[' and 6458 if val[0] == '[' and val[-1] == ']': 6666 for prop in v 6459 for prop in val[1:-1].split(','): 6667 p = p 6460 p = prop.split('=') 6668 if p[ 6461 if p[0] == 'color': 6669 6462 try: 6670 6463 color = int(p[1], 16) 6671 6464 color = '#'+p[1] 6672 6465 except: 6673 6466 color = p[1] 6674 continue 6467 continue 6675 # first real arg shou 6468 # first real arg should be the format string 6676 if i == 0: 6469 if i == 0: 6677 format = val 6470 format = val 6678 # all other args are 6471 # all other args are actual function args 6679 else: 6472 else: 6680 d = val.split 6473 d = val.split('=') 6681 args[d[0]] = 6474 args[d[0]] = d[1] 6682 i += 1 6475 i += 1 6683 if not function or not format 6476 if not function or not format: 6684 doError('Invalid kpro 6477 doError('Invalid kprobe: %s' % name) 6685 for arg in re.findall('{(?P<n 6478 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format): 6686 if arg not in args: 6479 if arg not in args: 6687 doError('Kpro 6480 doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 6688 if (dev and name in sysvals.d 6481 if (dev and name in sysvals.dev_tracefuncs) or (not dev and name in sysvals.tracefuncs): 6689 doError('Duplicate ti 6482 doError('Duplicate timeline function found "%s"' % (name)) 6690 6483 6691 kp = { 6484 kp = { 6692 'name': name, 6485 'name': name, 6693 'func': function, 6486 'func': function, 6694 'format': format, 6487 'format': format, 6695 sysvals.archargs: arg 6488 sysvals.archargs: args 6696 } 6489 } 6697 if color: 6490 if color: 6698 kp['color'] = color 6491 kp['color'] = color 6699 if dev: 6492 if dev: 6700 sysvals.dev_tracefunc 6493 sysvals.dev_tracefuncs[name] = kp 6701 else: 6494 else: 6702 sysvals.tracefuncs[na 6495 sysvals.tracefuncs[name] = kp 6703 6496 6704 # Function: printHelp 6497 # Function: printHelp 6705 # Description: 6498 # Description: 6706 # print out the help text 6499 # print out the help text 6707 def printHelp(): 6500 def printHelp(): 6708 pprint('\n%s v%s\n'\ 6501 pprint('\n%s v%s\n'\ 6709 'Usage: sudo sleepgraph <options> <co 6502 'Usage: sudo sleepgraph <options> <commands>\n'\ 6710 '\n'\ 6503 '\n'\ 6711 'Description:\n'\ 6504 'Description:\n'\ 6712 ' This tool is designed to assist ke 6505 ' This tool is designed to assist kernel and OS developers in optimizing\n'\ 6713 ' their linux stack\'s suspend/resum 6506 ' their linux stack\'s suspend/resume time. Using a kernel image built\n'\ 6714 ' with a few extra options enabled, 6507 ' with a few extra options enabled, the tool will execute a suspend and\n'\ 6715 ' capture dmesg and ftrace data unti 6508 ' capture dmesg and ftrace data until resume is complete. This data is\n'\ 6716 ' transformed into a device timeline 6509 ' transformed into a device timeline and an optional callgraph to give\n'\ 6717 ' a detailed view of which devices/s 6510 ' a detailed view of which devices/subsystems are taking the most\n'\ 6718 ' time in suspend/resume.\n'\ 6511 ' time in suspend/resume.\n'\ 6719 '\n'\ 6512 '\n'\ 6720 ' If no specific command is given, t 6513 ' If no specific command is given, the default behavior is to initiate\n'\ 6721 ' a suspend/resume and capture the d 6514 ' a suspend/resume and capture the dmesg/ftrace output as an html timeline.\n'\ 6722 '\n'\ 6515 '\n'\ 6723 ' Generates output files in subdirec 6516 ' Generates output files in subdirectory: suspend-yymmdd-HHMMSS\n'\ 6724 ' HTML output: < 6517 ' HTML output: <hostname>_<mode>.html\n'\ 6725 ' raw dmesg output: < 6518 ' raw dmesg output: <hostname>_<mode>_dmesg.txt\n'\ 6726 ' raw ftrace output: < 6519 ' raw ftrace output: <hostname>_<mode>_ftrace.txt\n'\ 6727 '\n'\ 6520 '\n'\ 6728 'Options:\n'\ 6521 'Options:\n'\ 6729 ' -h Print this help text 6522 ' -h Print this help text\n'\ 6730 ' -v Print the current to 6523 ' -v Print the current tool version\n'\ 6731 ' -config fn Pull arguments and c 6524 ' -config fn Pull arguments and config options from file fn\n'\ 6732 ' -verbose Print extra informat 6525 ' -verbose Print extra information during execution and analysis\n'\ 6733 ' -m mode Mode to initiate for 6526 ' -m mode Mode to initiate for suspend (default: %s)\n'\ 6734 ' -o name Overrides the output 6527 ' -o name Overrides the output subdirectory name when running a new test\n'\ 6735 ' default: suspend-{da 6528 ' default: suspend-{date}-{time}\n'\ 6736 ' -rtcwake t Wakeup t seconds aft 6529 ' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)\n'\ 6737 ' -addlogs Add the dmesg and ft 6530 ' -addlogs Add the dmesg and ftrace logs to the html output\n'\ 6738 ' -noturbostat Dont use turbostat i 6531 ' -noturbostat Dont use turbostat in freeze mode (default: disabled)\n'\ 6739 ' -srgap Add a visible gap in 6532 ' -srgap Add a visible gap in the timeline between sus/res (default: disabled)\n'\ 6740 ' -skiphtml Run the test and cap 6533 ' -skiphtml Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\ 6741 ' -result fn Export a results tab 6534 ' -result fn Export a results table to a text file for parsing.\n'\ 6742 ' -wifi If a wifi connection 6535 ' -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'\ 6536 ' [testprep]\n'\ 6746 ' -sync Sync the filesystems 6537 ' -sync Sync the filesystems before starting the test\n'\ 6747 ' -rs on/off Enable/disable runti 6538 ' -rs on/off Enable/disable runtime suspend for all devices, restore all after test\n'\ 6748 ' -display m Change the display m 6539 ' -display m Change the display mode to m for the test (on/off/standby/suspend)\n'\ 6749 ' [advanced]\n'\ 6540 ' [advanced]\n'\ 6750 ' -gzip Gzip the trace and d 6541 ' -gzip Gzip the trace and dmesg logs to save space\n'\ 6751 ' -cmd {s} Run the timeline ove 6542 ' -cmd {s} Run the timeline over a custom command, e.g. "sync -d"\n'\ 6752 ' -proc Add usermode process 6543 ' -proc Add usermode process info into the timeline (default: disabled)\n'\ 6753 ' -dev Add kernel function 6544 ' -dev Add kernel function calls and threads to the timeline (default: disabled)\n'\ 6754 ' -x2 Run two suspend/resu 6545 ' -x2 Run two suspend/resumes back to back (default: disabled)\n'\ 6755 ' -x2delay t Include t ms delay b 6546 ' -x2delay t Include t ms delay between multiple test runs (default: 0 ms)\n'\ 6756 ' -predelay t Include t ms delay b 6547 ' -predelay t Include t ms delay before 1st suspend (default: 0 ms)\n'\ 6757 ' -postdelay t Include t ms delay a 6548 ' -postdelay t Include t ms delay after last resume (default: 0 ms)\n'\ 6758 ' -mindev ms Discard all device b 6549 ' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 6759 ' -multi n d Execute <n> consecut 6550 ' -multi n d Execute <n> consecutive tests at <d> seconds intervals. If <n> is followed\n'\ 6760 ' by a "d", "h", or "m 6551 ' by a "d", "h", or "m" execute for <n> days, hours, or mins instead.\n'\ 6761 ' The outputs will be 6552 ' The outputs will be created in a new subdirectory with a summary page.\n'\ 6762 ' -maxfail n Abort a -multi run a 6553 ' -maxfail n Abort a -multi run after n consecutive fails (default is 0 = never abort)\n'\ 6763 ' [debug]\n'\ 6554 ' [debug]\n'\ 6764 ' -f Use ftrace to create 6555 ' -f Use ftrace to create device callgraphs (default: disabled)\n'\ 6765 ' -ftop Use ftrace on the to 6556 ' -ftop Use ftrace on the top level call: "%s" (default: disabled)\n'\ 6766 ' -maxdepth N limit the callgraph 6557 ' -maxdepth N limit the callgraph data to N call levels (default: 0=all)\n'\ 6767 ' -expandcg pre-expand the callg 6558 ' -expandcg pre-expand the callgraph data in the html output (default: disabled)\n'\ 6768 ' -fadd file Add functions to be 6559 ' -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 6560 ' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names\n'\ 6770 ' -mincg ms Discard all callgrap 6561 ' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 6771 ' -cgphase P Only show callgraph 6562 ' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)\n'\ 6772 ' -cgtest N Only show callgraph 6563 ' -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 6564 ' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)\n'\ 6774 ' -cgfilter S Filter the callgraph 6565 ' -cgfilter S Filter the callgraph output in the timeline\n'\ 6775 ' -cgskip file Callgraph functions 6566 ' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\ 6776 ' -bufsize N Set trace buffer siz 6567 ' -bufsize N Set trace buffer size to N kilo-bytes (default: all of free memory)\n'\ 6777 ' -devdump Print out all the ra 6568 ' -devdump Print out all the raw device data for each phase\n'\ 6778 ' -cgdump Print out all the ra 6569 ' -cgdump Print out all the raw callgraph data\n'\ 6779 '\n'\ 6570 '\n'\ 6780 'Other commands:\n'\ 6571 'Other commands:\n'\ 6781 ' -modes List available suspe 6572 ' -modes List available suspend modes\n'\ 6782 ' -status Test to see if the s 6573 ' -status Test to see if the system is enabled to run this tool\n'\ 6783 ' -fpdt Print out the conten 6574 ' -fpdt Print out the contents of the ACPI Firmware Performance Data Table\n'\ 6784 ' -wificheck Print out wifi conne 6575 ' -wificheck Print out wifi connection info\n'\ 6785 ' -x<mode> Test xset by togglin 6576 ' -x<mode> Test xset by toggling the given mode (on/off/standby/suspend)\n'\ 6786 ' -sysinfo Print out system inf 6577 ' -sysinfo Print out system info extracted from BIOS\n'\ 6787 ' -devinfo Print out the pm set 6578 ' -devinfo Print out the pm settings of all devices which support runtime suspend\n'\ 6788 ' -cmdinfo Print out all the pl 6579 ' -cmdinfo Print out all the platform info collected before and after suspend/resume\n'\ 6789 ' -flist Print the list of fu 6580 ' -flist Print the list of functions currently being captured in ftrace\n'\ 6790 ' -flistall Print all functions 6581 ' -flistall Print all functions capable of being captured in ftrace\n'\ 6791 ' -summary dir Create a summary of 6582 ' -summary dir Create a summary of tests in this dir [-genhtml builds missing html]\n'\ 6792 ' [redo]\n'\ 6583 ' [redo]\n'\ 6793 ' -ftrace ftracefile Create HTML o 6584 ' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)\n'\ 6794 ' -dmesg dmesgfile Create HTML o 6585 ' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)\n'\ 6795 '' % (sysvals.title, sysvals.version, 6586 '' % (sysvals.title, sysvals.version, sysvals.suspendmode, sysvals.ftopfunc)) 6796 return True 6587 return True 6797 6588 6798 # ----------------- MAIN -------------------- 6589 # ----------------- MAIN -------------------- 6799 # exec start (skipped if script is loaded as 6590 # exec start (skipped if script is loaded as library) 6800 if __name__ == '__main__': 6591 if __name__ == '__main__': 6801 genhtml = False 6592 genhtml = False 6802 cmd = '' 6593 cmd = '' 6803 simplecmds = ['-sysinfo', '-modes', ' 6594 simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall', 6804 '-devinfo', '-status', '-xon' 6595 '-devinfo', '-status', '-xon', '-xoff', '-xstandby', '-xsuspend', 6805 '-xinit', '-xreset', '-xstat' 6596 '-xinit', '-xreset', '-xstat', '-wificheck', '-cmdinfo'] 6806 if '-f' in sys.argv: 6597 if '-f' in sys.argv: 6807 sysvals.cgskip = sysvals.conf 6598 sysvals.cgskip = sysvals.configFile('cgskip.txt') 6808 # loop through the command line argum 6599 # loop through the command line arguments 6809 args = iter(sys.argv[1:]) 6600 args = iter(sys.argv[1:]) 6810 for arg in args: 6601 for arg in args: 6811 if(arg == '-m'): 6602 if(arg == '-m'): 6812 try: 6603 try: 6813 val = next(ar 6604 val = next(args) 6814 except: 6605 except: 6815 doError('No m 6606 doError('No mode supplied', True) 6816 if val == 'command' a 6607 if val == 'command' and not sysvals.testcommand: 6817 doError('No c 6608 doError('No command supplied for mode "command"', True) 6818 sysvals.suspendmode = 6609 sysvals.suspendmode = val 6819 elif(arg in simplecmds): 6610 elif(arg in simplecmds): 6820 cmd = arg[1:] 6611 cmd = arg[1:] 6821 elif(arg == '-h'): 6612 elif(arg == '-h'): 6822 printHelp() 6613 printHelp() 6823 sys.exit(0) 6614 sys.exit(0) 6824 elif(arg == '-v'): 6615 elif(arg == '-v'): 6825 pprint("Version %s" % 6616 pprint("Version %s" % sysvals.version) 6826 sys.exit(0) 6617 sys.exit(0) 6827 elif(arg == '-debugtiming'): << 6828 debugtiming = True << 6829 elif(arg == '-x2'): 6618 elif(arg == '-x2'): 6830 sysvals.execcount = 2 6619 sysvals.execcount = 2 6831 elif(arg == '-x2delay'): 6620 elif(arg == '-x2delay'): 6832 sysvals.x2delay = get 6621 sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000) 6833 elif(arg == '-predelay'): 6622 elif(arg == '-predelay'): 6834 sysvals.predelay = ge 6623 sysvals.predelay = getArgInt('-predelay', args, 0, 60000) 6835 elif(arg == '-postdelay'): 6624 elif(arg == '-postdelay'): 6836 sysvals.postdelay = g 6625 sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000) 6837 elif(arg == '-f'): 6626 elif(arg == '-f'): 6838 sysvals.usecallgraph 6627 sysvals.usecallgraph = True 6839 elif(arg == '-ftop'): 6628 elif(arg == '-ftop'): 6840 sysvals.usecallgraph 6629 sysvals.usecallgraph = True 6841 sysvals.ftop = True 6630 sysvals.ftop = True 6842 sysvals.usekprobes = 6631 sysvals.usekprobes = False 6843 elif(arg == '-skiphtml'): 6632 elif(arg == '-skiphtml'): 6844 sysvals.skiphtml = Tr 6633 sysvals.skiphtml = True 6845 elif(arg == '-cgdump'): 6634 elif(arg == '-cgdump'): 6846 sysvals.cgdump = True 6635 sysvals.cgdump = True 6847 elif(arg == '-devdump'): 6636 elif(arg == '-devdump'): 6848 sysvals.devdump = Tru 6637 sysvals.devdump = True 6849 elif(arg == '-genhtml'): 6638 elif(arg == '-genhtml'): 6850 genhtml = True 6639 genhtml = True 6851 elif(arg == '-addlogs'): 6640 elif(arg == '-addlogs'): 6852 sysvals.dmesglog = sy 6641 sysvals.dmesglog = sysvals.ftracelog = True 6853 elif(arg == '-nologs'): 6642 elif(arg == '-nologs'): 6854 sysvals.dmesglog = sy 6643 sysvals.dmesglog = sysvals.ftracelog = False 6855 elif(arg == '-addlogdmesg'): 6644 elif(arg == '-addlogdmesg'): 6856 sysvals.dmesglog = Tr 6645 sysvals.dmesglog = True 6857 elif(arg == '-addlogftrace'): 6646 elif(arg == '-addlogftrace'): 6858 sysvals.ftracelog = T 6647 sysvals.ftracelog = True 6859 elif(arg == '-noturbostat'): 6648 elif(arg == '-noturbostat'): 6860 sysvals.tstat = False 6649 sysvals.tstat = False 6861 elif(arg == '-verbose'): 6650 elif(arg == '-verbose'): 6862 sysvals.verbose = Tru 6651 sysvals.verbose = True 6863 elif(arg == '-proc'): 6652 elif(arg == '-proc'): 6864 sysvals.useprocmon = 6653 sysvals.useprocmon = True 6865 elif(arg == '-dev'): 6654 elif(arg == '-dev'): 6866 sysvals.usedevsrc = T 6655 sysvals.usedevsrc = True 6867 elif(arg == '-sync'): 6656 elif(arg == '-sync'): 6868 sysvals.sync = True 6657 sysvals.sync = True 6869 elif(arg == '-wifi'): 6658 elif(arg == '-wifi'): 6870 sysvals.wifi = True 6659 sysvals.wifi = True 6871 elif(arg == '-wifitrace'): << 6872 sysvals.wifitrace = T << 6873 elif(arg == '-netfix'): << 6874 sysvals.netfix = True << 6875 elif(arg == '-gzip'): 6660 elif(arg == '-gzip'): 6876 sysvals.gzip = True 6661 sysvals.gzip = True 6877 elif(arg == '-info'): 6662 elif(arg == '-info'): 6878 try: 6663 try: 6879 val = next(ar 6664 val = next(args) 6880 except: 6665 except: 6881 doError('-inf 6666 doError('-info requires one string argument', True) 6882 elif(arg == '-desc'): 6667 elif(arg == '-desc'): 6883 try: 6668 try: 6884 val = next(ar 6669 val = next(args) 6885 except: 6670 except: 6886 doError('-des 6671 doError('-desc requires one string argument', True) 6887 elif(arg == '-rs'): 6672 elif(arg == '-rs'): 6888 try: 6673 try: 6889 val = next(ar 6674 val = next(args) 6890 except: 6675 except: 6891 doError('-rs 6676 doError('-rs requires "enable" or "disable"', True) 6892 if val.lower() in swi 6677 if val.lower() in switchvalues: 6893 if val.lower( 6678 if val.lower() in switchoff: 6894 sysva 6679 sysvals.rs = -1 6895 else: 6680 else: 6896 sysva 6681 sysvals.rs = 1 6897 else: 6682 else: 6898 doError('inva 6683 doError('invalid option: %s, use "enable/disable" or "on/off"' % val, True) 6899 elif(arg == '-display'): 6684 elif(arg == '-display'): 6900 try: 6685 try: 6901 val = next(ar 6686 val = next(args) 6902 except: 6687 except: 6903 doError('-dis 6688 doError('-display requires an mode value', True) 6904 disopt = ['on', 'off' 6689 disopt = ['on', 'off', 'standby', 'suspend'] 6905 if val.lower() not in 6690 if val.lower() not in disopt: 6906 doError('vali 6691 doError('valid display mode values are %s' % disopt, True) 6907 sysvals.display = val 6692 sysvals.display = val.lower() 6908 elif(arg == '-maxdepth'): 6693 elif(arg == '-maxdepth'): 6909 sysvals.max_graph_dep 6694 sysvals.max_graph_depth = getArgInt('-maxdepth', args, 0, 1000) 6910 elif(arg == '-rtcwake'): 6695 elif(arg == '-rtcwake'): 6911 try: 6696 try: 6912 val = next(ar 6697 val = next(args) 6913 except: 6698 except: 6914 doError('No r 6699 doError('No rtcwake time supplied', True) 6915 if val.lower() in swi 6700 if val.lower() in switchoff: 6916 sysvals.rtcwa 6701 sysvals.rtcwake = False 6917 else: 6702 else: 6918 sysvals.rtcwa 6703 sysvals.rtcwake = True 6919 sysvals.rtcwa 6704 sysvals.rtcwaketime = getArgInt('-rtcwake', val, 0, 3600, False) 6920 elif(arg == '-timeprec'): 6705 elif(arg == '-timeprec'): 6921 sysvals.setPrecision( 6706 sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6)) 6922 elif(arg == '-mindev'): 6707 elif(arg == '-mindev'): 6923 sysvals.mindevlen = g 6708 sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0) 6924 elif(arg == '-mincg'): 6709 elif(arg == '-mincg'): 6925 sysvals.mincglen = ge 6710 sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0) 6926 elif(arg == '-bufsize'): 6711 elif(arg == '-bufsize'): 6927 sysvals.bufsize = get 6712 sysvals.bufsize = getArgInt('-bufsize', args, 1, 1024*1024*8) 6928 elif(arg == '-cgtest'): 6713 elif(arg == '-cgtest'): 6929 sysvals.cgtest = getA 6714 sysvals.cgtest = getArgInt('-cgtest', args, 0, 1) 6930 elif(arg == '-cgphase'): 6715 elif(arg == '-cgphase'): 6931 try: 6716 try: 6932 val = next(ar 6717 val = next(args) 6933 except: 6718 except: 6934 doError('No p 6719 doError('No phase name supplied', True) 6935 d = Data(0) 6720 d = Data(0) 6936 if val not in d.phase 6721 if val not in d.phasedef: 6937 doError('inva 6722 doError('invalid phase --> (%s: %s), valid phases are %s'\ 6938 % (ar 6723 % (arg, val, d.phasedef.keys()), True) 6939 sysvals.cgphase = val 6724 sysvals.cgphase = val 6940 elif(arg == '-cgfilter'): 6725 elif(arg == '-cgfilter'): 6941 try: 6726 try: 6942 val = next(ar 6727 val = next(args) 6943 except: 6728 except: 6944 doError('No c 6729 doError('No callgraph functions supplied', True) 6945 sysvals.setCallgraphF 6730 sysvals.setCallgraphFilter(val) 6946 elif(arg == '-skipkprobe'): 6731 elif(arg == '-skipkprobe'): 6947 try: 6732 try: 6948 val = next(ar 6733 val = next(args) 6949 except: 6734 except: 6950 doError('No k 6735 doError('No kprobe functions supplied', True) 6951 sysvals.skipKprobes(v 6736 sysvals.skipKprobes(val) 6952 elif(arg == '-cgskip'): 6737 elif(arg == '-cgskip'): 6953 try: 6738 try: 6954 val = next(ar 6739 val = next(args) 6955 except: 6740 except: 6956 doError('No f 6741 doError('No file supplied', True) 6957 if val.lower() in swi 6742 if val.lower() in switchoff: 6958 sysvals.cgski 6743 sysvals.cgskip = '' 6959 else: 6744 else: 6960 sysvals.cgski 6745 sysvals.cgskip = sysvals.configFile(val) 6961 if(not sysval 6746 if(not sysvals.cgskip): 6962 doErr 6747 doError('%s does not exist' % sysvals.cgskip) 6963 elif(arg == '-callloop-maxgap 6748 elif(arg == '-callloop-maxgap'): 6964 sysvals.callloopmaxga 6749 sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', args, 0.0, 1.0) 6965 elif(arg == '-callloop-maxlen 6750 elif(arg == '-callloop-maxlen'): 6966 sysvals.callloopmaxle 6751 sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0) 6967 elif(arg == '-cmd'): 6752 elif(arg == '-cmd'): 6968 try: 6753 try: 6969 val = next(ar 6754 val = next(args) 6970 except: 6755 except: 6971 doError('No c 6756 doError('No command string supplied', True) 6972 sysvals.testcommand = 6757 sysvals.testcommand = val 6973 sysvals.suspendmode = 6758 sysvals.suspendmode = 'command' 6974 elif(arg == '-expandcg'): 6759 elif(arg == '-expandcg'): 6975 sysvals.cgexp = True 6760 sysvals.cgexp = True 6976 elif(arg == '-srgap'): 6761 elif(arg == '-srgap'): 6977 sysvals.srgap = 5 6762 sysvals.srgap = 5 6978 elif(arg == '-maxfail'): 6763 elif(arg == '-maxfail'): 6979 sysvals.maxfail = get 6764 sysvals.maxfail = getArgInt('-maxfail', args, 0, 1000000) 6980 elif(arg == '-multi'): 6765 elif(arg == '-multi'): 6981 try: 6766 try: 6982 c, d = next(a 6767 c, d = next(args), next(args) 6983 except: 6768 except: 6984 doError('-mul 6769 doError('-multi requires two values', True) 6985 sysvals.multiinit(c, 6770 sysvals.multiinit(c, d) 6986 elif(arg == '-o'): 6771 elif(arg == '-o'): 6987 try: 6772 try: 6988 val = next(ar 6773 val = next(args) 6989 except: 6774 except: 6990 doError('No s 6775 doError('No subdirectory name supplied', True) 6991 sysvals.outdir = sysv 6776 sysvals.outdir = sysvals.setOutputFolder(val) 6992 elif(arg == '-config'): 6777 elif(arg == '-config'): 6993 try: 6778 try: 6994 val = next(ar 6779 val = next(args) 6995 except: 6780 except: 6996 doError('No t 6781 doError('No text file supplied', True) 6997 file = sysvals.config 6782 file = sysvals.configFile(val) 6998 if(not file): 6783 if(not file): 6999 doError('%s d 6784 doError('%s does not exist' % val) 7000 configFromFile(file) 6785 configFromFile(file) 7001 elif(arg == '-fadd'): 6786 elif(arg == '-fadd'): 7002 try: 6787 try: 7003 val = next(ar 6788 val = next(args) 7004 except: 6789 except: 7005 doError('No t 6790 doError('No text file supplied', True) 7006 file = sysvals.config 6791 file = sysvals.configFile(val) 7007 if(not file): 6792 if(not file): 7008 doError('%s d 6793 doError('%s does not exist' % val) 7009 sysvals.addFtraceFilt 6794 sysvals.addFtraceFilterFunctions(file) 7010 elif(arg == '-dmesg'): 6795 elif(arg == '-dmesg'): 7011 try: 6796 try: 7012 val = next(ar 6797 val = next(args) 7013 except: 6798 except: 7014 doError('No d 6799 doError('No dmesg file supplied', True) 7015 sysvals.notestrun = T 6800 sysvals.notestrun = True 7016 sysvals.dmesgfile = v 6801 sysvals.dmesgfile = val 7017 if(os.path.exists(sys 6802 if(os.path.exists(sysvals.dmesgfile) == False): 7018 doError('%s d 6803 doError('%s does not exist' % sysvals.dmesgfile) 7019 elif(arg == '-ftrace'): 6804 elif(arg == '-ftrace'): 7020 try: 6805 try: 7021 val = next(ar 6806 val = next(args) 7022 except: 6807 except: 7023 doError('No f 6808 doError('No ftrace file supplied', True) 7024 sysvals.notestrun = T 6809 sysvals.notestrun = True 7025 sysvals.ftracefile = 6810 sysvals.ftracefile = val 7026 if(os.path.exists(sys 6811 if(os.path.exists(sysvals.ftracefile) == False): 7027 doError('%s d 6812 doError('%s does not exist' % sysvals.ftracefile) 7028 elif(arg == '-summary'): 6813 elif(arg == '-summary'): 7029 try: 6814 try: 7030 val = next(ar 6815 val = next(args) 7031 except: 6816 except: 7032 doError('No d 6817 doError('No directory supplied', True) 7033 cmd = 'summary' 6818 cmd = 'summary' 7034 sysvals.outdir = val 6819 sysvals.outdir = val 7035 sysvals.notestrun = T 6820 sysvals.notestrun = True 7036 if(os.path.isdir(val) 6821 if(os.path.isdir(val) == False): 7037 doError('%s i 6822 doError('%s is not accesible' % val) 7038 elif(arg == '-filter'): 6823 elif(arg == '-filter'): 7039 try: 6824 try: 7040 val = next(ar 6825 val = next(args) 7041 except: 6826 except: 7042 doError('No d 6827 doError('No devnames supplied', True) 7043 sysvals.setDeviceFilt 6828 sysvals.setDeviceFilter(val) 7044 elif(arg == '-result'): 6829 elif(arg == '-result'): 7045 try: 6830 try: 7046 val = next(ar 6831 val = next(args) 7047 except: 6832 except: 7048 doError('No r 6833 doError('No result file supplied', True) 7049 sysvals.result = val 6834 sysvals.result = val 7050 sysvals.signalHandler 6835 sysvals.signalHandlerInit() 7051 else: 6836 else: 7052 doError('Invalid argu 6837 doError('Invalid argument: '+arg, True) 7053 6838 7054 # compatibility errors 6839 # compatibility errors 7055 if(sysvals.usecallgraph and sysvals.u 6840 if(sysvals.usecallgraph and sysvals.usedevsrc): 7056 doError('-dev is not compatib 6841 doError('-dev is not compatible with -f') 7057 if(sysvals.usecallgraph and sysvals.u 6842 if(sysvals.usecallgraph and sysvals.useprocmon): 7058 doError('-proc is not compati 6843 doError('-proc is not compatible with -f') 7059 6844 7060 if sysvals.usecallgraph and sysvals.c 6845 if sysvals.usecallgraph and sysvals.cgskip: 7061 sysvals.vprint('Using cgskip 6846 sysvals.vprint('Using cgskip file: %s' % sysvals.cgskip) 7062 sysvals.setCallgraphBlacklist 6847 sysvals.setCallgraphBlacklist(sysvals.cgskip) 7063 6848 7064 # callgraph size cannot exceed device 6849 # callgraph size cannot exceed device size 7065 if sysvals.mincglen < sysvals.mindevl 6850 if sysvals.mincglen < sysvals.mindevlen: 7066 sysvals.mincglen = sysvals.mi 6851 sysvals.mincglen = sysvals.mindevlen 7067 6852 7068 # remove existing buffers before calc 6853 # remove existing buffers before calculating memory 7069 if(sysvals.usecallgraph or sysvals.us 6854 if(sysvals.usecallgraph or sysvals.usedevsrc): 7070 sysvals.fsetVal('16', 'buffer 6855 sysvals.fsetVal('16', 'buffer_size_kb') 7071 sysvals.cpuInfo() 6856 sysvals.cpuInfo() 7072 6857 7073 # just run a utility command and exit 6858 # just run a utility command and exit 7074 if(cmd != ''): 6859 if(cmd != ''): 7075 ret = 0 6860 ret = 0 7076 if(cmd == 'status'): 6861 if(cmd == 'status'): 7077 if not statusCheck(Tr 6862 if not statusCheck(True): 7078 ret = 1 6863 ret = 1 7079 elif(cmd == 'fpdt'): 6864 elif(cmd == 'fpdt'): 7080 if not getFPDT(True): 6865 if not getFPDT(True): 7081 ret = 1 6866 ret = 1 7082 elif(cmd == 'sysinfo'): 6867 elif(cmd == 'sysinfo'): 7083 sysvals.printSystemIn 6868 sysvals.printSystemInfo(True) 7084 elif(cmd == 'devinfo'): 6869 elif(cmd == 'devinfo'): 7085 deviceInfo() 6870 deviceInfo() 7086 elif(cmd == 'modes'): 6871 elif(cmd == 'modes'): 7087 pprint(getModes()) 6872 pprint(getModes()) 7088 elif(cmd == 'flist'): 6873 elif(cmd == 'flist'): 7089 sysvals.getFtraceFilt 6874 sysvals.getFtraceFilterFunctions(True) 7090 elif(cmd == 'flistall'): 6875 elif(cmd == 'flistall'): 7091 sysvals.getFtraceFilt 6876 sysvals.getFtraceFilterFunctions(False) 7092 elif(cmd == 'summary'): 6877 elif(cmd == 'summary'): 7093 runSummary(sysvals.ou 6878 runSummary(sysvals.outdir, True, genhtml) 7094 elif(cmd in ['xon', 'xoff', ' 6879 elif(cmd in ['xon', 'xoff', 'xstandby', 'xsuspend', 'xinit', 'xreset']): 7095 sysvals.verbose = Tru 6880 sysvals.verbose = True 7096 ret = sysvals.display 6881 ret = sysvals.displayControl(cmd[1:]) 7097 elif(cmd == 'xstat'): 6882 elif(cmd == 'xstat'): 7098 pprint('Display Statu 6883 pprint('Display Status: %s' % sysvals.displayControl('stat').upper()) 7099 elif(cmd == 'wificheck'): 6884 elif(cmd == 'wificheck'): 7100 dev = sysvals.checkWi 6885 dev = sysvals.checkWifi() 7101 if dev: 6886 if dev: 7102 print('%s is 6887 print('%s is connected' % sysvals.wifiDetails(dev)) 7103 else: 6888 else: 7104 print('No wif 6889 print('No wifi connection found') 7105 elif(cmd == 'cmdinfo'): 6890 elif(cmd == 'cmdinfo'): 7106 for out in sysvals.cm 6891 for out in sysvals.cmdinfo(False, True): 7107 print('[%s - 6892 print('[%s - %s]\n%s\n' % out) 7108 sys.exit(ret) 6893 sys.exit(ret) 7109 6894 7110 # if instructed, re-analyze existing 6895 # if instructed, re-analyze existing data files 7111 if(sysvals.notestrun): 6896 if(sysvals.notestrun): 7112 stamp = rerunTest(sysvals.out 6897 stamp = rerunTest(sysvals.outdir) 7113 sysvals.outputResult(stamp) 6898 sysvals.outputResult(stamp) 7114 sys.exit(0) 6899 sys.exit(0) 7115 6900 7116 # verify that we can run a test 6901 # verify that we can run a test 7117 error = statusCheck() 6902 error = statusCheck() 7118 if(error): 6903 if(error): 7119 doError(error) 6904 doError(error) 7120 6905 7121 # extract mem/disk extra modes and co 6906 # extract mem/disk extra modes and convert 7122 mode = sysvals.suspendmode 6907 mode = sysvals.suspendmode 7123 if mode.startswith('mem'): 6908 if mode.startswith('mem'): 7124 memmode = mode.split('-', 1)[ 6909 memmode = mode.split('-', 1)[-1] if '-' in mode else 'deep' 7125 if memmode == 'shallow': 6910 if memmode == 'shallow': 7126 mode = 'standby' 6911 mode = 'standby' 7127 elif memmode == 's2idle': 6912 elif memmode == 's2idle': 7128 mode = 'freeze' 6913 mode = 'freeze' 7129 else: 6914 else: 7130 mode = 'mem' 6915 mode = 'mem' 7131 sysvals.memmode = memmode 6916 sysvals.memmode = memmode 7132 sysvals.suspendmode = mode 6917 sysvals.suspendmode = mode 7133 if mode.startswith('disk-'): 6918 if mode.startswith('disk-'): 7134 sysvals.diskmode = mode.split 6919 sysvals.diskmode = mode.split('-', 1)[-1] 7135 sysvals.suspendmode = 'disk' 6920 sysvals.suspendmode = 'disk' 7136 sysvals.systemInfo(dmidecode(sysvals. 6921 sysvals.systemInfo(dmidecode(sysvals.mempath)) 7137 6922 7138 failcnt, ret = 0, 0 6923 failcnt, ret = 0, 0 7139 if sysvals.multitest['run']: 6924 if sysvals.multitest['run']: 7140 # run multiple tests in a sep 6925 # run multiple tests in a separate subdirectory 7141 if not sysvals.outdir: 6926 if not sysvals.outdir: 7142 if 'time' in sysvals. 6927 if 'time' in sysvals.multitest: 7143 s = '-%dm' % 6928 s = '-%dm' % sysvals.multitest['time'] 7144 else: 6929 else: 7145 s = '-x%d' % 6930 s = '-x%d' % sysvals.multitest['count'] 7146 sysvals.outdir = date 6931 sysvals.outdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S'+s) 7147 if not os.path.isdir(sysvals. 6932 if not os.path.isdir(sysvals.outdir): 7148 os.makedirs(sysvals.o 6933 os.makedirs(sysvals.outdir) 7149 sysvals.sudoUserchown(sysvals 6934 sysvals.sudoUserchown(sysvals.outdir) 7150 finish = datetime.now() 6935 finish = datetime.now() 7151 if 'time' in sysvals.multites 6936 if 'time' in sysvals.multitest: 7152 finish += timedelta(m 6937 finish += timedelta(minutes=sysvals.multitest['time']) 7153 for i in range(sysvals.multit 6938 for i in range(sysvals.multitest['count']): 7154 sysvals.multistat(Tru 6939 sysvals.multistat(True, i, finish) 7155 if i != 0 and sysvals 6940 if i != 0 and sysvals.multitest['delay'] > 0: 7156 pprint('Waiti 6941 pprint('Waiting %d seconds...' % (sysvals.multitest['delay'])) 7157 time.sleep(sy 6942 time.sleep(sysvals.multitest['delay']) 7158 fmt = 'suspend-%y%m%d 6943 fmt = 'suspend-%y%m%d-%H%M%S' 7159 sysvals.testdir = os. 6944 sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt)) 7160 ret = runTest(i+1, no !! 6945 ret = runTest(i+1, True) 7161 failcnt = 0 if not re 6946 failcnt = 0 if not ret else failcnt + 1 7162 if sysvals.maxfail > 6947 if sysvals.maxfail > 0 and failcnt >= sysvals.maxfail: 7163 pprint('Maxim 6948 pprint('Maximum fail count of %d reached, aborting multitest' % (sysvals.maxfail)) 7164 break 6949 break >> 6950 time.sleep(5) 7165 sysvals.resetlog() 6951 sysvals.resetlog() 7166 sysvals.multistat(Fal 6952 sysvals.multistat(False, i, finish) 7167 if 'time' in sysvals. 6953 if 'time' in sysvals.multitest and datetime.now() >= finish: 7168 break 6954 break 7169 if not sysvals.skiphtml: 6955 if not sysvals.skiphtml: 7170 runSummary(sysvals.ou 6956 runSummary(sysvals.outdir, False, False) 7171 sysvals.sudoUserchown(sysvals 6957 sysvals.sudoUserchown(sysvals.outdir) 7172 else: 6958 else: 7173 if sysvals.outdir: 6959 if sysvals.outdir: 7174 sysvals.testdir = sys 6960 sysvals.testdir = sysvals.outdir 7175 # run the test in the current 6961 # run the test in the current directory 7176 ret = runTest() 6962 ret = runTest() 7177 6963 7178 # reset to default values after testi 6964 # reset to default values after testing 7179 if sysvals.display: 6965 if sysvals.display: 7180 sysvals.displayControl('reset 6966 sysvals.displayControl('reset') 7181 if sysvals.rs != 0: 6967 if sysvals.rs != 0: 7182 sysvals.setRuntimeSuspend(Fal 6968 sysvals.setRuntimeSuspend(False) 7183 sys.exit(ret) 6969 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.