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 69 debugtiming = False 70 mystarttime = time.time() 70 mystarttime = time.time() 71 def pprint(msg): 71 def pprint(msg): 72 if debugtiming: 72 if debugtiming: 73 print('[%09.3f] %s' % (time.ti 73 print('[%09.3f] %s' % (time.time()-mystarttime, msg)) 74 else: 74 else: 75 print(msg) 75 print(msg) 76 sys.stdout.flush() 76 sys.stdout.flush() 77 77 78 def ascii(text): 78 def ascii(text): 79 return text.decode('ascii', 'ignore') 79 return text.decode('ascii', 'ignore') 80 80 81 # ----------------- CLASSES ------------------ 81 # ----------------- CLASSES -------------------- 82 82 83 # Class: SystemValues 83 # Class: SystemValues 84 # Description: 84 # Description: 85 # A global, single-instance container u 85 # A global, single-instance container used to 86 # store system values and test paramete 86 # store system values and test parameters 87 class SystemValues: 87 class SystemValues: 88 title = 'SleepGraph' 88 title = 'SleepGraph' 89 version = '5.12' !! 89 version = '5.10' 90 ansi = False 90 ansi = False 91 rs = 0 91 rs = 0 92 display = '' 92 display = '' 93 gzip = False 93 gzip = False 94 sync = False 94 sync = False 95 wifi = False 95 wifi = False 96 netfix = False 96 netfix = False 97 verbose = False 97 verbose = False 98 testlog = True 98 testlog = True 99 dmesglog = True 99 dmesglog = True 100 ftracelog = False 100 ftracelog = False 101 acpidebug = True 101 acpidebug = True 102 tstat = True 102 tstat = True 103 wifitrace = False 103 wifitrace = False 104 mindevlen = 0.0001 104 mindevlen = 0.0001 105 mincglen = 0.0 105 mincglen = 0.0 106 cgphase = '' 106 cgphase = '' 107 cgtest = -1 107 cgtest = -1 108 cgskip = '' 108 cgskip = '' 109 maxfail = 0 109 maxfail = 0 110 multitest = {'run': False, 'count': 10 110 multitest = {'run': False, 'count': 1000000, 'delay': 0} 111 max_graph_depth = 0 111 max_graph_depth = 0 112 callloopmaxgap = 0.0001 112 callloopmaxgap = 0.0001 113 callloopmaxlen = 0.005 113 callloopmaxlen = 0.005 114 bufsize = 0 114 bufsize = 0 115 cpucount = 0 115 cpucount = 0 116 memtotal = 204800 116 memtotal = 204800 117 memfree = 204800 117 memfree = 204800 118 osversion = '' 118 osversion = '' 119 srgap = 0 119 srgap = 0 120 cgexp = False 120 cgexp = False 121 testdir = '' 121 testdir = '' 122 outdir = '' 122 outdir = '' 123 tpath = '/sys/kernel/tracing/' 123 tpath = '/sys/kernel/tracing/' 124 fpdtpath = '/sys/firmware/acpi/tables/ 124 fpdtpath = '/sys/firmware/acpi/tables/FPDT' 125 epath = '/sys/kernel/tracing/events/po 125 epath = '/sys/kernel/tracing/events/power/' 126 pmdpath = '/sys/power/pm_debug_message 126 pmdpath = '/sys/power/pm_debug_messages' 127 s0ixpath = '/sys/module/intel_pmc_core 127 s0ixpath = '/sys/module/intel_pmc_core/parameters/warn_on_s0ix_failures' 128 s0ixres = '/sys/devices/system/cpu/cpu 128 s0ixres = '/sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us' 129 acpipath='/sys/module/acpi/parameters/ 129 acpipath='/sys/module/acpi/parameters/debug_level' 130 traceevents = [ 130 traceevents = [ 131 'suspend_resume', 131 'suspend_resume', 132 'wakeup_source_activate', 132 'wakeup_source_activate', 133 'wakeup_source_deactivate', 133 'wakeup_source_deactivate', 134 'device_pm_callback_end', 134 'device_pm_callback_end', 135 'device_pm_callback_start' 135 'device_pm_callback_start' 136 ] 136 ] 137 logmsg = '' 137 logmsg = '' 138 testcommand = '' 138 testcommand = '' 139 mempath = '/dev/mem' 139 mempath = '/dev/mem' 140 powerfile = '/sys/power/state' 140 powerfile = '/sys/power/state' 141 mempowerfile = '/sys/power/mem_sleep' 141 mempowerfile = '/sys/power/mem_sleep' 142 diskpowerfile = '/sys/power/disk' 142 diskpowerfile = '/sys/power/disk' 143 suspendmode = 'mem' 143 suspendmode = 'mem' 144 memmode = '' 144 memmode = '' 145 diskmode = '' 145 diskmode = '' 146 hostname = 'localhost' 146 hostname = 'localhost' 147 prefix = 'test' 147 prefix = 'test' 148 teststamp = '' 148 teststamp = '' 149 sysstamp = '' 149 sysstamp = '' 150 dmesgstart = 0.0 150 dmesgstart = 0.0 151 dmesgfile = '' 151 dmesgfile = '' 152 ftracefile = '' 152 ftracefile = '' 153 htmlfile = 'output.html' 153 htmlfile = 'output.html' 154 result = '' 154 result = '' 155 rtcwake = True 155 rtcwake = True 156 rtcwaketime = 15 156 rtcwaketime = 15 157 rtcpath = '' 157 rtcpath = '' 158 devicefilter = [] 158 devicefilter = [] 159 cgfilter = [] 159 cgfilter = [] 160 stamp = 0 160 stamp = 0 161 execcount = 1 161 execcount = 1 162 x2delay = 0 162 x2delay = 0 163 skiphtml = False 163 skiphtml = False 164 usecallgraph = False 164 usecallgraph = False 165 ftopfunc = 'pm_suspend' 165 ftopfunc = 'pm_suspend' 166 ftop = False 166 ftop = False 167 usetraceevents = False 167 usetraceevents = False 168 usetracemarkers = True 168 usetracemarkers = True 169 useftrace = True 169 useftrace = True 170 usekprobes = True 170 usekprobes = True 171 usedevsrc = False 171 usedevsrc = False 172 useprocmon = False 172 useprocmon = False 173 notestrun = False 173 notestrun = False 174 cgdump = False 174 cgdump = False 175 devdump = False 175 devdump = False 176 mixedphaseheight = True 176 mixedphaseheight = True 177 devprops = dict() 177 devprops = dict() 178 cfgdef = dict() 178 cfgdef = dict() 179 platinfo = [] 179 platinfo = [] 180 predelay = 0 180 predelay = 0 181 postdelay = 0 181 postdelay = 0 182 tmstart = 'SUSPEND START %Y%m%d-%H:%M: 182 tmstart = 'SUSPEND START %Y%m%d-%H:%M:%S.%f' 183 tmend = 'RESUME COMPLETE %Y%m%d-%H:%M: 183 tmend = 'RESUME COMPLETE %Y%m%d-%H:%M:%S.%f' 184 tracefuncs = { 184 tracefuncs = { 185 'async_synchronize_full': {}, 185 'async_synchronize_full': {}, 186 'sys_sync': {}, 186 'sys_sync': {}, 187 'ksys_sync': {}, 187 'ksys_sync': {}, 188 '__pm_notifier_call_chain': {} 188 '__pm_notifier_call_chain': {}, 189 'pm_prepare_console': {}, 189 'pm_prepare_console': {}, 190 'pm_notifier_call_chain': {}, 190 'pm_notifier_call_chain': {}, 191 'freeze_processes': {}, 191 'freeze_processes': {}, 192 'freeze_kernel_threads': {}, 192 'freeze_kernel_threads': {}, 193 'pm_restrict_gfp_mask': {}, 193 'pm_restrict_gfp_mask': {}, 194 'acpi_suspend_begin': {}, 194 'acpi_suspend_begin': {}, 195 'acpi_hibernation_begin': {}, 195 'acpi_hibernation_begin': {}, 196 'acpi_hibernation_enter': {}, 196 'acpi_hibernation_enter': {}, 197 'acpi_hibernation_leave': {}, 197 'acpi_hibernation_leave': {}, 198 'acpi_pm_freeze': {}, 198 'acpi_pm_freeze': {}, 199 'acpi_pm_thaw': {}, 199 'acpi_pm_thaw': {}, 200 'acpi_s2idle_end': {}, 200 'acpi_s2idle_end': {}, 201 'acpi_s2idle_sync': {}, 201 'acpi_s2idle_sync': {}, 202 'acpi_s2idle_begin': {}, 202 'acpi_s2idle_begin': {}, 203 'acpi_s2idle_prepare': {}, 203 'acpi_s2idle_prepare': {}, 204 'acpi_s2idle_prepare_late': {} 204 'acpi_s2idle_prepare_late': {}, 205 'acpi_s2idle_wake': {}, 205 'acpi_s2idle_wake': {}, 206 'acpi_s2idle_wakeup': {}, 206 'acpi_s2idle_wakeup': {}, 207 'acpi_s2idle_restore': {}, 207 'acpi_s2idle_restore': {}, 208 'acpi_s2idle_restore_early': { 208 'acpi_s2idle_restore_early': {}, 209 'hibernate_preallocate_memory' 209 'hibernate_preallocate_memory': {}, 210 'create_basic_memory_bitmaps': 210 'create_basic_memory_bitmaps': {}, 211 'swsusp_write': {}, 211 'swsusp_write': {}, 212 'suspend_console': {}, 212 'suspend_console': {}, 213 'acpi_pm_prepare': {}, 213 'acpi_pm_prepare': {}, 214 'syscore_suspend': {}, 214 'syscore_suspend': {}, 215 'arch_enable_nonboot_cpus_end' 215 'arch_enable_nonboot_cpus_end': {}, 216 'syscore_resume': {}, 216 'syscore_resume': {}, 217 'acpi_pm_finish': {}, 217 'acpi_pm_finish': {}, 218 'resume_console': {}, 218 'resume_console': {}, 219 'acpi_pm_end': {}, 219 'acpi_pm_end': {}, 220 'pm_restore_gfp_mask': {}, 220 'pm_restore_gfp_mask': {}, 221 'thaw_processes': {}, 221 'thaw_processes': {}, 222 'pm_restore_console': {}, 222 'pm_restore_console': {}, 223 'CPU_OFF': { 223 'CPU_OFF': { 224 'func':'_cpu_down', 224 'func':'_cpu_down', 225 'args_x86_64': {'cpu': 225 'args_x86_64': {'cpu':'%di:s32'}, 226 'format': 'CPU_OFF[{cp 226 'format': 'CPU_OFF[{cpu}]' 227 }, 227 }, 228 'CPU_ON': { 228 'CPU_ON': { 229 'func':'_cpu_up', 229 'func':'_cpu_up', 230 'args_x86_64': {'cpu': 230 'args_x86_64': {'cpu':'%di:s32'}, 231 'format': 'CPU_ON[{cpu 231 'format': 'CPU_ON[{cpu}]' 232 }, 232 }, 233 } 233 } 234 dev_tracefuncs = { 234 dev_tracefuncs = { 235 # general wait/delay/sleep 235 # general wait/delay/sleep 236 'msleep': { 'args_x86_64': {'t 236 'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 }, 237 'schedule_timeout': { 'args_x8 237 'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 }, 238 'udelay': { 'func':'__const_ud 238 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 }, 239 'usleep_range': { 'args_x86_64 239 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 }, 240 'mutex_lock_slowpath': { 'func 240 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 }, 241 'acpi_os_stall': {'ub': 1}, 241 'acpi_os_stall': {'ub': 1}, 242 'rt_mutex_slowlock': {'ub': 1} 242 'rt_mutex_slowlock': {'ub': 1}, 243 # ACPI 243 # ACPI 244 'acpi_resume_power_resources': 244 'acpi_resume_power_resources': {}, 245 'acpi_ps_execute_method': { 'a 245 'acpi_ps_execute_method': { 'args_x86_64': { 246 'fullpath':'+0(+40(%di 246 'fullpath':'+0(+40(%di)):string', 247 }}, 247 }}, 248 # mei_me 248 # mei_me 249 'mei_reset': {}, 249 'mei_reset': {}, 250 # filesystem 250 # filesystem 251 'ext4_sync_fs': {}, 251 'ext4_sync_fs': {}, 252 # 80211 252 # 80211 253 'ath10k_bmi_read_memory': { 'a 253 'ath10k_bmi_read_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 254 'ath10k_bmi_write_memory': { ' 254 'ath10k_bmi_write_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 255 'ath10k_bmi_fast_download': { 255 'ath10k_bmi_fast_download': { 'args_x86_64': {'length':'%cx:s32'} }, 256 'iwlagn_mac_start': {}, 256 'iwlagn_mac_start': {}, 257 'iwlagn_alloc_bcast_station': 257 'iwlagn_alloc_bcast_station': {}, 258 'iwl_trans_pcie_start_hw': {}, 258 'iwl_trans_pcie_start_hw': {}, 259 'iwl_trans_pcie_start_fw': {}, 259 'iwl_trans_pcie_start_fw': {}, 260 'iwl_run_init_ucode': {}, 260 'iwl_run_init_ucode': {}, 261 'iwl_load_ucode_wait_alive': { 261 'iwl_load_ucode_wait_alive': {}, 262 'iwl_alive_start': {}, 262 'iwl_alive_start': {}, 263 'iwlagn_mac_stop': {}, 263 'iwlagn_mac_stop': {}, 264 'iwlagn_mac_suspend': {}, 264 'iwlagn_mac_suspend': {}, 265 'iwlagn_mac_resume': {}, 265 'iwlagn_mac_resume': {}, 266 'iwlagn_mac_add_interface': {} 266 'iwlagn_mac_add_interface': {}, 267 'iwlagn_mac_remove_interface': 267 'iwlagn_mac_remove_interface': {}, 268 'iwlagn_mac_change_interface': 268 'iwlagn_mac_change_interface': {}, 269 'iwlagn_mac_config': {}, 269 'iwlagn_mac_config': {}, 270 'iwlagn_configure_filter': {}, 270 'iwlagn_configure_filter': {}, 271 'iwlagn_mac_hw_scan': {}, 271 'iwlagn_mac_hw_scan': {}, 272 'iwlagn_bss_info_changed': {}, 272 'iwlagn_bss_info_changed': {}, 273 'iwlagn_mac_channel_switch': { 273 'iwlagn_mac_channel_switch': {}, 274 'iwlagn_mac_flush': {}, 274 'iwlagn_mac_flush': {}, 275 # ATA 275 # ATA 276 'ata_eh_recover': { 'args_x86_ 276 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} }, 277 # i915 277 # i915 278 'i915_gem_resume': {}, 278 'i915_gem_resume': {}, 279 'i915_restore_state': {}, 279 'i915_restore_state': {}, 280 'intel_opregion_setup': {}, 280 'intel_opregion_setup': {}, 281 'g4x_pre_enable_dp': {}, 281 'g4x_pre_enable_dp': {}, 282 'vlv_pre_enable_dp': {}, 282 'vlv_pre_enable_dp': {}, 283 'chv_pre_enable_dp': {}, 283 'chv_pre_enable_dp': {}, 284 'g4x_enable_dp': {}, 284 'g4x_enable_dp': {}, 285 'vlv_enable_dp': {}, 285 'vlv_enable_dp': {}, 286 'intel_hpd_init': {}, 286 'intel_hpd_init': {}, 287 'intel_opregion_register': {}, 287 'intel_opregion_register': {}, 288 'intel_dp_detect': {}, 288 'intel_dp_detect': {}, 289 'intel_hdmi_detect': {}, 289 'intel_hdmi_detect': {}, 290 'intel_opregion_init': {}, 290 'intel_opregion_init': {}, 291 'intel_fbdev_set_suspend': {}, 291 'intel_fbdev_set_suspend': {}, 292 } 292 } 293 infocmds = [ 293 infocmds = [ 294 [0, 'sysinfo', 'uname', '-a'], 294 [0, 'sysinfo', 'uname', '-a'], 295 [0, 'cpuinfo', 'head', '-7', ' 295 [0, 'cpuinfo', 'head', '-7', '/proc/cpuinfo'], 296 [0, 'kparams', 'cat', '/proc/c 296 [0, 'kparams', 'cat', '/proc/cmdline'], 297 [0, 'mcelog', 'mcelog'], 297 [0, 'mcelog', 'mcelog'], 298 [0, 'pcidevices', 'lspci', '-t 298 [0, 'pcidevices', 'lspci', '-tv'], 299 [0, 'usbdevices', 'lsusb', '-t 299 [0, 'usbdevices', 'lsusb', '-tv'], 300 [0, 'acpidevices', 'sh', '-c', 300 [0, 'acpidevices', 'sh', '-c', 'ls -l /sys/bus/acpi/devices/*/physical_node'], 301 [0, 's0ix_require', 'cat', '/s 301 [0, 's0ix_require', 'cat', '/sys/kernel/debug/pmc_core/substate_requirements'], 302 [0, 's0ix_debug', 'cat', '/sys 302 [0, 's0ix_debug', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_debug_status'], 303 [0, 'ethtool', 'ethtool', '{et << 304 [1, 's0ix_residency', 'cat', ' 303 [1, 's0ix_residency', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_residency_usec'], 305 [1, 'interrupts', 'cat', '/pro 304 [1, 'interrupts', 'cat', '/proc/interrupts'], 306 [1, 'wakeups', 'cat', '/sys/ke 305 [1, 'wakeups', 'cat', '/sys/kernel/debug/wakeup_sources'], 307 [2, 'gpecounts', 'sh', '-c', ' 306 [2, 'gpecounts', 'sh', '-c', 'grep -v invalid /sys/firmware/acpi/interrupts/*'], 308 [2, 'suspendstats', 'sh', '-c' 307 [2, 'suspendstats', 'sh', '-c', 'grep -v invalid /sys/power/suspend_stats/*'], 309 [2, 'cpuidle', 'sh', '-c', 'gr 308 [2, 'cpuidle', 'sh', '-c', 'grep -v invalid /sys/devices/system/cpu/cpu*/cpuidle/state*/s2idle/*'], 310 [2, 'battery', 'sh', '-c', 'gr 309 [2, 'battery', 'sh', '-c', 'grep -v invalid /sys/class/power_supply/*/*'], 311 [2, 'thermal', 'sh', '-c', 'gr 310 [2, 'thermal', 'sh', '-c', 'grep . /sys/class/thermal/thermal_zone*/temp'], 312 ] 311 ] 313 cgblacklist = [] 312 cgblacklist = [] 314 kprobes = dict() 313 kprobes = dict() 315 timeformat = '%.3f' 314 timeformat = '%.3f' 316 cmdline = '%s %s' % \ 315 cmdline = '%s %s' % \ 317 (os.path.basename(sys. 316 (os.path.basename(sys.argv[0]), ' '.join(sys.argv[1:])) 318 sudouser = '' 317 sudouser = '' 319 def __init__(self): 318 def __init__(self): 320 self.archargs = 'args_'+platfo 319 self.archargs = 'args_'+platform.machine() 321 self.hostname = platform.node( 320 self.hostname = platform.node() 322 if(self.hostname == ''): 321 if(self.hostname == ''): 323 self.hostname = 'local 322 self.hostname = 'localhost' 324 rtc = "rtc0" 323 rtc = "rtc0" 325 if os.path.exists('/dev/rtc'): 324 if os.path.exists('/dev/rtc'): 326 rtc = os.readlink('/de 325 rtc = os.readlink('/dev/rtc') 327 rtc = '/sys/class/rtc/'+rtc 326 rtc = '/sys/class/rtc/'+rtc 328 if os.path.exists(rtc) and os. 327 if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \ 329 os.path.exists(rtc+'/t 328 os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'): 330 self.rtcpath = rtc 329 self.rtcpath = rtc 331 if (hasattr(sys.stdout, 'isatt 330 if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): 332 self.ansi = True 331 self.ansi = True 333 self.testdir = datetime.now(). 332 self.testdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S') 334 if os.getuid() == 0 and 'SUDO_ 333 if os.getuid() == 0 and 'SUDO_USER' in os.environ and \ 335 os.environ['SUDO_USER' 334 os.environ['SUDO_USER']: 336 self.sudouser = os.env 335 self.sudouser = os.environ['SUDO_USER'] 337 def resetlog(self): 336 def resetlog(self): 338 self.logmsg = '' 337 self.logmsg = '' 339 self.platinfo = [] 338 self.platinfo = [] 340 def vprint(self, msg): 339 def vprint(self, msg): 341 self.logmsg += msg+'\n' 340 self.logmsg += msg+'\n' 342 if self.verbose or msg.startsw 341 if self.verbose or msg.startswith('WARNING:'): 343 pprint(msg) 342 pprint(msg) 344 def signalHandler(self, signum, frame) 343 def signalHandler(self, signum, frame): 345 if not self.result: 344 if not self.result: 346 return 345 return 347 signame = self.signames[signum 346 signame = self.signames[signum] if signum in self.signames else 'UNKNOWN' 348 msg = 'Signal %s caused a tool 347 msg = 'Signal %s caused a tool exit, line %d' % (signame, frame.f_lineno) 349 self.outputResult({'error':msg 348 self.outputResult({'error':msg}) 350 sys.exit(3) 349 sys.exit(3) 351 def signalHandlerInit(self): 350 def signalHandlerInit(self): 352 capture = ['BUS', 'SYS', 'XCPU 351 capture = ['BUS', 'SYS', 'XCPU', 'XFSZ', 'PWR', 'HUP', 'INT', 'QUIT', 353 'ILL', 'ABRT', 'FPE', 352 'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM'] 354 self.signames = dict() 353 self.signames = dict() 355 for i in capture: 354 for i in capture: 356 s = 'SIG'+i 355 s = 'SIG'+i 357 try: 356 try: 358 signum = getat 357 signum = getattr(signal, s) 359 signal.signal( 358 signal.signal(signum, self.signalHandler) 360 except: 359 except: 361 continue 360 continue 362 self.signames[signum] 361 self.signames[signum] = s 363 def rootCheck(self, fatal=True): 362 def rootCheck(self, fatal=True): 364 if(os.access(self.powerfile, o 363 if(os.access(self.powerfile, os.W_OK)): 365 return True 364 return True 366 if fatal: 365 if fatal: 367 msg = 'This command re 366 msg = 'This command requires sysfs mount and root access' 368 pprint('ERROR: %s\n' % 367 pprint('ERROR: %s\n' % msg) 369 self.outputResult({'er 368 self.outputResult({'error':msg}) 370 sys.exit(1) 369 sys.exit(1) 371 return False 370 return False 372 def rootUser(self, fatal=False): 371 def rootUser(self, fatal=False): 373 if 'USER' in os.environ and os 372 if 'USER' in os.environ and os.environ['USER'] == 'root': 374 return True 373 return True 375 if fatal: 374 if fatal: 376 msg = 'This command mu 375 msg = 'This command must be run as root' 377 pprint('ERROR: %s\n' % 376 pprint('ERROR: %s\n' % msg) 378 self.outputResult({'er 377 self.outputResult({'error':msg}) 379 sys.exit(1) 378 sys.exit(1) 380 return False 379 return False 381 def usable(self, file, ishtml=False): 380 def usable(self, file, ishtml=False): 382 if not os.path.exists(file) or 381 if not os.path.exists(file) or os.path.getsize(file) < 1: 383 return False 382 return False 384 if ishtml: 383 if ishtml: 385 try: 384 try: 386 fp = open(file 385 fp = open(file, 'r') 387 res = fp.read( 386 res = fp.read(1000) 388 fp.close() 387 fp.close() 389 except: 388 except: 390 return False 389 return False 391 if '<html>' not in res 390 if '<html>' not in res: 392 return False 391 return False 393 return True 392 return True 394 def getExec(self, cmd): 393 def getExec(self, cmd): 395 try: 394 try: 396 fp = Popen(['which', c 395 fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout 397 out = ascii(fp.read()) 396 out = ascii(fp.read()).strip() 398 fp.close() 397 fp.close() 399 except: 398 except: 400 out = '' 399 out = '' 401 if out: 400 if out: 402 return out 401 return out 403 for path in ['/sbin', '/bin', 402 for path in ['/sbin', '/bin', '/usr/sbin', '/usr/bin', 404 '/usr/local/sbin', '/u 403 '/usr/local/sbin', '/usr/local/bin']: 405 cmdfull = os.path.join 404 cmdfull = os.path.join(path, cmd) 406 if os.path.exists(cmdf 405 if os.path.exists(cmdfull): 407 return cmdfull 406 return cmdfull 408 return out 407 return out 409 def setPrecision(self, num): 408 def setPrecision(self, num): 410 if num < 0 or num > 6: 409 if num < 0 or num > 6: 411 return 410 return 412 self.timeformat = '%.{0}f'.for 411 self.timeformat = '%.{0}f'.format(num) 413 def setOutputFolder(self, value): 412 def setOutputFolder(self, value): 414 args = dict() 413 args = dict() 415 n = datetime.now() 414 n = datetime.now() 416 args['date'] = n.strftime('%y% 415 args['date'] = n.strftime('%y%m%d') 417 args['time'] = n.strftime('%H% 416 args['time'] = n.strftime('%H%M%S') 418 args['hostname'] = args['host' 417 args['hostname'] = args['host'] = self.hostname 419 args['mode'] = self.suspendmod 418 args['mode'] = self.suspendmode 420 return value.format(**args) 419 return value.format(**args) 421 def setOutputFile(self): 420 def setOutputFile(self): 422 if self.dmesgfile != '': 421 if self.dmesgfile != '': 423 m = re.match(r'(?P<nam !! 422 m = re.match('(?P<name>.*)_dmesg\.txt.*', self.dmesgfile) 424 if(m): 423 if(m): 425 self.htmlfile 424 self.htmlfile = m.group('name')+'.html' 426 if self.ftracefile != '': 425 if self.ftracefile != '': 427 m = re.match(r'(?P<nam !! 426 m = re.match('(?P<name>.*)_ftrace\.txt.*', self.ftracefile) 428 if(m): 427 if(m): 429 self.htmlfile 428 self.htmlfile = m.group('name')+'.html' 430 def systemInfo(self, info): 429 def systemInfo(self, info): 431 p = m = '' 430 p = m = '' 432 if 'baseboard-manufacturer' in 431 if 'baseboard-manufacturer' in info: 433 m = info['baseboard-ma 432 m = info['baseboard-manufacturer'] 434 elif 'system-manufacturer' in 433 elif 'system-manufacturer' in info: 435 m = info['system-manuf 434 m = info['system-manufacturer'] 436 if 'system-product-name' in in 435 if 'system-product-name' in info: 437 p = info['system-produ 436 p = info['system-product-name'] 438 elif 'baseboard-product-name' 437 elif 'baseboard-product-name' in info: 439 p = info['baseboard-pr 438 p = info['baseboard-product-name'] 440 if m[:5].lower() == 'intel' an 439 if m[:5].lower() == 'intel' and 'baseboard-product-name' in info: 441 p = info['baseboard-pr 440 p = info['baseboard-product-name'] 442 c = info['processor-version'] 441 c = info['processor-version'] if 'processor-version' in info else '' 443 b = info['bios-version'] if 'b 442 b = info['bios-version'] if 'bios-version' in info else '' 444 r = info['bios-release-date'] 443 r = info['bios-release-date'] if 'bios-release-date' in info else '' 445 self.sysstamp = '# sysinfo | m 444 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 445 (m, p, c, b, r, self.cpucount, self.memtotal, self.memfree) 447 if self.osversion: 446 if self.osversion: 448 self.sysstamp += ' | o 447 self.sysstamp += ' | os:%s' % self.osversion 449 def printSystemInfo(self, fatal=False) 448 def printSystemInfo(self, fatal=False): 450 self.rootCheck(True) 449 self.rootCheck(True) 451 out = dmidecode(self.mempath, 450 out = dmidecode(self.mempath, fatal) 452 if len(out) < 1: 451 if len(out) < 1: 453 return 452 return 454 fmt = '%-24s: %s' 453 fmt = '%-24s: %s' 455 if self.osversion: 454 if self.osversion: 456 print(fmt % ('os-versi 455 print(fmt % ('os-version', self.osversion)) 457 for name in sorted(out): 456 for name in sorted(out): 458 print(fmt % (name, out 457 print(fmt % (name, out[name])) 459 print(fmt % ('cpucount', ('%d' 458 print(fmt % ('cpucount', ('%d' % self.cpucount))) 460 print(fmt % ('memtotal', ('%d 459 print(fmt % ('memtotal', ('%d kB' % self.memtotal))) 461 print(fmt % ('memfree', ('%d k 460 print(fmt % ('memfree', ('%d kB' % self.memfree))) 462 def cpuInfo(self): 461 def cpuInfo(self): 463 self.cpucount = 0 462 self.cpucount = 0 464 if os.path.exists('/proc/cpuin 463 if os.path.exists('/proc/cpuinfo'): 465 with open('/proc/cpuin 464 with open('/proc/cpuinfo', 'r') as fp: 466 for line in fp 465 for line in fp: 467 if re. !! 466 if re.match('^processor[ \t]*:[ \t]*[0-9]*', line): 468 467 self.cpucount += 1 469 if os.path.exists('/proc/memin 468 if os.path.exists('/proc/meminfo'): 470 with open('/proc/memin 469 with open('/proc/meminfo', 'r') as fp: 471 for line in fp 470 for line in fp: 472 m = re !! 471 m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line) 473 if m: 472 if m: 474 473 self.memtotal = int(m.group('sz')) 475 m = re !! 474 m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line) 476 if m: 475 if m: 477 476 self.memfree = int(m.group('sz')) 478 if os.path.exists('/etc/os-rel 477 if os.path.exists('/etc/os-release'): 479 with open('/etc/os-rel 478 with open('/etc/os-release', 'r') as fp: 480 for line in fp 479 for line in fp: 481 if lin 480 if line.startswith('PRETTY_NAME='): 482 481 self.osversion = line[12:].strip().replace('"', '') 483 def initTestOutput(self, name): 482 def initTestOutput(self, name): 484 self.prefix = self.hostname 483 self.prefix = self.hostname 485 v = open('/proc/version', 'r') 484 v = open('/proc/version', 'r').read().strip() 486 kver = v.split()[2] 485 kver = v.split()[2] 487 fmt = name+'-%m%d%y-%H%M%S' 486 fmt = name+'-%m%d%y-%H%M%S' 488 testtime = datetime.now().strf 487 testtime = datetime.now().strftime(fmt) 489 self.teststamp = \ 488 self.teststamp = \ 490 '# '+testtime+' '+self 489 '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver 491 ext = '' 490 ext = '' 492 if self.gzip: 491 if self.gzip: 493 ext = '.gz' 492 ext = '.gz' 494 self.dmesgfile = \ 493 self.dmesgfile = \ 495 self.testdir+'/'+self. 494 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt'+ext 496 self.ftracefile = \ 495 self.ftracefile = \ 497 self.testdir+'/'+self. 496 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt'+ext 498 self.htmlfile = \ 497 self.htmlfile = \ 499 self.testdir+'/'+self. 498 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' 500 if not os.path.isdir(self.test 499 if not os.path.isdir(self.testdir): 501 os.makedirs(self.testd 500 os.makedirs(self.testdir) 502 self.sudoUserchown(self.testdi 501 self.sudoUserchown(self.testdir) 503 def getValueList(self, value): 502 def getValueList(self, value): 504 out = [] 503 out = [] 505 for i in value.split(','): 504 for i in value.split(','): 506 if i.strip(): 505 if i.strip(): 507 out.append(i.s 506 out.append(i.strip()) 508 return out 507 return out 509 def setDeviceFilter(self, value): 508 def setDeviceFilter(self, value): 510 self.devicefilter = self.getVa 509 self.devicefilter = self.getValueList(value) 511 def setCallgraphFilter(self, value): 510 def setCallgraphFilter(self, value): 512 self.cgfilter = self.getValueL 511 self.cgfilter = self.getValueList(value) 513 def skipKprobes(self, value): 512 def skipKprobes(self, value): 514 for k in self.getValueList(val 513 for k in self.getValueList(value): 515 if k in self.tracefunc 514 if k in self.tracefuncs: 516 del self.trace 515 del self.tracefuncs[k] 517 if k in self.dev_trace 516 if k in self.dev_tracefuncs: 518 del self.dev_t 517 del self.dev_tracefuncs[k] 519 def setCallgraphBlacklist(self, file): 518 def setCallgraphBlacklist(self, file): 520 self.cgblacklist = self.listFr 519 self.cgblacklist = self.listFromFile(file) 521 def rtcWakeAlarmOn(self): 520 def rtcWakeAlarmOn(self): 522 call('echo 0 > '+self.rtcpath+ 521 call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True) 523 nowtime = open(self.rtcpath+'/ 522 nowtime = open(self.rtcpath+'/since_epoch', 'r').read().strip() 524 if nowtime: 523 if nowtime: 525 nowtime = int(nowtime) 524 nowtime = int(nowtime) 526 else: 525 else: 527 # if hardware time fai 526 # if hardware time fails, use the software time 528 nowtime = int(datetime 527 nowtime = int(datetime.now().strftime('%s')) 529 alarm = nowtime + self.rtcwake 528 alarm = nowtime + self.rtcwaketime 530 call('echo %d > %s/wakealarm' 529 call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True) 531 def rtcWakeAlarmOff(self): 530 def rtcWakeAlarmOff(self): 532 call('echo 0 > %s/wakealarm' % 531 call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True) 533 def initdmesg(self): 532 def initdmesg(self): 534 # get the latest time stamp fr 533 # get the latest time stamp from the dmesg log 535 lines = Popen('dmesg', stdout= 534 lines = Popen('dmesg', stdout=PIPE).stdout.readlines() 536 ktime = '0' 535 ktime = '0' 537 for line in reversed(lines): 536 for line in reversed(lines): 538 line = ascii(line).rep 537 line = ascii(line).replace('\r\n', '') 539 idx = line.find('[') 538 idx = line.find('[') 540 if idx > 1: 539 if idx > 1: 541 line = line[id 540 line = line[idx:] 542 m = re.match(r'[ \t]*( !! 541 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 543 if(m): 542 if(m): 544 ktime = m.grou 543 ktime = m.group('ktime') 545 break 544 break 546 self.dmesgstart = float(ktime) 545 self.dmesgstart = float(ktime) 547 def getdmesg(self, testdata): 546 def getdmesg(self, testdata): 548 op = self.writeDatafileHeader( 547 op = self.writeDatafileHeader(self.dmesgfile, testdata) 549 # store all new dmesg lines si 548 # store all new dmesg lines since initdmesg was called 550 fp = Popen('dmesg', stdout=PIP 549 fp = Popen('dmesg', stdout=PIPE).stdout 551 for line in fp: 550 for line in fp: 552 line = ascii(line).rep 551 line = ascii(line).replace('\r\n', '') 553 idx = line.find('[') 552 idx = line.find('[') 554 if idx > 1: 553 if idx > 1: 555 line = line[id 554 line = line[idx:] 556 m = re.match(r'[ \t]*( !! 555 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 557 if(not m): 556 if(not m): 558 continue 557 continue 559 ktime = float(m.group( 558 ktime = float(m.group('ktime')) 560 if ktime > self.dmesgs 559 if ktime > self.dmesgstart: 561 op.write(line) 560 op.write(line) 562 fp.close() 561 fp.close() 563 op.close() 562 op.close() 564 def listFromFile(self, file): 563 def listFromFile(self, file): 565 list = [] 564 list = [] 566 fp = open(file) 565 fp = open(file) 567 for i in fp.read().split('\n') 566 for i in fp.read().split('\n'): 568 i = i.strip() 567 i = i.strip() 569 if i and i[0] != '#': 568 if i and i[0] != '#': 570 list.append(i) 569 list.append(i) 571 fp.close() 570 fp.close() 572 return list 571 return list 573 def addFtraceFilterFunctions(self, fil 572 def addFtraceFilterFunctions(self, file): 574 for i in self.listFromFile(fil 573 for i in self.listFromFile(file): 575 if len(i) < 2: 574 if len(i) < 2: 576 continue 575 continue 577 self.tracefuncs[i] = d 576 self.tracefuncs[i] = dict() 578 def getFtraceFilterFunctions(self, cur 577 def getFtraceFilterFunctions(self, current): 579 self.rootCheck(True) 578 self.rootCheck(True) 580 if not current: 579 if not current: 581 call('cat '+self.tpath 580 call('cat '+self.tpath+'available_filter_functions', shell=True) 582 return 581 return 583 master = self.listFromFile(sel 582 master = self.listFromFile(self.tpath+'available_filter_functions') 584 for i in sorted(self.tracefunc 583 for i in sorted(self.tracefuncs): 585 if 'func' in self.trac 584 if 'func' in self.tracefuncs[i]: 586 i = self.trace 585 i = self.tracefuncs[i]['func'] 587 if i in master: 586 if i in master: 588 print(i) 587 print(i) 589 else: 588 else: 590 print(self.col 589 print(self.colorText(i)) 591 def setFtraceFilterFunctions(self, lis 590 def setFtraceFilterFunctions(self, list): 592 master = self.listFromFile(sel 591 master = self.listFromFile(self.tpath+'available_filter_functions') 593 flist = '' 592 flist = '' 594 for i in list: 593 for i in list: 595 if i not in master: 594 if i not in master: 596 continue 595 continue 597 if ' [' in i: 596 if ' [' in i: 598 flist += i.spl 597 flist += i.split(' ')[0]+'\n' 599 else: 598 else: 600 flist += i+'\n 599 flist += i+'\n' 601 fp = open(self.tpath+'set_grap 600 fp = open(self.tpath+'set_graph_function', 'w') 602 fp.write(flist) 601 fp.write(flist) 603 fp.close() 602 fp.close() 604 def basicKprobe(self, name): 603 def basicKprobe(self, name): 605 self.kprobes[name] = {'name': 604 self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name} 606 def defaultKprobe(self, name, kdata): 605 def defaultKprobe(self, name, kdata): 607 k = kdata 606 k = kdata 608 for field in ['name', 'format' 607 for field in ['name', 'format', 'func']: 609 if field not in k: 608 if field not in k: 610 k[field] = nam 609 k[field] = name 611 if self.archargs in k: 610 if self.archargs in k: 612 k['args'] = k[self.arc 611 k['args'] = k[self.archargs] 613 else: 612 else: 614 k['args'] = dict() 613 k['args'] = dict() 615 k['format'] = name 614 k['format'] = name 616 self.kprobes[name] = k 615 self.kprobes[name] = k 617 def kprobeColor(self, name): 616 def kprobeColor(self, name): 618 if name not in self.kprobes or 617 if name not in self.kprobes or 'color' not in self.kprobes[name]: 619 return '' 618 return '' 620 return self.kprobes[name]['col 619 return self.kprobes[name]['color'] 621 def kprobeDisplayName(self, name, data 620 def kprobeDisplayName(self, name, dataraw): 622 if name not in self.kprobes: 621 if name not in self.kprobes: 623 self.basicKprobe(name) 622 self.basicKprobe(name) 624 data = '' 623 data = '' 625 quote=0 624 quote=0 626 # first remvoe any spaces insi 625 # first remvoe any spaces inside quotes, and the quotes 627 for c in dataraw: 626 for c in dataraw: 628 if c == '"': 627 if c == '"': 629 quote = (quote 628 quote = (quote + 1) % 2 630 if quote and c == ' ': 629 if quote and c == ' ': 631 data += '_' 630 data += '_' 632 elif c != '"': 631 elif c != '"': 633 data += c 632 data += c 634 fmt, args = self.kprobes[name] 633 fmt, args = self.kprobes[name]['format'], self.kprobes[name]['args'] 635 arglist = dict() 634 arglist = dict() 636 # now process the args 635 # now process the args 637 for arg in sorted(args): 636 for arg in sorted(args): 638 arglist[arg] = '' 637 arglist[arg] = '' 639 m = re.match(r'.* '+ar !! 638 m = re.match('.* '+arg+'=(?P<arg>.*) ', data); 640 if m: 639 if m: 641 arglist[arg] = 640 arglist[arg] = m.group('arg') 642 else: 641 else: 643 m = re.match(r !! 642 m = re.match('.* '+arg+'=(?P<arg>.*)', data); 644 if m: 643 if m: 645 arglis 644 arglist[arg] = m.group('arg') 646 out = fmt.format(**arglist) 645 out = fmt.format(**arglist) 647 out = out.replace(' ', '_').re 646 out = out.replace(' ', '_').replace('"', '') 648 return out 647 return out 649 def kprobeText(self, kname, kprobe): 648 def kprobeText(self, kname, kprobe): 650 name = fmt = func = kname 649 name = fmt = func = kname 651 args = dict() 650 args = dict() 652 if 'name' in kprobe: 651 if 'name' in kprobe: 653 name = kprobe['name'] 652 name = kprobe['name'] 654 if 'format' in kprobe: 653 if 'format' in kprobe: 655 fmt = kprobe['format'] 654 fmt = kprobe['format'] 656 if 'func' in kprobe: 655 if 'func' in kprobe: 657 func = kprobe['func'] 656 func = kprobe['func'] 658 if self.archargs in kprobe: 657 if self.archargs in kprobe: 659 args = kprobe[self.arc 658 args = kprobe[self.archargs] 660 if 'args' in kprobe: 659 if 'args' in kprobe: 661 args = kprobe['args'] 660 args = kprobe['args'] 662 if re.findall('{(?P<n>[a-z,A-Z 661 if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func): 663 doError('Kprobe "%s" h 662 doError('Kprobe "%s" has format info in the function name "%s"' % (name, func)) 664 for arg in re.findall('{(?P<n> 663 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt): 665 if arg not in args: 664 if arg not in args: 666 doError('Kprob 665 doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 667 val = 'p:%s_cal %s' % (name, f 666 val = 'p:%s_cal %s' % (name, func) 668 for i in sorted(args): 667 for i in sorted(args): 669 val += ' %s=%s' % (i, 668 val += ' %s=%s' % (i, args[i]) 670 val += '\nr:%s_ret %s $retval\ 669 val += '\nr:%s_ret %s $retval\n' % (name, func) 671 return val 670 return val 672 def addKprobes(self, output=False): 671 def addKprobes(self, output=False): 673 if len(self.kprobes) < 1: 672 if len(self.kprobes) < 1: 674 return 673 return 675 if output: 674 if output: 676 pprint(' kprobe fun 675 pprint(' kprobe functions in this kernel:') 677 # first test each kprobe 676 # first test each kprobe 678 rejects = [] 677 rejects = [] 679 # sort kprobes: trace, ub-dev, 678 # sort kprobes: trace, ub-dev, custom, dev 680 kpl = [[], [], [], []] 679 kpl = [[], [], [], []] 681 linesout = len(self.kprobes) 680 linesout = len(self.kprobes) 682 for name in sorted(self.kprobe 681 for name in sorted(self.kprobes): 683 res = self.colorText(' 682 res = self.colorText('YES', 32) 684 if not self.testKprobe 683 if not self.testKprobe(name, self.kprobes[name]): 685 res = self.col 684 res = self.colorText('NO') 686 rejects.append 685 rejects.append(name) 687 else: 686 else: 688 if name in sel 687 if name in self.tracefuncs: 689 kpl[0] 688 kpl[0].append(name) 690 elif name in s 689 elif name in self.dev_tracefuncs: 691 if 'ub 690 if 'ub' in self.dev_tracefuncs[name]: 692 691 kpl[1].append(name) 693 else: 692 else: 694 693 kpl[3].append(name) 695 else: 694 else: 696 kpl[2] 695 kpl[2].append(name) 697 if output: 696 if output: 698 pprint(' 697 pprint(' %s: %s' % (name, res)) 699 kplist = kpl[0] + kpl[1] + kpl 698 kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3] 700 # remove all failed ones from 699 # remove all failed ones from the list 701 for name in rejects: 700 for name in rejects: 702 self.kprobes.pop(name) 701 self.kprobes.pop(name) 703 # set the kprobes all at once 702 # set the kprobes all at once 704 self.fsetVal('', 'kprobe_event 703 self.fsetVal('', 'kprobe_events') 705 kprobeevents = '' 704 kprobeevents = '' 706 for kp in kplist: 705 for kp in kplist: 707 kprobeevents += self.k 706 kprobeevents += self.kprobeText(kp, self.kprobes[kp]) 708 self.fsetVal(kprobeevents, 'kp 707 self.fsetVal(kprobeevents, 'kprobe_events') 709 if output: 708 if output: 710 check = self.fgetVal(' 709 check = self.fgetVal('kprobe_events') 711 linesack = (len(check. 710 linesack = (len(check.split('\n')) - 1) // 2 712 pprint(' kprobe fun 711 pprint(' kprobe functions enabled: %d/%d' % (linesack, linesout)) 713 self.fsetVal('1', 'events/kpro 712 self.fsetVal('1', 'events/kprobes/enable') 714 def testKprobe(self, kname, kprobe): 713 def testKprobe(self, kname, kprobe): 715 self.fsetVal('0', 'events/kpro 714 self.fsetVal('0', 'events/kprobes/enable') 716 kprobeevents = self.kprobeText 715 kprobeevents = self.kprobeText(kname, kprobe) 717 if not kprobeevents: 716 if not kprobeevents: 718 return False 717 return False 719 try: 718 try: 720 self.fsetVal(kprobeeve 719 self.fsetVal(kprobeevents, 'kprobe_events') 721 check = self.fgetVal(' 720 check = self.fgetVal('kprobe_events') 722 except: 721 except: 723 return False 722 return False 724 linesout = len(kprobeevents.sp 723 linesout = len(kprobeevents.split('\n')) 725 linesack = len(check.split('\n 724 linesack = len(check.split('\n')) 726 if linesack < linesout: 725 if linesack < linesout: 727 return False 726 return False 728 return True 727 return True 729 def setVal(self, val, file): 728 def setVal(self, val, file): 730 if not os.path.exists(file): 729 if not os.path.exists(file): 731 return False 730 return False 732 try: 731 try: 733 fp = open(file, 'wb', 732 fp = open(file, 'wb', 0) 734 fp.write(val.encode()) 733 fp.write(val.encode()) 735 fp.flush() 734 fp.flush() 736 fp.close() 735 fp.close() 737 except: 736 except: 738 return False 737 return False 739 return True 738 return True 740 def fsetVal(self, val, path): 739 def fsetVal(self, val, path): 741 if not self.useftrace: 740 if not self.useftrace: 742 return False 741 return False 743 return self.setVal(val, self.t 742 return self.setVal(val, self.tpath+path) 744 def getVal(self, file): 743 def getVal(self, file): 745 res = '' 744 res = '' 746 if not os.path.exists(file): 745 if not os.path.exists(file): 747 return res 746 return res 748 try: 747 try: 749 fp = open(file, 'r') 748 fp = open(file, 'r') 750 res = fp.read() 749 res = fp.read() 751 fp.close() 750 fp.close() 752 except: 751 except: 753 pass 752 pass 754 return res 753 return res 755 def fgetVal(self, path): 754 def fgetVal(self, path): 756 if not self.useftrace: 755 if not self.useftrace: 757 return '' 756 return '' 758 return self.getVal(self.tpath+ 757 return self.getVal(self.tpath+path) 759 def cleanupFtrace(self): 758 def cleanupFtrace(self): 760 if self.useftrace: 759 if self.useftrace: 761 self.fsetVal('0', 'eve 760 self.fsetVal('0', 'events/kprobes/enable') 762 self.fsetVal('', 'kpro 761 self.fsetVal('', 'kprobe_events') 763 self.fsetVal('1024', ' 762 self.fsetVal('1024', 'buffer_size_kb') 764 def setupAllKprobes(self): 763 def setupAllKprobes(self): 765 for name in self.tracefuncs: 764 for name in self.tracefuncs: 766 self.defaultKprobe(nam 765 self.defaultKprobe(name, self.tracefuncs[name]) 767 for name in self.dev_tracefunc 766 for name in self.dev_tracefuncs: 768 self.defaultKprobe(nam 767 self.defaultKprobe(name, self.dev_tracefuncs[name]) 769 def isCallgraphFunc(self, name): 768 def isCallgraphFunc(self, name): 770 if len(self.tracefuncs) < 1 an 769 if len(self.tracefuncs) < 1 and self.suspendmode == 'command': 771 return True 770 return True 772 for i in self.tracefuncs: 771 for i in self.tracefuncs: 773 if 'func' in self.trac 772 if 'func' in self.tracefuncs[i]: 774 f = self.trace 773 f = self.tracefuncs[i]['func'] 775 else: 774 else: 776 f = i 775 f = i 777 if name == f: 776 if name == f: 778 return True 777 return True 779 return False 778 return False 780 def initFtrace(self, quiet=False): 779 def initFtrace(self, quiet=False): 781 if not self.useftrace: 780 if not self.useftrace: 782 return 781 return 783 if not quiet: 782 if not quiet: 784 sysvals.printSystemInf 783 sysvals.printSystemInfo(False) 785 pprint('INITIALIZING F 784 pprint('INITIALIZING FTRACE') 786 # turn trace off 785 # turn trace off 787 self.fsetVal('0', 'tracing_on' 786 self.fsetVal('0', 'tracing_on') 788 self.cleanupFtrace() 787 self.cleanupFtrace() 789 # set the trace clock to globa 788 # set the trace clock to global 790 self.fsetVal('global', 'trace_ 789 self.fsetVal('global', 'trace_clock') 791 self.fsetVal('nop', 'current_t 790 self.fsetVal('nop', 'current_tracer') 792 # set trace buffer to an appro 791 # set trace buffer to an appropriate value 793 cpus = max(1, self.cpucount) 792 cpus = max(1, self.cpucount) 794 if self.bufsize > 0: 793 if self.bufsize > 0: 795 tgtsize = self.bufsize 794 tgtsize = self.bufsize 796 elif self.usecallgraph or self 795 elif self.usecallgraph or self.usedevsrc: 797 bmax = (1*1024*1024) i 796 bmax = (1*1024*1024) if self.suspendmode in ['disk', 'command'] \ 798 else (3*1024*1 797 else (3*1024*1024) 799 tgtsize = min(self.mem 798 tgtsize = min(self.memfree, bmax) 800 else: 799 else: 801 tgtsize = 65536 800 tgtsize = 65536 802 while not self.fsetVal('%d' % 801 while not self.fsetVal('%d' % (tgtsize // cpus), 'buffer_size_kb'): 803 # if the size failed t 802 # if the size failed to set, lower it and keep trying 804 tgtsize -= 65536 803 tgtsize -= 65536 805 if tgtsize < 65536: 804 if tgtsize < 65536: 806 tgtsize = int( 805 tgtsize = int(self.fgetVal('buffer_size_kb')) * cpus 807 break 806 break 808 self.vprint('Setting trace buf 807 self.vprint('Setting trace buffers to %d kB (%d kB per cpu)' % (tgtsize, tgtsize/cpus)) 809 # initialize the callgraph tra 808 # initialize the callgraph trace 810 if(self.usecallgraph): 809 if(self.usecallgraph): 811 # set trace type 810 # set trace type 812 self.fsetVal('function 811 self.fsetVal('function_graph', 'current_tracer') 813 self.fsetVal('', 'set_ 812 self.fsetVal('', 'set_ftrace_filter') 814 # temporary hack to fi 813 # temporary hack to fix https://bugzilla.kernel.org/show_bug.cgi?id=212761 815 fp = open(self.tpath+' 814 fp = open(self.tpath+'set_ftrace_notrace', 'w') 816 fp.write('native_queue 815 fp.write('native_queued_spin_lock_slowpath\ndev_driver_string') 817 fp.close() 816 fp.close() 818 # set trace format opt 817 # set trace format options 819 self.fsetVal('print-pa 818 self.fsetVal('print-parent', 'trace_options') 820 self.fsetVal('funcgrap 819 self.fsetVal('funcgraph-abstime', 'trace_options') 821 self.fsetVal('funcgrap 820 self.fsetVal('funcgraph-cpu', 'trace_options') 822 self.fsetVal('funcgrap 821 self.fsetVal('funcgraph-duration', 'trace_options') 823 self.fsetVal('funcgrap 822 self.fsetVal('funcgraph-proc', 'trace_options') 824 self.fsetVal('funcgrap 823 self.fsetVal('funcgraph-tail', 'trace_options') 825 self.fsetVal('nofuncgr 824 self.fsetVal('nofuncgraph-overhead', 'trace_options') 826 self.fsetVal('context- 825 self.fsetVal('context-info', 'trace_options') 827 self.fsetVal('graph-ti 826 self.fsetVal('graph-time', 'trace_options') 828 self.fsetVal('%d' % se 827 self.fsetVal('%d' % self.max_graph_depth, 'max_graph_depth') 829 cf = ['dpm_run_callbac 828 cf = ['dpm_run_callback'] 830 if(self.usetraceevents 829 if(self.usetraceevents): 831 cf += ['dpm_pr 830 cf += ['dpm_prepare', 'dpm_complete'] 832 for fn in self.tracefu 831 for fn in self.tracefuncs: 833 if 'func' in s 832 if 'func' in self.tracefuncs[fn]: 834 cf.app 833 cf.append(self.tracefuncs[fn]['func']) 835 else: 834 else: 836 cf.app 835 cf.append(fn) 837 if self.ftop: 836 if self.ftop: 838 self.setFtrace 837 self.setFtraceFilterFunctions([self.ftopfunc]) 839 else: 838 else: 840 self.setFtrace 839 self.setFtraceFilterFunctions(cf) 841 # initialize the kprobe trace 840 # initialize the kprobe trace 842 elif self.usekprobes: 841 elif self.usekprobes: 843 for name in self.trace 842 for name in self.tracefuncs: 844 self.defaultKp 843 self.defaultKprobe(name, self.tracefuncs[name]) 845 if self.usedevsrc: 844 if self.usedevsrc: 846 for name in se 845 for name in self.dev_tracefuncs: 847 self.d 846 self.defaultKprobe(name, self.dev_tracefuncs[name]) 848 if not quiet: 847 if not quiet: 849 pprint('INITIA 848 pprint('INITIALIZING KPROBES') 850 self.addKprobes(self.v 849 self.addKprobes(self.verbose) 851 if(self.usetraceevents): 850 if(self.usetraceevents): 852 # turn trace events on 851 # turn trace events on 853 events = iter(self.tra 852 events = iter(self.traceevents) 854 for e in events: 853 for e in events: 855 self.fsetVal(' 854 self.fsetVal('1', 'events/power/'+e+'/enable') 856 # clear the trace buffer 855 # clear the trace buffer 857 self.fsetVal('', 'trace') 856 self.fsetVal('', 'trace') 858 def verifyFtrace(self): 857 def verifyFtrace(self): 859 # files needed for any trace d 858 # files needed for any trace data 860 files = ['buffer_size_kb', 'cu 859 files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock', 861 'trace_marker 860 'trace_marker', 'trace_options', 'tracing_on'] 862 # files needed for callgraph t 861 # files needed for callgraph trace data 863 tp = self.tpath 862 tp = self.tpath 864 if(self.usecallgraph): 863 if(self.usecallgraph): 865 files += [ 864 files += [ 866 'available_fil 865 'available_filter_functions', 867 'set_ftrace_fi 866 'set_ftrace_filter', 868 'set_graph_fun 867 'set_graph_function' 869 ] 868 ] 870 for f in files: 869 for f in files: 871 if(os.path.exists(tp+f 870 if(os.path.exists(tp+f) == False): 872 return False 871 return False 873 return True 872 return True 874 def verifyKprobes(self): 873 def verifyKprobes(self): 875 # files needed for kprobes to 874 # files needed for kprobes to work 876 files = ['kprobe_events', 'eve 875 files = ['kprobe_events', 'events'] 877 tp = self.tpath 876 tp = self.tpath 878 for f in files: 877 for f in files: 879 if(os.path.exists(tp+f 878 if(os.path.exists(tp+f) == False): 880 return False 879 return False 881 return True 880 return True 882 def colorText(self, str, color=31): 881 def colorText(self, str, color=31): 883 if not self.ansi: 882 if not self.ansi: 884 return str 883 return str 885 return '\x1B[%d;40m%s\x1B[m' % 884 return '\x1B[%d;40m%s\x1B[m' % (color, str) 886 def writeDatafileHeader(self, filename 885 def writeDatafileHeader(self, filename, testdata): 887 fp = self.openlog(filename, 'w 886 fp = self.openlog(filename, 'w') 888 fp.write('%s\n%s\n# command | 887 fp.write('%s\n%s\n# command | %s\n' % (self.teststamp, self.sysstamp, self.cmdline)) 889 for test in testdata: 888 for test in testdata: 890 if 'fw' in test: 889 if 'fw' in test: 891 fw = test['fw' 890 fw = test['fw'] 892 if(fw): 891 if(fw): 893 fp.wri 892 fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) 894 if 'turbo' in test: 893 if 'turbo' in test: 895 fp.write('# tu 894 fp.write('# turbostat %s\n' % test['turbo']) 896 if 'wifi' in test: 895 if 'wifi' in test: 897 fp.write('# wi 896 fp.write('# wifi %s\n' % test['wifi']) 898 if 'netfix' in test: 897 if 'netfix' in test: 899 fp.write('# ne 898 fp.write('# netfix %s\n' % test['netfix']) 900 if test['error'] or le 899 if test['error'] or len(testdata) > 1: 901 fp.write('# en 900 fp.write('# enter_sleep_error %s\n' % test['error']) 902 return fp 901 return fp 903 def sudoUserchown(self, dir): 902 def sudoUserchown(self, dir): 904 if os.path.exists(dir) and sel 903 if os.path.exists(dir) and self.sudouser: 905 cmd = 'chown -R {0}:{0 904 cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' 906 call(cmd.format(self.s 905 call(cmd.format(self.sudouser, dir), shell=True) 907 def outputResult(self, testdata, num=0 906 def outputResult(self, testdata, num=0): 908 if not self.result: 907 if not self.result: 909 return 908 return 910 n = '' 909 n = '' 911 if num > 0: 910 if num > 0: 912 n = '%d' % num 911 n = '%d' % num 913 fp = open(self.result, 'a') 912 fp = open(self.result, 'a') 914 if 'error' in testdata: 913 if 'error' in testdata: 915 fp.write('result%s: fa 914 fp.write('result%s: fail\n' % n) 916 fp.write('error%s: %s\ 915 fp.write('error%s: %s\n' % (n, testdata['error'])) 917 else: 916 else: 918 fp.write('result%s: pa 917 fp.write('result%s: pass\n' % n) 919 if 'mode' in testdata: 918 if 'mode' in testdata: 920 fp.write('mode%s: %s\n 919 fp.write('mode%s: %s\n' % (n, testdata['mode'])) 921 for v in ['suspend', 'resume', 920 for v in ['suspend', 'resume', 'boot', 'lastinit']: 922 if v in testdata: 921 if v in testdata: 923 fp.write('%s%s 922 fp.write('%s%s: %.3f\n' % (v, n, testdata[v])) 924 for v in ['fwsuspend', 'fwresu 923 for v in ['fwsuspend', 'fwresume']: 925 if v in testdata: 924 if v in testdata: 926 fp.write('%s%s 925 fp.write('%s%s: %.3f\n' % (v, n, testdata[v] / 1000000.0)) 927 if 'bugurl' in testdata: 926 if 'bugurl' in testdata: 928 fp.write('url%s: %s\n' 927 fp.write('url%s: %s\n' % (n, testdata['bugurl'])) 929 fp.close() 928 fp.close() 930 self.sudoUserchown(self.result 929 self.sudoUserchown(self.result) 931 def configFile(self, file): 930 def configFile(self, file): 932 dir = os.path.dirname(os.path. 931 dir = os.path.dirname(os.path.realpath(__file__)) 933 if os.path.exists(file): 932 if os.path.exists(file): 934 return file 933 return file 935 elif os.path.exists(dir+'/'+fi 934 elif os.path.exists(dir+'/'+file): 936 return dir+'/'+file 935 return dir+'/'+file 937 elif os.path.exists(dir+'/conf 936 elif os.path.exists(dir+'/config/'+file): 938 return dir+'/config/'+ 937 return dir+'/config/'+file 939 return '' 938 return '' 940 def openlog(self, filename, mode): 939 def openlog(self, filename, mode): 941 isgz = self.gzip 940 isgz = self.gzip 942 if mode == 'r': 941 if mode == 'r': 943 try: 942 try: 944 with gzip.open 943 with gzip.open(filename, mode+'t') as fp: 945 test = 944 test = fp.read(64) 946 isgz = True 945 isgz = True 947 except: 946 except: 948 isgz = False 947 isgz = False 949 if isgz: 948 if isgz: 950 return gzip.open(filen 949 return gzip.open(filename, mode+'t') 951 return open(filename, mode) 950 return open(filename, mode) 952 def putlog(self, filename, text): 951 def putlog(self, filename, text): 953 with self.openlog(filename, 'a 952 with self.openlog(filename, 'a') as fp: 954 fp.write(text) 953 fp.write(text) 955 fp.close() 954 fp.close() 956 def dlog(self, text): 955 def dlog(self, text): 957 if not self.dmesgfile: 956 if not self.dmesgfile: 958 return 957 return 959 self.putlog(self.dmesgfile, '# 958 self.putlog(self.dmesgfile, '# %s\n' % text) 960 def flog(self, text): 959 def flog(self, text): 961 self.putlog(self.ftracefile, t 960 self.putlog(self.ftracefile, text) 962 def b64unzip(self, data): 961 def b64unzip(self, data): 963 try: 962 try: 964 out = codecs.decode(ba 963 out = codecs.decode(base64.b64decode(data), 'zlib').decode() 965 except: 964 except: 966 out = data 965 out = data 967 return out 966 return out 968 def b64zip(self, data): 967 def b64zip(self, data): 969 out = base64.b64encode(codecs. 968 out = base64.b64encode(codecs.encode(data.encode(), 'zlib')).decode() 970 return out 969 return out 971 def platforminfo(self, cmdafter): 970 def platforminfo(self, cmdafter): 972 # add platform info on to a co 971 # add platform info on to a completed ftrace file 973 if not os.path.exists(self.ftr 972 if not os.path.exists(self.ftracefile): 974 return False 973 return False 975 footer = '#\n' 974 footer = '#\n' 976 975 977 # add test command string line 976 # add test command string line if need be 978 if self.suspendmode == 'comman 977 if self.suspendmode == 'command' and self.testcommand: 979 footer += '# platform- 978 footer += '# platform-testcmd: %s\n' % (self.testcommand) 980 979 981 # get a list of target devices 980 # get a list of target devices from the ftrace file 982 props = dict() 981 props = dict() 983 tp = TestProps() 982 tp = TestProps() 984 tf = self.openlog(self.ftracef 983 tf = self.openlog(self.ftracefile, 'r') 985 for line in tf: 984 for line in tf: 986 if tp.stampInfo(line, 985 if tp.stampInfo(line, self): 987 continue 986 continue 988 # parse only valid lin 987 # parse only valid lines, if this is not one move on 989 m = re.match(tp.ftrace 988 m = re.match(tp.ftrace_line_fmt, line) 990 if(not m or 'device_pm 989 if(not m or 'device_pm_callback_start' not in line): 991 continue 990 continue 992 m = re.match(r'.*: (?P !! 991 m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg')); 993 if(not m): 992 if(not m): 994 continue 993 continue 995 dev = m.group('d') 994 dev = m.group('d') 996 if dev not in props: 995 if dev not in props: 997 props[dev] = D 996 props[dev] = DevProps() 998 tf.close() 997 tf.close() 999 998 1000 # now get the syspath for eac 999 # now get the syspath for each target device 1001 for dirname, dirnames, filena 1000 for dirname, dirnames, filenames in os.walk('/sys/devices'): 1002 if(re.match(r'.*/powe !! 1001 if(re.match('.*/power', dirname) and 'async' in filenames): 1003 dev = dirname 1002 dev = dirname.split('/')[-2] 1004 if dev in pro 1003 if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)): 1005 props 1004 props[dev].syspath = dirname[:-6] 1006 1005 1007 # now fill in the properties 1006 # now fill in the properties for our target devices 1008 for dev in sorted(props): 1007 for dev in sorted(props): 1009 dirname = props[dev]. 1008 dirname = props[dev].syspath 1010 if not dirname or not 1009 if not dirname or not os.path.exists(dirname): 1011 continue 1010 continue 1012 props[dev].isasync = 1011 props[dev].isasync = False 1013 if os.path.exists(dir 1012 if os.path.exists(dirname+'/power/async'): 1014 fp = open(dir 1013 fp = open(dirname+'/power/async') 1015 if 'enabled' 1014 if 'enabled' in fp.read(): 1016 props 1015 props[dev].isasync = True 1017 fp.close() 1016 fp.close() 1018 fields = os.listdir(d 1017 fields = os.listdir(dirname) 1019 for file in ['product 1018 for file in ['product', 'name', 'model', 'description', 'id', 'idVendor']: 1020 if file not i 1019 if file not in fields: 1021 conti 1020 continue 1022 try: 1021 try: 1023 with 1022 with open(os.path.join(dirname, file), 'rb') as fp: 1024 1023 props[dev].altname = ascii(fp.read()) 1025 except: 1024 except: 1026 conti 1025 continue 1027 if file == 'i 1026 if file == 'idVendor': 1028 idv, 1027 idv, idp = props[dev].altname.strip(), '' 1029 try: 1028 try: 1030 1029 with open(os.path.join(dirname, 'idProduct'), 'rb') as fp: 1031 1030 idp = ascii(fp.read()).strip() 1032 excep 1031 except: 1033 1032 props[dev].altname = '' 1034 1033 break 1035 props 1034 props[dev].altname = '%s:%s' % (idv, idp) 1036 break 1035 break 1037 if props[dev].altname 1036 if props[dev].altname: 1038 out = props[d 1037 out = props[dev].altname.strip().replace('\n', ' ')\ 1039 .repl 1038 .replace(',', ' ').replace(';', ' ') 1040 props[dev].al 1039 props[dev].altname = out 1041 1040 1042 # add a devinfo line to the b 1041 # add a devinfo line to the bottom of ftrace 1043 out = '' 1042 out = '' 1044 for dev in sorted(props): 1043 for dev in sorted(props): 1045 out += props[dev].out 1044 out += props[dev].out(dev) 1046 footer += '# platform-devinfo 1045 footer += '# platform-devinfo: %s\n' % self.b64zip(out) 1047 1046 1048 # add a line for each of thes 1047 # add a line for each of these commands with their outputs 1049 for name, cmdline, info in cm 1048 for name, cmdline, info in cmdafter: 1050 footer += '# platform 1049 footer += '# platform-%s: %s | %s\n' % (name, cmdline, self.b64zip(info)) 1051 self.flog(footer) 1050 self.flog(footer) 1052 return True 1051 return True 1053 def commonPrefix(self, list): 1052 def commonPrefix(self, list): 1054 if len(list) < 2: 1053 if len(list) < 2: 1055 return '' 1054 return '' 1056 prefix = list[0] 1055 prefix = list[0] 1057 for s in list[1:]: 1056 for s in list[1:]: 1058 while s[:len(prefix)] 1057 while s[:len(prefix)] != prefix and prefix: 1059 prefix = pref 1058 prefix = prefix[:len(prefix)-1] 1060 if not prefix: 1059 if not prefix: 1061 break 1060 break 1062 if '/' in prefix and prefix[- 1061 if '/' in prefix and prefix[-1] != '/': 1063 prefix = prefix[0:pre 1062 prefix = prefix[0:prefix.rfind('/')+1] 1064 return prefix 1063 return prefix 1065 def dictify(self, text, format): 1064 def dictify(self, text, format): 1066 out = dict() 1065 out = dict() 1067 header = True if format == 1 1066 header = True if format == 1 else False 1068 delim = ' ' if format == 1 el 1067 delim = ' ' if format == 1 else ':' 1069 for line in text.split('\n'): 1068 for line in text.split('\n'): 1070 if header: 1069 if header: 1071 header, out[' 1070 header, out['@'] = False, line 1072 continue 1071 continue 1073 line = line.strip() 1072 line = line.strip() 1074 if delim in line: 1073 if delim in line: 1075 data = line.s 1074 data = line.split(delim, 1) 1076 num = re.sear 1075 num = re.search(r'[\d]+', data[1]) 1077 if format == 1076 if format == 2 and num: 1078 out[d 1077 out[data[0].strip()] = num.group() 1079 else: 1078 else: 1080 out[d 1079 out[data[0].strip()] = data[1] 1081 return out 1080 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) 1081 def cmdinfo(self, begin, debug=False): 1097 out = [] 1082 out = [] 1098 if begin: 1083 if begin: 1099 self.cmd1 = dict() 1084 self.cmd1 = dict() 1100 for cargs in self.infocmds: 1085 for cargs in self.infocmds: 1101 delta, name, args = c !! 1086 delta, name = cargs[0], cargs[1] 1102 for i in range(len(ar !! 1087 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 1088 if not cmdpath or (begin and not delta): 1107 continue 1089 continue 1108 self.dlog('[%s]' % cm 1090 self.dlog('[%s]' % cmdline) 1109 try: 1091 try: 1110 fp = Popen([c !! 1092 fp = Popen([cmdpath]+cargs[3:], stdout=PIPE, stderr=PIPE).stdout 1111 info = ascii( 1093 info = ascii(fp.read()).strip() 1112 fp.close() 1094 fp.close() 1113 except: 1095 except: 1114 continue 1096 continue 1115 if not debug and begi 1097 if not debug and begin: 1116 self.cmd1[nam 1098 self.cmd1[name] = self.dictify(info, delta) 1117 elif not debug and de 1099 elif not debug and delta and name in self.cmd1: 1118 before, after 1100 before, after = self.cmd1[name], self.dictify(info, delta) 1119 dinfo = ('\t% 1101 dinfo = ('\t%s\n' % before['@']) if '@' in before and len(before) > 1 else '' 1120 prefix = self 1102 prefix = self.commonPrefix(list(before.keys())) 1121 for key in so 1103 for key in sorted(before): 1122 if ke 1104 if key in after and before[key] != after[key]: 1123 1105 title = key.replace(prefix, '') 1124 1106 if delta == 2: 1125 1107 dinfo += '\t%s : %s -> %s\n' % \ 1126 1108 (title, before[key].strip(), after[key].strip()) 1127 1109 else: 1128 1110 dinfo += '%10s (start) : %s\n%10s (after) : %s\n' % \ 1129 1111 (title, before[key], title, after[key]) 1130 dinfo = '\tno 1112 dinfo = '\tnothing changed' if not dinfo else dinfo.rstrip() 1131 out.append((n 1113 out.append((name, cmdline, dinfo)) 1132 else: 1114 else: 1133 out.append((n 1115 out.append((name, cmdline, '\tnothing' if not info else info)) 1134 return out 1116 return out 1135 def testVal(self, file, fmt='basic', 1117 def testVal(self, file, fmt='basic', value=''): 1136 if file == 'restoreall': 1118 if file == 'restoreall': 1137 for f in self.cfgdef: 1119 for f in self.cfgdef: 1138 if os.path.ex 1120 if os.path.exists(f): 1139 fp = 1121 fp = open(f, 'w') 1140 fp.wr 1122 fp.write(self.cfgdef[f]) 1141 fp.cl 1123 fp.close() 1142 self.cfgdef = dict() 1124 self.cfgdef = dict() 1143 elif value and os.path.exists 1125 elif value and os.path.exists(file): 1144 fp = open(file, 'r+') 1126 fp = open(file, 'r+') 1145 if fmt == 'radio': 1127 if fmt == 'radio': 1146 m = re.match( !! 1128 m = re.match('.*\[(?P<v>.*)\].*', fp.read()) 1147 if m: 1129 if m: 1148 self. 1130 self.cfgdef[file] = m.group('v') 1149 elif fmt == 'acpi': 1131 elif fmt == 'acpi': 1150 line = fp.rea 1132 line = fp.read().strip().split('\n')[-1] 1151 m = re.match( !! 1133 m = re.match('.* (?P<v>[0-9A-Fx]*) .*', line) 1152 if m: 1134 if m: 1153 self. 1135 self.cfgdef[file] = m.group('v') 1154 else: 1136 else: 1155 self.cfgdef[f 1137 self.cfgdef[file] = fp.read().strip() 1156 fp.write(value) 1138 fp.write(value) 1157 fp.close() 1139 fp.close() 1158 def s0ixSupport(self): 1140 def s0ixSupport(self): 1159 if not os.path.exists(self.s0 1141 if not os.path.exists(self.s0ixres) or not os.path.exists(self.mempowerfile): 1160 return False 1142 return False 1161 fp = open(sysvals.mempowerfil 1143 fp = open(sysvals.mempowerfile, 'r') 1162 data = fp.read().strip() 1144 data = fp.read().strip() 1163 fp.close() 1145 fp.close() 1164 if '[s2idle]' in data: 1146 if '[s2idle]' in data: 1165 return True 1147 return True 1166 return False 1148 return False 1167 def haveTurbostat(self): 1149 def haveTurbostat(self): 1168 if not self.tstat: 1150 if not self.tstat: 1169 return False 1151 return False 1170 cmd = self.getExec('turbostat 1152 cmd = self.getExec('turbostat') 1171 if not cmd: 1153 if not cmd: 1172 return False 1154 return False 1173 fp = Popen([cmd, '-v'], stdou 1155 fp = Popen([cmd, '-v'], stdout=PIPE, stderr=PIPE).stderr 1174 out = ascii(fp.read()).strip( 1156 out = ascii(fp.read()).strip() 1175 fp.close() 1157 fp.close() 1176 if re.match(r'turbostat versi !! 1158 if re.match('turbostat version .*', out): 1177 self.vprint(out) 1159 self.vprint(out) 1178 return True 1160 return True 1179 return False 1161 return False 1180 def turbostat(self, s0ixready): 1162 def turbostat(self, s0ixready): 1181 cmd = self.getExec('turbostat 1163 cmd = self.getExec('turbostat') 1182 rawout = keyline = valline = 1164 rawout = keyline = valline = '' 1183 fullcmd = '%s -q -S echo free 1165 fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile) 1184 fp = Popen(['sh', '-c', fullc !! 1166 fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE).stderr 1185 for line in fp.stderr: !! 1167 for line in fp: 1186 line = ascii(line) 1168 line = ascii(line) 1187 rawout += line 1169 rawout += line 1188 if keyline and vallin 1170 if keyline and valline: 1189 continue 1171 continue 1190 if re.match(r'(?i)Avg !! 1172 if re.match('(?i)Avg_MHz.*', line): 1191 keyline = lin 1173 keyline = line.strip().split() 1192 elif keyline: 1174 elif keyline: 1193 valline = lin 1175 valline = line.strip().split() 1194 fp.wait() !! 1176 fp.close() 1195 if not keyline or not valline 1177 if not keyline or not valline or len(keyline) != len(valline): 1196 errmsg = 'unrecognize 1178 errmsg = 'unrecognized turbostat output:\n'+rawout.strip() 1197 self.vprint(errmsg) 1179 self.vprint(errmsg) 1198 if not self.verbose: 1180 if not self.verbose: 1199 pprint(errmsg 1181 pprint(errmsg) 1200 return (fp.returncode !! 1182 return '' 1201 if self.verbose: 1183 if self.verbose: 1202 pprint(rawout.strip() 1184 pprint(rawout.strip()) 1203 out = [] 1185 out = [] 1204 for key in keyline: 1186 for key in keyline: 1205 idx = keyline.index(k 1187 idx = keyline.index(key) 1206 val = valline[idx] 1188 val = valline[idx] 1207 if key == 'SYS%LPI' a !! 1189 if key == 'SYS%LPI' and not s0ixready and re.match('^[0\.]*$', val): 1208 continue 1190 continue 1209 out.append('%s=%s' % 1191 out.append('%s=%s' % (key, val)) 1210 return (fp.returncode, '|'.jo !! 1192 return '|'.join(out) 1211 def netfixon(self, net='both'): 1193 def netfixon(self, net='both'): 1212 cmd = self.getExec('netfix') 1194 cmd = self.getExec('netfix') 1213 if not cmd: 1195 if not cmd: 1214 return '' 1196 return '' 1215 fp = Popen([cmd, '-s', net, ' 1197 fp = Popen([cmd, '-s', net, 'on'], stdout=PIPE, stderr=PIPE).stdout 1216 out = ascii(fp.read()).strip( 1198 out = ascii(fp.read()).strip() 1217 fp.close() 1199 fp.close() 1218 return out 1200 return out 1219 def wifiDetails(self, dev): 1201 def wifiDetails(self, dev): 1220 try: 1202 try: 1221 info = open('/sys/cla 1203 info = open('/sys/class/net/%s/device/uevent' % dev, 'r').read().strip() 1222 except: 1204 except: 1223 return dev 1205 return dev 1224 vals = [dev] 1206 vals = [dev] 1225 for prop in info.split('\n'): 1207 for prop in info.split('\n'): 1226 if prop.startswith('D 1208 if prop.startswith('DRIVER=') or prop.startswith('PCI_ID='): 1227 vals.append(p 1209 vals.append(prop.split('=')[-1]) 1228 return ':'.join(vals) 1210 return ':'.join(vals) 1229 def checkWifi(self, dev=''): 1211 def checkWifi(self, dev=''): 1230 try: 1212 try: 1231 w = open('/proc/net/w 1213 w = open('/proc/net/wireless', 'r').read().strip() 1232 except: 1214 except: 1233 return '' 1215 return '' 1234 for line in reversed(w.split( 1216 for line in reversed(w.split('\n')): 1235 m = re.match(r' *(?P< !! 1217 m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', line) 1236 if not m or (dev and 1218 if not m or (dev and dev != m.group('dev')): 1237 continue 1219 continue 1238 return m.group('dev') 1220 return m.group('dev') 1239 return '' 1221 return '' 1240 def pollWifi(self, dev, timeout=10): 1222 def pollWifi(self, dev, timeout=10): 1241 start = time.time() 1223 start = time.time() 1242 while (time.time() - start) < 1224 while (time.time() - start) < timeout: 1243 w = self.checkWifi(de 1225 w = self.checkWifi(dev) 1244 if w: 1226 if w: 1245 return '%s re 1227 return '%s reconnected %.2f' % \ 1246 (self 1228 (self.wifiDetails(dev), max(0, time.time() - start)) 1247 time.sleep(0.01) 1229 time.sleep(0.01) 1248 return '%s timeout %d' % (sel 1230 return '%s timeout %d' % (self.wifiDetails(dev), timeout) 1249 def errorSummary(self, errinfo, msg): 1231 def errorSummary(self, errinfo, msg): 1250 found = False 1232 found = False 1251 for entry in errinfo: 1233 for entry in errinfo: 1252 if re.match(entry['ma 1234 if re.match(entry['match'], msg): 1253 entry['count' 1235 entry['count'] += 1 1254 if self.hostn 1236 if self.hostname not in entry['urls']: 1255 entry 1237 entry['urls'][self.hostname] = [self.htmlfile] 1256 elif self.htm 1238 elif self.htmlfile not in entry['urls'][self.hostname]: 1257 entry 1239 entry['urls'][self.hostname].append(self.htmlfile) 1258 found = True 1240 found = True 1259 break 1241 break 1260 if found: 1242 if found: 1261 return 1243 return 1262 arr = msg.split() 1244 arr = msg.split() 1263 for j in range(len(arr)): 1245 for j in range(len(arr)): 1264 if re.match(r'^[0-9,\ !! 1246 if re.match('^[0-9,\-\.]*$', arr[j]): 1265 arr[j] = r'[0 !! 1247 arr[j] = '[0-9,\-\.]*' 1266 else: 1248 else: 1267 arr[j] = arr[ 1249 arr[j] = arr[j]\ 1268 .repl !! 1250 .replace('\\', '\\\\').replace(']', '\]').replace('[', '\[')\ 1269 .repl !! 1251 .replace('.', '\.').replace('+', '\+').replace('*', '\*')\ 1270 .repl !! 1252 .replace('(', '\(').replace(')', '\)').replace('}', '\}')\ 1271 .repl !! 1253 .replace('{', '\{') 1272 mstr = ' *'.join(arr) 1254 mstr = ' *'.join(arr) 1273 entry = { 1255 entry = { 1274 'line': msg, 1256 'line': msg, 1275 'match': mstr, 1257 'match': mstr, 1276 'count': 1, 1258 'count': 1, 1277 'urls': {self.hostnam 1259 'urls': {self.hostname: [self.htmlfile]} 1278 } 1260 } 1279 errinfo.append(entry) 1261 errinfo.append(entry) 1280 def multistat(self, start, idx, finis 1262 def multistat(self, start, idx, finish): 1281 if 'time' in self.multitest: 1263 if 'time' in self.multitest: 1282 id = '%d Duration=%dm 1264 id = '%d Duration=%dmin' % (idx+1, self.multitest['time']) 1283 else: 1265 else: 1284 id = '%d/%d' % (idx+1 1266 id = '%d/%d' % (idx+1, self.multitest['count']) 1285 t = time.time() 1267 t = time.time() 1286 if 'start' not in self.multit 1268 if 'start' not in self.multitest: 1287 self.multitest['start 1269 self.multitest['start'] = self.multitest['last'] = t 1288 self.multitest['total 1270 self.multitest['total'] = 0.0 1289 pprint('TEST (%s) STA 1271 pprint('TEST (%s) START' % id) 1290 return 1272 return 1291 dt = t - self.multitest['last 1273 dt = t - self.multitest['last'] 1292 if not start: 1274 if not start: 1293 if idx == 0 and self. 1275 if idx == 0 and self.multitest['delay'] > 0: 1294 self.multites 1276 self.multitest['total'] += self.multitest['delay'] 1295 pprint('TEST (%s) COM 1277 pprint('TEST (%s) COMPLETE -- Duration %.1fs' % (id, dt)) 1296 return 1278 return 1297 self.multitest['total'] += dt 1279 self.multitest['total'] += dt 1298 self.multitest['last'] = t 1280 self.multitest['last'] = t 1299 avg = self.multitest['total'] 1281 avg = self.multitest['total'] / idx 1300 if 'time' in self.multitest: 1282 if 'time' in self.multitest: 1301 left = finish - datet 1283 left = finish - datetime.now() 1302 left -= timedelta(mic 1284 left -= timedelta(microseconds=left.microseconds) 1303 else: 1285 else: 1304 left = timedelta(seco 1286 left = timedelta(seconds=((self.multitest['count'] - idx) * int(avg))) 1305 pprint('TEST (%s) START - Avg 1287 pprint('TEST (%s) START - Avg Duration %.1fs, Time left %s' % \ 1306 (id, avg, str(left))) 1288 (id, avg, str(left))) 1307 def multiinit(self, c, d): 1289 def multiinit(self, c, d): 1308 sz, unit = 'count', 'm' 1290 sz, unit = 'count', 'm' 1309 if c.endswith('d') or c.endsw 1291 if c.endswith('d') or c.endswith('h') or c.endswith('m'): 1310 sz, unit, c = 'time', 1292 sz, unit, c = 'time', c[-1], c[:-1] 1311 self.multitest['run'] = True 1293 self.multitest['run'] = True 1312 self.multitest[sz] = getArgIn 1294 self.multitest[sz] = getArgInt('multi: n d (exec count)', c, 1, 1000000, False) 1313 self.multitest['delay'] = get 1295 self.multitest['delay'] = getArgInt('multi: n d (delay between tests)', d, 0, 3600, False) 1314 if unit == 'd': 1296 if unit == 'd': 1315 self.multitest[sz] *= 1297 self.multitest[sz] *= 1440 1316 elif unit == 'h': 1298 elif unit == 'h': 1317 self.multitest[sz] *= 1299 self.multitest[sz] *= 60 1318 def displayControl(self, cmd): 1300 def displayControl(self, cmd): 1319 xset, ret = 'timeout 10 xset 1301 xset, ret = 'timeout 10 xset -d :0.0 {0}', 0 1320 if self.sudouser: 1302 if self.sudouser: 1321 xset = 'sudo -u %s %s 1303 xset = 'sudo -u %s %s' % (self.sudouser, xset) 1322 if cmd == 'init': 1304 if cmd == 'init': 1323 ret = call(xset.forma 1305 ret = call(xset.format('dpms 0 0 0'), shell=True) 1324 if not ret: 1306 if not ret: 1325 ret = call(xs 1307 ret = call(xset.format('s off'), shell=True) 1326 elif cmd == 'reset': 1308 elif cmd == 'reset': 1327 ret = call(xset.forma 1309 ret = call(xset.format('s reset'), shell=True) 1328 elif cmd in ['on', 'off', 'st 1310 elif cmd in ['on', 'off', 'standby', 'suspend']: 1329 b4 = self.displayCont 1311 b4 = self.displayControl('stat') 1330 ret = call(xset.forma 1312 ret = call(xset.format('dpms force %s' % cmd), shell=True) 1331 if not ret: 1313 if not ret: 1332 curr = self.d 1314 curr = self.displayControl('stat') 1333 self.vprint(' 1315 self.vprint('Display Switched: %s -> %s' % (b4, curr)) 1334 if curr != cm 1316 if curr != cmd: 1335 self. 1317 self.vprint('WARNING: Display failed to change to %s' % cmd) 1336 if ret: 1318 if ret: 1337 self.vprint(' 1319 self.vprint('WARNING: Display failed to change to %s with xset' % cmd) 1338 return ret 1320 return ret 1339 elif cmd == 'stat': 1321 elif cmd == 'stat': 1340 fp = Popen(xset.forma 1322 fp = Popen(xset.format('q').split(' '), stdout=PIPE).stdout 1341 ret = 'unknown' 1323 ret = 'unknown' 1342 for line in fp: 1324 for line in fp: 1343 m = re.match( !! 1325 m = re.match('[\s]*Monitor is (?P<m>.*)', ascii(line)) 1344 if(m and len( 1326 if(m and len(m.group('m')) >= 2): 1345 out = 1327 out = m.group('m').lower() 1346 ret = 1328 ret = out[3:] if out[0:2] == 'in' else out 1347 break 1329 break 1348 fp.close() 1330 fp.close() 1349 return ret 1331 return ret 1350 def setRuntimeSuspend(self, before=Tr 1332 def setRuntimeSuspend(self, before=True): 1351 if before: 1333 if before: 1352 # runtime suspend dis 1334 # runtime suspend disable or enable 1353 if self.rs > 0: 1335 if self.rs > 0: 1354 self.rstgt, s 1336 self.rstgt, self.rsval, self.rsdir = 'on', 'auto', 'enabled' 1355 else: 1337 else: 1356 self.rstgt, s 1338 self.rstgt, self.rsval, self.rsdir = 'auto', 'on', 'disabled' 1357 pprint('CONFIGURING R 1339 pprint('CONFIGURING RUNTIME SUSPEND...') 1358 self.rslist = deviceI 1340 self.rslist = deviceInfo(self.rstgt) 1359 for i in self.rslist: 1341 for i in self.rslist: 1360 self.setVal(s 1342 self.setVal(self.rsval, i) 1361 pprint('runtime suspe 1343 pprint('runtime suspend %s on all devices (%d changed)' % (self.rsdir, len(self.rslist))) 1362 pprint('waiting 5 sec 1344 pprint('waiting 5 seconds...') 1363 time.sleep(5) 1345 time.sleep(5) 1364 else: 1346 else: 1365 # runtime suspend re- 1347 # runtime suspend re-enable or re-disable 1366 for i in self.rslist: 1348 for i in self.rslist: 1367 self.setVal(s 1349 self.setVal(self.rstgt, i) 1368 pprint('runtime suspe 1350 pprint('runtime suspend settings restored on %d devices' % len(self.rslist)) 1369 def start(self, pm): 1351 def start(self, pm): 1370 if self.useftrace: 1352 if self.useftrace: 1371 self.dlog('start ftra 1353 self.dlog('start ftrace tracing') 1372 self.fsetVal('1', 'tr 1354 self.fsetVal('1', 'tracing_on') 1373 if self.useprocmon: 1355 if self.useprocmon: 1374 self.dlog('st 1356 self.dlog('start the process monitor') 1375 pm.start() 1357 pm.start() 1376 def stop(self, pm): 1358 def stop(self, pm): 1377 if self.useftrace: 1359 if self.useftrace: 1378 if self.useprocmon: 1360 if self.useprocmon: 1379 self.dlog('st 1361 self.dlog('stop the process monitor') 1380 pm.stop() 1362 pm.stop() 1381 self.dlog('stop ftrac 1363 self.dlog('stop ftrace tracing') 1382 self.fsetVal('0', 'tr 1364 self.fsetVal('0', 'tracing_on') 1383 1365 1384 sysvals = SystemValues() 1366 sysvals = SystemValues() 1385 switchvalues = ['enable', 'disable', 'on', 'o 1367 switchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0'] 1386 switchoff = ['disable', 'off', 'false', '0'] 1368 switchoff = ['disable', 'off', 'false', '0'] 1387 suspendmodename = { 1369 suspendmodename = { 1388 'standby': 'standby (S1)', 1370 'standby': 'standby (S1)', 1389 'freeze': 'freeze (S2idle)', 1371 'freeze': 'freeze (S2idle)', 1390 'mem': 'suspend (S3)', 1372 'mem': 'suspend (S3)', 1391 'disk': 'hibernate (S4)' 1373 'disk': 'hibernate (S4)' 1392 } 1374 } 1393 1375 1394 # Class: DevProps 1376 # Class: DevProps 1395 # Description: 1377 # Description: 1396 # Simple class which holds property va 1378 # Simple class which holds property values collected 1397 # for all the devices used in the time 1379 # for all the devices used in the timeline. 1398 class DevProps: 1380 class DevProps: 1399 def __init__(self): 1381 def __init__(self): 1400 self.syspath = '' 1382 self.syspath = '' 1401 self.altname = '' 1383 self.altname = '' 1402 self.isasync = True 1384 self.isasync = True 1403 self.xtraclass = '' 1385 self.xtraclass = '' 1404 self.xtrainfo = '' 1386 self.xtrainfo = '' 1405 def out(self, dev): 1387 def out(self, dev): 1406 return '%s,%s,%d;' % (dev, se 1388 return '%s,%s,%d;' % (dev, self.altname, self.isasync) 1407 def debug(self, dev): 1389 def debug(self, dev): 1408 pprint('%s:\n\taltname = %s\n 1390 pprint('%s:\n\taltname = %s\n\t async = %s' % (dev, self.altname, self.isasync)) 1409 def altName(self, dev): 1391 def altName(self, dev): 1410 if not self.altname or self.a 1392 if not self.altname or self.altname == dev: 1411 return dev 1393 return dev 1412 return '%s [%s]' % (self.altn 1394 return '%s [%s]' % (self.altname, dev) 1413 def xtraClass(self): 1395 def xtraClass(self): 1414 if self.xtraclass: 1396 if self.xtraclass: 1415 return ' '+self.xtrac 1397 return ' '+self.xtraclass 1416 if not self.isasync: 1398 if not self.isasync: 1417 return ' sync' 1399 return ' sync' 1418 return '' 1400 return '' 1419 def xtraInfo(self): 1401 def xtraInfo(self): 1420 if self.xtraclass: 1402 if self.xtraclass: 1421 return ' '+self.xtrac 1403 return ' '+self.xtraclass 1422 if self.isasync: 1404 if self.isasync: 1423 return ' (async)' 1405 return ' (async)' 1424 return ' (sync)' 1406 return ' (sync)' 1425 1407 1426 # Class: DeviceNode 1408 # Class: DeviceNode 1427 # Description: 1409 # Description: 1428 # A container used to create a device 1410 # A container used to create a device hierachy, with a single root node 1429 # and a tree of child nodes. Used by D 1411 # and a tree of child nodes. Used by Data.deviceTopology() 1430 class DeviceNode: 1412 class DeviceNode: 1431 def __init__(self, nodename, nodedept 1413 def __init__(self, nodename, nodedepth): 1432 self.name = nodename 1414 self.name = nodename 1433 self.children = [] 1415 self.children = [] 1434 self.depth = nodedepth 1416 self.depth = nodedepth 1435 1417 1436 # Class: Data 1418 # Class: Data 1437 # Description: 1419 # Description: 1438 # The primary container for suspend/re 1420 # The primary container for suspend/resume test data. There is one for 1439 # each test run. The data is organized 1421 # each test run. The data is organized into a cronological hierarchy: 1440 # Data.dmesg { 1422 # Data.dmesg { 1441 # phases { 1423 # phases { 1442 # 10 sequential, non-ov 1424 # 10 sequential, non-overlapping phases of S/R 1443 # contents: times for p 1425 # contents: times for phase start/end, order/color data for html 1444 # devlist { 1426 # devlist { 1445 # device callba 1427 # device callback or action list for this phase 1446 # device { 1428 # device { 1447 # a sin 1429 # a single device callback or generic action 1448 # conte 1430 # contents: start/stop times, pid/cpu/driver info 1449 # 1431 # parents/children, html id for timeline/callgraph 1450 # 1432 # optionally includes an ftrace callgraph 1451 # 1433 # optionally includes dev/ps data 1452 # } 1434 # } 1453 # } 1435 # } 1454 # } 1436 # } 1455 # } 1437 # } 1456 # 1438 # 1457 class Data: 1439 class Data: 1458 phasedef = { 1440 phasedef = { 1459 'suspend_prepare': {'order': 1441 'suspend_prepare': {'order': 0, 'color': '#CCFFCC'}, 1460 'suspend': {'order': 1442 'suspend': {'order': 1, 'color': '#88FF88'}, 1461 'suspend_late': {'order': 1443 'suspend_late': {'order': 2, 'color': '#00AA00'}, 1462 'suspend_noirq': {'order': 1444 'suspend_noirq': {'order': 3, 'color': '#008888'}, 1463 'suspend_machine': {'order': 1445 'suspend_machine': {'order': 4, 'color': '#0000FF'}, 1464 'resume_machine': {'order': 1446 'resume_machine': {'order': 5, 'color': '#FF0000'}, 1465 'resume_noirq': {'order': 1447 'resume_noirq': {'order': 6, 'color': '#FF9900'}, 1466 'resume_early': {'order': 1448 'resume_early': {'order': 7, 'color': '#FFCC00'}, 1467 'resume': {'order': 1449 'resume': {'order': 8, 'color': '#FFFF88'}, 1468 'resume_complete': {'order': 1450 'resume_complete': {'order': 9, 'color': '#FFFFCC'}, 1469 } 1451 } 1470 errlist = { 1452 errlist = { 1471 'HWERROR' : r'.*\[ *Hardware 1453 'HWERROR' : r'.*\[ *Hardware Error *\].*', 1472 'FWBUG' : r'.*\[ *Firmware 1454 'FWBUG' : r'.*\[ *Firmware Bug *\].*', 1473 'TASKFAIL': r'.*Freezing .*af << 1474 'BUG' : r'(?i).*\bBUG\b.* 1455 'BUG' : r'(?i).*\bBUG\b.*', 1475 'ERROR' : r'(?i).*\bERROR\b 1456 'ERROR' : r'(?i).*\bERROR\b.*', 1476 'WARNING' : r'(?i).*\bWARNING 1457 'WARNING' : r'(?i).*\bWARNING\b.*', 1477 'FAULT' : r'(?i).*\bFAULT\b 1458 'FAULT' : r'(?i).*\bFAULT\b.*', 1478 'FAIL' : r'(?i).*\bFAILED\ 1459 'FAIL' : r'(?i).*\bFAILED\b.*', 1479 'INVALID' : r'(?i).*\bINVALID 1460 'INVALID' : r'(?i).*\bINVALID\b.*', 1480 'CRASH' : r'(?i).*\bCRASHED 1461 'CRASH' : r'(?i).*\bCRASHED\b.*', 1481 'TIMEOUT' : r'(?i).*\bTIMEOUT 1462 'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*', 1482 'ABORT' : r'(?i).*\bABORT\b 1463 'ABORT' : r'(?i).*\bABORT\b.*', 1483 'IRQ' : r'.*\bgenirq: .*' 1464 'IRQ' : r'.*\bgenirq: .*', >> 1465 'TASKFAIL': r'.*Freezing .*after *.*', 1484 'ACPI' : r'.*\bACPI *(?P<b 1466 'ACPI' : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*', 1485 'DISKFULL': r'.*\bNo space le 1467 'DISKFULL': r'.*\bNo space left on device.*', 1486 'USBERR' : r'.*usb .*device 1468 'USBERR' : r'.*usb .*device .*, error [0-9-]*', 1487 'ATAERR' : r' *ata[0-9\.]*: 1469 'ATAERR' : r' *ata[0-9\.]*: .*failed.*', 1488 'MEIERR' : r' *mei.*: .*fail 1470 'MEIERR' : r' *mei.*: .*failed.*', 1489 'TPMERR' : r'(?i) *tpm *tpm[ 1471 'TPMERR' : r'(?i) *tpm *tpm[0-9]*: .*error.*', 1490 } 1472 } 1491 def __init__(self, num): 1473 def __init__(self, num): 1492 idchar = 'abcdefghij' 1474 idchar = 'abcdefghij' 1493 self.start = 0.0 # test start 1475 self.start = 0.0 # test start 1494 self.end = 0.0 # test end 1476 self.end = 0.0 # test end 1495 self.hwstart = 0 # rtc test s 1477 self.hwstart = 0 # rtc test start 1496 self.hwend = 0 # rtc test e 1478 self.hwend = 0 # rtc test end 1497 self.tSuspended = 0.0 # low-l 1479 self.tSuspended = 0.0 # low-level suspend start 1498 self.tResumed = 0.0 # low-l 1480 self.tResumed = 0.0 # low-level resume start 1499 self.tKernSus = 0.0 # kerne 1481 self.tKernSus = 0.0 # kernel level suspend start 1500 self.tKernRes = 0.0 # kerne 1482 self.tKernRes = 0.0 # kernel level resume end 1501 self.fwValid = False # is fi 1483 self.fwValid = False # is firmware data available 1502 self.fwSuspend = 0 # time 1484 self.fwSuspend = 0 # time spent in firmware suspend 1503 self.fwResume = 0 # time 1485 self.fwResume = 0 # time spent in firmware resume 1504 self.html_device_id = 0 1486 self.html_device_id = 0 1505 self.stamp = 0 1487 self.stamp = 0 1506 self.outfile = '' 1488 self.outfile = '' 1507 self.kerror = False 1489 self.kerror = False 1508 self.wifi = dict() 1490 self.wifi = dict() 1509 self.turbostat = 0 1491 self.turbostat = 0 1510 self.enterfail = '' 1492 self.enterfail = '' 1511 self.currphase = '' 1493 self.currphase = '' 1512 self.pstl = dict() # proce 1494 self.pstl = dict() # process timeline 1513 self.testnumber = num 1495 self.testnumber = num 1514 self.idstr = idchar[num] 1496 self.idstr = idchar[num] 1515 self.dmesgtext = [] # dmesg 1497 self.dmesgtext = [] # dmesg text file in memory 1516 self.dmesg = dict() # root 1498 self.dmesg = dict() # root data structure 1517 self.errorinfo = {'suspend':[ 1499 self.errorinfo = {'suspend':[],'resume':[]} 1518 self.tLow = [] # time 1500 self.tLow = [] # time spent in low-level suspends (standby/freeze) 1519 self.devpids = [] 1501 self.devpids = [] 1520 self.devicegroups = 0 1502 self.devicegroups = 0 1521 def sortedPhases(self): 1503 def sortedPhases(self): 1522 return sorted(self.dmesg, key 1504 return sorted(self.dmesg, key=lambda k:self.dmesg[k]['order']) 1523 def initDevicegroups(self): 1505 def initDevicegroups(self): 1524 # called when phases are all 1506 # called when phases are all finished being added 1525 for phase in sorted(self.dmes 1507 for phase in sorted(self.dmesg.keys()): 1526 if '*' in phase: 1508 if '*' in phase: 1527 p = phase.spl 1509 p = phase.split('*') 1528 pnew = '%s%d' 1510 pnew = '%s%d' % (p[0], len(p)) 1529 self.dmesg[pn 1511 self.dmesg[pnew] = self.dmesg.pop(phase) 1530 self.devicegroups = [] 1512 self.devicegroups = [] 1531 for phase in self.sortedPhase 1513 for phase in self.sortedPhases(): 1532 self.devicegroups.app 1514 self.devicegroups.append([phase]) 1533 def nextPhase(self, phase, offset): 1515 def nextPhase(self, phase, offset): 1534 order = self.dmesg[phase]['or 1516 order = self.dmesg[phase]['order'] + offset 1535 for p in self.dmesg: 1517 for p in self.dmesg: 1536 if self.dmesg[p]['ord 1518 if self.dmesg[p]['order'] == order: 1537 return p 1519 return p 1538 return '' 1520 return '' 1539 def lastPhase(self, depth=1): 1521 def lastPhase(self, depth=1): 1540 plist = self.sortedPhases() 1522 plist = self.sortedPhases() 1541 if len(plist) < depth: 1523 if len(plist) < depth: 1542 return '' 1524 return '' 1543 return plist[-1*depth] 1525 return plist[-1*depth] 1544 def turbostatInfo(self): 1526 def turbostatInfo(self): 1545 tp = TestProps() 1527 tp = TestProps() 1546 out = {'syslpi':'N/A','pkgpc1 1528 out = {'syslpi':'N/A','pkgpc10':'N/A'} 1547 for line in self.dmesgtext: 1529 for line in self.dmesgtext: 1548 m = re.match(tp.tstat 1530 m = re.match(tp.tstatfmt, line) 1549 if not m: 1531 if not m: 1550 continue 1532 continue 1551 for i in m.group('t') 1533 for i in m.group('t').split('|'): 1552 if 'SYS%LPI' 1534 if 'SYS%LPI' in i: 1553 out[' 1535 out['syslpi'] = i.split('=')[-1]+'%' 1554 elif 'pc10' i 1536 elif 'pc10' in i: 1555 out[' 1537 out['pkgpc10'] = i.split('=')[-1]+'%' 1556 break 1538 break 1557 return out 1539 return out 1558 def extractErrorInfo(self): 1540 def extractErrorInfo(self): 1559 lf = self.dmesgtext 1541 lf = self.dmesgtext 1560 if len(self.dmesgtext) < 1 an 1542 if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 1561 lf = sysvals.openlog( 1543 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 1562 i = 0 1544 i = 0 1563 tp = TestProps() 1545 tp = TestProps() 1564 list = [] 1546 list = [] 1565 for line in lf: 1547 for line in lf: 1566 i += 1 1548 i += 1 1567 if tp.stampInfo(line, 1549 if tp.stampInfo(line, sysvals): 1568 continue 1550 continue 1569 m = re.match(r'[ \t]* !! 1551 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 1570 if not m: 1552 if not m: 1571 continue 1553 continue 1572 t = float(m.group('kt 1554 t = float(m.group('ktime')) 1573 if t < self.start or 1555 if t < self.start or t > self.end: 1574 continue 1556 continue 1575 dir = 'suspend' if t 1557 dir = 'suspend' if t < self.tSuspended else 'resume' 1576 msg = m.group('msg') 1558 msg = m.group('msg') 1577 if re.match(r'capabil !! 1559 if re.match('capability: warning: .*', msg): 1578 continue 1560 continue 1579 for err in self.errli 1561 for err in self.errlist: 1580 if re.match(s 1562 if re.match(self.errlist[err], msg): 1581 list. 1563 list.append((msg, err, dir, t, i, i)) 1582 self. 1564 self.kerror = True 1583 break 1565 break 1584 tp.msglist = [] 1566 tp.msglist = [] 1585 for msg, type, dir, t, idx1, 1567 for msg, type, dir, t, idx1, idx2 in list: 1586 tp.msglist.append(msg 1568 tp.msglist.append(msg) 1587 self.errorinfo[dir].a 1569 self.errorinfo[dir].append((type, t, idx1, idx2)) 1588 if self.kerror: 1570 if self.kerror: 1589 sysvals.dmesglog = Tr 1571 sysvals.dmesglog = True 1590 if len(self.dmesgtext) < 1 an 1572 if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 1591 lf.close() 1573 lf.close() 1592 return tp 1574 return tp 1593 def setStart(self, time, msg=''): 1575 def setStart(self, time, msg=''): 1594 self.start = time 1576 self.start = time 1595 if msg: 1577 if msg: 1596 try: 1578 try: 1597 self.hwstart 1579 self.hwstart = datetime.strptime(msg, sysvals.tmstart) 1598 except: 1580 except: 1599 self.hwstart 1581 self.hwstart = 0 1600 def setEnd(self, time, msg=''): 1582 def setEnd(self, time, msg=''): 1601 self.end = time 1583 self.end = time 1602 if msg: 1584 if msg: 1603 try: 1585 try: 1604 self.hwend = 1586 self.hwend = datetime.strptime(msg, sysvals.tmend) 1605 except: 1587 except: 1606 self.hwend = 1588 self.hwend = 0 1607 def isTraceEventOutsideDeviceCalls(se 1589 def isTraceEventOutsideDeviceCalls(self, pid, time): 1608 for phase in self.sortedPhase 1590 for phase in self.sortedPhases(): 1609 list = self.dmesg[pha 1591 list = self.dmesg[phase]['list'] 1610 for dev in list: 1592 for dev in list: 1611 d = list[dev] 1593 d = list[dev] 1612 if(d['pid'] = 1594 if(d['pid'] == pid and time >= d['start'] and 1613 time 1595 time < d['end']): 1614 retur 1596 return False 1615 return True 1597 return True 1616 def sourcePhase(self, start): 1598 def sourcePhase(self, start): 1617 for phase in self.sortedPhase 1599 for phase in self.sortedPhases(): 1618 if 'machine' in phase 1600 if 'machine' in phase: 1619 continue 1601 continue 1620 pend = self.dmesg[pha 1602 pend = self.dmesg[phase]['end'] 1621 if start <= pend: 1603 if start <= pend: 1622 return phase 1604 return phase 1623 return 'resume_complete' if ' !! 1605 return 'resume_complete' 1624 def sourceDevice(self, phaselist, sta 1606 def sourceDevice(self, phaselist, start, end, pid, type): 1625 tgtdev = '' 1607 tgtdev = '' 1626 for phase in phaselist: 1608 for phase in phaselist: 1627 list = self.dmesg[pha 1609 list = self.dmesg[phase]['list'] 1628 for devname in list: 1610 for devname in list: 1629 dev = list[de 1611 dev = list[devname] 1630 # pid must ma 1612 # pid must match 1631 if dev['pid'] 1613 if dev['pid'] != pid: 1632 conti 1614 continue 1633 devS = dev['s 1615 devS = dev['start'] 1634 devE = dev['e 1616 devE = dev['end'] 1635 if type == 'd 1617 if type == 'device': 1636 # dev 1618 # device target event is entirely inside the source boundary 1637 if(st 1619 if(start < devS or start >= devE or end <= devS or end > devE): 1638 1620 continue 1639 elif type == 1621 elif type == 'thread': 1640 # thr 1622 # thread target event will expand the source boundary 1641 if st 1623 if start < devS: 1642 1624 dev['start'] = start 1643 if en 1625 if end > devE: 1644 1626 dev['end'] = end 1645 tgtdev = dev 1627 tgtdev = dev 1646 break 1628 break 1647 return tgtdev 1629 return tgtdev 1648 def addDeviceFunctionCall(self, displ 1630 def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata): 1649 # try to place the call in a 1631 # try to place the call in a device 1650 phases = self.sortedPhases() 1632 phases = self.sortedPhases() 1651 tgtdev = self.sourceDevice(ph 1633 tgtdev = self.sourceDevice(phases, start, end, pid, 'device') 1652 # calls with device pids that 1634 # calls with device pids that occur outside device bounds are dropped 1653 # TODO: include these somehow 1635 # TODO: include these somehow 1654 if not tgtdev and pid in self 1636 if not tgtdev and pid in self.devpids: 1655 return False 1637 return False 1656 # try to place the call in a 1638 # try to place the call in a thread 1657 if not tgtdev: 1639 if not tgtdev: 1658 tgtdev = self.sourceD 1640 tgtdev = self.sourceDevice(phases, start, end, pid, 'thread') 1659 # create new thread blocks, e 1641 # create new thread blocks, expand as new calls are found 1660 if not tgtdev: 1642 if not tgtdev: 1661 if proc == '<...>': 1643 if proc == '<...>': 1662 threadname = 1644 threadname = 'kthread-%d' % (pid) 1663 else: 1645 else: 1664 threadname = 1646 threadname = '%s-%d' % (proc, pid) 1665 tgtphase = self.sourc 1647 tgtphase = self.sourcePhase(start) 1666 if not tgtphase: << 1667 return False << 1668 self.newAction(tgtpha 1648 self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '') 1669 return self.addDevice 1649 return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata) 1670 # this should not happen 1650 # this should not happen 1671 if not tgtdev: 1651 if not tgtdev: 1672 sysvals.vprint('[%f - 1652 sysvals.vprint('[%f - %f] %s-%d %s %s %s' % \ 1673 (start, end, 1653 (start, end, proc, pid, kprobename, cdata, rdata)) 1674 return False 1654 return False 1675 # place the call data inside 1655 # place the call data inside the src element of the tgtdev 1676 if('src' not in tgtdev): 1656 if('src' not in tgtdev): 1677 tgtdev['src'] = [] 1657 tgtdev['src'] = [] 1678 dtf = sysvals.dev_tracefuncs 1658 dtf = sysvals.dev_tracefuncs 1679 ubiquitous = False 1659 ubiquitous = False 1680 if kprobename in dtf and 'ub' 1660 if kprobename in dtf and 'ub' in dtf[kprobename]: 1681 ubiquitous = True 1661 ubiquitous = True 1682 mc = re.match(r'\(.*\) *(?P<a !! 1662 mc = re.match('\(.*\) *(?P<args>.*)', cdata) 1683 mr = re.match(r'\((?P<caller> !! 1663 mr = re.match('\((?P<caller>\S*).* arg1=(?P<ret>.*)', rdata) 1684 if mc and mr: 1664 if mc and mr: 1685 c = mr.group('caller' 1665 c = mr.group('caller').split('+')[0] 1686 a = mc.group('args'). 1666 a = mc.group('args').strip() 1687 r = mr.group('ret') 1667 r = mr.group('ret') 1688 if len(r) > 6: 1668 if len(r) > 6: 1689 r = '' 1669 r = '' 1690 else: 1670 else: 1691 r = 'ret=%s ' 1671 r = 'ret=%s ' % r 1692 if ubiquitous and c i 1672 if ubiquitous and c in dtf and 'ub' in dtf[c]: 1693 return False 1673 return False 1694 else: 1674 else: 1695 return False 1675 return False 1696 color = sysvals.kprobeColor(k 1676 color = sysvals.kprobeColor(kprobename) 1697 e = DevFunction(displayname, 1677 e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color) 1698 tgtdev['src'].append(e) 1678 tgtdev['src'].append(e) 1699 return True 1679 return True 1700 def overflowDevices(self): 1680 def overflowDevices(self): 1701 # get a list of devices that 1681 # get a list of devices that extend beyond the end of this test run 1702 devlist = [] 1682 devlist = [] 1703 for phase in self.sortedPhase 1683 for phase in self.sortedPhases(): 1704 list = self.dmesg[pha 1684 list = self.dmesg[phase]['list'] 1705 for devname in list: 1685 for devname in list: 1706 dev = list[de 1686 dev = list[devname] 1707 if dev['end'] 1687 if dev['end'] > self.end: 1708 devli 1688 devlist.append(dev) 1709 return devlist 1689 return devlist 1710 def mergeOverlapDevices(self, devlist 1690 def mergeOverlapDevices(self, devlist): 1711 # merge any devices that over 1691 # merge any devices that overlap devlist 1712 for dev in devlist: 1692 for dev in devlist: 1713 devname = dev['name'] 1693 devname = dev['name'] 1714 for phase in self.sor 1694 for phase in self.sortedPhases(): 1715 list = self.d 1695 list = self.dmesg[phase]['list'] 1716 if devname no 1696 if devname not in list: 1717 conti 1697 continue 1718 tdev = list[d 1698 tdev = list[devname] 1719 o = min(dev[' 1699 o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start']) 1720 if o <= 0: 1700 if o <= 0: 1721 conti 1701 continue 1722 dev['end'] = 1702 dev['end'] = tdev['end'] 1723 if 'src' not 1703 if 'src' not in dev or 'src' not in tdev: 1724 conti 1704 continue 1725 dev['src'] += 1705 dev['src'] += tdev['src'] 1726 del list[devn 1706 del list[devname] 1727 def usurpTouchingThread(self, name, d 1707 def usurpTouchingThread(self, name, dev): 1728 # the caller test has priorit 1708 # the caller test has priority of this thread, give it to him 1729 for phase in self.sortedPhase 1709 for phase in self.sortedPhases(): 1730 list = self.dmesg[pha 1710 list = self.dmesg[phase]['list'] 1731 if name in list: 1711 if name in list: 1732 tdev = list[n 1712 tdev = list[name] 1733 if tdev['star 1713 if tdev['start'] - dev['end'] < 0.1: 1734 dev[' 1714 dev['end'] = tdev['end'] 1735 if 's 1715 if 'src' not in dev: 1736 1716 dev['src'] = [] 1737 if 's 1717 if 'src' in tdev: 1738 1718 dev['src'] += tdev['src'] 1739 del l 1719 del list[name] 1740 break 1720 break 1741 def stitchTouchingThreads(self, testl 1721 def stitchTouchingThreads(self, testlist): 1742 # merge any threads between t 1722 # merge any threads between tests that touch 1743 for phase in self.sortedPhase 1723 for phase in self.sortedPhases(): 1744 list = self.dmesg[pha 1724 list = self.dmesg[phase]['list'] 1745 for devname in list: 1725 for devname in list: 1746 dev = list[de 1726 dev = list[devname] 1747 if 'htmlclass 1727 if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']: 1748 conti 1728 continue 1749 for data in t 1729 for data in testlist: 1750 data. 1730 data.usurpTouchingThread(devname, dev) 1751 def optimizeDevSrc(self): 1731 def optimizeDevSrc(self): 1752 # merge any src call loops to 1732 # merge any src call loops to reduce timeline size 1753 for phase in self.sortedPhase 1733 for phase in self.sortedPhases(): 1754 list = self.dmesg[pha 1734 list = self.dmesg[phase]['list'] 1755 for dev in list: 1735 for dev in list: 1756 if 'src' not 1736 if 'src' not in list[dev]: 1757 conti 1737 continue 1758 src = list[de 1738 src = list[dev]['src'] 1759 p = 0 1739 p = 0 1760 for e in sort 1740 for e in sorted(src, key=lambda event: event.time): 1761 if no 1741 if not p or not e.repeat(p): 1762 1742 p = e 1763 1743 continue 1764 # e i 1744 # e is another iteration of p, move it into p 1765 p.end 1745 p.end = e.end 1766 p.len 1746 p.length = p.end - p.time 1767 p.cou 1747 p.count += 1 1768 src.r 1748 src.remove(e) 1769 def trimTimeVal(self, t, t0, dT, left 1749 def trimTimeVal(self, t, t0, dT, left): 1770 if left: 1750 if left: 1771 if(t > t0): 1751 if(t > t0): 1772 if(t - dT < t 1752 if(t - dT < t0): 1773 retur 1753 return t0 1774 return t - dT 1754 return t - dT 1775 else: 1755 else: 1776 return t 1756 return t 1777 else: 1757 else: 1778 if(t < t0 + dT): 1758 if(t < t0 + dT): 1779 if(t > t0): 1759 if(t > t0): 1780 retur 1760 return t0 + dT 1781 return t + dT 1761 return t + dT 1782 else: 1762 else: 1783 return t 1763 return t 1784 def trimTime(self, t0, dT, left): 1764 def trimTime(self, t0, dT, left): 1785 self.tSuspended = self.trimTi 1765 self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left) 1786 self.tResumed = self.trimTime 1766 self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left) 1787 self.start = self.trimTimeVal 1767 self.start = self.trimTimeVal(self.start, t0, dT, left) 1788 self.tKernSus = self.trimTime 1768 self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left) 1789 self.tKernRes = self.trimTime 1769 self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left) 1790 self.end = self.trimTimeVal(s 1770 self.end = self.trimTimeVal(self.end, t0, dT, left) 1791 for phase in self.sortedPhase 1771 for phase in self.sortedPhases(): 1792 p = self.dmesg[phase] 1772 p = self.dmesg[phase] 1793 p['start'] = self.tri 1773 p['start'] = self.trimTimeVal(p['start'], t0, dT, left) 1794 p['end'] = self.trimT 1774 p['end'] = self.trimTimeVal(p['end'], t0, dT, left) 1795 list = p['list'] 1775 list = p['list'] 1796 for name in list: 1776 for name in list: 1797 d = list[name 1777 d = list[name] 1798 d['start'] = 1778 d['start'] = self.trimTimeVal(d['start'], t0, dT, left) 1799 d['end'] = se 1779 d['end'] = self.trimTimeVal(d['end'], t0, dT, left) 1800 d['length'] = 1780 d['length'] = d['end'] - d['start'] 1801 if('ftrace' i 1781 if('ftrace' in d): 1802 cg = 1782 cg = d['ftrace'] 1803 cg.st 1783 cg.start = self.trimTimeVal(cg.start, t0, dT, left) 1804 cg.en 1784 cg.end = self.trimTimeVal(cg.end, t0, dT, left) 1805 for l 1785 for line in cg.list: 1806 1786 line.time = self.trimTimeVal(line.time, t0, dT, left) 1807 if('src' in d 1787 if('src' in d): 1808 for e 1788 for e in d['src']: 1809 1789 e.time = self.trimTimeVal(e.time, t0, dT, left) 1810 1790 e.end = self.trimTimeVal(e.end, t0, dT, left) 1811 1791 e.length = e.end - e.time 1812 if('cpuexec' 1792 if('cpuexec' in d): 1813 cpuex 1793 cpuexec = dict() 1814 for e 1794 for e in d['cpuexec']: 1815 1795 c0, cN = e 1816 1796 c0 = self.trimTimeVal(c0, t0, dT, left) 1817 1797 cN = self.trimTimeVal(cN, t0, dT, left) 1818 1798 cpuexec[(c0, cN)] = d['cpuexec'][e] 1819 d['cp 1799 d['cpuexec'] = cpuexec 1820 for dir in ['suspend', 'resum 1800 for dir in ['suspend', 'resume']: 1821 list = [] 1801 list = [] 1822 for e in self.errorin 1802 for e in self.errorinfo[dir]: 1823 type, tm, idx 1803 type, tm, idx1, idx2 = e 1824 tm = self.tri 1804 tm = self.trimTimeVal(tm, t0, dT, left) 1825 list.append(( 1805 list.append((type, tm, idx1, idx2)) 1826 self.errorinfo[dir] = 1806 self.errorinfo[dir] = list 1827 def trimFreezeTime(self, tZero): 1807 def trimFreezeTime(self, tZero): 1828 # trim out any standby or fre 1808 # trim out any standby or freeze clock time 1829 lp = '' 1809 lp = '' 1830 for phase in self.sortedPhase 1810 for phase in self.sortedPhases(): 1831 if 'resume_machine' i 1811 if 'resume_machine' in phase and 'suspend_machine' in lp: 1832 tS, tR = self 1812 tS, tR = self.dmesg[lp]['end'], self.dmesg[phase]['start'] 1833 tL = tR - tS 1813 tL = tR - tS 1834 if tL <= 0: 1814 if tL <= 0: 1835 conti 1815 continue 1836 left = True i 1816 left = True if tR > tZero else False 1837 self.trimTime 1817 self.trimTime(tS, tL, left) 1838 if 'waking' i 1818 if 'waking' in self.dmesg[lp]: 1839 tCnt 1819 tCnt = self.dmesg[lp]['waking'][0] 1840 if se 1820 if self.dmesg[lp]['waking'][1] >= 0.001: 1841 1821 tTry = '%.0f' % (round(self.dmesg[lp]['waking'][1] * 1000)) 1842 else: 1822 else: 1843 1823 tTry = '%.3f' % (self.dmesg[lp]['waking'][1] * 1000) 1844 text 1824 text = '%.0f (%s ms waking %d times)' % (tL * 1000, tTry, tCnt) 1845 else: 1825 else: 1846 text 1826 text = '%.0f' % (tL * 1000) 1847 self.tLow.app 1827 self.tLow.append(text) 1848 lp = phase 1828 lp = phase 1849 def getMemTime(self): 1829 def getMemTime(self): 1850 if not self.hwstart or not se 1830 if not self.hwstart or not self.hwend: 1851 return 1831 return 1852 stime = (self.tSuspended - se 1832 stime = (self.tSuspended - self.start) * 1000000 1853 rtime = (self.end - self.tRes 1833 rtime = (self.end - self.tResumed) * 1000000 1854 hws = self.hwstart + timedelt 1834 hws = self.hwstart + timedelta(microseconds=stime) 1855 hwr = self.hwend - timedelta( 1835 hwr = self.hwend - timedelta(microseconds=rtime) 1856 self.tLow.append('%.0f'%((hwr 1836 self.tLow.append('%.0f'%((hwr - hws).total_seconds() * 1000)) 1857 def getTimeValues(self): 1837 def getTimeValues(self): 1858 s = (self.tSuspended - self.t !! 1838 sktime = (self.tSuspended - self.tKernSus) * 1000 1859 r = (self.tKernRes - self.tRe !! 1839 rktime = (self.tKernRes - self.tResumed) * 1000 1860 return (max(s, 0), max(r, 0)) !! 1840 return (sktime, rktime) 1861 def setPhase(self, phase, ktime, isbe 1841 def setPhase(self, phase, ktime, isbegin, order=-1): 1862 if(isbegin): 1842 if(isbegin): 1863 # phase start over cu 1843 # phase start over current phase 1864 if self.currphase: 1844 if self.currphase: 1865 if 'resume_ma 1845 if 'resume_machine' not in self.currphase: 1866 sysva 1846 sysvals.vprint('WARNING: phase %s failed to end' % self.currphase) 1867 self.dmesg[se 1847 self.dmesg[self.currphase]['end'] = ktime 1868 phases = self.dmesg.k 1848 phases = self.dmesg.keys() 1869 color = self.phasedef 1849 color = self.phasedef[phase]['color'] 1870 count = len(phases) i 1850 count = len(phases) if order < 0 else order 1871 # create unique name 1851 # create unique name for every new phase 1872 while phase in phases 1852 while phase in phases: 1873 phase += '*' 1853 phase += '*' 1874 self.dmesg[phase] = { 1854 self.dmesg[phase] = {'list': dict(), 'start': -1.0, 'end': -1.0, 1875 'row': 0, 'co 1855 'row': 0, 'color': color, 'order': count} 1876 self.dmesg[phase]['st 1856 self.dmesg[phase]['start'] = ktime 1877 self.currphase = phas 1857 self.currphase = phase 1878 else: 1858 else: 1879 # phase end without a 1859 # phase end without a start 1880 if phase not in self. 1860 if phase not in self.currphase: 1881 if self.currp 1861 if self.currphase: 1882 sysva 1862 sysvals.vprint('WARNING: %s ended instead of %s, ftrace corruption?' % (phase, self.currphase)) 1883 else: 1863 else: 1884 sysva 1864 sysvals.vprint('WARNING: %s ended without a start, ftrace corruption?' % phase) 1885 retur 1865 return phase 1886 phase = self.currphas 1866 phase = self.currphase 1887 self.dmesg[phase]['en 1867 self.dmesg[phase]['end'] = ktime 1888 self.currphase = '' 1868 self.currphase = '' 1889 return phase 1869 return phase 1890 def sortedDevices(self, phase): 1870 def sortedDevices(self, phase): 1891 list = self.dmesg[phase]['lis 1871 list = self.dmesg[phase]['list'] 1892 return sorted(list, key=lambd 1872 return sorted(list, key=lambda k:list[k]['start']) 1893 def fixupInitcalls(self, phase): 1873 def fixupInitcalls(self, phase): 1894 # if any calls never returned 1874 # if any calls never returned, clip them at system resume end 1895 phaselist = self.dmesg[phase] 1875 phaselist = self.dmesg[phase]['list'] 1896 for devname in phaselist: 1876 for devname in phaselist: 1897 dev = phaselist[devna 1877 dev = phaselist[devname] 1898 if(dev['end'] < 0): 1878 if(dev['end'] < 0): 1899 for p in self 1879 for p in self.sortedPhases(): 1900 if se 1880 if self.dmesg[p]['end'] > dev['start']: 1901 1881 dev['end'] = self.dmesg[p]['end'] 1902 1882 break 1903 sysvals.vprin 1883 sysvals.vprint('%s (%s): callback didnt return' % (devname, phase)) 1904 def deviceFilter(self, devicefilter): 1884 def deviceFilter(self, devicefilter): 1905 for phase in self.sortedPhase 1885 for phase in self.sortedPhases(): 1906 list = self.dmesg[pha 1886 list = self.dmesg[phase]['list'] 1907 rmlist = [] 1887 rmlist = [] 1908 for name in list: 1888 for name in list: 1909 keep = False 1889 keep = False 1910 for filter in 1890 for filter in devicefilter: 1911 if fi 1891 if filter in name or \ 1912 1892 ('drv' in list[name] and filter in list[name]['drv']): 1913 1893 keep = True 1914 if not keep: 1894 if not keep: 1915 rmlis 1895 rmlist.append(name) 1916 for name in rmlist: 1896 for name in rmlist: 1917 del list[name 1897 del list[name] 1918 def fixupInitcallsThatDidntReturn(sel 1898 def fixupInitcallsThatDidntReturn(self): 1919 # if any calls never returned 1899 # if any calls never returned, clip them at system resume end 1920 for phase in self.sortedPhase 1900 for phase in self.sortedPhases(): 1921 self.fixupInitcalls(p 1901 self.fixupInitcalls(phase) 1922 def phaseOverlap(self, phases): 1902 def phaseOverlap(self, phases): 1923 rmgroups = [] 1903 rmgroups = [] 1924 newgroup = [] 1904 newgroup = [] 1925 for group in self.devicegroup 1905 for group in self.devicegroups: 1926 for phase in phases: 1906 for phase in phases: 1927 if phase not 1907 if phase not in group: 1928 conti 1908 continue 1929 for p in grou 1909 for p in group: 1930 if p 1910 if p not in newgroup: 1931 1911 newgroup.append(p) 1932 if group not 1912 if group not in rmgroups: 1933 rmgro 1913 rmgroups.append(group) 1934 for group in rmgroups: 1914 for group in rmgroups: 1935 self.devicegroups.rem 1915 self.devicegroups.remove(group) 1936 self.devicegroups.append(newg 1916 self.devicegroups.append(newgroup) 1937 def newActionGlobal(self, name, start 1917 def newActionGlobal(self, name, start, end, pid=-1, color=''): 1938 # which phase is this device 1918 # which phase is this device callback or action in 1939 phases = self.sortedPhases() 1919 phases = self.sortedPhases() 1940 targetphase = 'none' 1920 targetphase = 'none' 1941 htmlclass = '' 1921 htmlclass = '' 1942 overlap = 0.0 1922 overlap = 0.0 1943 myphases = [] 1923 myphases = [] 1944 for phase in phases: 1924 for phase in phases: 1945 pstart = self.dmesg[p 1925 pstart = self.dmesg[phase]['start'] 1946 pend = self.dmesg[pha 1926 pend = self.dmesg[phase]['end'] 1947 # see if the action o 1927 # see if the action overlaps this phase 1948 o = max(0, min(end, p 1928 o = max(0, min(end, pend) - max(start, pstart)) 1949 if o > 0: 1929 if o > 0: 1950 myphases.appe 1930 myphases.append(phase) 1951 # set the target phas 1931 # set the target phase to the one that overlaps most 1952 if o > overlap: 1932 if o > overlap: 1953 if overlap > 1933 if overlap > 0 and phase == 'post_resume': 1954 conti 1934 continue 1955 targetphase = 1935 targetphase = phase 1956 overlap = o 1936 overlap = o 1957 # if no target phase was foun 1937 # if no target phase was found, pin it to the edge 1958 if targetphase == 'none': 1938 if targetphase == 'none': 1959 p0start = self.dmesg[ 1939 p0start = self.dmesg[phases[0]]['start'] 1960 if start <= p0start: 1940 if start <= p0start: 1961 targetphase = 1941 targetphase = phases[0] 1962 else: 1942 else: 1963 targetphase = 1943 targetphase = phases[-1] 1964 if pid == -2: 1944 if pid == -2: 1965 htmlclass = ' bg' 1945 htmlclass = ' bg' 1966 elif pid == -3: 1946 elif pid == -3: 1967 htmlclass = ' ps' 1947 htmlclass = ' ps' 1968 if len(myphases) > 1: 1948 if len(myphases) > 1: 1969 htmlclass = ' bg' 1949 htmlclass = ' bg' 1970 self.phaseOverlap(myp 1950 self.phaseOverlap(myphases) 1971 if targetphase in phases: 1951 if targetphase in phases: 1972 newname = self.newAct 1952 newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color) 1973 return (targetphase, 1953 return (targetphase, newname) 1974 return False 1954 return False 1975 def newAction(self, phase, name, pid, 1955 def newAction(self, phase, name, pid, parent, start, end, drv, htmlclass='', color=''): 1976 # new device callback for a s 1956 # new device callback for a specific phase 1977 self.html_device_id += 1 1957 self.html_device_id += 1 1978 devid = '%s%d' % (self.idstr, 1958 devid = '%s%d' % (self.idstr, self.html_device_id) 1979 list = self.dmesg[phase]['lis 1959 list = self.dmesg[phase]['list'] 1980 length = -1.0 1960 length = -1.0 1981 if(start >= 0 and end >= 0): 1961 if(start >= 0 and end >= 0): 1982 length = end - start 1962 length = end - start 1983 if pid == -2 or name not in s 1963 if pid == -2 or name not in sysvals.tracefuncs.keys(): 1984 i = 2 1964 i = 2 1985 origname = name 1965 origname = name 1986 while(name in list): 1966 while(name in list): 1987 name = '%s[%d 1967 name = '%s[%d]' % (origname, i) 1988 i += 1 1968 i += 1 1989 list[name] = {'name': name, ' 1969 list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid, 1990 'par': parent, 'lengt 1970 'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv } 1991 if htmlclass: 1971 if htmlclass: 1992 list[name]['htmlclass 1972 list[name]['htmlclass'] = htmlclass 1993 if color: 1973 if color: 1994 list[name]['color'] = 1974 list[name]['color'] = color 1995 return name 1975 return name 1996 def findDevice(self, phase, name): 1976 def findDevice(self, phase, name): 1997 list = self.dmesg[phase]['lis 1977 list = self.dmesg[phase]['list'] 1998 mydev = '' 1978 mydev = '' 1999 for devname in sorted(list): 1979 for devname in sorted(list): 2000 if name == devname or !! 1980 if name == devname or re.match('^%s\[(?P<num>[0-9]*)\]$' % name, devname): 2001 mydev = devna 1981 mydev = devname 2002 if mydev: 1982 if mydev: 2003 return list[mydev] 1983 return list[mydev] 2004 return False 1984 return False 2005 def deviceChildren(self, devname, pha 1985 def deviceChildren(self, devname, phase): 2006 devlist = [] 1986 devlist = [] 2007 list = self.dmesg[phase]['lis 1987 list = self.dmesg[phase]['list'] 2008 for child in list: 1988 for child in list: 2009 if(list[child]['par'] 1989 if(list[child]['par'] == devname): 2010 devlist.appen 1990 devlist.append(child) 2011 return devlist 1991 return devlist 2012 def maxDeviceNameSize(self, phase): 1992 def maxDeviceNameSize(self, phase): 2013 size = 0 1993 size = 0 2014 for name in self.dmesg[phase] 1994 for name in self.dmesg[phase]['list']: 2015 if len(name) > size: 1995 if len(name) > size: 2016 size = len(na 1996 size = len(name) 2017 return size 1997 return size 2018 def printDetails(self): 1998 def printDetails(self): 2019 sysvals.vprint('Timeline Deta 1999 sysvals.vprint('Timeline Details:') 2020 sysvals.vprint(' tes 2000 sysvals.vprint(' test start: %f' % self.start) 2021 sysvals.vprint('kernel suspen 2001 sysvals.vprint('kernel suspend start: %f' % self.tKernSus) 2022 tS = tR = False 2002 tS = tR = False 2023 for phase in self.sortedPhase 2003 for phase in self.sortedPhases(): 2024 devlist = self.dmesg[ 2004 devlist = self.dmesg[phase]['list'] 2025 dc, ps, pe = len(devl 2005 dc, ps, pe = len(devlist), self.dmesg[phase]['start'], self.dmesg[phase]['end'] 2026 if not tS and ps >= s 2006 if not tS and ps >= self.tSuspended: 2027 sysvals.vprin 2007 sysvals.vprint(' machine suspended: %f' % self.tSuspended) 2028 tS = True 2008 tS = True 2029 if not tR and ps >= s 2009 if not tR and ps >= self.tResumed: 2030 sysvals.vprin 2010 sysvals.vprint(' machine resumed: %f' % self.tResumed) 2031 tR = True 2011 tR = True 2032 sysvals.vprint('%20s: 2012 sysvals.vprint('%20s: %f - %f (%d devices)' % (phase, ps, pe, dc)) 2033 if sysvals.devdump: 2013 if sysvals.devdump: 2034 sysvals.vprin 2014 sysvals.vprint(''.join('-' for i in range(80))) 2035 maxname = '%d 2015 maxname = '%d' % self.maxDeviceNameSize(phase) 2036 fmt = '%3d) % 2016 fmt = '%3d) %'+maxname+'s - %f - %f' 2037 c = 1 2017 c = 1 2038 for name in s 2018 for name in sorted(devlist): 2039 s = d 2019 s = devlist[name]['start'] 2040 e = d 2020 e = devlist[name]['end'] 2041 sysva 2021 sysvals.vprint(fmt % (c, name, s, e)) 2042 c += 2022 c += 1 2043 sysvals.vprin 2023 sysvals.vprint(''.join('-' for i in range(80))) 2044 sysvals.vprint(' kernel res 2024 sysvals.vprint(' kernel resume end: %f' % self.tKernRes) 2045 sysvals.vprint(' t 2025 sysvals.vprint(' test end: %f' % self.end) 2046 def deviceChildrenAllPhases(self, dev 2026 def deviceChildrenAllPhases(self, devname): 2047 devlist = [] 2027 devlist = [] 2048 for phase in self.sortedPhase 2028 for phase in self.sortedPhases(): 2049 list = self.deviceChi 2029 list = self.deviceChildren(devname, phase) 2050 for dev in sorted(lis 2030 for dev in sorted(list): 2051 if dev not in 2031 if dev not in devlist: 2052 devli 2032 devlist.append(dev) 2053 return devlist 2033 return devlist 2054 def masterTopology(self, name, list, 2034 def masterTopology(self, name, list, depth): 2055 node = DeviceNode(name, depth 2035 node = DeviceNode(name, depth) 2056 for cname in list: 2036 for cname in list: 2057 # avoid recursions 2037 # avoid recursions 2058 if name == cname: 2038 if name == cname: 2059 continue 2039 continue 2060 clist = self.deviceCh 2040 clist = self.deviceChildrenAllPhases(cname) 2061 cnode = self.masterTo 2041 cnode = self.masterTopology(cname, clist, depth+1) 2062 node.children.append( 2042 node.children.append(cnode) 2063 return node 2043 return node 2064 def printTopology(self, node): 2044 def printTopology(self, node): 2065 html = '' 2045 html = '' 2066 if node.name: 2046 if node.name: 2067 info = '' 2047 info = '' 2068 drv = '' 2048 drv = '' 2069 for phase in self.sor 2049 for phase in self.sortedPhases(): 2070 list = self.d 2050 list = self.dmesg[phase]['list'] 2071 if node.name 2051 if node.name in list: 2072 s = l 2052 s = list[node.name]['start'] 2073 e = l 2053 e = list[node.name]['end'] 2074 if li 2054 if list[node.name]['drv']: 2075 2055 drv = ' {'+list[node.name]['drv']+'}' 2076 info 2056 info += ('<li>%s: %.3fms</li>' % (phase, (e-s)*1000)) 2077 html += '<li><b>'+nod 2057 html += '<li><b>'+node.name+drv+'</b>' 2078 if info: 2058 if info: 2079 html += '<ul> 2059 html += '<ul>'+info+'</ul>' 2080 html += '</li>' 2060 html += '</li>' 2081 if len(node.children) > 0: 2061 if len(node.children) > 0: 2082 html += '<ul>' 2062 html += '<ul>' 2083 for cnode in node.chi 2063 for cnode in node.children: 2084 html += self. 2064 html += self.printTopology(cnode) 2085 html += '</ul>' 2065 html += '</ul>' 2086 return html 2066 return html 2087 def rootDeviceList(self): 2067 def rootDeviceList(self): 2088 # list of devices graphed 2068 # list of devices graphed 2089 real = [] 2069 real = [] 2090 for phase in self.sortedPhase 2070 for phase in self.sortedPhases(): 2091 list = self.dmesg[pha 2071 list = self.dmesg[phase]['list'] 2092 for dev in sorted(lis 2072 for dev in sorted(list): 2093 if list[dev][ 2073 if list[dev]['pid'] >= 0 and dev not in real: 2094 real. 2074 real.append(dev) 2095 # list of top-most root devic 2075 # list of top-most root devices 2096 rootlist = [] 2076 rootlist = [] 2097 for phase in self.sortedPhase 2077 for phase in self.sortedPhases(): 2098 list = self.dmesg[pha 2078 list = self.dmesg[phase]['list'] 2099 for dev in sorted(lis 2079 for dev in sorted(list): 2100 pdev = list[d 2080 pdev = list[dev]['par'] 2101 pid = list[de 2081 pid = list[dev]['pid'] 2102 if(pid < 0 or !! 2082 if(pid < 0 or re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)): 2103 conti 2083 continue 2104 if pdev and p 2084 if pdev and pdev not in real and pdev not in rootlist: 2105 rootl 2085 rootlist.append(pdev) 2106 return rootlist 2086 return rootlist 2107 def deviceTopology(self): 2087 def deviceTopology(self): 2108 rootlist = self.rootDeviceLis 2088 rootlist = self.rootDeviceList() 2109 master = self.masterTopology( 2089 master = self.masterTopology('', rootlist, 0) 2110 return self.printTopology(mas 2090 return self.printTopology(master) 2111 def selectTimelineDevices(self, widfm 2091 def selectTimelineDevices(self, widfmt, tTotal, mindevlen): 2112 # only select devices that wi 2092 # only select devices that will actually show up in html 2113 self.tdevlist = dict() 2093 self.tdevlist = dict() 2114 for phase in self.dmesg: 2094 for phase in self.dmesg: 2115 devlist = [] 2095 devlist = [] 2116 list = self.dmesg[pha 2096 list = self.dmesg[phase]['list'] 2117 for dev in list: 2097 for dev in list: 2118 length = (lis 2098 length = (list[dev]['end'] - list[dev]['start']) * 1000 2119 width = widfm 2099 width = widfmt % (((list[dev]['end']-list[dev]['start'])*100)/tTotal) 2120 if length >= 2100 if length >= mindevlen: 2121 devli 2101 devlist.append(dev) 2122 self.tdevlist[phase] 2102 self.tdevlist[phase] = devlist 2123 def addHorizontalDivider(self, devnam 2103 def addHorizontalDivider(self, devname, devend): 2124 phase = 'suspend_prepare' 2104 phase = 'suspend_prepare' 2125 self.newAction(phase, devname 2105 self.newAction(phase, devname, -2, '', \ 2126 self.start, devend, ' 2106 self.start, devend, '', ' sec', '') 2127 if phase not in self.tdevlist 2107 if phase not in self.tdevlist: 2128 self.tdevlist[phase] 2108 self.tdevlist[phase] = [] 2129 self.tdevlist[phase].append(d 2109 self.tdevlist[phase].append(devname) 2130 d = DevItem(0, phase, self.dm 2110 d = DevItem(0, phase, self.dmesg[phase]['list'][devname]) 2131 return d 2111 return d 2132 def addProcessUsageEvent(self, name, 2112 def addProcessUsageEvent(self, name, times): 2133 # get the start and end times 2113 # get the start and end times for this process 2134 cpuexec = dict() 2114 cpuexec = dict() 2135 tlast = start = end = -1 2115 tlast = start = end = -1 2136 for t in sorted(times): 2116 for t in sorted(times): 2137 if tlast < 0: 2117 if tlast < 0: 2138 tlast = t 2118 tlast = t 2139 continue 2119 continue 2140 if name in self.pstl[ 2120 if name in self.pstl[t] and self.pstl[t][name] > 0: 2141 if start < 0: 2121 if start < 0: 2142 start 2122 start = tlast 2143 end, key = t, 2123 end, key = t, (tlast, t) 2144 maxj = (t - t 2124 maxj = (t - tlast) * 1024.0 2145 cpuexec[key] 2125 cpuexec[key] = min(1.0, float(self.pstl[t][name]) / maxj) 2146 tlast = t 2126 tlast = t 2147 if start < 0 or end < 0: 2127 if start < 0 or end < 0: 2148 return 2128 return 2149 # add a new action for this p 2129 # add a new action for this process and get the object 2150 out = self.newActionGlobal(na 2130 out = self.newActionGlobal(name, start, end, -3) 2151 if out: 2131 if out: 2152 phase, devname = out 2132 phase, devname = out 2153 dev = self.dmesg[phas 2133 dev = self.dmesg[phase]['list'][devname] 2154 dev['cpuexec'] = cpue 2134 dev['cpuexec'] = cpuexec 2155 def createProcessUsageEvents(self): 2135 def createProcessUsageEvents(self): 2156 # get an array of process nam 2136 # get an array of process names and times 2157 proclist = {'sus': dict(), 'r 2137 proclist = {'sus': dict(), 'res': dict()} 2158 tdata = {'sus': [], 'res': [] 2138 tdata = {'sus': [], 'res': []} 2159 for t in sorted(self.pstl): 2139 for t in sorted(self.pstl): 2160 dir = 'sus' if t < se 2140 dir = 'sus' if t < self.tSuspended else 'res' 2161 for ps in sorted(self 2141 for ps in sorted(self.pstl[t]): 2162 if ps not in 2142 if ps not in proclist[dir]: 2163 procl 2143 proclist[dir][ps] = 0 2164 tdata[dir].append(t) 2144 tdata[dir].append(t) 2165 # process the events for susp 2145 # process the events for suspend and resume 2166 if len(proclist['sus']) > 0 o 2146 if len(proclist['sus']) > 0 or len(proclist['res']) > 0: 2167 sysvals.vprint('Proce 2147 sysvals.vprint('Process Execution:') 2168 for dir in ['sus', 'res']: 2148 for dir in ['sus', 'res']: 2169 for ps in sorted(proc 2149 for ps in sorted(proclist[dir]): 2170 self.addProce 2150 self.addProcessUsageEvent(ps, tdata[dir]) 2171 def handleEndMarker(self, time, msg=' 2151 def handleEndMarker(self, time, msg=''): 2172 dm = self.dmesg 2152 dm = self.dmesg 2173 self.setEnd(time, msg) 2153 self.setEnd(time, msg) 2174 self.initDevicegroups() 2154 self.initDevicegroups() 2175 # give suspend_prepare an end 2155 # give suspend_prepare an end if needed 2176 if 'suspend_prepare' in dm an 2156 if 'suspend_prepare' in dm and dm['suspend_prepare']['end'] < 0: 2177 dm['suspend_prepare'] 2157 dm['suspend_prepare']['end'] = time 2178 # assume resume machine ends 2158 # assume resume machine ends at next phase start 2179 if 'resume_machine' in dm and 2159 if 'resume_machine' in dm and dm['resume_machine']['end'] < 0: 2180 np = self.nextPhase(' 2160 np = self.nextPhase('resume_machine', 1) 2181 if np: 2161 if np: 2182 dm['resume_ma 2162 dm['resume_machine']['end'] = dm[np]['start'] 2183 # if kernel resume end not fo 2163 # if kernel resume end not found, assume its the end marker 2184 if self.tKernRes == 0.0: 2164 if self.tKernRes == 0.0: 2185 self.tKernRes = time 2165 self.tKernRes = time 2186 # if kernel suspend start not 2166 # if kernel suspend start not found, assume its the end marker 2187 if self.tKernSus == 0.0: 2167 if self.tKernSus == 0.0: 2188 self.tKernSus = time 2168 self.tKernSus = time 2189 # set resume complete to end 2169 # set resume complete to end at end marker 2190 if 'resume_complete' in dm: 2170 if 'resume_complete' in dm: 2191 dm['resume_complete'] 2171 dm['resume_complete']['end'] = time 2192 def initcall_debug_call(self, line, q 2172 def initcall_debug_call(self, line, quick=False): 2193 m = re.match(r'.*(\[ *)(?P<t> !! 2173 m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\ 2194 r'PM: *calling .* @ ( !! 2174 'PM: *calling .* @ (?P<n>.*), parent: (?P<p>.*)', line) 2195 if not m: 2175 if not m: 2196 m = re.match(r'.*(\[ !! 2176 m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\ 2197 r'calling .* !! 2177 'calling .* @ (?P<n>.*), parent: (?P<p>.*)', line) 2198 if not m: 2178 if not m: 2199 m = re.match(r'.*(\[ !! 2179 m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling '+\ 2200 r'(?P<f>.*)\+ !! 2180 '(?P<f>.*)\+ @ (?P<n>.*), parent: (?P<p>.*)', line) 2201 if m: 2181 if m: 2202 return True if quick 2182 return True if quick else m.group('t', 'f', 'n', 'p') 2203 return False if quick else (' 2183 return False if quick else ('', '', '', '') 2204 def initcall_debug_return(self, line, 2184 def initcall_debug_return(self, line, quick=False): 2205 m = re.match(r'.*(\[ *)(?P<t> !! 2185 m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: PM: '+\ 2206 r'.* returned (?P<r>[ !! 2186 '.* returned (?P<r>[0-9]*) after (?P<dt>[0-9]*) usecs', line) 2207 if not m: 2187 if not m: 2208 m = re.match(r'.*(\[ !! 2188 m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\ 2209 r'.* returned !! 2189 '.* returned (?P<r>[0-9]*) after (?P<dt>[0-9]*) usecs', line) 2210 if not m: 2190 if not m: 2211 m = re.match(r'.*(\[ !! 2191 m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\ 2212 r'(?P<f>.*)\+ !! 2192 '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', line) 2213 if m: 2193 if m: 2214 return True if quick 2194 return True if quick else m.group('t', 'f', 'dt') 2215 return False if quick else (' 2195 return False if quick else ('', '', '') 2216 def debugPrint(self): 2196 def debugPrint(self): 2217 for p in self.sortedPhases(): 2197 for p in self.sortedPhases(): 2218 list = self.dmesg[p][ 2198 list = self.dmesg[p]['list'] 2219 for devname in sorted 2199 for devname in sorted(list): 2220 dev = list[de 2200 dev = list[devname] 2221 if 'ftrace' i 2201 if 'ftrace' in dev: 2222 dev[' 2202 dev['ftrace'].debugPrint(' [%s]' % devname) 2223 2203 2224 # Class: DevFunction 2204 # Class: DevFunction 2225 # Description: 2205 # Description: 2226 # A container for kprobe function data 2206 # A container for kprobe function data we want in the dev timeline 2227 class DevFunction: 2207 class DevFunction: 2228 def __init__(self, name, args, caller 2208 def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color): 2229 self.row = 0 2209 self.row = 0 2230 self.count = 1 2210 self.count = 1 2231 self.name = name 2211 self.name = name 2232 self.args = args 2212 self.args = args 2233 self.caller = caller 2213 self.caller = caller 2234 self.ret = ret 2214 self.ret = ret 2235 self.time = start 2215 self.time = start 2236 self.length = end - start 2216 self.length = end - start 2237 self.end = end 2217 self.end = end 2238 self.ubiquitous = u 2218 self.ubiquitous = u 2239 self.proc = proc 2219 self.proc = proc 2240 self.pid = pid 2220 self.pid = pid 2241 self.color = color 2221 self.color = color 2242 def title(self): 2222 def title(self): 2243 cnt = '' 2223 cnt = '' 2244 if self.count > 1: 2224 if self.count > 1: 2245 cnt = '(x%d)' % self. 2225 cnt = '(x%d)' % self.count 2246 l = '%0.3fms' % (self.length 2226 l = '%0.3fms' % (self.length * 1000) 2247 if self.ubiquitous: 2227 if self.ubiquitous: 2248 title = '%s(%s)%s <- 2228 title = '%s(%s)%s <- %s, %s(%s)' % \ 2249 (self.name, s 2229 (self.name, self.args, cnt, self.caller, self.ret, l) 2250 else: 2230 else: 2251 title = '%s(%s) %s%s( 2231 title = '%s(%s) %s%s(%s)' % (self.name, self.args, self.ret, cnt, l) 2252 return title.replace('"', '') 2232 return title.replace('"', '') 2253 def text(self): 2233 def text(self): 2254 if self.count > 1: 2234 if self.count > 1: 2255 text = '%s(x%d)' % (s 2235 text = '%s(x%d)' % (self.name, self.count) 2256 else: 2236 else: 2257 text = self.name 2237 text = self.name 2258 return text 2238 return text 2259 def repeat(self, tgt): 2239 def repeat(self, tgt): 2260 # is the tgt call just a repe 2240 # is the tgt call just a repeat of this call (e.g. are we in a loop) 2261 dt = self.time - tgt.end 2241 dt = self.time - tgt.end 2262 # only combine calls if -all- 2242 # only combine calls if -all- attributes are identical 2263 if tgt.caller == self.caller 2243 if tgt.caller == self.caller and \ 2264 tgt.name == self.name 2244 tgt.name == self.name and tgt.args == self.args and \ 2265 tgt.proc == self.proc 2245 tgt.proc == self.proc and tgt.pid == self.pid and \ 2266 tgt.ret == self.ret a 2246 tgt.ret == self.ret and dt >= 0 and \ 2267 dt <= sysvals.callloo 2247 dt <= sysvals.callloopmaxgap and \ 2268 self.length < sysvals 2248 self.length < sysvals.callloopmaxlen: 2269 return True 2249 return True 2270 return False 2250 return False 2271 2251 2272 # Class: FTraceLine 2252 # Class: FTraceLine 2273 # Description: 2253 # Description: 2274 # A container for a single line of ftr 2254 # A container for a single line of ftrace data. There are six basic types: 2275 # callgraph line: 2255 # callgraph line: 2276 # call: " dpm_run_ca 2256 # call: " dpm_run_callback() {" 2277 # return: " }" 2257 # return: " }" 2278 # leaf: " dpm_run_cal 2258 # leaf: " dpm_run_callback();" 2279 # trace event: 2259 # trace event: 2280 # tracing_mark_write: 2260 # tracing_mark_write: SUSPEND START or RESUME COMPLETE 2281 # suspend_resume: phas 2261 # suspend_resume: phase or custom exec block data 2282 # device_pm_callback: 2262 # device_pm_callback: device callback info 2283 class FTraceLine: 2263 class FTraceLine: 2284 def __init__(self, t, m='', d=''): 2264 def __init__(self, t, m='', d=''): 2285 self.length = 0.0 2265 self.length = 0.0 2286 self.fcall = False 2266 self.fcall = False 2287 self.freturn = False 2267 self.freturn = False 2288 self.fevent = False 2268 self.fevent = False 2289 self.fkprobe = False 2269 self.fkprobe = False 2290 self.depth = 0 2270 self.depth = 0 2291 self.name = '' 2271 self.name = '' 2292 self.type = '' 2272 self.type = '' 2293 self.time = float(t) 2273 self.time = float(t) 2294 if not m and not d: 2274 if not m and not d: 2295 return 2275 return 2296 # is this a trace event 2276 # is this a trace event 2297 if(d == 'traceevent' or re.ma !! 2277 if(d == 'traceevent' or re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m)): 2298 if(d == 'traceevent') 2278 if(d == 'traceevent'): 2299 # nop format 2279 # nop format trace event 2300 msg = m 2280 msg = m 2301 else: 2281 else: 2302 # function_gr 2282 # function_graph format trace event 2303 em = re.match !! 2283 em = re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m) 2304 msg = em.grou 2284 msg = em.group('msg') 2305 2285 2306 emm = re.match(r'^(?P !! 2286 emm = re.match('^(?P<call>.*?): (?P<msg>.*)', msg) 2307 if(emm): 2287 if(emm): 2308 self.name = e 2288 self.name = emm.group('msg') 2309 self.type = e 2289 self.type = emm.group('call') 2310 else: 2290 else: 2311 self.name = m 2291 self.name = msg 2312 km = re.match(r'^(?P< !! 2292 km = re.match('^(?P<n>.*)_cal$', self.type) 2313 if km: 2293 if km: 2314 self.fcall = 2294 self.fcall = True 2315 self.fkprobe 2295 self.fkprobe = True 2316 self.type = k 2296 self.type = km.group('n') 2317 return 2297 return 2318 km = re.match(r'^(?P< !! 2298 km = re.match('^(?P<n>.*)_ret$', self.type) 2319 if km: 2299 if km: 2320 self.freturn 2300 self.freturn = True 2321 self.fkprobe 2301 self.fkprobe = True 2322 self.type = k 2302 self.type = km.group('n') 2323 return 2303 return 2324 self.fevent = True 2304 self.fevent = True 2325 return 2305 return 2326 # convert the duration to sec 2306 # convert the duration to seconds 2327 if(d): 2307 if(d): 2328 self.length = float(d 2308 self.length = float(d)/1000000 2329 # the indentation determines 2309 # the indentation determines the depth 2330 match = re.match(r'^(?P<d> *) !! 2310 match = re.match('^(?P<d> *)(?P<o>.*)$', m) 2331 if(not match): 2311 if(not match): 2332 return 2312 return 2333 self.depth = self.getDepth(ma 2313 self.depth = self.getDepth(match.group('d')) 2334 m = match.group('o') 2314 m = match.group('o') 2335 # function return 2315 # function return 2336 if(m[0] == '}'): 2316 if(m[0] == '}'): 2337 self.freturn = True 2317 self.freturn = True 2338 if(len(m) > 1): 2318 if(len(m) > 1): 2339 # includes co 2319 # includes comment with function name 2340 match = re.ma !! 2320 match = re.match('^} *\/\* *(?P<n>.*) *\*\/$', m) 2341 if(match): 2321 if(match): 2342 self. 2322 self.name = match.group('n').strip() 2343 # function call 2323 # function call 2344 else: 2324 else: 2345 self.fcall = True 2325 self.fcall = True 2346 # function call with 2326 # function call with children 2347 if(m[-1] == '{'): 2327 if(m[-1] == '{'): 2348 match = re.ma !! 2328 match = re.match('^(?P<n>.*) *\(.*', m) 2349 if(match): 2329 if(match): 2350 self. 2330 self.name = match.group('n').strip() 2351 # function call with 2331 # function call with no children (leaf) 2352 elif(m[-1] == ';'): 2332 elif(m[-1] == ';'): 2353 self.freturn 2333 self.freturn = True 2354 match = re.ma !! 2334 match = re.match('^(?P<n>.*) *\(.*', m) 2355 if(match): 2335 if(match): 2356 self. 2336 self.name = match.group('n').strip() 2357 # something else (pos 2337 # something else (possibly a trace marker) 2358 else: 2338 else: 2359 self.name = m 2339 self.name = m 2360 def isCall(self): 2340 def isCall(self): 2361 return self.fcall and not sel 2341 return self.fcall and not self.freturn 2362 def isReturn(self): 2342 def isReturn(self): 2363 return self.freturn and not s 2343 return self.freturn and not self.fcall 2364 def isLeaf(self): 2344 def isLeaf(self): 2365 return self.fcall and self.fr 2345 return self.fcall and self.freturn 2366 def getDepth(self, str): 2346 def getDepth(self, str): 2367 return len(str)/2 2347 return len(str)/2 2368 def debugPrint(self, info=''): 2348 def debugPrint(self, info=''): 2369 if self.isLeaf(): 2349 if self.isLeaf(): 2370 pprint(' -- %12.6f (d 2350 pprint(' -- %12.6f (depth=%02d): %s(); (%.3f us) %s' % (self.time, \ 2371 self.depth, s 2351 self.depth, self.name, self.length*1000000, info)) 2372 elif self.freturn: 2352 elif self.freturn: 2373 pprint(' -- %12.6f (d 2353 pprint(' -- %12.6f (depth=%02d): %s} (%.3f us) %s' % (self.time, \ 2374 self.depth, s 2354 self.depth, self.name, self.length*1000000, info)) 2375 else: 2355 else: 2376 pprint(' -- %12.6f (d 2356 pprint(' -- %12.6f (depth=%02d): %s() { (%.3f us) %s' % (self.time, \ 2377 self.depth, s 2357 self.depth, self.name, self.length*1000000, info)) 2378 def startMarker(self): 2358 def startMarker(self): 2379 # Is this the starting line o 2359 # Is this the starting line of a suspend? 2380 if not self.fevent: 2360 if not self.fevent: 2381 return False 2361 return False 2382 if sysvals.usetracemarkers: 2362 if sysvals.usetracemarkers: 2383 if(self.name.startswi 2363 if(self.name.startswith('SUSPEND START')): 2384 return True 2364 return True 2385 return False 2365 return False 2386 else: 2366 else: 2387 if(self.type == 'susp 2367 if(self.type == 'suspend_resume' and 2388 re.match(r'su !! 2368 re.match('suspend_enter\[.*\] begin', self.name)): 2389 return True 2369 return True 2390 return False 2370 return False 2391 def endMarker(self): 2371 def endMarker(self): 2392 # Is this the ending line of 2372 # Is this the ending line of a resume? 2393 if not self.fevent: 2373 if not self.fevent: 2394 return False 2374 return False 2395 if sysvals.usetracemarkers: 2375 if sysvals.usetracemarkers: 2396 if(self.name.startswi 2376 if(self.name.startswith('RESUME COMPLETE')): 2397 return True 2377 return True 2398 return False 2378 return False 2399 else: 2379 else: 2400 if(self.type == 'susp 2380 if(self.type == 'suspend_resume' and 2401 re.match(r'th !! 2381 re.match('thaw_processes\[.*\] end', self.name)): 2402 return True 2382 return True 2403 return False 2383 return False 2404 2384 2405 # Class: FTraceCallGraph 2385 # Class: FTraceCallGraph 2406 # Description: 2386 # Description: 2407 # A container for the ftrace callgraph 2387 # A container for the ftrace callgraph of a single recursive function. 2408 # This can be a dpm_run_callback, dpm_ 2388 # This can be a dpm_run_callback, dpm_prepare, or dpm_complete callgraph 2409 # Each instance is tied to a single de 2389 # Each instance is tied to a single device in a single phase, and is 2410 # comprised of an ordered list of FTra 2390 # comprised of an ordered list of FTraceLine objects 2411 class FTraceCallGraph: 2391 class FTraceCallGraph: 2412 vfname = 'missing_function_name' 2392 vfname = 'missing_function_name' 2413 def __init__(self, pid, sv): 2393 def __init__(self, pid, sv): 2414 self.id = '' 2394 self.id = '' 2415 self.invalid = False 2395 self.invalid = False 2416 self.name = '' 2396 self.name = '' 2417 self.partial = False 2397 self.partial = False 2418 self.ignore = False 2398 self.ignore = False 2419 self.start = -1.0 2399 self.start = -1.0 2420 self.end = -1.0 2400 self.end = -1.0 2421 self.list = [] 2401 self.list = [] 2422 self.depth = 0 2402 self.depth = 0 2423 self.pid = pid 2403 self.pid = pid 2424 self.sv = sv 2404 self.sv = sv 2425 def addLine(self, line): 2405 def addLine(self, line): 2426 # if this is already invalid, 2406 # if this is already invalid, just leave 2427 if(self.invalid): 2407 if(self.invalid): 2428 if(line.depth == 0 an 2408 if(line.depth == 0 and line.freturn): 2429 return 1 2409 return 1 2430 return 0 2410 return 0 2431 # invalidate on bad depth 2411 # invalidate on bad depth 2432 if(self.depth < 0): 2412 if(self.depth < 0): 2433 self.invalidate(line) 2413 self.invalidate(line) 2434 return 0 2414 return 0 2435 # ignore data til we return t 2415 # ignore data til we return to the current depth 2436 if self.ignore: 2416 if self.ignore: 2437 if line.depth > self. 2417 if line.depth > self.depth: 2438 return 0 2418 return 0 2439 else: 2419 else: 2440 self.list[-1] 2420 self.list[-1].freturn = True 2441 self.list[-1] 2421 self.list[-1].length = line.time - self.list[-1].time 2442 self.ignore = 2422 self.ignore = False 2443 # if this is 2423 # if this is a return at self.depth, no more work is needed 2444 if line.depth 2424 if line.depth == self.depth and line.isReturn(): 2445 if li 2425 if line.depth == 0: 2446 2426 self.end = line.time 2447 2427 return 1 2448 retur 2428 return 0 2449 # compare current depth with 2429 # compare current depth with this lines pre-call depth 2450 prelinedep = line.depth 2430 prelinedep = line.depth 2451 if line.isReturn(): 2431 if line.isReturn(): 2452 prelinedep += 1 2432 prelinedep += 1 2453 last = 0 2433 last = 0 2454 lasttime = line.time 2434 lasttime = line.time 2455 if len(self.list) > 0: 2435 if len(self.list) > 0: 2456 last = self.list[-1] 2436 last = self.list[-1] 2457 lasttime = last.time 2437 lasttime = last.time 2458 if last.isLeaf(): 2438 if last.isLeaf(): 2459 lasttime += l 2439 lasttime += last.length 2460 # handle low misalignments by 2440 # handle low misalignments by inserting returns 2461 mismatch = prelinedep - self. 2441 mismatch = prelinedep - self.depth 2462 warning = self.sv.verbose and 2442 warning = self.sv.verbose and abs(mismatch) > 1 2463 info = [] 2443 info = [] 2464 if mismatch < 0: 2444 if mismatch < 0: 2465 idx = 0 2445 idx = 0 2466 # add return calls to 2446 # add return calls to get the depth down 2467 while prelinedep < se 2447 while prelinedep < self.depth: 2468 self.depth -= 2448 self.depth -= 1 2469 if idx == 0 a 2449 if idx == 0 and last and last.isCall(): 2470 # spe 2450 # special case, turn last call into a leaf 2471 last. 2451 last.depth = self.depth 2472 last. 2452 last.freturn = True 2473 last. 2453 last.length = line.time - last.time 2474 if wa 2454 if warning: 2475 2455 info.append(('[make leaf]', last)) 2476 else: 2456 else: 2477 vline 2457 vline = FTraceLine(lasttime) 2478 vline 2458 vline.depth = self.depth 2479 vline 2459 vline.name = self.vfname 2480 vline 2460 vline.freturn = True 2481 self. 2461 self.list.append(vline) 2482 if wa 2462 if warning: 2483 2463 if idx == 0: 2484 2464 info.append(('', last)) 2485 2465 info.append(('[add return]', vline)) 2486 idx += 1 2466 idx += 1 2487 if warning: 2467 if warning: 2488 info.append(( 2468 info.append(('', line)) 2489 # handle high misalignments b 2469 # handle high misalignments by inserting calls 2490 elif mismatch > 0: 2470 elif mismatch > 0: 2491 idx = 0 2471 idx = 0 2492 if warning: 2472 if warning: 2493 info.append(( 2473 info.append(('', last)) 2494 # add calls to get th 2474 # add calls to get the depth up 2495 while prelinedep > se 2475 while prelinedep > self.depth: 2496 if idx == 0 a 2476 if idx == 0 and line.isReturn(): 2497 # spe 2477 # special case, turn this return into a leaf 2498 line. 2478 line.fcall = True 2499 preli 2479 prelinedep -= 1 2500 if wa 2480 if warning: 2501 2481 info.append(('[make leaf]', line)) 2502 else: 2482 else: 2503 vline 2483 vline = FTraceLine(lasttime) 2504 vline 2484 vline.depth = self.depth 2505 vline 2485 vline.name = self.vfname 2506 vline 2486 vline.fcall = True 2507 self. 2487 self.list.append(vline) 2508 self. 2488 self.depth += 1 2509 if no 2489 if not last: 2510 2490 self.start = vline.time 2511 if wa 2491 if warning: 2512 2492 info.append(('[add call]', vline)) 2513 idx += 1 2493 idx += 1 2514 if warning and ('[mak 2494 if warning and ('[make leaf]', line) not in info: 2515 info.append(( 2495 info.append(('', line)) 2516 if warning: 2496 if warning: 2517 pprint('WARNING: ftra 2497 pprint('WARNING: ftrace data missing, corrections made:') 2518 for i in info: 2498 for i in info: 2519 t, obj = i 2499 t, obj = i 2520 if obj: 2500 if obj: 2521 obj.d 2501 obj.debugPrint(t) 2522 # process the call and set th 2502 # process the call and set the new depth 2523 skipadd = False 2503 skipadd = False 2524 md = self.sv.max_graph_depth 2504 md = self.sv.max_graph_depth 2525 if line.isCall(): 2505 if line.isCall(): 2526 # ignore blacklisted/ 2506 # ignore blacklisted/overdepth funcs 2527 if (md and self.depth 2507 if (md and self.depth >= md - 1) or (line.name in self.sv.cgblacklist): 2528 self.ignore = 2508 self.ignore = True 2529 else: 2509 else: 2530 self.depth += 2510 self.depth += 1 2531 elif line.isReturn(): 2511 elif line.isReturn(): 2532 self.depth -= 1 2512 self.depth -= 1 2533 # remove blacklisted/ 2513 # remove blacklisted/overdepth/empty funcs that slipped through 2534 if (last and last.isC 2514 if (last and last.isCall() and last.depth == line.depth) or \ 2535 (md and last 2515 (md and last and last.depth >= md) or \ 2536 (line.name in 2516 (line.name in self.sv.cgblacklist): 2537 while len(sel 2517 while len(self.list) > 0 and self.list[-1].depth > line.depth: 2538 self. 2518 self.list.pop(-1) 2539 if len(self.l 2519 if len(self.list) == 0: 2540 self. 2520 self.invalid = True 2541 retur 2521 return 1 2542 self.list[-1] 2522 self.list[-1].freturn = True 2543 self.list[-1] 2523 self.list[-1].length = line.time - self.list[-1].time 2544 self.list[-1] 2524 self.list[-1].name = line.name 2545 skipadd = Tru 2525 skipadd = True 2546 if len(self.list) < 1: 2526 if len(self.list) < 1: 2547 self.start = line.tim 2527 self.start = line.time 2548 # check for a mismatch that r 2528 # check for a mismatch that returned all the way to callgraph end 2549 res = 1 2529 res = 1 2550 if mismatch < 0 and self.list 2530 if mismatch < 0 and self.list[-1].depth == 0 and self.list[-1].freturn: 2551 line = self.list[-1] 2531 line = self.list[-1] 2552 skipadd = True 2532 skipadd = True 2553 res = -1 2533 res = -1 2554 if not skipadd: 2534 if not skipadd: 2555 self.list.append(line 2535 self.list.append(line) 2556 if(line.depth == 0 and line.f 2536 if(line.depth == 0 and line.freturn): 2557 if(self.start < 0): 2537 if(self.start < 0): 2558 self.start = 2538 self.start = line.time 2559 self.end = line.time 2539 self.end = line.time 2560 if line.fcall: 2540 if line.fcall: 2561 self.end += l 2541 self.end += line.length 2562 if self.list[0].name 2542 if self.list[0].name == self.vfname: 2563 self.invalid 2543 self.invalid = True 2564 if res == -1: 2544 if res == -1: 2565 self.partial 2545 self.partial = True 2566 return res 2546 return res 2567 return 0 2547 return 0 2568 def invalidate(self, line): 2548 def invalidate(self, line): 2569 if(len(self.list) > 0): 2549 if(len(self.list) > 0): 2570 first = self.list[0] 2550 first = self.list[0] 2571 self.list = [] 2551 self.list = [] 2572 self.list.append(firs 2552 self.list.append(first) 2573 self.invalid = True 2553 self.invalid = True 2574 id = 'task %s' % (self.pid) 2554 id = 'task %s' % (self.pid) 2575 window = '(%f - %f)' % (self. 2555 window = '(%f - %f)' % (self.start, line.time) 2576 if(self.depth < 0): 2556 if(self.depth < 0): 2577 pprint('Data misalign 2557 pprint('Data misalignment for '+id+\ 2578 ' (buffer ove 2558 ' (buffer overflow), ignoring this callback') 2579 else: 2559 else: 2580 pprint('Too much data 2560 pprint('Too much data for '+id+\ 2581 ' '+window+', 2561 ' '+window+', ignoring this callback') 2582 def slice(self, dev): 2562 def slice(self, dev): 2583 minicg = FTraceCallGraph(dev[ 2563 minicg = FTraceCallGraph(dev['pid'], self.sv) 2584 minicg.name = self.name 2564 minicg.name = self.name 2585 mydepth = -1 2565 mydepth = -1 2586 good = False 2566 good = False 2587 for l in self.list: 2567 for l in self.list: 2588 if(l.time < dev['star 2568 if(l.time < dev['start'] or l.time > dev['end']): 2589 continue 2569 continue 2590 if mydepth < 0: 2570 if mydepth < 0: 2591 if l.name == 2571 if l.name == 'mutex_lock' and l.freturn: 2592 mydep 2572 mydepth = l.depth 2593 continue 2573 continue 2594 elif l.depth == mydep 2574 elif l.depth == mydepth and l.name == 'mutex_unlock' and l.fcall: 2595 good = True 2575 good = True 2596 break 2576 break 2597 l.depth -= mydepth 2577 l.depth -= mydepth 2598 minicg.addLine(l) 2578 minicg.addLine(l) 2599 if not good or len(minicg.lis 2579 if not good or len(minicg.list) < 1: 2600 return 0 2580 return 0 2601 return minicg 2581 return minicg 2602 def repair(self, enddepth): 2582 def repair(self, enddepth): 2603 # bring the depth back to 0 w 2583 # bring the depth back to 0 with additional returns 2604 fixed = False 2584 fixed = False 2605 last = self.list[-1] 2585 last = self.list[-1] 2606 for i in reversed(range(endde 2586 for i in reversed(range(enddepth)): 2607 t = FTraceLine(last.t 2587 t = FTraceLine(last.time) 2608 t.depth = i 2588 t.depth = i 2609 t.freturn = True 2589 t.freturn = True 2610 fixed = self.addLine( 2590 fixed = self.addLine(t) 2611 if fixed != 0: 2591 if fixed != 0: 2612 self.end = la 2592 self.end = last.time 2613 return True 2593 return True 2614 return False 2594 return False 2615 def postProcess(self): 2595 def postProcess(self): 2616 if len(self.list) > 0: 2596 if len(self.list) > 0: 2617 self.name = self.list 2597 self.name = self.list[0].name 2618 stack = dict() 2598 stack = dict() 2619 cnt = 0 2599 cnt = 0 2620 last = 0 2600 last = 0 2621 for l in self.list: 2601 for l in self.list: 2622 # ftrace bug: reporte 2602 # ftrace bug: reported duration is not reliable 2623 # check each leaf and 2603 # check each leaf and clip it at max possible length 2624 if last and last.isLe 2604 if last and last.isLeaf(): 2625 if last.lengt 2605 if last.length > l.time - last.time: 2626 last. 2606 last.length = l.time - last.time 2627 if l.isCall(): 2607 if l.isCall(): 2628 stack[l.depth 2608 stack[l.depth] = l 2629 cnt += 1 2609 cnt += 1 2630 elif l.isReturn(): 2610 elif l.isReturn(): 2631 if(l.depth no 2611 if(l.depth not in stack): 2632 if se 2612 if self.sv.verbose: 2633 2613 pprint('Post Process Error: Depth missing') 2634 2614 l.debugPrint() 2635 retur 2615 return False 2636 # calculate c 2616 # calculate call length from call/return lines 2637 cl = stack[l. 2617 cl = stack[l.depth] 2638 cl.length = l 2618 cl.length = l.time - cl.time 2639 if cl.name == 2619 if cl.name == self.vfname: 2640 cl.na 2620 cl.name = l.name 2641 stack.pop(l.d 2621 stack.pop(l.depth) 2642 l.length = 0 2622 l.length = 0 2643 cnt -= 1 2623 cnt -= 1 2644 last = l 2624 last = l 2645 if(cnt == 0): 2625 if(cnt == 0): 2646 # trace caught the wh 2626 # trace caught the whole call tree 2647 return True 2627 return True 2648 elif(cnt < 0): 2628 elif(cnt < 0): 2649 if self.sv.verbose: 2629 if self.sv.verbose: 2650 pprint('Post 2630 pprint('Post Process Error: Depth is less than 0') 2651 return False 2631 return False 2652 # trace ended before call tre 2632 # trace ended before call tree finished 2653 return self.repair(cnt) 2633 return self.repair(cnt) 2654 def deviceMatch(self, pid, data): 2634 def deviceMatch(self, pid, data): 2655 found = '' 2635 found = '' 2656 # add the callgraph data to t 2636 # add the callgraph data to the device hierarchy 2657 borderphase = { 2637 borderphase = { 2658 'dpm_prepare': 'suspe 2638 'dpm_prepare': 'suspend_prepare', 2659 'dpm_complete': 'resu 2639 'dpm_complete': 'resume_complete' 2660 } 2640 } 2661 if(self.name in borderphase): 2641 if(self.name in borderphase): 2662 p = borderphase[self. 2642 p = borderphase[self.name] 2663 list = data.dmesg[p][ 2643 list = data.dmesg[p]['list'] 2664 for devname in list: 2644 for devname in list: 2665 dev = list[de 2645 dev = list[devname] 2666 if(pid == dev 2646 if(pid == dev['pid'] and 2667 self. 2647 self.start <= dev['start'] and 2668 self. 2648 self.end >= dev['end']): 2669 cg = 2649 cg = self.slice(dev) 2670 if cg 2650 if cg: 2671 2651 dev['ftrace'] = cg 2672 found 2652 found = devname 2673 return found 2653 return found 2674 for p in data.sortedPhases(): 2654 for p in data.sortedPhases(): 2675 if(data.dmesg[p]['sta 2655 if(data.dmesg[p]['start'] <= self.start and 2676 self.start <= 2656 self.start <= data.dmesg[p]['end']): 2677 list = data.d 2657 list = data.dmesg[p]['list'] 2678 for devname i 2658 for devname in sorted(list, key=lambda k:list[k]['start']): 2679 dev = 2659 dev = list[devname] 2680 if(pi 2660 if(pid == dev['pid'] and 2681 2661 self.start <= dev['start'] and 2682 2662 self.end >= dev['end']): 2683 2663 dev['ftrace'] = self 2684 2664 found = devname 2685 2665 break 2686 break 2666 break 2687 return found 2667 return found 2688 def newActionFromFunction(self, data) 2668 def newActionFromFunction(self, data): 2689 name = self.name 2669 name = self.name 2690 if name in ['dpm_run_callback 2670 if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']: 2691 return 2671 return 2692 fs = self.start 2672 fs = self.start 2693 fe = self.end 2673 fe = self.end 2694 if fs < data.start or fe > da 2674 if fs < data.start or fe > data.end: 2695 return 2675 return 2696 phase = '' 2676 phase = '' 2697 for p in data.sortedPhases(): 2677 for p in data.sortedPhases(): 2698 if(data.dmesg[p]['sta 2678 if(data.dmesg[p]['start'] <= self.start and 2699 self.start < 2679 self.start < data.dmesg[p]['end']): 2700 phase = p 2680 phase = p 2701 break 2681 break 2702 if not phase: 2682 if not phase: 2703 return 2683 return 2704 out = data.newActionGlobal(na 2684 out = data.newActionGlobal(name, fs, fe, -2) 2705 if out: 2685 if out: 2706 phase, myname = out 2686 phase, myname = out 2707 data.dmesg[phase]['li 2687 data.dmesg[phase]['list'][myname]['ftrace'] = self 2708 def debugPrint(self, info=''): 2688 def debugPrint(self, info=''): 2709 pprint('%s pid=%d [%f - %f] % 2689 pprint('%s pid=%d [%f - %f] %.3f us' % \ 2710 (self.name, self.pid, 2690 (self.name, self.pid, self.start, self.end, 2711 (self.end - self.star 2691 (self.end - self.start)*1000000)) 2712 for l in self.list: 2692 for l in self.list: 2713 if l.isLeaf(): 2693 if l.isLeaf(): 2714 pprint('%f (% 2694 pprint('%f (%02d): %s(); (%.3f us)%s' % (l.time, \ 2715 l.dep 2695 l.depth, l.name, l.length*1000000, info)) 2716 elif l.freturn: 2696 elif l.freturn: 2717 pprint('%f (% 2697 pprint('%f (%02d): %s} (%.3f us)%s' % (l.time, \ 2718 l.dep 2698 l.depth, l.name, l.length*1000000, info)) 2719 else: 2699 else: 2720 pprint('%f (% 2700 pprint('%f (%02d): %s() { (%.3f us)%s' % (l.time, \ 2721 l.dep 2701 l.depth, l.name, l.length*1000000, info)) 2722 pprint(' ') 2702 pprint(' ') 2723 2703 2724 class DevItem: 2704 class DevItem: 2725 def __init__(self, test, phase, dev): 2705 def __init__(self, test, phase, dev): 2726 self.test = test 2706 self.test = test 2727 self.phase = phase 2707 self.phase = phase 2728 self.dev = dev 2708 self.dev = dev 2729 def isa(self, cls): 2709 def isa(self, cls): 2730 if 'htmlclass' in self.dev an 2710 if 'htmlclass' in self.dev and cls in self.dev['htmlclass']: 2731 return True 2711 return True 2732 return False 2712 return False 2733 2713 2734 # Class: Timeline 2714 # Class: Timeline 2735 # Description: 2715 # Description: 2736 # A container for a device timeline wh 2716 # A container for a device timeline which calculates 2737 # all the html properties to display i 2717 # all the html properties to display it correctly 2738 class Timeline: 2718 class Timeline: 2739 html_tblock = '<div id="block{0}" cla 2719 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="{ 2720 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 2721 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= 2722 html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' 2743 html_legend = '<div id="p{3}" class=" 2723 html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' 2744 def __init__(self, rowheight, scalehe 2724 def __init__(self, rowheight, scaleheight): 2745 self.html = '' 2725 self.html = '' 2746 self.height = 0 # total time 2726 self.height = 0 # total timeline height 2747 self.scaleH = scaleheight # t 2727 self.scaleH = scaleheight # timescale (top) row height 2748 self.rowH = rowheight # d 2728 self.rowH = rowheight # device row height 2749 self.bodyH = 0 # body heigh 2729 self.bodyH = 0 # body height 2750 self.rows = 0 # total time 2730 self.rows = 0 # total timeline rows 2751 self.rowlines = dict() 2731 self.rowlines = dict() 2752 self.rowheight = dict() 2732 self.rowheight = dict() 2753 def createHeader(self, sv, stamp): 2733 def createHeader(self, sv, stamp): 2754 if(not stamp['time']): 2734 if(not stamp['time']): 2755 return 2735 return 2756 self.html += '<div class="ver 2736 self.html += '<div class="version"><a href="https://01.org/pm-graph">%s v%s</a></div>' \ 2757 % (sv.title, sv.versi 2737 % (sv.title, sv.version) 2758 if sv.logmsg and sv.testlog: 2738 if sv.logmsg and sv.testlog: 2759 self.html += '<button 2739 self.html += '<button id="showtest" class="logbtn btnfmt">log</button>' 2760 if sv.dmesglog: 2740 if sv.dmesglog: 2761 self.html += '<button 2741 self.html += '<button id="showdmesg" class="logbtn btnfmt">dmesg</button>' 2762 if sv.ftracelog: 2742 if sv.ftracelog: 2763 self.html += '<button 2743 self.html += '<button id="showftrace" class="logbtn btnfmt">ftrace</button>' 2764 headline_stamp = '<div class= 2744 headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' 2765 self.html += headline_stamp.f 2745 self.html += headline_stamp.format(stamp['host'], stamp['kernel'], 2766 stamp['mode'], stamp[ 2746 stamp['mode'], stamp['time']) 2767 if 'man' in stamp and 'plat' 2747 if 'man' in stamp and 'plat' in stamp and 'cpu' in stamp and \ 2768 stamp['man'] and stam 2748 stamp['man'] and stamp['plat'] and stamp['cpu']: 2769 headline_sysinfo = '< 2749 headline_sysinfo = '<div class="stamp sysinfo">{0} {1} <i>with</i> {2}</div>\n' 2770 self.html += headline 2750 self.html += headline_sysinfo.format(stamp['man'], stamp['plat'], stamp['cpu']) 2771 2751 2772 # Function: getDeviceRows 2752 # Function: getDeviceRows 2773 # Description: 2753 # Description: 2774 # determine how may rows the devic 2754 # determine how may rows the device funcs will take 2775 # Arguments: 2755 # Arguments: 2776 # rawlist: the list of devices 2756 # rawlist: the list of devices/actions for a single phase 2777 # Output: 2757 # Output: 2778 # The total number of rows nee 2758 # The total number of rows needed to display this phase of the timeline 2779 def getDeviceRows(self, rawlist): 2759 def getDeviceRows(self, rawlist): 2780 # clear all rows and set them 2760 # clear all rows and set them to undefined 2781 sortdict = dict() 2761 sortdict = dict() 2782 for item in rawlist: 2762 for item in rawlist: 2783 item.row = -1 2763 item.row = -1 2784 sortdict[item] = item 2764 sortdict[item] = item.length 2785 sortlist = sorted(sortdict, k 2765 sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 2786 remaining = len(sortlist) 2766 remaining = len(sortlist) 2787 rowdata = dict() 2767 rowdata = dict() 2788 row = 1 2768 row = 1 2789 # try to pack each row with a 2769 # try to pack each row with as many ranges as possible 2790 while(remaining > 0): 2770 while(remaining > 0): 2791 if(row not in rowdata 2771 if(row not in rowdata): 2792 rowdata[row] 2772 rowdata[row] = [] 2793 for i in sortlist: 2773 for i in sortlist: 2794 if(i.row >= 0 2774 if(i.row >= 0): 2795 conti 2775 continue 2796 s = i.time 2776 s = i.time 2797 e = i.time + 2777 e = i.time + i.length 2798 valid = True 2778 valid = True 2799 for ritem in 2779 for ritem in rowdata[row]: 2800 rs = 2780 rs = ritem.time 2801 re = 2781 re = ritem.time + ritem.length 2802 if(no 2782 if(not (((s <= rs) and (e <= rs)) or 2803 2783 ((s >= re) and (e >= re)))): 2804 2784 valid = False 2805 2785 break 2806 if(valid): 2786 if(valid): 2807 rowda 2787 rowdata[row].append(i) 2808 i.row 2788 i.row = row 2809 remai 2789 remaining -= 1 2810 row += 1 2790 row += 1 2811 return row 2791 return row 2812 # Function: getPhaseRows 2792 # Function: getPhaseRows 2813 # Description: 2793 # Description: 2814 # Organize the timeline entrie 2794 # Organize the timeline entries into the smallest 2815 # number of rows possible, wit 2795 # number of rows possible, with no entry overlapping 2816 # Arguments: 2796 # Arguments: 2817 # devlist: the list of devices 2797 # devlist: the list of devices/actions in a group of contiguous phases 2818 # Output: 2798 # Output: 2819 # The total number of rows nee 2799 # The total number of rows needed to display this phase of the timeline 2820 def getPhaseRows(self, devlist, row=0 2800 def getPhaseRows(self, devlist, row=0, sortby='length'): 2821 # clear all rows and set them 2801 # clear all rows and set them to undefined 2822 remaining = len(devlist) 2802 remaining = len(devlist) 2823 rowdata = dict() 2803 rowdata = dict() 2824 sortdict = dict() 2804 sortdict = dict() 2825 myphases = [] 2805 myphases = [] 2826 # initialize all device rows 2806 # initialize all device rows to -1 and calculate devrows 2827 for item in devlist: 2807 for item in devlist: 2828 dev = item.dev 2808 dev = item.dev 2829 tp = (item.test, item 2809 tp = (item.test, item.phase) 2830 if tp not in myphases 2810 if tp not in myphases: 2831 myphases.appe 2811 myphases.append(tp) 2832 dev['row'] = -1 2812 dev['row'] = -1 2833 if sortby == 'start': 2813 if sortby == 'start': 2834 # sort by sta 2814 # sort by start 1st, then length 2nd 2835 sortdict[item 2815 sortdict[item] = (-1*float(dev['start']), float(dev['end']) - float(dev['start'])) 2836 else: 2816 else: 2837 # sort by len 2817 # sort by length 1st, then name 2nd 2838 sortdict[item 2818 sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) 2839 if 'src' in dev: 2819 if 'src' in dev: 2840 dev['devrows' 2820 dev['devrows'] = self.getDeviceRows(dev['src']) 2841 # sort the devlist by length 2821 # sort the devlist by length so that large items graph on top 2842 sortlist = sorted(sortdict, k 2822 sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 2843 orderedlist = [] 2823 orderedlist = [] 2844 for item in sortlist: 2824 for item in sortlist: 2845 if item.dev['pid'] == 2825 if item.dev['pid'] == -2: 2846 orderedlist.a 2826 orderedlist.append(item) 2847 for item in sortlist: 2827 for item in sortlist: 2848 if item not in ordere 2828 if item not in orderedlist: 2849 orderedlist.a 2829 orderedlist.append(item) 2850 # try to pack each row with a 2830 # try to pack each row with as many devices as possible 2851 while(remaining > 0): 2831 while(remaining > 0): 2852 rowheight = 1 2832 rowheight = 1 2853 if(row not in rowdata 2833 if(row not in rowdata): 2854 rowdata[row] 2834 rowdata[row] = [] 2855 for item in orderedli 2835 for item in orderedlist: 2856 dev = item.de 2836 dev = item.dev 2857 if(dev['row'] 2837 if(dev['row'] < 0): 2858 s = d 2838 s = dev['start'] 2859 e = d 2839 e = dev['end'] 2860 valid 2840 valid = True 2861 for r 2841 for ritem in rowdata[row]: 2862 2842 rs = ritem.dev['start'] 2863 2843 re = ritem.dev['end'] 2864 2844 if(not (((s <= rs) and (e <= rs)) or 2865 2845 ((s >= re) and (e >= re)))): 2866 2846 valid = False 2867 2847 break 2868 if(va 2848 if(valid): 2869 2849 rowdata[row].append(item) 2870 2850 dev['row'] = row 2871 2851 remaining -= 1 2872 2852 if 'devrows' in dev and dev['devrows'] > rowheight: 2873 2853 rowheight = dev['devrows'] 2874 for t, p in myphases: 2854 for t, p in myphases: 2875 if t not in s 2855 if t not in self.rowlines or t not in self.rowheight: 2876 self. 2856 self.rowlines[t] = dict() 2877 self. 2857 self.rowheight[t] = dict() 2878 if p not in s 2858 if p not in self.rowlines[t] or p not in self.rowheight[t]: 2879 self. 2859 self.rowlines[t][p] = dict() 2880 self. 2860 self.rowheight[t][p] = dict() 2881 rh = self.row 2861 rh = self.rowH 2882 # section hea 2862 # section headers should use a different row height 2883 if len(rowdat 2863 if len(rowdata[row]) == 1 and \ 2884 'html 2864 'htmlclass' in rowdata[row][0].dev and \ 2885 'sec' 2865 'sec' in rowdata[row][0].dev['htmlclass']: 2886 rh = 2866 rh = 15 2887 self.rowlines 2867 self.rowlines[t][p][row] = rowheight 2888 self.rowheigh 2868 self.rowheight[t][p][row] = rowheight * rh 2889 row += 1 2869 row += 1 2890 if(row > self.rows): 2870 if(row > self.rows): 2891 self.rows = int(row) 2871 self.rows = int(row) 2892 return row 2872 return row 2893 def phaseRowHeight(self, test, phase, 2873 def phaseRowHeight(self, test, phase, row): 2894 return self.rowheight[test][p 2874 return self.rowheight[test][phase][row] 2895 def phaseRowTop(self, test, phase, ro 2875 def phaseRowTop(self, test, phase, row): 2896 top = 0 2876 top = 0 2897 for i in sorted(self.rowheigh 2877 for i in sorted(self.rowheight[test][phase]): 2898 if i >= row: 2878 if i >= row: 2899 break 2879 break 2900 top += self.rowheight 2880 top += self.rowheight[test][phase][i] 2901 return top 2881 return top 2902 def calcTotalRows(self): 2882 def calcTotalRows(self): 2903 # Calculate the heights and o 2883 # Calculate the heights and offsets for the header and rows 2904 maxrows = 0 2884 maxrows = 0 2905 standardphases = [] 2885 standardphases = [] 2906 for t in self.rowlines: 2886 for t in self.rowlines: 2907 for p in self.rowline 2887 for p in self.rowlines[t]: 2908 total = 0 2888 total = 0 2909 for i in sort 2889 for i in sorted(self.rowlines[t][p]): 2910 total 2890 total += self.rowlines[t][p][i] 2911 if total > ma 2891 if total > maxrows: 2912 maxro 2892 maxrows = total 2913 if total == l 2893 if total == len(self.rowlines[t][p]): 2914 stand 2894 standardphases.append((t, p)) 2915 self.height = self.scaleH + ( 2895 self.height = self.scaleH + (maxrows*self.rowH) 2916 self.bodyH = self.height - se 2896 self.bodyH = self.height - self.scaleH 2917 # if there is 1 line per row, 2897 # if there is 1 line per row, draw them the standard way 2918 for t, p in standardphases: 2898 for t, p in standardphases: 2919 for i in sorted(self. 2899 for i in sorted(self.rowheight[t][p]): 2920 self.rowheigh 2900 self.rowheight[t][p][i] = float(self.bodyH)/len(self.rowlines[t][p]) 2921 def createZoomBox(self, mode='command 2901 def createZoomBox(self, mode='command', testcount=1): 2922 # Create bounding box, add bu 2902 # Create bounding box, add buttons 2923 html_zoombox = '<center><butt 2903 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 2904 html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' 2925 html_devlist1 = '<button id=" 2905 html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail{0}</button>' 2926 html_devlist2 = '<button id=" 2906 html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' 2927 if mode != 'command': 2907 if mode != 'command': 2928 if testcount > 1: 2908 if testcount > 1: 2929 self.html += 2909 self.html += html_devlist2 2930 self.html += 2910 self.html += html_devlist1.format('1') 2931 else: 2911 else: 2932 self.html += 2912 self.html += html_devlist1.format('') 2933 self.html += html_zoombox 2913 self.html += html_zoombox 2934 self.html += html_timeline.fo 2914 self.html += html_timeline.format('dmesg', self.height) 2935 # Function: createTimeScale 2915 # Function: createTimeScale 2936 # Description: 2916 # Description: 2937 # Create the timescale for a t 2917 # Create the timescale for a timeline block 2938 # Arguments: 2918 # Arguments: 2939 # m0: start time (mode begin) 2919 # m0: start time (mode begin) 2940 # mMax: end time (mode end) 2920 # mMax: end time (mode end) 2941 # tTotal: total timeline time 2921 # tTotal: total timeline time 2942 # mode: suspend or resume 2922 # mode: suspend or resume 2943 # Output: 2923 # Output: 2944 # The html code needed to disp 2924 # The html code needed to display the time scale 2945 def createTimeScale(self, m0, mMax, t 2925 def createTimeScale(self, m0, mMax, tTotal, mode): 2946 timescale = '<div class="t" s 2926 timescale = '<div class="t" style="right:{0}%">{1}</div>\n' 2947 rline = '<div class="t" style 2927 rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">{0}</div>\n' 2948 output = '<div class="timesca 2928 output = '<div class="timescale">\n' 2949 # set scale for timeline 2929 # set scale for timeline 2950 mTotal = mMax - m0 2930 mTotal = mMax - m0 2951 tS = 0.1 2931 tS = 0.1 2952 if(tTotal <= 0): 2932 if(tTotal <= 0): 2953 return output+'</div> 2933 return output+'</div>\n' 2954 if(tTotal > 4): 2934 if(tTotal > 4): 2955 tS = 1 2935 tS = 1 2956 divTotal = int(mTotal/tS) + 1 2936 divTotal = int(mTotal/tS) + 1 2957 divEdge = (mTotal - tS*(divTo 2937 divEdge = (mTotal - tS*(divTotal-1))*100/mTotal 2958 for i in range(divTotal): 2938 for i in range(divTotal): 2959 htmlline = '' 2939 htmlline = '' 2960 if(mode == 'suspend') 2940 if(mode == 'suspend'): 2961 pos = '%0.3f' 2941 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge) 2962 val = '%0.fms 2942 val = '%0.fms' % (float(i-divTotal+1)*tS*1000) 2963 if(i == divTo 2943 if(i == divTotal - 1): 2964 val = 2944 val = mode 2965 htmlline = ti 2945 htmlline = timescale.format(pos, val) 2966 else: 2946 else: 2967 pos = '%0.3f' 2947 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal)) 2968 val = '%0.fms 2948 val = '%0.fms' % (float(i)*tS*1000) 2969 htmlline = ti 2949 htmlline = timescale.format(pos, val) 2970 if(i == 0): 2950 if(i == 0): 2971 htmll 2951 htmlline = rline.format(mode) 2972 output += htmlline 2952 output += htmlline 2973 self.html += output+'</div>\n 2953 self.html += output+'</div>\n' 2974 2954 2975 # Class: TestProps 2955 # Class: TestProps 2976 # Description: 2956 # Description: 2977 # A list of values describing the prop 2957 # A list of values describing the properties of these test runs 2978 class TestProps: 2958 class TestProps: 2979 stampfmt = r'# [a-z]*-(?P<m>[0-9]{2}) !! 2959 stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ 2980 r'(?P<H>[0-9] !! 2960 '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ 2981 r' (?P<host>. !! 2961 ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' 2982 wififmt = r'^# wifi *(?P<d>\S*) *( !! 2962 wififmt = '^# wifi *(?P<d>\S*) *(?P<s>\S*) *(?P<t>[0-9\.]+).*' 2983 tstatfmt = r'^# turbostat (?P<t>\S* !! 2963 tstatfmt = '^# turbostat (?P<t>\S*)' 2984 testerrfmt = r'^# enter_sleep_error ( !! 2964 testerrfmt = '^# enter_sleep_error (?P<e>.*)' 2985 sysinfofmt = r'^# sysinfo .*' !! 2965 sysinfofmt = '^# sysinfo .*' 2986 cmdlinefmt = r'^# command \| (?P<cmd> !! 2966 cmdlinefmt = '^# command \| (?P<cmd>.*)' 2987 kparamsfmt = r'^# kparams \| (?P<kp>. !! 2967 kparamsfmt = '^# kparams \| (?P<kp>.*)' 2988 devpropfmt = r'# Device Properties: . !! 2968 devpropfmt = '# Device Properties: .*' 2989 pinfofmt = r'# platform-(?P<val>[a- !! 2969 pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9,_]*): (?P<info>.*)' 2990 tracertypefmt = r'# tracer: (?P<t>.*) !! 2970 tracertypefmt = '# tracer: (?P<t>.*)' 2991 firmwarefmt = r'# fwsuspend (?P<s>[0- !! 2971 firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' 2992 procexecfmt = r'ps - (?P<ps>.*)$' !! 2972 procexecfmt = 'ps - (?P<ps>.*)$' 2993 procmultifmt = r'@(?P<n>[0-9]*)\|(?P< !! 2973 procmultifmt = '@(?P<n>[0-9]*)\|(?P<ps>.*)$' 2994 ftrace_line_fmt_fg = \ 2974 ftrace_line_fmt_fg = \ 2995 r'^ *(?P<time>[0-9\.]*) *\| * !! 2975 '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ 2996 r' *(?P<proc>.*)-(?P<pid>[0-9 !! 2976 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ 2997 r'[ +!#\*@$]*(?P<dur>[0-9\.]* !! 2977 '[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)' 2998 ftrace_line_fmt_nop = \ 2978 ftrace_line_fmt_nop = \ 2999 r' *(?P<proc>.*)-(?P<pid>[0-9 !! 2979 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\ 3000 r'(?P<flags>\S*) *(?P<time>[0 !! 2980 '(?P<flags>\S*) *(?P<time>[0-9\.]*): *'+\ 3001 r'(?P<msg>.*)' !! 2981 '(?P<msg>.*)' 3002 machinesuspend = r'machine_suspend\[. !! 2982 machinesuspend = 'machine_suspend\[.*' 3003 multiproclist = dict() 2983 multiproclist = dict() 3004 multiproctime = 0.0 2984 multiproctime = 0.0 3005 multiproccnt = 0 2985 multiproccnt = 0 3006 def __init__(self): 2986 def __init__(self): 3007 self.stamp = '' 2987 self.stamp = '' 3008 self.sysinfo = '' 2988 self.sysinfo = '' 3009 self.cmdline = '' 2989 self.cmdline = '' 3010 self.testerror = [] 2990 self.testerror = [] 3011 self.turbostat = [] 2991 self.turbostat = [] 3012 self.wifi = [] 2992 self.wifi = [] 3013 self.fwdata = [] 2993 self.fwdata = [] 3014 self.ftrace_line_fmt = self.f 2994 self.ftrace_line_fmt = self.ftrace_line_fmt_nop 3015 self.cgformat = False 2995 self.cgformat = False 3016 self.data = 0 2996 self.data = 0 3017 self.ktemp = dict() 2997 self.ktemp = dict() 3018 def setTracerType(self, tracer): 2998 def setTracerType(self, tracer): 3019 if(tracer == 'function_graph' 2999 if(tracer == 'function_graph'): 3020 self.cgformat = True 3000 self.cgformat = True 3021 self.ftrace_line_fmt 3001 self.ftrace_line_fmt = self.ftrace_line_fmt_fg 3022 elif(tracer == 'nop'): 3002 elif(tracer == 'nop'): 3023 self.ftrace_line_fmt 3003 self.ftrace_line_fmt = self.ftrace_line_fmt_nop 3024 else: 3004 else: 3025 doError('Invalid trac 3005 doError('Invalid tracer format: [%s]' % tracer) 3026 def stampInfo(self, line, sv): 3006 def stampInfo(self, line, sv): 3027 if re.match(self.stampfmt, li 3007 if re.match(self.stampfmt, line): 3028 self.stamp = line 3008 self.stamp = line 3029 return True 3009 return True 3030 elif re.match(self.sysinfofmt 3010 elif re.match(self.sysinfofmt, line): 3031 self.sysinfo = line 3011 self.sysinfo = line 3032 return True 3012 return True 3033 elif re.match(self.tstatfmt, 3013 elif re.match(self.tstatfmt, line): 3034 self.turbostat.append 3014 self.turbostat.append(line) 3035 return True 3015 return True 3036 elif re.match(self.wififmt, l 3016 elif re.match(self.wififmt, line): 3037 self.wifi.append(line 3017 self.wifi.append(line) 3038 return True 3018 return True 3039 elif re.match(self.testerrfmt 3019 elif re.match(self.testerrfmt, line): 3040 self.testerror.append 3020 self.testerror.append(line) 3041 return True 3021 return True 3042 elif re.match(self.firmwarefm 3022 elif re.match(self.firmwarefmt, line): 3043 self.fwdata.append(li 3023 self.fwdata.append(line) 3044 return True 3024 return True 3045 elif(re.match(self.devpropfmt 3025 elif(re.match(self.devpropfmt, line)): 3046 self.parseDevprops(li 3026 self.parseDevprops(line, sv) 3047 return True 3027 return True 3048 elif(re.match(self.pinfofmt, 3028 elif(re.match(self.pinfofmt, line)): 3049 self.parsePlatformInf 3029 self.parsePlatformInfo(line, sv) 3050 return True 3030 return True 3051 m = re.match(self.cmdlinefmt, 3031 m = re.match(self.cmdlinefmt, line) 3052 if m: 3032 if m: 3053 self.cmdline = m.grou 3033 self.cmdline = m.group('cmd') 3054 return True 3034 return True 3055 m = re.match(self.tracertypef 3035 m = re.match(self.tracertypefmt, line) 3056 if(m): 3036 if(m): 3057 self.setTracerType(m. 3037 self.setTracerType(m.group('t')) 3058 return True 3038 return True 3059 return False 3039 return False 3060 def parseStamp(self, data, sv): 3040 def parseStamp(self, data, sv): 3061 # global test data 3041 # global test data 3062 m = re.match(self.stampfmt, s 3042 m = re.match(self.stampfmt, self.stamp) 3063 if not self.stamp or not m: 3043 if not self.stamp or not m: 3064 doError('data does no 3044 doError('data does not include the expected stamp') 3065 data.stamp = {'time': '', 'ho 3045 data.stamp = {'time': '', 'host': '', 'mode': ''} 3066 dt = datetime(int(m.group('y' 3046 dt = datetime(int(m.group('y'))+2000, int(m.group('m')), 3067 int(m.group('d')), in 3047 int(m.group('d')), int(m.group('H')), int(m.group('M')), 3068 int(m.group('S'))) 3048 int(m.group('S'))) 3069 data.stamp['time'] = dt.strft 3049 data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') 3070 data.stamp['host'] = m.group( 3050 data.stamp['host'] = m.group('host') 3071 data.stamp['mode'] = m.group( 3051 data.stamp['mode'] = m.group('mode') 3072 data.stamp['kernel'] = m.grou 3052 data.stamp['kernel'] = m.group('kernel') 3073 if re.match(self.sysinfofmt, 3053 if re.match(self.sysinfofmt, self.sysinfo): 3074 for f in self.sysinfo 3054 for f in self.sysinfo.split('|'): 3075 if '#' in f: 3055 if '#' in f: 3076 conti 3056 continue 3077 tmp = f.strip 3057 tmp = f.strip().split(':', 1) 3078 key = tmp[0] 3058 key = tmp[0] 3079 val = tmp[1] 3059 val = tmp[1] 3080 data.stamp[ke 3060 data.stamp[key] = val 3081 sv.hostname = data.stamp['hos 3061 sv.hostname = data.stamp['host'] 3082 sv.suspendmode = data.stamp[' 3062 sv.suspendmode = data.stamp['mode'] 3083 if sv.suspendmode == 'freeze' 3063 if sv.suspendmode == 'freeze': 3084 self.machinesuspend = !! 3064 self.machinesuspend = 'timekeeping_freeze\[.*' 3085 else: 3065 else: 3086 self.machinesuspend = !! 3066 self.machinesuspend = 'machine_suspend\[.*' 3087 if sv.suspendmode == 'command 3067 if sv.suspendmode == 'command' and sv.ftracefile != '': 3088 modes = ['on', 'freez 3068 modes = ['on', 'freeze', 'standby', 'mem', 'disk'] 3089 fp = sv.openlog(sv.ft 3069 fp = sv.openlog(sv.ftracefile, 'r') 3090 for line in fp: 3070 for line in fp: 3091 m = re.match( !! 3071 m = re.match('.* machine_suspend\[(?P<mode>.*)\]', line) 3092 if m and m.gr 3072 if m and m.group('mode') in ['1', '2', '3', '4']: 3093 sv.su 3073 sv.suspendmode = modes[int(m.group('mode'))] 3094 data. 3074 data.stamp['mode'] = sv.suspendmode 3095 break 3075 break 3096 fp.close() 3076 fp.close() 3097 sv.cmdline = self.cmdline 3077 sv.cmdline = self.cmdline 3098 if not sv.stamp: 3078 if not sv.stamp: 3099 sv.stamp = data.stamp 3079 sv.stamp = data.stamp 3100 # firmware data 3080 # firmware data 3101 if sv.suspendmode == 'mem' an 3081 if sv.suspendmode == 'mem' and len(self.fwdata) > data.testnumber: 3102 m = re.match(self.fir 3082 m = re.match(self.firmwarefmt, self.fwdata[data.testnumber]) 3103 if m: 3083 if m: 3104 data.fwSuspen 3084 data.fwSuspend, data.fwResume = int(m.group('s')), int(m.group('r')) 3105 if(data.fwSus 3085 if(data.fwSuspend > 0 or data.fwResume > 0): 3106 data. 3086 data.fwValid = True 3107 # turbostat data 3087 # turbostat data 3108 if len(self.turbostat) > data 3088 if len(self.turbostat) > data.testnumber: 3109 m = re.match(self.tst 3089 m = re.match(self.tstatfmt, self.turbostat[data.testnumber]) 3110 if m: 3090 if m: 3111 data.turbosta 3091 data.turbostat = m.group('t') 3112 # wifi data 3092 # wifi data 3113 if len(self.wifi) > data.test 3093 if len(self.wifi) > data.testnumber: 3114 m = re.match(self.wif 3094 m = re.match(self.wififmt, self.wifi[data.testnumber]) 3115 if m: 3095 if m: 3116 data.wifi = { 3096 data.wifi = {'dev': m.group('d'), 'stat': m.group('s'), 3117 'time 3097 'time': float(m.group('t'))} 3118 data.stamp['w 3098 data.stamp['wifi'] = m.group('d') 3119 # sleep mode enter errors 3099 # sleep mode enter errors 3120 if len(self.testerror) > data 3100 if len(self.testerror) > data.testnumber: 3121 m = re.match(self.tes 3101 m = re.match(self.testerrfmt, self.testerror[data.testnumber]) 3122 if m: 3102 if m: 3123 data.enterfai 3103 data.enterfail = m.group('e') 3124 def devprops(self, data): 3104 def devprops(self, data): 3125 props = dict() 3105 props = dict() 3126 devlist = data.split(';') 3106 devlist = data.split(';') 3127 for dev in devlist: 3107 for dev in devlist: 3128 f = dev.split(',') 3108 f = dev.split(',') 3129 if len(f) < 3: 3109 if len(f) < 3: 3130 continue 3110 continue 3131 dev = f[0] 3111 dev = f[0] 3132 props[dev] = DevProps 3112 props[dev] = DevProps() 3133 props[dev].altname = 3113 props[dev].altname = f[1] 3134 if int(f[2]): 3114 if int(f[2]): 3135 props[dev].is 3115 props[dev].isasync = True 3136 else: 3116 else: 3137 props[dev].is 3117 props[dev].isasync = False 3138 return props 3118 return props 3139 def parseDevprops(self, line, sv): 3119 def parseDevprops(self, line, sv): 3140 idx = line.index(': ') + 2 3120 idx = line.index(': ') + 2 3141 if idx >= len(line): 3121 if idx >= len(line): 3142 return 3122 return 3143 props = self.devprops(line[id 3123 props = self.devprops(line[idx:]) 3144 if sv.suspendmode == 'command 3124 if sv.suspendmode == 'command' and 'testcommandstring' in props: 3145 sv.testcommand = prop 3125 sv.testcommand = props['testcommandstring'].altname 3146 sv.devprops = props 3126 sv.devprops = props 3147 def parsePlatformInfo(self, line, sv) 3127 def parsePlatformInfo(self, line, sv): 3148 m = re.match(self.pinfofmt, l 3128 m = re.match(self.pinfofmt, line) 3149 if not m: 3129 if not m: 3150 return 3130 return 3151 name, info = m.group('val'), 3131 name, info = m.group('val'), m.group('info') 3152 if name == 'devinfo': 3132 if name == 'devinfo': 3153 sv.devprops = self.de 3133 sv.devprops = self.devprops(sv.b64unzip(info)) 3154 return 3134 return 3155 elif name == 'testcmd': 3135 elif name == 'testcmd': 3156 sv.testcommand = info 3136 sv.testcommand = info 3157 return 3137 return 3158 field = info.split('|') 3138 field = info.split('|') 3159 if len(field) < 2: 3139 if len(field) < 2: 3160 return 3140 return 3161 cmdline = field[0].strip() 3141 cmdline = field[0].strip() 3162 output = sv.b64unzip(field[1] 3142 output = sv.b64unzip(field[1].strip()) 3163 sv.platinfo.append([name, cmd 3143 sv.platinfo.append([name, cmdline, output]) 3164 3144 3165 # Class: TestRun 3145 # Class: TestRun 3166 # Description: 3146 # Description: 3167 # A container for a suspend/resume tes 3147 # A container for a suspend/resume test run. This is necessary as 3168 # there could be more than one, and th 3148 # there could be more than one, and they need to be separate. 3169 class TestRun: 3149 class TestRun: 3170 def __init__(self, dataobj): 3150 def __init__(self, dataobj): 3171 self.data = dataobj 3151 self.data = dataobj 3172 self.ftemp = dict() 3152 self.ftemp = dict() 3173 self.ttemp = dict() 3153 self.ttemp = dict() 3174 3154 3175 class ProcessMonitor: 3155 class ProcessMonitor: 3176 maxchars = 512 3156 maxchars = 512 3177 def __init__(self): 3157 def __init__(self): 3178 self.proclist = dict() 3158 self.proclist = dict() 3179 self.running = False 3159 self.running = False 3180 def procstat(self): 3160 def procstat(self): 3181 c = ['cat /proc/[1-9]*/stat 2 3161 c = ['cat /proc/[1-9]*/stat 2>/dev/null'] 3182 process = Popen(c, shell=True 3162 process = Popen(c, shell=True, stdout=PIPE) 3183 running = dict() 3163 running = dict() 3184 for line in process.stdout: 3164 for line in process.stdout: 3185 data = ascii(line).sp 3165 data = ascii(line).split() 3186 pid = data[0] 3166 pid = data[0] 3187 name = re.sub('[()]', 3167 name = re.sub('[()]', '', data[1]) 3188 user = int(data[13]) 3168 user = int(data[13]) 3189 kern = int(data[14]) 3169 kern = int(data[14]) 3190 kjiff = ujiff = 0 3170 kjiff = ujiff = 0 3191 if pid not in self.pr 3171 if pid not in self.proclist: 3192 self.proclist 3172 self.proclist[pid] = {'name' : name, 'user' : user, 'kern' : kern} 3193 else: 3173 else: 3194 val = self.pr 3174 val = self.proclist[pid] 3195 ujiff = user 3175 ujiff = user - val['user'] 3196 kjiff = kern 3176 kjiff = kern - val['kern'] 3197 val['user'] = 3177 val['user'] = user 3198 val['kern'] = 3178 val['kern'] = kern 3199 if ujiff > 0 or kjiff 3179 if ujiff > 0 or kjiff > 0: 3200 running[pid] 3180 running[pid] = ujiff + kjiff 3201 process.wait() 3181 process.wait() 3202 out = [''] 3182 out = [''] 3203 for pid in running: 3183 for pid in running: 3204 jiffies = running[pid 3184 jiffies = running[pid] 3205 val = self.proclist[p 3185 val = self.proclist[pid] 3206 if len(out[-1]) > sel 3186 if len(out[-1]) > self.maxchars: 3207 out.append('' 3187 out.append('') 3208 elif len(out[-1]) > 0 3188 elif len(out[-1]) > 0: 3209 out[-1] += ', 3189 out[-1] += ',' 3210 out[-1] += '%s-%s %d' 3190 out[-1] += '%s-%s %d' % (val['name'], pid, jiffies) 3211 if len(out) > 1: 3191 if len(out) > 1: 3212 for line in out: 3192 for line in out: 3213 sysvals.fsetV 3193 sysvals.fsetVal('ps - @%d|%s' % (len(out), line), 'trace_marker') 3214 else: 3194 else: 3215 sysvals.fsetVal('ps - 3195 sysvals.fsetVal('ps - %s' % out[0], 'trace_marker') 3216 def processMonitor(self, tid): 3196 def processMonitor(self, tid): 3217 while self.running: 3197 while self.running: 3218 self.procstat() 3198 self.procstat() 3219 def start(self): 3199 def start(self): 3220 self.thread = Thread(target=s 3200 self.thread = Thread(target=self.processMonitor, args=(0,)) 3221 self.running = True 3201 self.running = True 3222 self.thread.start() 3202 self.thread.start() 3223 def stop(self): 3203 def stop(self): 3224 self.running = False 3204 self.running = False 3225 3205 3226 # ----------------- FUNCTIONS --------------- 3206 # ----------------- FUNCTIONS -------------------- 3227 3207 3228 # Function: doesTraceLogHaveTraceEvents 3208 # Function: doesTraceLogHaveTraceEvents 3229 # Description: 3209 # Description: 3230 # Quickly determine if the ftrace log 3210 # Quickly determine if the ftrace log has all of the trace events, 3231 # markers, and/or kprobes required for 3211 # markers, and/or kprobes required for primary parsing. 3232 def doesTraceLogHaveTraceEvents(): 3212 def doesTraceLogHaveTraceEvents(): 3233 kpcheck = ['_cal: (', '_ret: ('] 3213 kpcheck = ['_cal: (', '_ret: ('] 3234 techeck = ['suspend_resume', 'device_ 3214 techeck = ['suspend_resume', 'device_pm_callback', 'tracing_mark_write'] 3235 tmcheck = ['SUSPEND START', 'RESUME C 3215 tmcheck = ['SUSPEND START', 'RESUME COMPLETE'] 3236 sysvals.usekprobes = False 3216 sysvals.usekprobes = False 3237 fp = sysvals.openlog(sysvals.ftracefi 3217 fp = sysvals.openlog(sysvals.ftracefile, 'r') 3238 for line in fp: 3218 for line in fp: 3239 # check for kprobes 3219 # check for kprobes 3240 if not sysvals.usekprobes: 3220 if not sysvals.usekprobes: 3241 for i in kpcheck: 3221 for i in kpcheck: 3242 if i in line: 3222 if i in line: 3243 sysva 3223 sysvals.usekprobes = True 3244 # check for all necessary tra 3224 # check for all necessary trace events 3245 check = techeck[:] 3225 check = techeck[:] 3246 for i in techeck: 3226 for i in techeck: 3247 if i in line: 3227 if i in line: 3248 check.remove( 3228 check.remove(i) 3249 techeck = check 3229 techeck = check 3250 # check for all necessary tra 3230 # check for all necessary trace markers 3251 check = tmcheck[:] 3231 check = tmcheck[:] 3252 for i in tmcheck: 3232 for i in tmcheck: 3253 if i in line: 3233 if i in line: 3254 check.remove( 3234 check.remove(i) 3255 tmcheck = check 3235 tmcheck = check 3256 fp.close() 3236 fp.close() 3257 sysvals.usetraceevents = True if len( 3237 sysvals.usetraceevents = True if len(techeck) < 3 else False 3258 sysvals.usetracemarkers = True if len 3238 sysvals.usetracemarkers = True if len(tmcheck) == 0 else False 3259 3239 3260 # Function: appendIncompleteTraceLog 3240 # Function: appendIncompleteTraceLog 3261 # Description: 3241 # Description: 3262 # Adds callgraph data which lacks trac 3242 # Adds callgraph data which lacks trace event data. This is only 3263 # for timelines generated from 3.15 or 3243 # for timelines generated from 3.15 or older 3264 # Arguments: 3244 # Arguments: 3265 # testruns: the array of Data objects 3245 # testruns: the array of Data objects obtained from parseKernelLog 3266 def appendIncompleteTraceLog(testruns): 3246 def appendIncompleteTraceLog(testruns): 3267 # create TestRun vessels for ftrace p 3247 # create TestRun vessels for ftrace parsing 3268 testcnt = len(testruns) 3248 testcnt = len(testruns) 3269 testidx = 0 3249 testidx = 0 3270 testrun = [] 3250 testrun = [] 3271 for data in testruns: 3251 for data in testruns: 3272 testrun.append(TestRun(data)) 3252 testrun.append(TestRun(data)) 3273 3253 3274 # extract the callgraph and traceeven 3254 # extract the callgraph and traceevent data 3275 sysvals.vprint('Analyzing the ftrace 3255 sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 3276 os.path.basename(sysvals.ftra 3256 os.path.basename(sysvals.ftracefile)) 3277 tp = TestProps() 3257 tp = TestProps() 3278 tf = sysvals.openlog(sysvals.ftracefi 3258 tf = sysvals.openlog(sysvals.ftracefile, 'r') 3279 data = 0 3259 data = 0 3280 for line in tf: 3260 for line in tf: 3281 # remove any latent carriage 3261 # remove any latent carriage returns 3282 line = line.replace('\r\n', ' 3262 line = line.replace('\r\n', '') 3283 if tp.stampInfo(line, sysvals 3263 if tp.stampInfo(line, sysvals): 3284 continue 3264 continue 3285 # parse only valid lines, if 3265 # parse only valid lines, if this is not one move on 3286 m = re.match(tp.ftrace_line_f 3266 m = re.match(tp.ftrace_line_fmt, line) 3287 if(not m): 3267 if(not m): 3288 continue 3268 continue 3289 # gather the basic message da 3269 # gather the basic message data from the line 3290 m_time = m.group('time') 3270 m_time = m.group('time') 3291 m_pid = m.group('pid') 3271 m_pid = m.group('pid') 3292 m_msg = m.group('msg') 3272 m_msg = m.group('msg') 3293 if(tp.cgformat): 3273 if(tp.cgformat): 3294 m_param3 = m.group('d 3274 m_param3 = m.group('dur') 3295 else: 3275 else: 3296 m_param3 = 'traceeven 3276 m_param3 = 'traceevent' 3297 if(m_time and m_pid and m_msg 3277 if(m_time and m_pid and m_msg): 3298 t = FTraceLine(m_time 3278 t = FTraceLine(m_time, m_msg, m_param3) 3299 pid = int(m_pid) 3279 pid = int(m_pid) 3300 else: 3280 else: 3301 continue 3281 continue 3302 # the line should be a call, 3282 # the line should be a call, return, or event 3303 if(not t.fcall and not t.fret 3283 if(not t.fcall and not t.freturn and not t.fevent): 3304 continue 3284 continue 3305 # look for the suspend start 3285 # look for the suspend start marker 3306 if(t.startMarker()): 3286 if(t.startMarker()): 3307 data = testrun[testid 3287 data = testrun[testidx].data 3308 tp.parseStamp(data, s 3288 tp.parseStamp(data, sysvals) 3309 data.setStart(t.time, 3289 data.setStart(t.time, t.name) 3310 continue 3290 continue 3311 if(not data): 3291 if(not data): 3312 continue 3292 continue 3313 # find the end of resume 3293 # find the end of resume 3314 if(t.endMarker()): 3294 if(t.endMarker()): 3315 data.setEnd(t.time, t 3295 data.setEnd(t.time, t.name) 3316 testidx += 1 3296 testidx += 1 3317 if(testidx >= testcnt 3297 if(testidx >= testcnt): 3318 break 3298 break 3319 continue 3299 continue 3320 # trace event processing 3300 # trace event processing 3321 if(t.fevent): 3301 if(t.fevent): 3322 continue 3302 continue 3323 # call/return processing 3303 # call/return processing 3324 elif sysvals.usecallgraph: 3304 elif sysvals.usecallgraph: 3325 # create a callgraph 3305 # create a callgraph object for the data 3326 if(pid not in testrun 3306 if(pid not in testrun[testidx].ftemp): 3327 testrun[testi 3307 testrun[testidx].ftemp[pid] = [] 3328 testrun[testi 3308 testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 3329 # when the call is fi 3309 # when the call is finished, see which device matches it 3330 cg = testrun[testidx] 3310 cg = testrun[testidx].ftemp[pid][-1] 3331 res = cg.addLine(t) 3311 res = cg.addLine(t) 3332 if(res != 0): 3312 if(res != 0): 3333 testrun[testi 3313 testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 3334 if(res == -1): 3314 if(res == -1): 3335 testrun[testi 3315 testrun[testidx].ftemp[pid][-1].addLine(t) 3336 tf.close() 3316 tf.close() 3337 3317 3338 for test in testrun: 3318 for test in testrun: 3339 # add the callgraph data to t 3319 # add the callgraph data to the device hierarchy 3340 for pid in test.ftemp: 3320 for pid in test.ftemp: 3341 for cg in test.ftemp[ 3321 for cg in test.ftemp[pid]: 3342 if len(cg.lis 3322 if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 3343 conti 3323 continue 3344 if(not cg.pos 3324 if(not cg.postProcess()): 3345 id = 3325 id = 'task %s cpu %s' % (pid, m.group('cpu')) 3346 sysva 3326 sysvals.vprint('Sanity check failed for '+\ 3347 3327 id+', ignoring this callback') 3348 conti 3328 continue 3349 callstart = c 3329 callstart = cg.start 3350 callend = cg. 3330 callend = cg.end 3351 for p in test 3331 for p in test.data.sortedPhases(): 3352 if(te 3332 if(test.data.dmesg[p]['start'] <= callstart and 3353 3333 callstart <= test.data.dmesg[p]['end']): 3354 3334 list = test.data.dmesg[p]['list'] 3355 3335 for devname in list: 3356 3336 dev = list[devname] 3357 3337 if(pid == dev['pid'] and 3358 3338 callstart <= dev['start'] and 3359 3339 callend >= dev['end']): 3360 3340 dev['ftrace'] = cg 3361 3341 break 3362 3342 3363 # Function: loadTraceLog 3343 # Function: loadTraceLog 3364 # Description: 3344 # Description: 3365 # load the ftrace file into memory and 3345 # load the ftrace file into memory and fix up any ordering issues 3366 # Output: 3346 # Output: 3367 # TestProps instance and an array of l 3347 # TestProps instance and an array of lines in proper order 3368 def loadTraceLog(): 3348 def loadTraceLog(): 3369 tp, data, lines, trace = TestProps(), 3349 tp, data, lines, trace = TestProps(), dict(), [], [] 3370 tf = sysvals.openlog(sysvals.ftracefi 3350 tf = sysvals.openlog(sysvals.ftracefile, 'r') 3371 for line in tf: 3351 for line in tf: 3372 # remove any latent carriage 3352 # remove any latent carriage returns 3373 line = line.replace('\r\n', ' 3353 line = line.replace('\r\n', '') 3374 if tp.stampInfo(line, sysvals 3354 if tp.stampInfo(line, sysvals): 3375 continue 3355 continue 3376 # ignore all other commented 3356 # ignore all other commented lines 3377 if line[0] == '#': 3357 if line[0] == '#': 3378 continue 3358 continue 3379 # ftrace line: parse only val 3359 # ftrace line: parse only valid lines 3380 m = re.match(tp.ftrace_line_f 3360 m = re.match(tp.ftrace_line_fmt, line) 3381 if(not m): 3361 if(not m): 3382 continue 3362 continue 3383 dur = m.group('dur') if tp.cg 3363 dur = m.group('dur') if tp.cgformat else 'traceevent' 3384 info = (m.group('time'), m.gr 3364 info = (m.group('time'), m.group('proc'), m.group('pid'), 3385 m.group('msg'), dur) 3365 m.group('msg'), dur) 3386 # group the data by timestamp 3366 # group the data by timestamp 3387 t = float(info[0]) 3367 t = float(info[0]) 3388 if t in data: 3368 if t in data: 3389 data[t].append(info) 3369 data[t].append(info) 3390 else: 3370 else: 3391 data[t] = [info] 3371 data[t] = [info] 3392 # we only care about trace ev 3372 # we only care about trace event ordering 3393 if (info[3].startswith('suspe 3373 if (info[3].startswith('suspend_resume:') or \ 3394 info[3].startswith('t 3374 info[3].startswith('tracing_mark_write:')) and t not in trace: 3395 trace.append( 3375 trace.append(t) 3396 tf.close() 3376 tf.close() 3397 for t in sorted(data): 3377 for t in sorted(data): 3398 first, last, blk = [], [], da 3378 first, last, blk = [], [], data[t] 3399 if len(blk) > 1 and t in trac 3379 if len(blk) > 1 and t in trace: 3400 # move certain lines 3380 # move certain lines to the start or end of a timestamp block 3401 for i in range(len(bl 3381 for i in range(len(blk)): 3402 if 'SUSPEND S 3382 if 'SUSPEND START' in blk[i][3]: 3403 first 3383 first.append(i) 3404 elif re.match !! 3384 elif re.match('.* timekeeping_freeze.*begin', blk[i][3]): 3405 last. 3385 last.append(i) 3406 elif re.match !! 3386 elif re.match('.* timekeeping_freeze.*end', blk[i][3]): 3407 first 3387 first.append(i) 3408 elif 'RESUME 3388 elif 'RESUME COMPLETE' in blk[i][3]: 3409 last. 3389 last.append(i) 3410 if len(first) == 1 an 3390 if len(first) == 1 and len(last) == 0: 3411 blk.insert(0, 3391 blk.insert(0, blk.pop(first[0])) 3412 elif len(last) == 1 a 3392 elif len(last) == 1 and len(first) == 0: 3413 blk.append(bl 3393 blk.append(blk.pop(last[0])) 3414 for info in blk: 3394 for info in blk: 3415 lines.append(info) 3395 lines.append(info) 3416 return (tp, lines) 3396 return (tp, lines) 3417 3397 3418 # Function: parseTraceLog 3398 # Function: parseTraceLog 3419 # Description: 3399 # Description: 3420 # Analyze an ftrace log output file ge 3400 # Analyze an ftrace log output file generated from this app during 3421 # the execution phase. Used when the f 3401 # the execution phase. Used when the ftrace log is the primary data source 3422 # and includes the suspend_resume and 3402 # and includes the suspend_resume and device_pm_callback trace events 3423 # The ftrace filename is taken from sy 3403 # The ftrace filename is taken from sysvals 3424 # Output: 3404 # Output: 3425 # An array of Data objects 3405 # An array of Data objects 3426 def parseTraceLog(live=False): 3406 def parseTraceLog(live=False): 3427 sysvals.vprint('Analyzing the ftrace 3407 sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 3428 os.path.basename(sysvals.ftra 3408 os.path.basename(sysvals.ftracefile)) 3429 if(os.path.exists(sysvals.ftracefile) 3409 if(os.path.exists(sysvals.ftracefile) == False): 3430 doError('%s does not exist' % 3410 doError('%s does not exist' % sysvals.ftracefile) 3431 if not live: 3411 if not live: 3432 sysvals.setupAllKprobes() 3412 sysvals.setupAllKprobes() 3433 ksuscalls = ['ksys_sync', 'pm_prepare 3413 ksuscalls = ['ksys_sync', 'pm_prepare_console'] 3434 krescalls = ['pm_restore_console'] 3414 krescalls = ['pm_restore_console'] 3435 tracewatch = ['irq_wakeup'] 3415 tracewatch = ['irq_wakeup'] 3436 if sysvals.usekprobes: 3416 if sysvals.usekprobes: 3437 tracewatch += ['sync_filesyst 3417 tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend', 3438 'syscore_resume', 're 3418 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 3439 'CPU_OFF', 'acpi_susp 3419 'CPU_OFF', 'acpi_suspend'] 3440 3420 3441 # extract the callgraph and traceeven 3421 # extract the callgraph and traceevent data 3442 s2idle_enter = hwsus = False 3422 s2idle_enter = hwsus = False 3443 testruns, testdata = [], [] 3423 testruns, testdata = [], [] 3444 testrun, data, limbo = 0, 0, True 3424 testrun, data, limbo = 0, 0, True 3445 phase = 'suspend_prepare' 3425 phase = 'suspend_prepare' 3446 tp, tf = loadTraceLog() 3426 tp, tf = loadTraceLog() 3447 for m_time, m_proc, m_pid, m_msg, m_p 3427 for m_time, m_proc, m_pid, m_msg, m_param3 in tf: 3448 # gather the basic message da 3428 # gather the basic message data from the line 3449 if(m_time and m_pid and m_msg 3429 if(m_time and m_pid and m_msg): 3450 t = FTraceLine(m_time 3430 t = FTraceLine(m_time, m_msg, m_param3) 3451 pid = int(m_pid) 3431 pid = int(m_pid) 3452 else: 3432 else: 3453 continue 3433 continue 3454 # the line should be a call, 3434 # the line should be a call, return, or event 3455 if(not t.fcall and not t.fret 3435 if(not t.fcall and not t.freturn and not t.fevent): 3456 continue 3436 continue 3457 # find the start of suspend 3437 # find the start of suspend 3458 if(t.startMarker()): 3438 if(t.startMarker()): 3459 data, limbo = Data(le 3439 data, limbo = Data(len(testdata)), False 3460 testdata.append(data) 3440 testdata.append(data) 3461 testrun = TestRun(dat 3441 testrun = TestRun(data) 3462 testruns.append(testr 3442 testruns.append(testrun) 3463 tp.parseStamp(data, s 3443 tp.parseStamp(data, sysvals) 3464 data.setStart(t.time, 3444 data.setStart(t.time, t.name) 3465 data.first_suspend_pr 3445 data.first_suspend_prepare = True 3466 phase = data.setPhase 3446 phase = data.setPhase('suspend_prepare', t.time, True) 3467 continue 3447 continue 3468 if(not data or limbo): 3448 if(not data or limbo): 3469 continue 3449 continue 3470 # process cpu exec line 3450 # process cpu exec line 3471 if t.type == 'tracing_mark_wr 3451 if t.type == 'tracing_mark_write': 3472 if t.name == 'CMD COM 3452 if t.name == 'CMD COMPLETE' and data.tKernRes == 0: 3473 data.tKernRes 3453 data.tKernRes = t.time 3474 m = re.match(tp.proce 3454 m = re.match(tp.procexecfmt, t.name) 3475 if(m): 3455 if(m): 3476 parts, msg = 3456 parts, msg = 1, m.group('ps') 3477 m = re.match( 3457 m = re.match(tp.procmultifmt, msg) 3478 if(m): 3458 if(m): 3479 parts 3459 parts, msg = int(m.group('n')), m.group('ps') 3480 if tp 3460 if tp.multiproccnt == 0: 3481 3461 tp.multiproctime = t.time 3482 3462 tp.multiproclist = dict() 3483 procl 3463 proclist = tp.multiproclist 3484 tp.mu 3464 tp.multiproccnt += 1 3485 else: 3465 else: 3486 procl 3466 proclist = dict() 3487 tp.mu 3467 tp.multiproccnt = 0 3488 for ps in msg 3468 for ps in msg.split(','): 3489 val = 3469 val = ps.split() 3490 if no 3470 if not val or len(val) != 2: 3491 3471 continue 3492 name 3472 name = val[0].replace('--', '-') 3493 procl 3473 proclist[name] = int(val[1]) 3494 if parts == 1 3474 if parts == 1: 3495 data. 3475 data.pstl[t.time] = proclist 3496 elif parts == 3476 elif parts == tp.multiproccnt: 3497 data. 3477 data.pstl[tp.multiproctime] = proclist 3498 tp.mu 3478 tp.multiproccnt = 0 3499 continue 3479 continue 3500 # find the end of resume 3480 # find the end of resume 3501 if(t.endMarker()): 3481 if(t.endMarker()): 3502 if data.tKernRes == 0 3482 if data.tKernRes == 0: 3503 data.tKernRes 3483 data.tKernRes = t.time 3504 data.handleEndMarker( 3484 data.handleEndMarker(t.time, t.name) 3505 if(not sysvals.usetra 3485 if(not sysvals.usetracemarkers): 3506 # no trace ma 3486 # no trace markers? then quit and be sure to finish recording 3507 # the event w 3487 # the event we used to trigger resume end 3508 if('thaw_proc 3488 if('thaw_processes' in testrun.ttemp and len(testrun.ttemp['thaw_processes']) > 0): 3509 # if 3489 # if an entry exists, assume this is its end 3510 testr 3490 testrun.ttemp['thaw_processes'][-1]['end'] = t.time 3511 limbo = True 3491 limbo = True 3512 continue 3492 continue 3513 # trace event processing 3493 # trace event processing 3514 if(t.fevent): 3494 if(t.fevent): 3515 if(t.type == 'suspend 3495 if(t.type == 'suspend_resume'): 3516 # suspend_res 3496 # suspend_resume trace events have two types, begin and end 3517 if(re.match(r !! 3497 if(re.match('(?P<name>.*) begin$', t.name)): 3518 isbeg 3498 isbegin = True 3519 elif(re.match !! 3499 elif(re.match('(?P<name>.*) end$', t.name)): 3520 isbeg 3500 isbegin = False 3521 else: 3501 else: 3522 conti 3502 continue 3523 if '[' in t.n 3503 if '[' in t.name: 3524 m = r !! 3504 m = re.match('(?P<name>.*)\[.*', t.name) 3525 else: 3505 else: 3526 m = r !! 3506 m = re.match('(?P<name>.*) .*', t.name) 3527 name = m.grou 3507 name = m.group('name') 3528 # ignore thes 3508 # ignore these events 3529 if(name.split 3509 if(name.split('[')[0] in tracewatch): 3530 conti 3510 continue 3531 # -- phase ch 3511 # -- phase changes -- 3532 # start of ke 3512 # start of kernel suspend 3533 if(re.match(r !! 3513 if(re.match('suspend_enter\[.*', t.name)): 3534 if(is 3514 if(isbegin and data.tKernSus == 0): 3535 3515 data.tKernSus = t.time 3536 conti 3516 continue 3537 # suspend_pre 3517 # suspend_prepare start 3538 elif(re.match !! 3518 elif(re.match('dpm_prepare\[.*', t.name)): 3539 if is 3519 if isbegin and data.first_suspend_prepare: 3540 3520 data.first_suspend_prepare = False 3541 3521 if data.tKernSus == 0: 3542 3522 data.tKernSus = t.time 3543 3523 continue 3544 phase 3524 phase = data.setPhase('suspend_prepare', t.time, isbegin) 3545 conti 3525 continue 3546 # suspend sta 3526 # suspend start 3547 elif(re.match !! 3527 elif(re.match('dpm_suspend\[.*', t.name)): 3548 phase 3528 phase = data.setPhase('suspend', t.time, isbegin) 3549 conti 3529 continue 3550 # suspend_lat 3530 # suspend_late start 3551 elif(re.match !! 3531 elif(re.match('dpm_suspend_late\[.*', t.name)): 3552 phase 3532 phase = data.setPhase('suspend_late', t.time, isbegin) 3553 conti 3533 continue 3554 # suspend_noi 3534 # suspend_noirq start 3555 elif(re.match !! 3535 elif(re.match('dpm_suspend_noirq\[.*', t.name)): 3556 phase 3536 phase = data.setPhase('suspend_noirq', t.time, isbegin) 3557 conti 3537 continue 3558 # suspend_mac 3538 # suspend_machine/resume_machine 3559 elif(re.match 3539 elif(re.match(tp.machinesuspend, t.name)): 3560 lp = 3540 lp = data.lastPhase() 3561 if(is 3541 if(isbegin): 3562 3542 hwsus = True 3563 3543 if lp.startswith('resume_machine'): 3564 3544 # trim out s2idle loops, track time trying to freeze 3565 3545 llp = data.lastPhase(2) 3566 3546 if llp.startswith('suspend_machine'): 3567 3547 if 'waking' not in data.dmesg[llp]: 3568 3548 data.dmesg[llp]['waking'] = [0, 0.0] 3569 3549 data.dmesg[llp]['waking'][0] += 1 3570 3550 data.dmesg[llp]['waking'][1] += \ 3571 3551 t.time - data.dmesg[lp]['start'] 3572 3552 data.currphase = '' 3573 3553 del data.dmesg[lp] 3574 3554 continue 3575 3555 phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True) 3576 3556 data.setPhase(phase, t.time, False) 3577 3557 if data.tSuspended == 0: 3578 3558 data.tSuspended = t.time 3579 else: 3559 else: 3580 3560 if lp.startswith('resume_machine'): 3581 3561 data.dmesg[lp]['end'] = t.time 3582 3562 continue 3583 3563 phase = data.setPhase('resume_machine', t.time, True) 3584 3564 if(sysvals.suspendmode in ['mem', 'disk']): 3585 3565 susp = phase.replace('resume', 'suspend') 3586 3566 if susp in data.dmesg: 3587 3567 data.dmesg[susp]['end'] = t.time 3588 3568 data.tSuspended = t.time 3589 3569 data.tResumed = t.time 3590 conti 3570 continue 3591 # resume_noir 3571 # resume_noirq start 3592 elif(re.match !! 3572 elif(re.match('dpm_resume_noirq\[.*', t.name)): 3593 phase 3573 phase = data.setPhase('resume_noirq', t.time, isbegin) 3594 conti 3574 continue 3595 # resume_earl 3575 # resume_early start 3596 elif(re.match !! 3576 elif(re.match('dpm_resume_early\[.*', t.name)): 3597 phase 3577 phase = data.setPhase('resume_early', t.time, isbegin) 3598 conti 3578 continue 3599 # resume star 3579 # resume start 3600 elif(re.match !! 3580 elif(re.match('dpm_resume\[.*', t.name)): 3601 phase 3581 phase = data.setPhase('resume', t.time, isbegin) 3602 conti 3582 continue 3603 # resume comp 3583 # resume complete start 3604 elif(re.match !! 3584 elif(re.match('dpm_complete\[.*', t.name)): 3605 phase 3585 phase = data.setPhase('resume_complete', t.time, isbegin) 3606 conti 3586 continue 3607 # skip trace 3587 # skip trace events inside devices calls 3608 if(not data.i 3588 if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)): 3609 conti 3589 continue 3610 # global even 3590 # global events (outside device calls) are graphed 3611 if(name not i 3591 if(name not in testrun.ttemp): 3612 testr 3592 testrun.ttemp[name] = [] 3613 # special han 3593 # special handling for s2idle_enter 3614 if name == 'm 3594 if name == 'machine_suspend': 3615 if hw 3595 if hwsus: 3616 3596 s2idle_enter = hwsus = False 3617 elif 3597 elif s2idle_enter and not isbegin: 3618 3598 if(len(testrun.ttemp[name]) > 0): 3619 3599 testrun.ttemp[name][-1]['end'] = t.time 3620 3600 testrun.ttemp[name][-1]['loop'] += 1 3621 elif 3601 elif not s2idle_enter and isbegin: 3622 3602 s2idle_enter = True 3623 3603 testrun.ttemp[name].append({'begin': t.time, 3624 3604 'end': t.time, 'pid': pid, 'loop': 0}) 3625 conti 3605 continue 3626 if(isbegin): 3606 if(isbegin): 3627 # cre 3607 # create a new list entry 3628 testr 3608 testrun.ttemp[name].append(\ 3629 3609 {'begin': t.time, 'end': t.time, 'pid': pid}) 3630 else: 3610 else: 3631 if(le 3611 if(len(testrun.ttemp[name]) > 0): 3632 3612 # if an entry exists, assume this is its end 3633 3613 testrun.ttemp[name][-1]['end'] = t.time 3634 # device callback sta 3614 # device callback start 3635 elif(t.type == 'devic 3615 elif(t.type == 'device_pm_callback_start'): 3636 if phase not 3616 if phase not in data.dmesg: 3637 conti 3617 continue 3638 m = re.match( !! 3618 m = re.match('(?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*',\ 3639 t.nam 3619 t.name); 3640 if(not m): 3620 if(not m): 3641 conti 3621 continue 3642 drv = m.group 3622 drv = m.group('drv') 3643 n = m.group(' 3623 n = m.group('d') 3644 p = m.group(' 3624 p = m.group('p') 3645 if(n and p): 3625 if(n and p): 3646 data. 3626 data.newAction(phase, n, pid, p, t.time, -1, drv) 3647 if pi 3627 if pid not in data.devpids: 3648 3628 data.devpids.append(pid) 3649 # device callback fin 3629 # device callback finish 3650 elif(t.type == 'devic 3630 elif(t.type == 'device_pm_callback_end'): 3651 if phase not 3631 if phase not in data.dmesg: 3652 conti 3632 continue 3653 m = re.match( !! 3633 m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name); 3654 if(not m): 3634 if(not m): 3655 conti 3635 continue 3656 n = m.group(' 3636 n = m.group('d') 3657 dev = data.fi 3637 dev = data.findDevice(phase, n) 3658 if dev: 3638 if dev: 3659 dev[' 3639 dev['length'] = t.time - dev['start'] 3660 dev[' 3640 dev['end'] = t.time 3661 # kprobe event processing 3641 # kprobe event processing 3662 elif(t.fkprobe): 3642 elif(t.fkprobe): 3663 kprobename = t.type 3643 kprobename = t.type 3664 kprobedata = t.name 3644 kprobedata = t.name 3665 key = (kprobename, pi 3645 key = (kprobename, pid) 3666 # displayname is gene 3646 # displayname is generated from kprobe data 3667 displayname = '' 3647 displayname = '' 3668 if(t.fcall): 3648 if(t.fcall): 3669 displayname = 3649 displayname = sysvals.kprobeDisplayName(kprobename, kprobedata) 3670 if not displa 3650 if not displayname: 3671 conti 3651 continue 3672 if(key not in 3652 if(key not in tp.ktemp): 3673 tp.kt 3653 tp.ktemp[key] = [] 3674 tp.ktemp[key] 3654 tp.ktemp[key].append({ 3675 'pid' 3655 'pid': pid, 3676 'begi 3656 'begin': t.time, 3677 'end' 3657 'end': -1, 3678 'name 3658 'name': displayname, 3679 'cdat 3659 'cdata': kprobedata, 3680 'proc 3660 'proc': m_proc, 3681 }) 3661 }) 3682 # start of ke 3662 # start of kernel resume 3683 if(data.tKern 3663 if(data.tKernSus == 0 and phase == 'suspend_prepare' \ 3684 and k 3664 and kprobename in ksuscalls): 3685 data. 3665 data.tKernSus = t.time 3686 elif(t.freturn): 3666 elif(t.freturn): 3687 if(key not in 3667 if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1: 3688 conti 3668 continue 3689 e = next((x f 3669 e = next((x for x in reversed(tp.ktemp[key]) if x['end'] < 0), 0) 3690 if not e: 3670 if not e: 3691 conti 3671 continue 3692 if (t.time - 3672 if (t.time - e['begin']) * 1000 < sysvals.mindevlen: 3693 tp.kt 3673 tp.ktemp[key].pop() 3694 conti 3674 continue 3695 e['end'] = t. 3675 e['end'] = t.time 3696 e['rdata'] = 3676 e['rdata'] = kprobedata 3697 # end of kern 3677 # end of kernel resume 3698 if(phase != ' 3678 if(phase != 'suspend_prepare' and kprobename in krescalls): 3699 if ph 3679 if phase in data.dmesg: 3700 3680 data.dmesg[phase]['end'] = t.time 3701 data. 3681 data.tKernRes = t.time 3702 3682 3703 # callgraph processing 3683 # callgraph processing 3704 elif sysvals.usecallgraph: 3684 elif sysvals.usecallgraph: 3705 # create a callgraph 3685 # create a callgraph object for the data 3706 key = (m_proc, pid) 3686 key = (m_proc, pid) 3707 if(key not in testrun 3687 if(key not in testrun.ftemp): 3708 testrun.ftemp 3688 testrun.ftemp[key] = [] 3709 testrun.ftemp 3689 testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 3710 # when the call is fi 3690 # when the call is finished, see which device matches it 3711 cg = testrun.ftemp[ke 3691 cg = testrun.ftemp[key][-1] 3712 res = cg.addLine(t) 3692 res = cg.addLine(t) 3713 if(res != 0): 3693 if(res != 0): 3714 testrun.ftemp 3694 testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 3715 if(res == -1): 3695 if(res == -1): 3716 testrun.ftemp 3696 testrun.ftemp[key][-1].addLine(t) 3717 if len(testdata) < 1: 3697 if len(testdata) < 1: 3718 sysvals.vprint('WARNING: ftra 3698 sysvals.vprint('WARNING: ftrace start marker is missing') 3719 if data and not data.devicegroups: 3699 if data and not data.devicegroups: 3720 sysvals.vprint('WARNING: ftra 3700 sysvals.vprint('WARNING: ftrace end marker is missing') 3721 data.handleEndMarker(t.time, 3701 data.handleEndMarker(t.time, t.name) 3722 3702 3723 if sysvals.suspendmode == 'command': 3703 if sysvals.suspendmode == 'command': 3724 for test in testruns: 3704 for test in testruns: 3725 for p in test.data.so 3705 for p in test.data.sortedPhases(): 3726 if p == 'susp 3706 if p == 'suspend_prepare': 3727 test. 3707 test.data.dmesg[p]['start'] = test.data.start 3728 test. 3708 test.data.dmesg[p]['end'] = test.data.end 3729 else: 3709 else: 3730 test. 3710 test.data.dmesg[p]['start'] = test.data.end 3731 test. 3711 test.data.dmesg[p]['end'] = test.data.end 3732 test.data.tSuspended 3712 test.data.tSuspended = test.data.end 3733 test.data.tResumed = 3713 test.data.tResumed = test.data.end 3734 test.data.fwValid = F 3714 test.data.fwValid = False 3735 3715 3736 # dev source and procmon events can b 3716 # dev source and procmon events can be unreadable with mixed phase height 3737 if sysvals.usedevsrc or sysvals.usepr 3717 if sysvals.usedevsrc or sysvals.useprocmon: 3738 sysvals.mixedphaseheight = Fa 3718 sysvals.mixedphaseheight = False 3739 3719 3740 # expand phase boundaries so there ar 3720 # expand phase boundaries so there are no gaps 3741 for data in testdata: 3721 for data in testdata: 3742 lp = data.sortedPhases()[0] 3722 lp = data.sortedPhases()[0] 3743 for p in data.sortedPhases(): 3723 for p in data.sortedPhases(): 3744 if(p != lp and not (' 3724 if(p != lp and not ('machine' in p and 'machine' in lp)): 3745 data.dmesg[lp 3725 data.dmesg[lp]['end'] = data.dmesg[p]['start'] 3746 lp = p 3726 lp = p 3747 3727 3748 for i in range(len(testruns)): 3728 for i in range(len(testruns)): 3749 test = testruns[i] 3729 test = testruns[i] 3750 data = test.data 3730 data = test.data 3751 # find the total time range f 3731 # find the total time range for this test (begin, end) 3752 tlb, tle = data.start, data.e 3732 tlb, tle = data.start, data.end 3753 if i < len(testruns) - 1: 3733 if i < len(testruns) - 1: 3754 tle = testruns[i+1].d 3734 tle = testruns[i+1].data.start 3755 # add the process usage data 3735 # add the process usage data to the timeline 3756 if sysvals.useprocmon: 3736 if sysvals.useprocmon: 3757 data.createProcessUsa 3737 data.createProcessUsageEvents() 3758 # add the traceevent data to 3738 # add the traceevent data to the device hierarchy 3759 if(sysvals.usetraceevents): 3739 if(sysvals.usetraceevents): 3760 # add actual trace fu 3740 # add actual trace funcs 3761 for name in sorted(te 3741 for name in sorted(test.ttemp): 3762 for event in 3742 for event in test.ttemp[name]: 3763 if ev 3743 if event['end'] - event['begin'] <= 0: 3764 3744 continue 3765 title 3745 title = name 3766 if na 3746 if name == 'machine_suspend' and 'loop' in event: 3767 3747 title = 's2idle_enter_%dx' % event['loop'] 3768 data. 3748 data.newActionGlobal(title, event['begin'], event['end'], event['pid']) 3769 # add the kprobe base 3749 # add the kprobe based virtual tracefuncs as actual devices 3770 for key in sorted(tp. 3750 for key in sorted(tp.ktemp): 3771 name, pid = k 3751 name, pid = key 3772 if name not i 3752 if name not in sysvals.tracefuncs: 3773 conti 3753 continue 3774 if pid not in 3754 if pid not in data.devpids: 3775 data. 3755 data.devpids.append(pid) 3776 for e in tp.k 3756 for e in tp.ktemp[key]: 3777 kb, k 3757 kb, ke = e['begin'], e['end'] 3778 if ke 3758 if ke - kb < 0.000001 or tlb > kb or tle <= kb: 3779 3759 continue 3780 color 3760 color = sysvals.kprobeColor(name) 3781 data. 3761 data.newActionGlobal(e['name'], kb, ke, pid, color) 3782 # add config base kpr 3762 # add config base kprobes and dev kprobes 3783 if sysvals.usedevsrc: 3763 if sysvals.usedevsrc: 3784 for key in so 3764 for key in sorted(tp.ktemp): 3785 name, 3765 name, pid = key 3786 if na 3766 if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs: 3787 3767 continue 3788 for e 3768 for e in tp.ktemp[key]: 3789 3769 kb, ke = e['begin'], e['end'] 3790 3770 if ke - kb < 0.000001 or tlb > kb or tle <= kb: 3791 3771 continue 3792 3772 data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb, 3793 3773 ke, e['cdata'], e['rdata']) 3794 if sysvals.usecallgraph: 3774 if sysvals.usecallgraph: 3795 # add the callgraph d 3775 # add the callgraph data to the device hierarchy 3796 sortlist = dict() 3776 sortlist = dict() 3797 for key in sorted(tes 3777 for key in sorted(test.ftemp): 3798 proc, pid = k 3778 proc, pid = key 3799 for cg in tes 3779 for cg in test.ftemp[key]: 3800 if le 3780 if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 3801 3781 continue 3802 if(no 3782 if(not cg.postProcess()): 3803 3783 id = 'task %s' % (pid) 3804 3784 sysvals.vprint('Sanity check failed for '+\ 3805 3785 id+', ignoring this callback') 3806 3786 continue 3807 # mat 3787 # match cg data to devices 3808 devna 3788 devname = '' 3809 if sy 3789 if sysvals.suspendmode != 'command': 3810 3790 devname = cg.deviceMatch(pid, data) 3811 if no 3791 if not devname: 3812 3792 sortkey = '%f%f%d' % (cg.start, cg.end, pid) 3813 3793 sortlist[sortkey] = cg 3814 elif 3794 elif len(cg.list) > 1000000 and cg.name != sysvals.ftopfunc: 3815 3795 sysvals.vprint('WARNING: the callgraph for %s is massive (%d lines)' %\ 3816 3796 (devname, len(cg.list))) 3817 # create blocks for o 3797 # create blocks for orphan cg data 3818 for sortkey in sorted 3798 for sortkey in sorted(sortlist): 3819 cg = sortlist 3799 cg = sortlist[sortkey] 3820 name = cg.nam 3800 name = cg.name 3821 if sysvals.is 3801 if sysvals.isCallgraphFunc(name): 3822 sysva 3802 sysvals.vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name)) 3823 cg.ne 3803 cg.newActionFromFunction(data) 3824 if sysvals.suspendmode == 'command': 3804 if sysvals.suspendmode == 'command': 3825 return (testdata, '') 3805 return (testdata, '') 3826 3806 3827 # fill in any missing phases 3807 # fill in any missing phases 3828 error = [] 3808 error = [] 3829 for data in testdata: 3809 for data in testdata: 3830 tn = '' if len(testdata) == 1 3810 tn = '' if len(testdata) == 1 else ('%d' % (data.testnumber + 1)) 3831 terr = '' 3811 terr = '' 3832 phasedef = data.phasedef 3812 phasedef = data.phasedef 3833 lp = 'suspend_prepare' 3813 lp = 'suspend_prepare' 3834 for p in sorted(phasedef, key 3814 for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 3835 if p not in data.dmes 3815 if p not in data.dmesg: 3836 if not terr: 3816 if not terr: 3837 ph = 3817 ph = p if 'machine' in p else lp 3838 if p 3818 if p == 'suspend_machine': 3839 3819 sm = sysvals.suspendmode 3840 3820 if sm in suspendmodename: 3841 3821 sm = suspendmodename[sm] 3842 3822 terr = 'test%s did not enter %s power mode' % (tn, sm) 3843 else: 3823 else: 3844 3824 terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph) 3845 pprin 3825 pprint('TEST%s FAILED: %s' % (tn, terr)) 3846 error 3826 error.append(terr) 3847 if da 3827 if data.tSuspended == 0: 3848 3828 data.tSuspended = data.dmesg[lp]['end'] 3849 if da 3829 if data.tResumed == 0: 3850 3830 data.tResumed = data.dmesg[lp]['end'] 3851 data. 3831 data.fwValid = False 3852 sysvals.vprin 3832 sysvals.vprint('WARNING: phase "%s" is missing!' % p) 3853 lp = p 3833 lp = p 3854 if not terr and 'dev' in data 3834 if not terr and 'dev' in data.wifi and data.wifi['stat'] == 'timeout': 3855 terr = '%s%s failed i 3835 terr = '%s%s failed in wifi_resume <i>(%s %.0fs timeout)</i>' % \ 3856 (sysvals.susp 3836 (sysvals.suspendmode, tn, data.wifi['dev'], data.wifi['time']) 3857 error.append(terr) 3837 error.append(terr) 3858 if not terr and data.enterfai 3838 if not terr and data.enterfail: 3859 pprint('test%s FAILED 3839 pprint('test%s FAILED: enter %s failed with %s' % (tn, sysvals.suspendmode, data.enterfail)) 3860 terr = 'test%s failed 3840 terr = 'test%s failed to enter %s mode' % (tn, sysvals.suspendmode) 3861 error.append(terr) 3841 error.append(terr) 3862 if data.tSuspended == 0: 3842 if data.tSuspended == 0: 3863 data.tSuspended = dat 3843 data.tSuspended = data.tKernRes 3864 if data.tResumed == 0: 3844 if data.tResumed == 0: 3865 data.tResumed = data. 3845 data.tResumed = data.tSuspended 3866 3846 3867 if(len(sysvals.devicefilter) 3847 if(len(sysvals.devicefilter) > 0): 3868 data.deviceFilter(sys 3848 data.deviceFilter(sysvals.devicefilter) 3869 data.fixupInitcallsThatDidntR 3849 data.fixupInitcallsThatDidntReturn() 3870 if sysvals.usedevsrc: 3850 if sysvals.usedevsrc: 3871 data.optimizeDevSrc() 3851 data.optimizeDevSrc() 3872 3852 3873 # x2: merge any overlapping devices b 3853 # x2: merge any overlapping devices between test runs 3874 if sysvals.usedevsrc and len(testdata 3854 if sysvals.usedevsrc and len(testdata) > 1: 3875 tc = len(testdata) 3855 tc = len(testdata) 3876 for i in range(tc - 1): 3856 for i in range(tc - 1): 3877 devlist = testdata[i] 3857 devlist = testdata[i].overflowDevices() 3878 for j in range(i + 1, 3858 for j in range(i + 1, tc): 3879 testdata[j].m 3859 testdata[j].mergeOverlapDevices(devlist) 3880 testdata[0].stitchTouchingThr 3860 testdata[0].stitchTouchingThreads(testdata[1:]) 3881 return (testdata, ', '.join(error)) 3861 return (testdata, ', '.join(error)) 3882 3862 3883 # Function: loadKernelLog 3863 # Function: loadKernelLog 3884 # Description: 3864 # Description: 3885 # load the dmesg file into memory and 3865 # load the dmesg file into memory and fix up any ordering issues 3886 # Output: 3866 # Output: 3887 # An array of empty Data objects with 3867 # An array of empty Data objects with only their dmesgtext attributes set 3888 def loadKernelLog(): 3868 def loadKernelLog(): 3889 sysvals.vprint('Analyzing the dmesg d 3869 sysvals.vprint('Analyzing the dmesg data (%s)...' % \ 3890 os.path.basename(sysvals.dmes 3870 os.path.basename(sysvals.dmesgfile)) 3891 if(os.path.exists(sysvals.dmesgfile) 3871 if(os.path.exists(sysvals.dmesgfile) == False): 3892 doError('%s does not exist' % 3872 doError('%s does not exist' % sysvals.dmesgfile) 3893 3873 3894 # there can be multiple test runs in 3874 # there can be multiple test runs in a single file 3895 tp = TestProps() 3875 tp = TestProps() 3896 tp.stamp = datetime.now().strftime('# 3876 tp.stamp = datetime.now().strftime('# suspend-%m%d%y-%H%M%S localhost mem unknown') 3897 testruns = [] 3877 testruns = [] 3898 data = 0 3878 data = 0 3899 lf = sysvals.openlog(sysvals.dmesgfil 3879 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 3900 for line in lf: 3880 for line in lf: 3901 line = line.replace('\r\n', ' 3881 line = line.replace('\r\n', '') 3902 idx = line.find('[') 3882 idx = line.find('[') 3903 if idx > 1: 3883 if idx > 1: 3904 line = line[idx:] 3884 line = line[idx:] 3905 if tp.stampInfo(line, sysvals 3885 if tp.stampInfo(line, sysvals): 3906 continue 3886 continue 3907 m = re.match(r'[ \t]*(\[ *)(? !! 3887 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 3908 if(not m): 3888 if(not m): 3909 continue 3889 continue 3910 msg = m.group("msg") 3890 msg = m.group("msg") 3911 if re.match(r'PM: Syncing fil !! 3891 if re.match('PM: Syncing filesystems.*', msg) or \ 3912 re.match(r'PM: suspen !! 3892 re.match('PM: suspend entry.*', msg): 3913 if(data): 3893 if(data): 3914 testruns.appe 3894 testruns.append(data) 3915 data = Data(len(testr 3895 data = Data(len(testruns)) 3916 tp.parseStamp(data, s 3896 tp.parseStamp(data, sysvals) 3917 if(not data): 3897 if(not data): 3918 continue 3898 continue 3919 m = re.match(r'.* *(?P<k>[0-9 !! 3899 m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg) 3920 if(m): 3900 if(m): 3921 sysvals.stamp['kernel 3901 sysvals.stamp['kernel'] = m.group('k') 3922 m = re.match(r'PM: Preparing !! 3902 m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg) 3923 if not m: 3903 if not m: 3924 m = re.match(r'PM: Pr !! 3904 m = re.match('PM: Preparing system for sleep \((?P<m>.*)\)', msg) 3925 if m: 3905 if m: 3926 sysvals.stamp['mode'] 3906 sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m') 3927 data.dmesgtext.append(line) 3907 data.dmesgtext.append(line) 3928 lf.close() 3908 lf.close() 3929 3909 3930 if sysvals.suspendmode == 's2idle': 3910 if sysvals.suspendmode == 's2idle': 3931 sysvals.suspendmode = 'freeze 3911 sysvals.suspendmode = 'freeze' 3932 elif sysvals.suspendmode == 'deep': 3912 elif sysvals.suspendmode == 'deep': 3933 sysvals.suspendmode = 'mem' 3913 sysvals.suspendmode = 'mem' 3934 if data: 3914 if data: 3935 testruns.append(data) 3915 testruns.append(data) 3936 if len(testruns) < 1: 3916 if len(testruns) < 1: 3937 doError('dmesg log has no sus 3917 doError('dmesg log has no suspend/resume data: %s' \ 3938 % sysvals.dmesgfile) 3918 % sysvals.dmesgfile) 3939 3919 3940 # fix lines with same timestamp/funct 3920 # fix lines with same timestamp/function with the call and return swapped 3941 for data in testruns: 3921 for data in testruns: 3942 last = '' 3922 last = '' 3943 for line in data.dmesgtext: 3923 for line in data.dmesgtext: 3944 ct, cf, n, p = data.i 3924 ct, cf, n, p = data.initcall_debug_call(line) 3945 rt, rf, l = data.init 3925 rt, rf, l = data.initcall_debug_return(last) 3946 if ct and rt and ct = 3926 if ct and rt and ct == rt and cf == rf: 3947 i = data.dmes 3927 i = data.dmesgtext.index(last) 3948 j = data.dmes 3928 j = data.dmesgtext.index(line) 3949 data.dmesgtex 3929 data.dmesgtext[i] = line 3950 data.dmesgtex 3930 data.dmesgtext[j] = last 3951 last = line 3931 last = line 3952 return testruns 3932 return testruns 3953 3933 3954 # Function: parseKernelLog 3934 # Function: parseKernelLog 3955 # Description: 3935 # Description: 3956 # Analyse a dmesg log output file gene 3936 # Analyse a dmesg log output file generated from this app during 3957 # the execution phase. Create a set of 3937 # the execution phase. Create a set of device structures in memory 3958 # for subsequent formatting in the htm 3938 # for subsequent formatting in the html output file 3959 # This call is only for legacy support 3939 # This call is only for legacy support on kernels where the ftrace 3960 # data lacks the suspend_resume or dev 3940 # data lacks the suspend_resume or device_pm_callbacks trace events. 3961 # Arguments: 3941 # Arguments: 3962 # data: an empty Data object (with dme 3942 # data: an empty Data object (with dmesgtext) obtained from loadKernelLog 3963 # Output: 3943 # Output: 3964 # The filled Data object 3944 # The filled Data object 3965 def parseKernelLog(data): 3945 def parseKernelLog(data): 3966 phase = 'suspend_runtime' 3946 phase = 'suspend_runtime' 3967 3947 3968 if(data.fwValid): 3948 if(data.fwValid): 3969 sysvals.vprint('Firmware Susp 3949 sysvals.vprint('Firmware Suspend = %u ns, Firmware Resume = %u ns' % \ 3970 (data.fwSuspend, data 3950 (data.fwSuspend, data.fwResume)) 3971 3951 3972 # dmesg phase match table 3952 # dmesg phase match table 3973 dm = { 3953 dm = { 3974 'suspend_prepare': ['PM: Sync 3954 'suspend_prepare': ['PM: Syncing filesystems.*', 'PM: suspend entry.*'], 3975 'suspend': ['PM: Ente 3955 'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*', 3976 'PM: Susp 3956 'PM: Suspending system .*'], 3977 'suspend_late': ['PM: susp 3957 'suspend_late': ['PM: suspend of devices complete after.*', 3978 3958 'PM: freeze of devices complete after.*'], 3979 'suspend_noirq': ['PM: late 3959 'suspend_noirq': ['PM: late suspend of devices complete after.*', 3980 3960 'PM: late freeze of devices complete after.*'], 3981 'suspend_machine': ['PM: susp 3961 'suspend_machine': ['PM: suspend-to-idle', 3982 3962 'PM: noirq suspend of devices complete after.*', 3983 3963 'PM: noirq freeze of devices complete after.*'], 3984 'resume_machine': ['[PM: ]*T !! 3964 'resume_machine': ['PM: Timekeeping suspended for.*', 3985 3965 'ACPI: Low-level resume complete.*', 3986 3966 'ACPI: resume from mwait', 3987 !! 3967 'Suspended for [0-9\.]* seconds'], 3988 'resume_noirq': ['PM: resu 3968 'resume_noirq': ['PM: resume from suspend-to-idle', 3989 3969 'ACPI: Waking up from system sleep state.*'], 3990 'resume_early': ['PM: noir 3970 'resume_early': ['PM: noirq resume of devices complete after.*', 3991 3971 'PM: noirq restore of devices complete after.*'], 3992 'resume': ['PM: earl 3972 'resume': ['PM: early resume of devices complete after.*', 3993 3973 'PM: early restore of devices complete after.*'], 3994 'resume_complete': ['PM: resu 3974 'resume_complete': ['PM: resume of devices complete after.*', 3995 3975 'PM: restore of devices complete after.*'], 3996 'post_resume': [r'.*Resta !! 3976 'post_resume': ['.*Restarting tasks \.\.\..*'], 3997 } 3977 } 3998 3978 3999 # action table (expected events that 3979 # action table (expected events that occur and show up in dmesg) 4000 at = { 3980 at = { 4001 'sync_filesystems': { 3981 'sync_filesystems': { 4002 'smsg': '.*[Ff]+ilesy !! 3982 'smsg': 'PM: Syncing filesystems.*', 4003 'emsg': 'PM: Preparin !! 3983 'emsg': 'PM: Preparing system for mem sleep.*' }, 4004 'freeze_user_processes': { 3984 'freeze_user_processes': { 4005 'smsg': 'Freezing use !! 3985 'smsg': 'Freezing user space processes .*', 4006 'emsg': 'Freezing rem 3986 'emsg': 'Freezing remaining freezable tasks.*' }, 4007 'freeze_tasks': { 3987 'freeze_tasks': { 4008 'smsg': 'Freezing rem 3988 'smsg': 'Freezing remaining freezable tasks.*', 4009 'emsg': 'PM: Suspendi !! 3989 'emsg': 'PM: Entering (?P<mode>[a-z,A-Z]*) sleep.*' }, 4010 'ACPI prepare': { 3990 'ACPI prepare': { 4011 'smsg': 'ACPI: Prepar 3991 'smsg': 'ACPI: Preparing to enter system sleep state.*', 4012 'emsg': 'PM: Saving p 3992 'emsg': 'PM: Saving platform NVS memory.*' }, 4013 'PM vns': { 3993 'PM vns': { 4014 'smsg': 'PM: Saving p 3994 'smsg': 'PM: Saving platform NVS memory.*', 4015 'emsg': 'Disabling no 3995 'emsg': 'Disabling non-boot CPUs .*' }, 4016 } 3996 } 4017 3997 4018 t0 = -1.0 3998 t0 = -1.0 4019 cpu_start = -1.0 3999 cpu_start = -1.0 4020 prevktime = -1.0 4000 prevktime = -1.0 4021 actions = dict() 4001 actions = dict() 4022 for line in data.dmesgtext: 4002 for line in data.dmesgtext: 4023 # parse each dmesg line into 4003 # parse each dmesg line into the time and message 4024 m = re.match(r'[ \t]*(\[ *)(? !! 4004 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 4025 if(m): 4005 if(m): 4026 val = m.group('ktime' 4006 val = m.group('ktime') 4027 try: 4007 try: 4028 ktime = float 4008 ktime = float(val) 4029 except: 4009 except: 4030 continue 4010 continue 4031 msg = m.group('msg') 4011 msg = m.group('msg') 4032 # initialize data sta 4012 # initialize data start to first line time 4033 if t0 < 0: 4013 if t0 < 0: 4034 data.setStart 4014 data.setStart(ktime) 4035 t0 = ktime 4015 t0 = ktime 4036 else: 4016 else: 4037 continue 4017 continue 4038 4018 4039 # check for a phase change li 4019 # check for a phase change line 4040 phasechange = False 4020 phasechange = False 4041 for p in dm: 4021 for p in dm: 4042 for s in dm[p]: 4022 for s in dm[p]: 4043 if(re.match(s 4023 if(re.match(s, msg)): 4044 phase 4024 phasechange, phase = True, p 4045 dm[p] 4025 dm[p] = [s] 4046 break 4026 break 4047 4027 4048 # hack for determining resume 4028 # hack for determining resume_machine end for freeze 4049 if(not sysvals.usetraceevents 4029 if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \ 4050 and phase == 'resume_ 4030 and phase == 'resume_machine' and \ 4051 data.initcall_debug_c 4031 data.initcall_debug_call(line, True)): 4052 data.setPhase(phase, 4032 data.setPhase(phase, ktime, False) 4053 phase = 'resume_noirq 4033 phase = 'resume_noirq' 4054 data.setPhase(phase, 4034 data.setPhase(phase, ktime, True) 4055 4035 4056 if phasechange: 4036 if phasechange: 4057 if phase == 'suspend_ 4037 if phase == 'suspend_prepare': 4058 data.setPhase 4038 data.setPhase(phase, ktime, True) 4059 data.setStart 4039 data.setStart(ktime) 4060 data.tKernSus 4040 data.tKernSus = ktime 4061 elif phase == 'suspen 4041 elif phase == 'suspend': 4062 lp = data.las 4042 lp = data.lastPhase() 4063 if lp: 4043 if lp: 4064 data. 4044 data.setPhase(lp, ktime, False) 4065 data.setPhase 4045 data.setPhase(phase, ktime, True) 4066 elif phase == 'suspen 4046 elif phase == 'suspend_late': 4067 lp = data.las 4047 lp = data.lastPhase() 4068 if lp: 4048 if lp: 4069 data. 4049 data.setPhase(lp, ktime, False) 4070 data.setPhase 4050 data.setPhase(phase, ktime, True) 4071 elif phase == 'suspen 4051 elif phase == 'suspend_noirq': 4072 lp = data.las 4052 lp = data.lastPhase() 4073 if lp: 4053 if lp: 4074 data. 4054 data.setPhase(lp, ktime, False) 4075 data.setPhase 4055 data.setPhase(phase, ktime, True) 4076 elif phase == 'suspen 4056 elif phase == 'suspend_machine': 4077 lp = data.las 4057 lp = data.lastPhase() 4078 if lp: 4058 if lp: 4079 data. 4059 data.setPhase(lp, ktime, False) 4080 data.setPhase 4060 data.setPhase(phase, ktime, True) 4081 elif phase == 'resume 4061 elif phase == 'resume_machine': 4082 lp = data.las 4062 lp = data.lastPhase() 4083 if(sysvals.su 4063 if(sysvals.suspendmode in ['freeze', 'standby']): 4084 data. 4064 data.tSuspended = prevktime 4085 if lp 4065 if lp: 4086 4066 data.setPhase(lp, prevktime, False) 4087 else: 4067 else: 4088 data. 4068 data.tSuspended = ktime 4089 if lp 4069 if lp: 4090 4070 data.setPhase(lp, prevktime, False) 4091 data.tResumed 4071 data.tResumed = ktime 4092 data.setPhase 4072 data.setPhase(phase, ktime, True) 4093 elif phase == 'resume 4073 elif phase == 'resume_noirq': 4094 lp = data.las 4074 lp = data.lastPhase() 4095 if lp: 4075 if lp: 4096 data. 4076 data.setPhase(lp, ktime, False) 4097 data.setPhase 4077 data.setPhase(phase, ktime, True) 4098 elif phase == 'resume 4078 elif phase == 'resume_early': 4099 lp = data.las 4079 lp = data.lastPhase() 4100 if lp: 4080 if lp: 4101 data. 4081 data.setPhase(lp, ktime, False) 4102 data.setPhase 4082 data.setPhase(phase, ktime, True) 4103 elif phase == 'resume 4083 elif phase == 'resume': 4104 lp = data.las 4084 lp = data.lastPhase() 4105 if lp: 4085 if lp: 4106 data. 4086 data.setPhase(lp, ktime, False) 4107 data.setPhase 4087 data.setPhase(phase, ktime, True) 4108 elif phase == 'resume 4088 elif phase == 'resume_complete': 4109 lp = data.las 4089 lp = data.lastPhase() 4110 if lp: 4090 if lp: 4111 data. 4091 data.setPhase(lp, ktime, False) 4112 data.setPhase 4092 data.setPhase(phase, ktime, True) 4113 elif phase == 'post_r 4093 elif phase == 'post_resume': 4114 lp = data.las 4094 lp = data.lastPhase() 4115 if lp: 4095 if lp: 4116 data. 4096 data.setPhase(lp, ktime, False) 4117 data.setEnd(k 4097 data.setEnd(ktime) 4118 data.tKernRes 4098 data.tKernRes = ktime 4119 break 4099 break 4120 4100 4121 # -- device callbacks -- 4101 # -- device callbacks -- 4122 if(phase in data.sortedPhases 4102 if(phase in data.sortedPhases()): 4123 # device init call 4103 # device init call 4124 t, f, n, p = data.ini 4104 t, f, n, p = data.initcall_debug_call(line) 4125 if t and f and n and 4105 if t and f and n and p: 4126 data.newActio 4106 data.newAction(phase, f, int(n), p, ktime, -1, '') 4127 else: 4107 else: 4128 # device init 4108 # device init return 4129 t, f, l = dat 4109 t, f, l = data.initcall_debug_return(line) 4130 if t and f an 4110 if t and f and l: 4131 list 4111 list = data.dmesg[phase]['list'] 4132 if(f 4112 if(f in list): 4133 4113 dev = list[f] 4134 4114 dev['length'] = int(l) 4135 4115 dev['end'] = ktime 4136 4116 4137 # if trace events are not ava 4117 # if trace events are not available, these are better than nothing 4138 if(not sysvals.usetraceevents 4118 if(not sysvals.usetraceevents): 4139 # look for known acti 4119 # look for known actions 4140 for a in sorted(at): 4120 for a in sorted(at): 4141 if(re.match(a 4121 if(re.match(at[a]['smsg'], msg)): 4142 if(a 4122 if(a not in actions): 4143 !! 4123 actions[a] = [] >> 4124 actions[a].append({'begin': ktime, 'end': ktime}) 4144 if(re.match(a 4125 if(re.match(at[a]['emsg'], msg)): 4145 if(a !! 4126 if(a in actions): 4146 4127 actions[a][-1]['end'] = ktime 4147 # now look for CPU on 4128 # now look for CPU on/off events 4148 if(re.match(r'Disabli !! 4129 if(re.match('Disabling non-boot CPUs .*', msg)): 4149 # start of fi 4130 # start of first cpu suspend 4150 cpu_start = k 4131 cpu_start = ktime 4151 elif(re.match(r'Enabl !! 4132 elif(re.match('Enabling non-boot CPUs .*', msg)): 4152 # start of fi 4133 # start of first cpu resume 4153 cpu_start = k 4134 cpu_start = ktime 4154 elif(re.match(r'smpbo !! 4135 elif(re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg)): 4155 or re.match(r << 4156 # end of a cp 4136 # end of a cpu suspend, start of the next 4157 m = re.match( !! 4137 m = re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg) 4158 if(not m): << 4159 m = r << 4160 cpu = 'CPU'+m 4138 cpu = 'CPU'+m.group('cpu') 4161 if(cpu not in 4139 if(cpu not in actions): 4162 actio 4140 actions[cpu] = [] 4163 actions[cpu]. 4141 actions[cpu].append({'begin': cpu_start, 'end': ktime}) 4164 cpu_start = k 4142 cpu_start = ktime 4165 elif(re.match(r'CPU(? !! 4143 elif(re.match('CPU(?P<cpu>[0-9]*) is up', msg)): 4166 # end of a cp 4144 # end of a cpu resume, start of the next 4167 m = re.match( !! 4145 m = re.match('CPU(?P<cpu>[0-9]*) is up', msg) 4168 cpu = 'CPU'+m 4146 cpu = 'CPU'+m.group('cpu') 4169 if(cpu not in 4147 if(cpu not in actions): 4170 actio 4148 actions[cpu] = [] 4171 actions[cpu]. 4149 actions[cpu].append({'begin': cpu_start, 'end': ktime}) 4172 cpu_start = k 4150 cpu_start = ktime 4173 prevktime = ktime 4151 prevktime = ktime 4174 data.initDevicegroups() 4152 data.initDevicegroups() 4175 4153 4176 # fill in any missing phases 4154 # fill in any missing phases 4177 phasedef = data.phasedef 4155 phasedef = data.phasedef 4178 terr, lp = '', 'suspend_prepare' 4156 terr, lp = '', 'suspend_prepare' 4179 if lp not in data.dmesg: 4157 if lp not in data.dmesg: 4180 doError('dmesg log format has 4158 doError('dmesg log format has changed, could not find start of suspend') 4181 for p in sorted(phasedef, key=lambda 4159 for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 4182 if p not in data.dmesg: 4160 if p not in data.dmesg: 4183 if not terr: 4161 if not terr: 4184 pprint('TEST 4162 pprint('TEST FAILED: %s failed in %s phase' % (sysvals.suspendmode, lp)) 4185 terr = '%s fa 4163 terr = '%s failed in %s phase' % (sysvals.suspendmode, lp) 4186 if data.tSusp 4164 if data.tSuspended == 0: 4187 data. 4165 data.tSuspended = data.dmesg[lp]['end'] 4188 if data.tResu 4166 if data.tResumed == 0: 4189 data. 4167 data.tResumed = data.dmesg[lp]['end'] 4190 sysvals.vprint('WARNI 4168 sysvals.vprint('WARNING: phase "%s" is missing!' % p) 4191 lp = p 4169 lp = p 4192 lp = data.sortedPhases()[0] 4170 lp = data.sortedPhases()[0] 4193 for p in data.sortedPhases(): 4171 for p in data.sortedPhases(): 4194 if(p != lp and not ('machine' 4172 if(p != lp and not ('machine' in p and 'machine' in lp)): 4195 data.dmesg[lp]['end'] 4173 data.dmesg[lp]['end'] = data.dmesg[p]['start'] 4196 lp = p 4174 lp = p 4197 if data.tSuspended == 0: 4175 if data.tSuspended == 0: 4198 data.tSuspended = data.tKernR 4176 data.tSuspended = data.tKernRes 4199 if data.tResumed == 0: 4177 if data.tResumed == 0: 4200 data.tResumed = data.tSuspend 4178 data.tResumed = data.tSuspended 4201 4179 4202 # fill in any actions we've found 4180 # fill in any actions we've found 4203 for name in sorted(actions): 4181 for name in sorted(actions): 4204 for event in actions[name]: 4182 for event in actions[name]: 4205 data.newActionGlobal( 4183 data.newActionGlobal(name, event['begin'], event['end']) 4206 4184 4207 if(len(sysvals.devicefilter) > 0): 4185 if(len(sysvals.devicefilter) > 0): 4208 data.deviceFilter(sysvals.dev 4186 data.deviceFilter(sysvals.devicefilter) 4209 data.fixupInitcallsThatDidntReturn() 4187 data.fixupInitcallsThatDidntReturn() 4210 return True 4188 return True 4211 4189 4212 def callgraphHTML(sv, hf, num, cg, title, col 4190 def callgraphHTML(sv, hf, num, cg, title, color, devid): 4213 html_func_top = '<article id="{0}" cl 4191 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 4192 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' 4193 html_func_end = '</article>\n' 4216 html_func_leaf = '<article>{0} {1}</a 4194 html_func_leaf = '<article>{0} {1}</article>\n' 4217 4195 4218 cgid = devid 4196 cgid = devid 4219 if cg.id: 4197 if cg.id: 4220 cgid += cg.id 4198 cgid += cg.id 4221 cglen = (cg.end - cg.start) * 1000 4199 cglen = (cg.end - cg.start) * 1000 4222 if cglen < sv.mincglen: 4200 if cglen < sv.mincglen: 4223 return num 4201 return num 4224 4202 4225 fmt = '<r>(%.3f ms @ '+sv.timeformat+' 4203 fmt = '<r>(%.3f ms @ '+sv.timeformat+' to '+sv.timeformat+')</r>' 4226 flen = fmt % (cglen, cg.start, cg.end 4204 flen = fmt % (cglen, cg.start, cg.end) 4227 hf.write(html_func_top.format(cgid, c 4205 hf.write(html_func_top.format(cgid, color, num, title, flen)) 4228 num += 1 4206 num += 1 4229 for line in cg.list: 4207 for line in cg.list: 4230 if(line.length < 0.000000001) 4208 if(line.length < 0.000000001): 4231 flen = '' 4209 flen = '' 4232 else: 4210 else: 4233 fmt = '<n>(%.3f ms @ ' 4211 fmt = '<n>(%.3f ms @ '+sv.timeformat+')</n>' 4234 flen = fmt % (line.le 4212 flen = fmt % (line.length*1000, line.time) 4235 if line.isLeaf(): 4213 if line.isLeaf(): 4236 if line.length * 1000 4214 if line.length * 1000 < sv.mincglen: 4237 continue 4215 continue 4238 hf.write(html_func_le 4216 hf.write(html_func_leaf.format(line.name, flen)) 4239 elif line.freturn: 4217 elif line.freturn: 4240 hf.write(html_func_en 4218 hf.write(html_func_end) 4241 else: 4219 else: 4242 hf.write(html_func_st 4220 hf.write(html_func_start.format(num, line.name, flen)) 4243 num += 1 4221 num += 1 4244 hf.write(html_func_end) 4222 hf.write(html_func_end) 4245 return num 4223 return num 4246 4224 4247 def addCallgraphs(sv, hf, data): 4225 def addCallgraphs(sv, hf, data): 4248 hf.write('<section id="callgraphs" cl 4226 hf.write('<section id="callgraphs" class="callgraph">\n') 4249 # write out the ftrace data converted 4227 # write out the ftrace data converted to html 4250 num = 0 4228 num = 0 4251 for p in data.sortedPhases(): 4229 for p in data.sortedPhases(): 4252 if sv.cgphase and p != sv.cgp 4230 if sv.cgphase and p != sv.cgphase: 4253 continue 4231 continue 4254 list = data.dmesg[p]['list'] 4232 list = data.dmesg[p]['list'] 4255 for d in data.sortedDevices(p 4233 for d in data.sortedDevices(p): 4256 if len(sv.cgfilter) > 4234 if len(sv.cgfilter) > 0 and d not in sv.cgfilter: 4257 continue 4235 continue 4258 dev = list[d] 4236 dev = list[d] 4259 color = 'white' 4237 color = 'white' 4260 if 'color' in data.dm 4238 if 'color' in data.dmesg[p]: 4261 color = data. 4239 color = data.dmesg[p]['color'] 4262 if 'color' in dev: 4240 if 'color' in dev: 4263 color = dev[' 4241 color = dev['color'] 4264 name = d if '[' not i 4242 name = d if '[' not in d else d.split('[')[0] 4265 if(d in sv.devprops): 4243 if(d in sv.devprops): 4266 name = sv.dev 4244 name = sv.devprops[d].altName(d) 4267 if 'drv' in dev and d 4245 if 'drv' in dev and dev['drv']: 4268 name += ' {%s 4246 name += ' {%s}' % dev['drv'] 4269 if sv.suspendmode in 4247 if sv.suspendmode in suspendmodename: 4270 name += ' '+p 4248 name += ' '+p 4271 if('ftrace' in dev): 4249 if('ftrace' in dev): 4272 cg = dev['ftr 4250 cg = dev['ftrace'] 4273 if cg.name == 4251 if cg.name == sv.ftopfunc: 4274 name 4252 name = 'top level suspend/resume call' 4275 num = callgra 4253 num = callgraphHTML(sv, hf, num, cg, 4276 name, 4254 name, color, dev['id']) 4277 if('ftraces' in dev): 4255 if('ftraces' in dev): 4278 for cg in dev 4256 for cg in dev['ftraces']: 4279 num = 4257 num = callgraphHTML(sv, hf, num, cg, 4280 4258 name+' → '+cg.name, color, dev['id']) 4281 hf.write('\n\n </section>\n') 4259 hf.write('\n\n </section>\n') 4282 4260 4283 def summaryCSS(title, center=True): 4261 def summaryCSS(title, center=True): 4284 tdcenter = 'text-align:center;' if ce 4262 tdcenter = 'text-align:center;' if center else '' 4285 out = '<!DOCTYPE html>\n<html>\n<head 4263 out = '<!DOCTYPE html>\n<html>\n<head>\n\ 4286 <meta http-equiv="content-type" conte 4264 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 4287 <title>'+title+'</title>\n\ 4265 <title>'+title+'</title>\n\ 4288 <style type=\'text/css\'>\n\ 4266 <style type=\'text/css\'>\n\ 4289 .stamp {width: 100%;text-alig 4267 .stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\ 4290 table {width:100%;border-coll 4268 table {width:100%;border-collapse: collapse;border:1px solid;}\n\ 4291 th {border: 1px solid black;b 4269 th {border: 1px solid black;background:#222;color:white;}\n\ 4292 td {font: 14px "Times New Rom 4270 td {font: 14px "Times New Roman";'+tdcenter+'}\n\ 4293 tr.head td {border: 1px solid 4271 tr.head td {border: 1px solid black;background:#aaa;}\n\ 4294 tr.alt {background-color:#ddd 4272 tr.alt {background-color:#ddd;}\n\ 4295 tr.notice {color:red;}\n\ 4273 tr.notice {color:red;}\n\ 4296 .minval {background-color:#BB 4274 .minval {background-color:#BBFFBB;}\n\ 4297 .medval {background-color:#BB 4275 .medval {background-color:#BBBBFF;}\n\ 4298 .maxval {background-color:#FF 4276 .maxval {background-color:#FFBBBB;}\n\ 4299 .head a {color:#000;text-deco 4277 .head a {color:#000;text-decoration: none;}\n\ 4300 </style>\n</head>\n<body>\n' 4278 </style>\n</head>\n<body>\n' 4301 return out 4279 return out 4302 4280 4303 # Function: createHTMLSummarySimple 4281 # Function: createHTMLSummarySimple 4304 # Description: 4282 # Description: 4305 # Create summary html file for a serie 4283 # Create summary html file for a series of tests 4306 # Arguments: 4284 # Arguments: 4307 # testruns: array of Data objects from 4285 # testruns: array of Data objects from parseTraceLog 4308 def createHTMLSummarySimple(testruns, htmlfil 4286 def createHTMLSummarySimple(testruns, htmlfile, title): 4309 # write the html header first (html h 4287 # write the html header first (html head, css code, up to body start) 4310 html = summaryCSS('Summary - SleepGra 4288 html = summaryCSS('Summary - SleepGraph') 4311 4289 4312 # extract the test data into list 4290 # extract the test data into list 4313 list = dict() 4291 list = dict() 4314 tAvg, tMin, tMax, tMed = [0.0, 0.0], 4292 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 4293 iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 4316 num = 0 4294 num = 0 4317 useturbo = usewifi = False 4295 useturbo = usewifi = False 4318 lastmode = '' 4296 lastmode = '' 4319 cnt = dict() 4297 cnt = dict() 4320 for data in sorted(testruns, key=lamb 4298 for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])): 4321 mode = data['mode'] 4299 mode = data['mode'] 4322 if mode not in list: 4300 if mode not in list: 4323 list[mode] = {'data': 4301 list[mode] = {'data': [], 'avg': [0,0], 'min': [0,0], 'max': [0,0], 'med': [0,0]} 4324 if lastmode and lastmode != m 4302 if lastmode and lastmode != mode and num > 0: 4325 for i in range(2): 4303 for i in range(2): 4326 s = sorted(tM 4304 s = sorted(tMed[i]) 4327 list[lastmode 4305 list[lastmode]['med'][i] = s[int(len(s)//2)] 4328 iMed[i] = tMe 4306 iMed[i] = tMed[i][list[lastmode]['med'][i]] 4329 list[lastmode]['avg'] 4307 list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 4330 list[lastmode]['min'] 4308 list[lastmode]['min'] = tMin 4331 list[lastmode]['max'] 4309 list[lastmode]['max'] = tMax 4332 list[lastmode]['idx'] 4310 list[lastmode]['idx'] = (iMin, iMed, iMax) 4333 tAvg, tMin, tMax, tMe 4311 tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 4334 iMin, iMed, iMax = [0 4312 iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 4335 num = 0 4313 num = 0 4336 pkgpc10 = syslpi = wifi = '' 4314 pkgpc10 = syslpi = wifi = '' 4337 if 'pkgpc10' in data and 'sys 4315 if 'pkgpc10' in data and 'syslpi' in data: 4338 pkgpc10, syslpi, uset 4316 pkgpc10, syslpi, useturbo = data['pkgpc10'], data['syslpi'], True 4339 if 'wifi' in data: 4317 if 'wifi' in data: 4340 wifi, usewifi = data[ 4318 wifi, usewifi = data['wifi'], True 4341 res = data['result'] 4319 res = data['result'] 4342 tVal = [float(data['suspend'] 4320 tVal = [float(data['suspend']), float(data['resume'])] 4343 list[mode]['data'].append([da 4321 list[mode]['data'].append([data['host'], data['kernel'], 4344 data['time'], tVal[0] 4322 data['time'], tVal[0], tVal[1], data['url'], res, 4345 data['issues'], data[ 4323 data['issues'], data['sus_worst'], data['sus_worsttime'], 4346 data['res_worst'], da !! 4324 data['res_worst'], data['res_worsttime'], pkgpc10, syslpi, wifi]) 4347 (data['fullmode'] if << 4348 idx = len(list[mode]['data']) 4325 idx = len(list[mode]['data']) - 1 4349 if res.startswith('fail in'): 4326 if res.startswith('fail in'): 4350 res = 'fail' 4327 res = 'fail' 4351 if res not in cnt: 4328 if res not in cnt: 4352 cnt[res] = 1 4329 cnt[res] = 1 4353 else: 4330 else: 4354 cnt[res] += 1 4331 cnt[res] += 1 4355 if res == 'pass': 4332 if res == 'pass': 4356 for i in range(2): 4333 for i in range(2): 4357 tMed[i][tVal[ 4334 tMed[i][tVal[i]] = idx 4358 tAvg[i] += tV 4335 tAvg[i] += tVal[i] 4359 if tMin[i] == 4336 if tMin[i] == 0 or tVal[i] < tMin[i]: 4360 iMin[ 4337 iMin[i] = idx 4361 tMin[ 4338 tMin[i] = tVal[i] 4362 if tMax[i] == 4339 if tMax[i] == 0 or tVal[i] > tMax[i]: 4363 iMax[ 4340 iMax[i] = idx 4364 tMax[ 4341 tMax[i] = tVal[i] 4365 num += 1 4342 num += 1 4366 lastmode = mode 4343 lastmode = mode 4367 if lastmode and num > 0: 4344 if lastmode and num > 0: 4368 for i in range(2): 4345 for i in range(2): 4369 s = sorted(tMed[i]) 4346 s = sorted(tMed[i]) 4370 list[lastmode]['med'] 4347 list[lastmode]['med'][i] = s[int(len(s)//2)] 4371 iMed[i] = tMed[i][lis 4348 iMed[i] = tMed[i][list[lastmode]['med'][i]] 4372 list[lastmode]['avg'] = [tAvg 4349 list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 4373 list[lastmode]['min'] = tMin 4350 list[lastmode]['min'] = tMin 4374 list[lastmode]['max'] = tMax 4351 list[lastmode]['max'] = tMax 4375 list[lastmode]['idx'] = (iMin 4352 list[lastmode]['idx'] = (iMin, iMed, iMax) 4376 4353 4377 # group test header 4354 # group test header 4378 desc = [] 4355 desc = [] 4379 for ilk in sorted(cnt, reverse=True): 4356 for ilk in sorted(cnt, reverse=True): 4380 if cnt[ilk] > 0: 4357 if cnt[ilk] > 0: 4381 desc.append('%d %s' % 4358 desc.append('%d %s' % (cnt[ilk], ilk)) 4382 html += '<div class="stamp">%s (%d te 4359 html += '<div class="stamp">%s (%d tests: %s)</div>\n' % (title, len(testruns), ', '.join(desc)) 4383 th = '\t<th>{0}</th>\n' 4360 th = '\t<th>{0}</th>\n' 4384 td = '\t<td>{0}</td>\n' 4361 td = '\t<td>{0}</td>\n' 4385 tdh = '\t<td{1}>{0}</td>\n' 4362 tdh = '\t<td{1}>{0}</td>\n' 4386 tdlink = '\t<td><a href="{0}">html</a 4363 tdlink = '\t<td><a href="{0}">html</a></td>\n' 4387 cols = 12 4364 cols = 12 4388 if useturbo: 4365 if useturbo: 4389 cols += 2 4366 cols += 2 4390 if usewifi: 4367 if usewifi: 4391 cols += 1 4368 cols += 1 4392 colspan = '%d' % cols 4369 colspan = '%d' % cols 4393 4370 4394 # table header 4371 # table header 4395 html += '<table>\n<tr>\n' + th.format 4372 html += '<table>\n<tr>\n' + th.format('#') +\ 4396 th.format('Mode') + th.format 4373 th.format('Mode') + th.format('Host') + th.format('Kernel') +\ 4397 th.format('Test Time') + th.f 4374 th.format('Test Time') + th.format('Result') + th.format('Issues') +\ 4398 th.format('Suspend') + th.for 4375 th.format('Suspend') + th.format('Resume') +\ 4399 th.format('Worst Suspend Devi 4376 th.format('Worst Suspend Device') + th.format('SD Time') +\ 4400 th.format('Worst Resume Devic 4377 th.format('Worst Resume Device') + th.format('RD Time') 4401 if useturbo: 4378 if useturbo: 4402 html += th.format('PkgPC10') 4379 html += th.format('PkgPC10') + th.format('SysLPI') 4403 if usewifi: 4380 if usewifi: 4404 html += th.format('Wifi') 4381 html += th.format('Wifi') 4405 html += th.format('Detail')+'</tr>\n' 4382 html += th.format('Detail')+'</tr>\n' 4406 # export list into html 4383 # export list into html 4407 head = '<tr class="head"><td>{0}</td> 4384 head = '<tr class="head"><td>{0}</td><td>{1}</td>'+\ 4408 '<td colspan='+colspan+' clas 4385 '<td colspan='+colspan+' class="sus">Suspend Avg={2} '+\ 4409 '<span class=minval><a href=" 4386 '<span class=minval><a href="#s{10}min">Min={3}</a></span> '+\ 4410 '<span class=medval><a href=" 4387 '<span class=medval><a href="#s{10}med">Med={4}</a></span> '+\ 4411 '<span class=maxval><a href=" 4388 '<span class=maxval><a href="#s{10}max">Max={5}</a></span> '+\ 4412 'Resume Avg={6} '+\ 4389 'Resume Avg={6} '+\ 4413 '<span class=minval><a href=" 4390 '<span class=minval><a href="#r{10}min">Min={7}</a></span> '+\ 4414 '<span class=medval><a href=" 4391 '<span class=medval><a href="#r{10}med">Med={8}</a></span> '+\ 4415 '<span class=maxval><a href=" 4392 '<span class=maxval><a href="#r{10}max">Max={9}</a></span></td>'+\ 4416 '</tr>\n' 4393 '</tr>\n' 4417 headnone = '<tr class="head"><td>{0}< 4394 headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan='+\ 4418 colspan+'></td></tr>\n' 4395 colspan+'></td></tr>\n' 4419 for mode in sorted(list): 4396 for mode in sorted(list): 4420 # header line for each suspen 4397 # header line for each suspend mode 4421 num = 0 4398 num = 0 4422 tAvg, tMin, tMax, tMed = list 4399 tAvg, tMin, tMax, tMed = list[mode]['avg'], list[mode]['min'],\ 4423 list[mode]['max'], li 4400 list[mode]['max'], list[mode]['med'] 4424 count = len(list[mode]['data' 4401 count = len(list[mode]['data']) 4425 if 'idx' in list[mode]: 4402 if 'idx' in list[mode]: 4426 iMin, iMed, iMax = li 4403 iMin, iMed, iMax = list[mode]['idx'] 4427 html += head.format(' 4404 html += head.format('%d' % count, mode.upper(), 4428 '%.3f' % tAvg 4405 '%.3f' % tAvg[0], '%.3f' % tMin[0], '%.3f' % tMed[0], '%.3f' % tMax[0], 4429 '%.3f' % tAvg 4406 '%.3f' % tAvg[1], '%.3f' % tMin[1], '%.3f' % tMed[1], '%.3f' % tMax[1], 4430 mode.lower() 4407 mode.lower() 4431 ) 4408 ) 4432 else: 4409 else: 4433 iMin = iMed = iMax = 4410 iMin = iMed = iMax = [-1, -1, -1] 4434 html += headnone.form 4411 html += headnone.format('%d' % count, mode.upper()) 4435 for d in list[mode]['data']: 4412 for d in list[mode]['data']: 4436 # row classes - alter 4413 # row classes - alternate row color 4437 rcls = ['alt'] if num 4414 rcls = ['alt'] if num % 2 == 1 else [] 4438 if d[6] != 'pass': 4415 if d[6] != 'pass': 4439 rcls.append(' 4416 rcls.append('notice') 4440 html += '<tr class="' 4417 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4441 # figure out if the l 4418 # figure out if the line has sus or res highlighted 4442 idx = list[mode]['dat 4419 idx = list[mode]['data'].index(d) 4443 tHigh = ['', ''] 4420 tHigh = ['', ''] 4444 for i in range(2): 4421 for i in range(2): 4445 tag = 's%s' % 4422 tag = 's%s' % mode if i == 0 else 'r%s' % mode 4446 if idx == iMi 4423 if idx == iMin[i]: 4447 tHigh 4424 tHigh[i] = ' id="%smin" class=minval title="Minimum"' % tag 4448 elif idx == i 4425 elif idx == iMax[i]: 4449 tHigh 4426 tHigh[i] = ' id="%smax" class=maxval title="Maximum"' % tag 4450 elif idx == i 4427 elif idx == iMed[i]: 4451 tHigh 4428 tHigh[i] = ' id="%smed" class=medval title="Median"' % tag 4452 html += td.format("%d 4429 html += td.format("%d" % (list[mode]['data'].index(d) + 1)) # row 4453 html += td.format(d[1 !! 4430 html += td.format(mode) # mode 4454 html += td.format(d[0 4431 html += td.format(d[0]) # host 4455 html += td.format(d[1 4432 html += td.format(d[1]) # kernel 4456 html += td.format(d[2 4433 html += td.format(d[2]) # time 4457 html += td.format(d[6 4434 html += td.format(d[6]) # result 4458 html += td.format(d[7 4435 html += td.format(d[7]) # issues 4459 html += tdh.format('% 4436 html += tdh.format('%.3f ms' % d[3], tHigh[0]) if d[3] else td.format('') # suspend 4460 html += tdh.format('% 4437 html += tdh.format('%.3f ms' % d[4], tHigh[1]) if d[4] else td.format('') # resume 4461 html += td.format(d[8 4438 html += td.format(d[8]) # sus_worst 4462 html += td.format('%. 4439 html += td.format('%.3f ms' % d[9]) if d[9] else td.format('') # sus_worst time 4463 html += td.format(d[1 4440 html += td.format(d[10]) # res_worst 4464 html += td.format('%. 4441 html += td.format('%.3f ms' % d[11]) if d[11] else td.format('') # res_worst time 4465 if useturbo: 4442 if useturbo: 4466 html += td.fo 4443 html += td.format(d[12]) # pkg_pc10 4467 html += td.fo 4444 html += td.format(d[13]) # syslpi 4468 if usewifi: 4445 if usewifi: 4469 html += td.fo 4446 html += td.format(d[14]) # wifi 4470 html += tdlink.format 4447 html += tdlink.format(d[5]) if d[5] else td.format('') # url 4471 html += '</tr>\n' 4448 html += '</tr>\n' 4472 num += 1 4449 num += 1 4473 4450 4474 # flush the data to file 4451 # flush the data to file 4475 hf = open(htmlfile, 'w') 4452 hf = open(htmlfile, 'w') 4476 hf.write(html+'</table>\n</body>\n</h 4453 hf.write(html+'</table>\n</body>\n</html>\n') 4477 hf.close() 4454 hf.close() 4478 4455 4479 def createHTMLDeviceSummary(testruns, htmlfil 4456 def createHTMLDeviceSummary(testruns, htmlfile, title): 4480 html = summaryCSS('Device Summary - S 4457 html = summaryCSS('Device Summary - SleepGraph', False) 4481 4458 4482 # create global device list from all 4459 # create global device list from all tests 4483 devall = dict() 4460 devall = dict() 4484 for data in testruns: 4461 for data in testruns: 4485 host, url, devlist = data['ho 4462 host, url, devlist = data['host'], data['url'], data['devlist'] 4486 for type in devlist: 4463 for type in devlist: 4487 if type not in devall 4464 if type not in devall: 4488 devall[type] 4465 devall[type] = dict() 4489 mdevlist, devlist = d 4466 mdevlist, devlist = devall[type], data['devlist'][type] 4490 for name in devlist: 4467 for name in devlist: 4491 length = devl 4468 length = devlist[name] 4492 if name not i 4469 if name not in mdevlist: 4493 mdevl 4470 mdevlist[name] = {'name': name, 'host': host, 4494 4471 'worst': length, 'total': length, 'count': 1, 4495 4472 'url': url} 4496 else: 4473 else: 4497 if le 4474 if length > mdevlist[name]['worst']: 4498 4475 mdevlist[name]['worst'] = length 4499 4476 mdevlist[name]['url'] = url 4500 4477 mdevlist[name]['host'] = host 4501 mdevl 4478 mdevlist[name]['total'] += length 4502 mdevl 4479 mdevlist[name]['count'] += 1 4503 4480 4504 # generate the html 4481 # generate the html 4505 th = '\t<th>{0}</th>\n' 4482 th = '\t<th>{0}</th>\n' 4506 td = '\t<td align=center>{0}</td>\n' 4483 td = '\t<td align=center>{0}</td>\n' 4507 tdr = '\t<td align=right>{0}</td>\n' 4484 tdr = '\t<td align=right>{0}</td>\n' 4508 tdlink = '\t<td align=center><a href= 4485 tdlink = '\t<td align=center><a href="{0}">html</a></td>\n' 4509 limit = 1 4486 limit = 1 4510 for type in sorted(devall, reverse=Tr 4487 for type in sorted(devall, reverse=True): 4511 num = 0 4488 num = 0 4512 devlist = devall[type] 4489 devlist = devall[type] 4513 # table header 4490 # table header 4514 html += '<div class="stamp">% 4491 html += '<div class="stamp">%s (%s devices > %d ms)</div><table>\n' % \ 4515 (title, type.upper(), 4492 (title, type.upper(), limit) 4516 html += '<tr>\n' + '<th align 4493 html += '<tr>\n' + '<th align=right>Device Name</th>' +\ 4517 th.format('Average Ti 4494 th.format('Average Time') + th.format('Count') +\ 4518 th.format('Worst Time 4495 th.format('Worst Time') + th.format('Host (worst time)') +\ 4519 th.format('Link (wors 4496 th.format('Link (worst time)') + '</tr>\n' 4520 for name in sorted(devlist, k 4497 for name in sorted(devlist, key=lambda k:(devlist[k]['worst'], \ 4521 devlist[k]['total'], 4498 devlist[k]['total'], devlist[k]['name']), reverse=True): 4522 data = devall[type][n 4499 data = devall[type][name] 4523 data['average'] = dat 4500 data['average'] = data['total'] / data['count'] 4524 if data['average'] < 4501 if data['average'] < limit: 4525 continue 4502 continue 4526 # row classes - alter 4503 # row classes - alternate row color 4527 rcls = ['alt'] if num 4504 rcls = ['alt'] if num % 2 == 1 else [] 4528 html += '<tr class="' 4505 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4529 html += tdr.format(da 4506 html += tdr.format(data['name']) # name 4530 html += td.format('%. 4507 html += td.format('%.3f ms' % data['average']) # average 4531 html += td.format(dat 4508 html += td.format(data['count']) # count 4532 html += td.format('%. 4509 html += td.format('%.3f ms' % data['worst']) # worst 4533 html += td.format(dat 4510 html += td.format(data['host']) # host 4534 html += tdlink.format 4511 html += tdlink.format(data['url']) # url 4535 html += '</tr>\n' 4512 html += '</tr>\n' 4536 num += 1 4513 num += 1 4537 html += '</table>\n' 4514 html += '</table>\n' 4538 4515 4539 # flush the data to file 4516 # flush the data to file 4540 hf = open(htmlfile, 'w') 4517 hf = open(htmlfile, 'w') 4541 hf.write(html+'</body>\n</html>\n') 4518 hf.write(html+'</body>\n</html>\n') 4542 hf.close() 4519 hf.close() 4543 return devall 4520 return devall 4544 4521 4545 def createHTMLIssuesSummary(testruns, issues, 4522 def createHTMLIssuesSummary(testruns, issues, htmlfile, title, extra=''): 4546 multihost = len([e for e in issues if 4523 multihost = len([e for e in issues if len(e['urls']) > 1]) > 0 4547 html = summaryCSS('Issues Summary - S 4524 html = summaryCSS('Issues Summary - SleepGraph', False) 4548 total = len(testruns) 4525 total = len(testruns) 4549 4526 4550 # generate the html 4527 # generate the html 4551 th = '\t<th>{0}</th>\n' 4528 th = '\t<th>{0}</th>\n' 4552 td = '\t<td align={0}>{1}</td>\n' 4529 td = '\t<td align={0}>{1}</td>\n' 4553 tdlink = '<a href="{1}">{0}</a>' 4530 tdlink = '<a href="{1}">{0}</a>' 4554 subtitle = '%d issues' % len(issues) 4531 subtitle = '%d issues' % len(issues) if len(issues) > 0 else 'no issues' 4555 html += '<div class="stamp">%s (%s)</ 4532 html += '<div class="stamp">%s (%s)</div><table>\n' % (title, subtitle) 4556 html += '<tr>\n' + th.format('Issue') 4533 html += '<tr>\n' + th.format('Issue') + th.format('Count') 4557 if multihost: 4534 if multihost: 4558 html += th.format('Hosts') 4535 html += th.format('Hosts') 4559 html += th.format('Tests') + th.forma 4536 html += th.format('Tests') + th.format('Fail Rate') +\ 4560 th.format('First Instance') + 4537 th.format('First Instance') + '</tr>\n' 4561 4538 4562 num = 0 4539 num = 0 4563 for e in sorted(issues, key=lambda v: 4540 for e in sorted(issues, key=lambda v:v['count'], reverse=True): 4564 testtotal = 0 4541 testtotal = 0 4565 links = [] 4542 links = [] 4566 for host in sorted(e['urls']) 4543 for host in sorted(e['urls']): 4567 links.append(tdlink.f 4544 links.append(tdlink.format(host, e['urls'][host][0])) 4568 testtotal += len(e['u 4545 testtotal += len(e['urls'][host]) 4569 rate = '%d/%d (%.2f%%)' % (te 4546 rate = '%d/%d (%.2f%%)' % (testtotal, total, 100*float(testtotal)/float(total)) 4570 # row classes - alternate row 4547 # row classes - alternate row color 4571 rcls = ['alt'] if num % 2 == 4548 rcls = ['alt'] if num % 2 == 1 else [] 4572 html += '<tr class="'+(' '.jo 4549 html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 4573 html += td.format('left', e[' 4550 html += td.format('left', e['line']) # issue 4574 html += td.format('center', e 4551 html += td.format('center', e['count']) # count 4575 if multihost: 4552 if multihost: 4576 html += td.format('ce 4553 html += td.format('center', len(e['urls'])) # hosts 4577 html += td.format('center', t 4554 html += td.format('center', testtotal) # test count 4578 html += td.format('center', r 4555 html += td.format('center', rate) # test rate 4579 html += td.format('center now 4556 html += td.format('center nowrap', '<br>'.join(links)) # links 4580 html += '</tr>\n' 4557 html += '</tr>\n' 4581 num += 1 4558 num += 1 4582 4559 4583 # flush the data to file 4560 # flush the data to file 4584 hf = open(htmlfile, 'w') 4561 hf = open(htmlfile, 'w') 4585 hf.write(html+'</table>\n'+extra+'</b 4562 hf.write(html+'</table>\n'+extra+'</body>\n</html>\n') 4586 hf.close() 4563 hf.close() 4587 return issues 4564 return issues 4588 4565 4589 def ordinal(value): 4566 def ordinal(value): 4590 suffix = 'th' 4567 suffix = 'th' 4591 if value < 10 or value > 19: 4568 if value < 10 or value > 19: 4592 if value % 10 == 1: 4569 if value % 10 == 1: 4593 suffix = 'st' 4570 suffix = 'st' 4594 elif value % 10 == 2: 4571 elif value % 10 == 2: 4595 suffix = 'nd' 4572 suffix = 'nd' 4596 elif value % 10 == 3: 4573 elif value % 10 == 3: 4597 suffix = 'rd' 4574 suffix = 'rd' 4598 return '%d%s' % (value, suffix) 4575 return '%d%s' % (value, suffix) 4599 4576 4600 # Function: createHTML 4577 # Function: createHTML 4601 # Description: 4578 # Description: 4602 # Create the output html file from the 4579 # Create the output html file from the resident test data 4603 # Arguments: 4580 # Arguments: 4604 # testruns: array of Data objects from 4581 # testruns: array of Data objects from parseKernelLog or parseTraceLog 4605 # Output: 4582 # Output: 4606 # True if the html file was created, f 4583 # True if the html file was created, false if it failed 4607 def createHTML(testruns, testfail): 4584 def createHTML(testruns, testfail): 4608 if len(testruns) < 1: 4585 if len(testruns) < 1: 4609 pprint('ERROR: Not enough tes 4586 pprint('ERROR: Not enough test data to build a timeline') 4610 return 4587 return 4611 4588 4612 kerror = False 4589 kerror = False 4613 for data in testruns: 4590 for data in testruns: 4614 if data.kerror: 4591 if data.kerror: 4615 kerror = True 4592 kerror = True 4616 if(sysvals.suspendmode in ['f 4593 if(sysvals.suspendmode in ['freeze', 'standby']): 4617 data.trimFreezeTime(t 4594 data.trimFreezeTime(testruns[-1].tSuspended) 4618 else: 4595 else: 4619 data.getMemTime() 4596 data.getMemTime() 4620 4597 4621 # html function templates 4598 # html function templates 4622 html_error = '<div id="{1}" title="ke 4599 html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">{2}→</div>\n' 4623 html_traceevent = '<div title="{0}" c 4600 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 4601 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 4602 html_timetotal = '<table class="time1">\n<tr>'\ 4626 '<td class="green" title="{3} 4603 '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ 4627 '<td class="yellow" title="{4 4604 '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ 4628 '</tr>\n</table>\n' 4605 '</tr>\n</table>\n' 4629 html_timetotal2 = '<table class="time 4606 html_timetotal2 = '<table class="time1">\n<tr>'\ 4630 '<td class="green" title="{4} 4607 '<td class="green" title="{4}">{3} Suspend Time: <b>{0} ms</b></td>'\ 4631 '<td class="gray" title="time 4608 '<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 4609 '<td class="yellow" title="{5}">{3} Resume Time: <b>{2} ms</b></td>'\ 4633 '</tr>\n</table>\n' 4610 '</tr>\n</table>\n' 4634 html_timetotal3 = '<table class="time 4611 html_timetotal3 = '<table class="time1">\n<tr>'\ 4635 '<td class="green">Execution 4612 '<td class="green">Execution Time: <b>{0} ms</b></td>'\ 4636 '<td class="yellow">Command: 4613 '<td class="yellow">Command: <b>{1}</b></td>'\ 4637 '</tr>\n</table>\n' 4614 '</tr>\n</table>\n' 4638 html_fail = '<table class="testfail"> 4615 html_fail = '<table class="testfail"><tr><td>{0}</td></tr></table>\n' 4639 html_kdesc = '<td class="{3}" title=" 4616 html_kdesc = '<td class="{3}" title="time spent in kernel execution">{0}Kernel {2}: {1} ms</td>' 4640 html_fwdesc = '<td class="{3}" title= 4617 html_fwdesc = '<td class="{3}" title="time spent in firmware">{0}Firmware {2}: {1} ms</td>' 4641 html_wifdesc = '<td class="yellow" ti 4618 html_wifdesc = '<td class="yellow" title="time for wifi to reconnect after resume complete ({2})">{0}Wifi Resume: {1}</td>' 4642 4619 4643 # html format variables 4620 # html format variables 4644 scaleH = 20 4621 scaleH = 20 4645 if kerror: 4622 if kerror: 4646 scaleH = 40 4623 scaleH = 40 4647 4624 4648 # device timeline 4625 # device timeline 4649 devtl = Timeline(30, scaleH) 4626 devtl = Timeline(30, scaleH) 4650 4627 4651 # write the test title and general in 4628 # write the test title and general info header 4652 devtl.createHeader(sysvals, testruns[ 4629 devtl.createHeader(sysvals, testruns[0].stamp) 4653 4630 4654 # Generate the header for this timeli 4631 # Generate the header for this timeline 4655 for data in testruns: 4632 for data in testruns: 4656 tTotal = data.end - data.star 4633 tTotal = data.end - data.start 4657 if(tTotal == 0): 4634 if(tTotal == 0): 4658 doError('No timeline 4635 doError('No timeline data') 4659 if sysvals.suspendmode == 'co 4636 if sysvals.suspendmode == 'command': 4660 run_time = '%.0f' % ( 4637 run_time = '%.0f' % (tTotal * 1000) 4661 if sysvals.testcomman 4638 if sysvals.testcommand: 4662 testdesc = sy 4639 testdesc = sysvals.testcommand 4663 else: 4640 else: 4664 testdesc = 'u 4641 testdesc = 'unknown' 4665 if(len(testruns) > 1) 4642 if(len(testruns) > 1): 4666 testdesc = or 4643 testdesc = ordinal(data.testnumber+1)+' '+testdesc 4667 thtml = html_timetota 4644 thtml = html_timetotal3.format(run_time, testdesc) 4668 devtl.html += thtml 4645 devtl.html += thtml 4669 continue 4646 continue 4670 # typical full suspend/resume 4647 # typical full suspend/resume header 4671 stot, rtot = sktime, rktime = 4648 stot, rtot = sktime, rktime = data.getTimeValues() 4672 ssrc, rsrc, testdesc, testdes 4649 ssrc, rsrc, testdesc, testdesc2 = ['kernel'], ['kernel'], 'Kernel', '' 4673 if data.fwValid: 4650 if data.fwValid: 4674 stot += (data.fwSuspe 4651 stot += (data.fwSuspend/1000000.0) 4675 rtot += (data.fwResum 4652 rtot += (data.fwResume/1000000.0) 4676 ssrc.append('firmware 4653 ssrc.append('firmware') 4677 rsrc.append('firmware 4654 rsrc.append('firmware') 4678 testdesc = 'Total' 4655 testdesc = 'Total' 4679 if 'time' in data.wifi and da 4656 if 'time' in data.wifi and data.wifi['stat'] != 'timeout': 4680 rtot += data.end - da 4657 rtot += data.end - data.tKernRes + (data.wifi['time'] * 1000.0) 4681 rsrc.append('wifi') 4658 rsrc.append('wifi') 4682 testdesc = 'Total' 4659 testdesc = 'Total' 4683 suspend_time, resume_time = ' 4660 suspend_time, resume_time = '%.3f' % stot, '%.3f' % rtot 4684 stitle = 'time from kernel su 4661 stitle = 'time from kernel suspend start to %s mode [%s time]' % \ 4685 (sysvals.suspendmode, 4662 (sysvals.suspendmode, ' & '.join(ssrc)) 4686 rtitle = 'time from %s mode t 4663 rtitle = 'time from %s mode to kernel resume complete [%s time]' % \ 4687 (sysvals.suspendmode, 4664 (sysvals.suspendmode, ' & '.join(rsrc)) 4688 if(len(testruns) > 1): 4665 if(len(testruns) > 1): 4689 testdesc = testdesc2 4666 testdesc = testdesc2 = ordinal(data.testnumber+1) 4690 testdesc2 += ' ' 4667 testdesc2 += ' ' 4691 if(len(data.tLow) == 0): 4668 if(len(data.tLow) == 0): 4692 thtml = html_timetota 4669 thtml = html_timetotal.format(suspend_time, \ 4693 resume_time, 4670 resume_time, testdesc, stitle, rtitle) 4694 else: 4671 else: 4695 low_time = '+'.join(d 4672 low_time = '+'.join(data.tLow) 4696 thtml = html_timetota 4673 thtml = html_timetotal2.format(suspend_time, low_time, \ 4697 resume_time, 4674 resume_time, testdesc, stitle, rtitle) 4698 devtl.html += thtml 4675 devtl.html += thtml 4699 if not data.fwValid and 'dev' 4676 if not data.fwValid and 'dev' not in data.wifi: 4700 continue 4677 continue 4701 # extra detail when the times 4678 # extra detail when the times come from multiple sources 4702 thtml = '<table class="time2" 4679 thtml = '<table class="time2">\n<tr>' 4703 thtml += html_kdesc.format(te 4680 thtml += html_kdesc.format(testdesc2, '%.3f'%sktime, 'Suspend', 'green') 4704 if data.fwValid: 4681 if data.fwValid: 4705 sftime = '%.3f'%(data 4682 sftime = '%.3f'%(data.fwSuspend / 1000000.0) 4706 rftime = '%.3f'%(data 4683 rftime = '%.3f'%(data.fwResume / 1000000.0) 4707 thtml += html_fwdesc. 4684 thtml += html_fwdesc.format(testdesc2, sftime, 'Suspend', 'green') 4708 thtml += html_fwdesc. 4685 thtml += html_fwdesc.format(testdesc2, rftime, 'Resume', 'yellow') 4709 thtml += html_kdesc.format(te 4686 thtml += html_kdesc.format(testdesc2, '%.3f'%rktime, 'Resume', 'yellow') 4710 if 'time' in data.wifi: 4687 if 'time' in data.wifi: 4711 if data.wifi['stat'] 4688 if data.wifi['stat'] != 'timeout': 4712 wtime = '%.0f 4689 wtime = '%.0f ms'%(data.end - data.tKernRes + (data.wifi['time'] * 1000.0)) 4713 else: 4690 else: 4714 wtime = 'TIME 4691 wtime = 'TIMEOUT' 4715 thtml += html_wifdesc 4692 thtml += html_wifdesc.format(testdesc2, wtime, data.wifi['dev']) 4716 thtml += '</tr>\n</table>\n' 4693 thtml += '</tr>\n</table>\n' 4717 devtl.html += thtml 4694 devtl.html += thtml 4718 if testfail: 4695 if testfail: 4719 devtl.html += html_fail.forma 4696 devtl.html += html_fail.format(testfail) 4720 4697 4721 # time scale for potentially multiple 4698 # time scale for potentially multiple datasets 4722 t0 = testruns[0].start 4699 t0 = testruns[0].start 4723 tMax = testruns[-1].end 4700 tMax = testruns[-1].end 4724 tTotal = tMax - t0 4701 tTotal = tMax - t0 4725 4702 4726 # determine the maximum number of row 4703 # determine the maximum number of rows we need to draw 4727 fulllist = [] 4704 fulllist = [] 4728 threadlist = [] 4705 threadlist = [] 4729 pscnt = 0 4706 pscnt = 0 4730 devcnt = 0 4707 devcnt = 0 4731 for data in testruns: 4708 for data in testruns: 4732 data.selectTimelineDevices('% 4709 data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen) 4733 for group in data.devicegroup 4710 for group in data.devicegroups: 4734 devlist = [] 4711 devlist = [] 4735 for phase in group: 4712 for phase in group: 4736 for devname i 4713 for devname in sorted(data.tdevlist[phase]): 4737 d = D 4714 d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname]) 4738 devli 4715 devlist.append(d) 4739 if d. 4716 if d.isa('kth'): 4740 4717 threadlist.append(d) 4741 else: 4718 else: 4742 4719 if d.isa('ps'): 4743 4720 pscnt += 1 4744 4721 else: 4745 4722 devcnt += 1 4746 4723 fulllist.append(d) 4747 if sysvals.mixedphase 4724 if sysvals.mixedphaseheight: 4748 devtl.getPhas 4725 devtl.getPhaseRows(devlist) 4749 if not sysvals.mixedphaseheight: 4726 if not sysvals.mixedphaseheight: 4750 if len(threadlist) > 0 and le 4727 if len(threadlist) > 0 and len(fulllist) > 0: 4751 if pscnt > 0 and devc 4728 if pscnt > 0 and devcnt > 0: 4752 msg = 'user p 4729 msg = 'user processes & device pm callbacks' 4753 elif pscnt > 0: 4730 elif pscnt > 0: 4754 msg = 'user p 4731 msg = 'user processes' 4755 else: 4732 else: 4756 msg = 'device 4733 msg = 'device pm callbacks' 4757 d = testruns[0].addHo 4734 d = testruns[0].addHorizontalDivider(msg, testruns[-1].end) 4758 fulllist.insert(0, d) 4735 fulllist.insert(0, d) 4759 devtl.getPhaseRows(fulllist) 4736 devtl.getPhaseRows(fulllist) 4760 if len(threadlist) > 0: 4737 if len(threadlist) > 0: 4761 d = testruns[0].addHo 4738 d = testruns[0].addHorizontalDivider('asynchronous kernel threads', testruns[-1].end) 4762 threadlist.insert(0, 4739 threadlist.insert(0, d) 4763 devtl.getPhaseRows(th 4740 devtl.getPhaseRows(threadlist, devtl.rows) 4764 devtl.calcTotalRows() 4741 devtl.calcTotalRows() 4765 4742 4766 # draw the full timeline 4743 # draw the full timeline 4767 devtl.createZoomBox(sysvals.suspendmo 4744 devtl.createZoomBox(sysvals.suspendmode, len(testruns)) 4768 for data in testruns: 4745 for data in testruns: 4769 # draw each test run and bloc 4746 # draw each test run and block chronologically 4770 phases = {'suspend':[],'resum 4747 phases = {'suspend':[],'resume':[]} 4771 for phase in data.sortedPhase 4748 for phase in data.sortedPhases(): 4772 if data.dmesg[phase][ 4749 if data.dmesg[phase]['start'] >= data.tSuspended: 4773 phases['resum 4750 phases['resume'].append(phase) 4774 else: 4751 else: 4775 phases['suspe 4752 phases['suspend'].append(phase) 4776 # now draw the actual timelin 4753 # now draw the actual timeline blocks 4777 for dir in phases: 4754 for dir in phases: 4778 # draw suspend and re 4755 # draw suspend and resume blocks separately 4779 bname = '%s%d' % (dir 4756 bname = '%s%d' % (dir[0], data.testnumber) 4780 if dir == 'suspend': 4757 if dir == 'suspend': 4781 m0 = data.sta 4758 m0 = data.start 4782 mMax = data.t 4759 mMax = data.tSuspended 4783 left = '%f' % 4760 left = '%f' % (((m0-t0)*100.0)/tTotal) 4784 else: 4761 else: 4785 m0 = data.tSu 4762 m0 = data.tSuspended 4786 mMax = data.e 4763 mMax = data.end 4787 # in an x2 ru 4764 # in an x2 run, remove any gap between blocks 4788 if len(testru 4765 if len(testruns) > 1 and data.testnumber == 0: 4789 mMax 4766 mMax = testruns[1].start 4790 left = '%f' % 4767 left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal) 4791 mTotal = mMax - m0 4768 mTotal = mMax - m0 4792 # if a timeline block 4769 # if a timeline block is 0 length, skip altogether 4793 if mTotal == 0: 4770 if mTotal == 0: 4794 continue 4771 continue 4795 width = '%f' % (((mTo 4772 width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal) 4796 devtl.html += devtl.h 4773 devtl.html += devtl.html_tblock.format(bname, left, width, devtl.scaleH) 4797 for b in phases[dir]: 4774 for b in phases[dir]: 4798 # draw the ph 4775 # draw the phase color background 4799 phase = data. 4776 phase = data.dmesg[b] 4800 length = phas 4777 length = phase['end']-phase['start'] 4801 left = '%f' % 4778 left = '%f' % (((phase['start']-m0)*100.0)/mTotal) 4802 width = '%f' 4779 width = '%f' % ((length*100.0)/mTotal) 4803 devtl.html += 4780 devtl.html += devtl.html_phase.format(left, width, \ 4804 '%.3f 4781 '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ 4805 data. 4782 data.dmesg[b]['color'], '') 4806 for e in data.errorin 4783 for e in data.errorinfo[dir]: 4807 # draw red li 4784 # draw red lines for any kernel errors found 4808 type, t, idx1 4785 type, t, idx1, idx2 = e 4809 id = '%d_%d' 4786 id = '%d_%d' % (idx1, idx2) 4810 right = '%f' 4787 right = '%f' % (((mMax-t)*100.0)/mTotal) 4811 devtl.html += 4788 devtl.html += html_error.format(right, id, type) 4812 for b in phases[dir]: 4789 for b in phases[dir]: 4813 # draw the de 4790 # draw the devices for this phase 4814 phaselist = d 4791 phaselist = data.dmesg[b]['list'] 4815 for d in sort 4792 for d in sorted(data.tdevlist[b]): 4816 dname 4793 dname = d if ('[' not in d or 'CPU' in d) else d.split('[')[0] 4817 name, 4794 name, dev = dname, phaselist[d] 4818 drv = 4795 drv = xtraclass = xtrainfo = xtrastyle = '' 4819 if 'h 4796 if 'htmlclass' in dev: 4820 4797 xtraclass = dev['htmlclass'] 4821 if 'c 4798 if 'color' in dev: 4822 4799 xtrastyle = 'background:%s;' % dev['color'] 4823 if(d 4800 if(d in sysvals.devprops): 4824 4801 name = sysvals.devprops[d].altName(d) 4825 4802 xtraclass = sysvals.devprops[d].xtraClass() 4826 4803 xtrainfo = sysvals.devprops[d].xtraInfo() 4827 elif 4804 elif xtraclass == ' kth': 4828 4805 xtrainfo = ' kernel_thread' 4829 if('d 4806 if('drv' in dev and dev['drv']): 4830 4807 drv = ' {%s}' % dev['drv'] 4831 rowhe 4808 rowheight = devtl.phaseRowHeight(data.testnumber, b, dev['row']) 4832 rowto 4809 rowtop = devtl.phaseRowTop(data.testnumber, b, dev['row']) 4833 top = 4810 top = '%.3f' % (rowtop + devtl.scaleH) 4834 left 4811 left = '%f' % (((dev['start']-m0)*100)/mTotal) 4835 width 4812 width = '%f' % (((dev['end']-dev['start'])*100)/mTotal) 4836 lengt 4813 length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) 4837 title 4814 title = name+drv+xtrainfo+length 4838 if sy 4815 if sysvals.suspendmode == 'command': 4839 4816 title += sysvals.testcommand 4840 elif 4817 elif xtraclass == ' ps': 4841 4818 if 'suspend' in b: 4842 4819 title += 'pre_suspend_process' 4843 4820 else: 4844 4821 title += 'post_resume_process' 4845 else: 4822 else: 4846 4823 title += b 4847 devtl 4824 devtl.html += devtl.html_device.format(dev['id'], \ 4848 4825 title, left, top, '%.3f'%rowheight, width, \ 4849 4826 dname+drv, xtraclass, xtrastyle) 4850 if('c 4827 if('cpuexec' in dev): 4851 4828 for t in sorted(dev['cpuexec']): 4852 4829 start, end = t 4853 4830 height = '%.3f' % (rowheight/3) 4854 4831 top = '%.3f' % (rowtop + devtl.scaleH + 2*rowheight/3) 4855 4832 left = '%f' % (((start-m0)*100)/mTotal) 4856 4833 width = '%f' % ((end-start)*100/mTotal) 4857 4834 color = 'rgba(255, 0, 0, %f)' % dev['cpuexec'][t] 4858 4835 devtl.html += \ 4859 4836 html_cpuexec.format(left, top, height, width, color) 4860 if('s 4837 if('src' not in dev): 4861 4838 continue 4862 # dra 4839 # draw any trace events for this device 4863 for e 4840 for e in dev['src']: 4864 4841 if e.length == 0: 4865 4842 continue 4866 4843 height = '%.3f' % devtl.rowH 4867 4844 top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH)) 4868 4845 left = '%f' % (((e.time-m0)*100)/mTotal) 4869 4846 width = '%f' % (e.length*100/mTotal) 4870 4847 xtrastyle = '' 4871 4848 if e.color: 4872 4849 xtrastyle = 'background:%s;' % e.color 4873 4850 devtl.html += \ 4874 4851 html_traceevent.format(e.title(), \ 4875 4852 left, top, height, width, e.text(), '', xtrastyle) 4876 # draw the time scale 4853 # draw the time scale, try to make the number of labels readable 4877 devtl.createTimeScale 4854 devtl.createTimeScale(m0, mMax, tTotal, dir) 4878 devtl.html += '</div> 4855 devtl.html += '</div>\n' 4879 4856 4880 # timeline is finished 4857 # timeline is finished 4881 devtl.html += '</div>\n</div>\n' 4858 devtl.html += '</div>\n</div>\n' 4882 4859 4883 # draw a legend which describes the p 4860 # draw a legend which describes the phases by color 4884 if sysvals.suspendmode != 'command': 4861 if sysvals.suspendmode != 'command': 4885 phasedef = testruns[-1].phase 4862 phasedef = testruns[-1].phasedef 4886 devtl.html += '<div class="le 4863 devtl.html += '<div class="legend">\n' 4887 pdelta = 100.0/len(phasedef.k 4864 pdelta = 100.0/len(phasedef.keys()) 4888 pmargin = pdelta / 4.0 4865 pmargin = pdelta / 4.0 4889 for phase in sorted(phasedef, 4866 for phase in sorted(phasedef, key=lambda k:phasedef[k]['order']): 4890 id, p = '', phasedef[ 4867 id, p = '', phasedef[phase] 4891 for word in phase.spl 4868 for word in phase.split('_'): 4892 id += word[0] 4869 id += word[0] 4893 order = '%.2f' % ((p[ 4870 order = '%.2f' % ((p['order'] * pdelta) + pmargin) 4894 name = phase.replace( 4871 name = phase.replace('_', ' ') 4895 devtl.html += devtl.h 4872 devtl.html += devtl.html_legend.format(order, p['color'], name, id) 4896 devtl.html += '</div>\n' 4873 devtl.html += '</div>\n' 4897 4874 4898 hf = open(sysvals.htmlfile, 'w') 4875 hf = open(sysvals.htmlfile, 'w') 4899 addCSS(hf, sysvals, len(testruns), ke 4876 addCSS(hf, sysvals, len(testruns), kerror) 4900 4877 4901 # write the device timeline 4878 # write the device timeline 4902 hf.write(devtl.html) 4879 hf.write(devtl.html) 4903 hf.write('<div id="devicedetailtitle" 4880 hf.write('<div id="devicedetailtitle"></div>\n') 4904 hf.write('<div id="devicedetail" styl 4881 hf.write('<div id="devicedetail" style="display:none;">\n') 4905 # draw the colored boxes for the devi 4882 # draw the colored boxes for the device detail section 4906 for data in testruns: 4883 for data in testruns: 4907 hf.write('<div id="devicedeta 4884 hf.write('<div id="devicedetail%d">\n' % data.testnumber) 4908 pscolor = 'linear-gradient(to 4885 pscolor = 'linear-gradient(to top left, #ccc, #eee)' 4909 hf.write(devtl.html_phaselet. 4886 hf.write(devtl.html_phaselet.format('pre_suspend_process', \ 4910 '0', '0', pscolor)) 4887 '0', '0', pscolor)) 4911 for b in data.sortedPhases(): 4888 for b in data.sortedPhases(): 4912 phase = data.dmesg[b] 4889 phase = data.dmesg[b] 4913 length = phase['end'] 4890 length = phase['end']-phase['start'] 4914 left = '%.3f' % (((ph 4891 left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) 4915 width = '%.3f' % ((le 4892 width = '%.3f' % ((length*100.0)/tTotal) 4916 hf.write(devtl.html_p 4893 hf.write(devtl.html_phaselet.format(b, left, width, \ 4917 data.dmesg[b] 4894 data.dmesg[b]['color'])) 4918 hf.write(devtl.html_phaselet. 4895 hf.write(devtl.html_phaselet.format('post_resume_process', \ 4919 '0', '0', pscolor)) 4896 '0', '0', pscolor)) 4920 if sysvals.suspendmode == 'co 4897 if sysvals.suspendmode == 'command': 4921 hf.write(devtl.html_p 4898 hf.write(devtl.html_phaselet.format('cmdexec', '0', '0', pscolor)) 4922 hf.write('</div>\n') 4899 hf.write('</div>\n') 4923 hf.write('</div>\n') 4900 hf.write('</div>\n') 4924 4901 4925 # write the ftrace data (callgraph) 4902 # write the ftrace data (callgraph) 4926 if sysvals.cgtest >= 0 and len(testru 4903 if sysvals.cgtest >= 0 and len(testruns) > sysvals.cgtest: 4927 data = testruns[sysvals.cgtes 4904 data = testruns[sysvals.cgtest] 4928 else: 4905 else: 4929 data = testruns[-1] 4906 data = testruns[-1] 4930 if sysvals.usecallgraph: 4907 if sysvals.usecallgraph: 4931 addCallgraphs(sysvals, hf, da 4908 addCallgraphs(sysvals, hf, data) 4932 4909 4933 # add the test log as a hidden div 4910 # add the test log as a hidden div 4934 if sysvals.testlog and sysvals.logmsg 4911 if sysvals.testlog and sysvals.logmsg: 4935 hf.write('<div id="testlog" s 4912 hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') 4936 # add the dmesg log as a hidden div 4913 # add the dmesg log as a hidden div 4937 if sysvals.dmesglog and sysvals.dmesg 4914 if sysvals.dmesglog and sysvals.dmesgfile: 4938 hf.write('<div id="dmesglog" 4915 hf.write('<div id="dmesglog" style="display:none;">\n') 4939 lf = sysvals.openlog(sysvals. 4916 lf = sysvals.openlog(sysvals.dmesgfile, 'r') 4940 for line in lf: 4917 for line in lf: 4941 line = line.replace(' 4918 line = line.replace('<', '<').replace('>', '>') 4942 hf.write(line) 4919 hf.write(line) 4943 lf.close() 4920 lf.close() 4944 hf.write('</div>\n') 4921 hf.write('</div>\n') 4945 # add the ftrace log as a hidden div 4922 # add the ftrace log as a hidden div 4946 if sysvals.ftracelog and sysvals.ftra 4923 if sysvals.ftracelog and sysvals.ftracefile: 4947 hf.write('<div id="ftracelog" 4924 hf.write('<div id="ftracelog" style="display:none;">\n') 4948 lf = sysvals.openlog(sysvals. 4925 lf = sysvals.openlog(sysvals.ftracefile, 'r') 4949 for line in lf: 4926 for line in lf: 4950 hf.write(line) 4927 hf.write(line) 4951 lf.close() 4928 lf.close() 4952 hf.write('</div>\n') 4929 hf.write('</div>\n') 4953 4930 4954 # write the footer and close 4931 # write the footer and close 4955 addScriptCode(hf, testruns) 4932 addScriptCode(hf, testruns) 4956 hf.write('</body>\n</html>\n') 4933 hf.write('</body>\n</html>\n') 4957 hf.close() 4934 hf.close() 4958 return True 4935 return True 4959 4936 4960 def addCSS(hf, sv, testcount=1, kerror=False, 4937 def addCSS(hf, sv, testcount=1, kerror=False, extra=''): 4961 kernel = sv.stamp['kernel'] 4938 kernel = sv.stamp['kernel'] 4962 host = sv.hostname[0].upper()+sv.host 4939 host = sv.hostname[0].upper()+sv.hostname[1:] 4963 mode = sv.suspendmode 4940 mode = sv.suspendmode 4964 if sv.suspendmode in suspendmodename: 4941 if sv.suspendmode in suspendmodename: 4965 mode = suspendmodename[sv.sus 4942 mode = suspendmodename[sv.suspendmode] 4966 title = host+' '+mode+' '+kernel 4943 title = host+' '+mode+' '+kernel 4967 4944 4968 # various format changes by flags 4945 # various format changes by flags 4969 cgchk = 'checked' 4946 cgchk = 'checked' 4970 cgnchk = 'not(:checked)' 4947 cgnchk = 'not(:checked)' 4971 if sv.cgexp: 4948 if sv.cgexp: 4972 cgchk = 'not(:checked)' 4949 cgchk = 'not(:checked)' 4973 cgnchk = 'checked' 4950 cgnchk = 'checked' 4974 4951 4975 hoverZ = 'z-index:8;' 4952 hoverZ = 'z-index:8;' 4976 if sv.usedevsrc: 4953 if sv.usedevsrc: 4977 hoverZ = '' 4954 hoverZ = '' 4978 4955 4979 devlistpos = 'absolute' 4956 devlistpos = 'absolute' 4980 if testcount > 1: 4957 if testcount > 1: 4981 devlistpos = 'relative' 4958 devlistpos = 'relative' 4982 4959 4983 scaleTH = 20 4960 scaleTH = 20 4984 if kerror: 4961 if kerror: 4985 scaleTH = 60 4962 scaleTH = 60 4986 4963 4987 # write the html header first (html h 4964 # write the html header first (html head, css code, up to body start) 4988 html_header = '<!DOCTYPE html>\n<html 4965 html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ 4989 <meta http-equiv="content-type" conte 4966 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 4990 <title>'+title+'</title>\n\ 4967 <title>'+title+'</title>\n\ 4991 <style type=\'text/css\'>\n\ 4968 <style type=\'text/css\'>\n\ 4992 body {overflow-y:scroll;}\n\ 4969 body {overflow-y:scroll;}\n\ 4993 .stamp {width:100%;text-align 4970 .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ 4994 .stamp.sysinfo {font:10px Ari 4971 .stamp.sysinfo {font:10px Arial;}\n\ 4995 .callgraph {margin-top:30px;b 4972 .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ 4996 .callgraph article * {padding 4973 .callgraph article * {padding-left:28px;}\n\ 4997 h1 {color:black;font:bold 30p 4974 h1 {color:black;font:bold 30px Times;}\n\ 4998 t0 {color:black;font:bold 30p 4975 t0 {color:black;font:bold 30px Times;}\n\ 4999 t1 {color:black;font:30px Tim 4976 t1 {color:black;font:30px Times;}\n\ 5000 t2 {color:black;font:25px Tim 4977 t2 {color:black;font:25px Times;}\n\ 5001 t3 {color:black;font:20px Tim 4978 t3 {color:black;font:20px Times;white-space:nowrap;}\n\ 5002 t4 {color:black;font:bold 30p 4979 t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ 5003 cS {font:bold 13px Times;}\n\ 4980 cS {font:bold 13px Times;}\n\ 5004 table {width:100%;}\n\ 4981 table {width:100%;}\n\ 5005 .gray {background:rgba(80,80, 4982 .gray {background:rgba(80,80,80,0.1);}\n\ 5006 .green {background:rgba(204,2 4983 .green {background:rgba(204,255,204,0.4);}\n\ 5007 .purple {background:rgba(128, 4984 .purple {background:rgba(128,0,128,0.2);}\n\ 5008 .yellow {background:rgba(255, 4985 .yellow {background:rgba(255,255,204,0.4);}\n\ 5009 .blue {background:rgba(169,20 4986 .blue {background:rgba(169,208,245,0.4);}\n\ 5010 .time1 {font:22px Arial;borde 4987 .time1 {font:22px Arial;border:1px solid;}\n\ 5011 .time2 {font:15px Arial;borde 4988 .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ 5012 .testfail {font:bold 22px Ari 4989 .testfail {font:bold 22px Arial;color:red;border:1px dashed;}\n\ 5013 td {text-align:center;}\n\ 4990 td {text-align:center;}\n\ 5014 r {color:#500000;font:15px Ta 4991 r {color:#500000;font:15px Tahoma;}\n\ 5015 n {color:#505050;font:15px Ta 4992 n {color:#505050;font:15px Tahoma;}\n\ 5016 .tdhl {color:red;}\n\ 4993 .tdhl {color:red;}\n\ 5017 .hide {display:none;}\n\ 4994 .hide {display:none;}\n\ 5018 .pf {display:none;}\n\ 4995 .pf {display:none;}\n\ 5019 .pf:'+cgchk+' + label {backgr 4996 .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 4997 .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 4998 .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ 5022 .zoombox {position:relative;w 4999 .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ 5023 .timeline {position:relative; 5000 .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ 5024 .thread {position:absolute;he 5001 .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 5002 .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ 5026 .thread:hover {background:whi 5003 .thread:hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 5027 .thread.sec,.thread.sec:hover 5004 .thread.sec,.thread.sec:hover {background:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ 5028 .hover {background:white;bord 5005 .hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 5029 .hover.sync {background:white 5006 .hover.sync {background:white;}\n\ 5030 .hover.bg,.hover.kth,.hover.s 5007 .hover.bg,.hover.kth,.hover.sync,.hover.ps {background:white;}\n\ 5031 .jiffie {position:absolute;po 5008 .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ 5032 .traceevent {position:absolut 5009 .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 5010 .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ 5034 .phase {position:absolute;ove 5011 .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ 5035 .phaselet {float:left;overflo 5012 .phaselet {float:left;overflow:hidden;border:0px;text-align:center;min-height:100px;font-size:24px;}\n\ 5036 .t {position:absolute;line-he 5013 .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 5014 .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 5015 .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ 5039 .legend .square {position:abs 5016 .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 5017 button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ 5041 .btnfmt {position:relative;fl 5018 .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 5019 .devlist {position:'+devlistpos+';width:190px;}\n\ 5043 a:link {color:white;text-deco 5020 a:link {color:white;text-decoration:none;}\n\ 5044 a:visited {color:white;}\n\ 5021 a:visited {color:white;}\n\ 5045 a:hover {color:white;}\n\ 5022 a:hover {color:white;}\n\ 5046 a:active {color:white;}\n\ 5023 a:active {color:white;}\n\ 5047 .version {position:relative;f 5024 .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ 5048 #devicedetail {min-height:100 5025 #devicedetail {min-height:100px;box-shadow:5px 5px 20px black;}\n\ 5049 .tblock {position:absolute;he 5026 .tblock {position:absolute;height:100%;background:#ddd;}\n\ 5050 .tback {position:absolute;wid 5027 .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ 5051 .bg {z-index:1;}\n\ 5028 .bg {z-index:1;}\n\ 5052 '+extra+'\ 5029 '+extra+'\ 5053 </style>\n</head>\n<body>\n' 5030 </style>\n</head>\n<body>\n' 5054 hf.write(html_header) 5031 hf.write(html_header) 5055 5032 5056 # Function: addScriptCode 5033 # Function: addScriptCode 5057 # Description: 5034 # Description: 5058 # Adds the javascript code to the outp 5035 # Adds the javascript code to the output html 5059 # Arguments: 5036 # Arguments: 5060 # hf: the open html file pointer 5037 # hf: the open html file pointer 5061 # testruns: array of Data objects from 5038 # testruns: array of Data objects from parseKernelLog or parseTraceLog 5062 def addScriptCode(hf, testruns): 5039 def addScriptCode(hf, testruns): 5063 t0 = testruns[0].start * 1000 5040 t0 = testruns[0].start * 1000 5064 tMax = testruns[-1].end * 1000 5041 tMax = testruns[-1].end * 1000 5065 hf.write('<script type="text/javascri << 5066 # create an array in javascript memor 5042 # create an array in javascript memory with the device details 5067 detail = ' var devtable = [];\n' 5043 detail = ' var devtable = [];\n' 5068 for data in testruns: 5044 for data in testruns: 5069 topo = data.deviceTopology() 5045 topo = data.deviceTopology() 5070 detail += ' devtable[%d] 5046 detail += ' devtable[%d] = "%s";\n' % (data.testnumber, topo) 5071 detail += ' var bounds = [%f,%f]; 5047 detail += ' var bounds = [%f,%f];\n' % (t0, tMax) 5072 # add the code which will manipulate 5048 # add the code which will manipulate the data in the browser 5073 hf.write(detail); !! 5049 script_code = \ 5074 script_code = r""" var resolutio !! 5050 '<script type="text/javascript">\n'+detail+\ 5075 var dragval = [0, 0]; !! 5051 ' var resolution = -1;\n'\ 5076 function redrawTimescale(t0, tMax, tS !! 5052 ' var dragval = [0, 0];\n'\ 5077 var rline = '<div class="t" s !! 5053 ' function redrawTimescale(t0, tMax, tS) {\n'\ 5078 var tTotal = tMax - t0; !! 5054 ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;">\';\n'\ 5079 var list = document.getElemen !! 5055 ' var tTotal = tMax - t0;\n'\ 5080 for (var i = 0; i < list.leng !! 5056 ' var list = document.getElementsByClassName("tblock");\n'\ 5081 var timescale = list[ !! 5057 ' for (var i = 0; i < list.length; i++) {\n'\ 5082 var m0 = t0 + (tTotal !! 5058 ' var timescale = list[i].getElementsByClassName("timescale")[0];\n'\ 5083 var mTotal = tTotal*p !! 5059 ' var m0 = t0 + (tTotal*parseFloat(list[i].style.left)/100);\n'\ 5084 var mMax = m0 + mTota !! 5060 ' var mTotal = tTotal*parseFloat(list[i].style.width)/100;\n'\ 5085 var html = ""; !! 5061 ' var mMax = m0 + mTotal;\n'\ 5086 var divTotal = Math.f !! 5062 ' var html = "";\n'\ 5087 if(divTotal > 1000) c !! 5063 ' var divTotal = Math.floor(mTotal/tS) + 1;\n'\ 5088 var divEdge = (mTotal !! 5064 ' if(divTotal > 1000) continue;\n'\ 5089 var pos = 0.0, val = !! 5065 ' var divEdge = (mTotal - tS*(divTotal-1))*100/mTotal;\n'\ 5090 for (var j = 0; j < d !! 5066 ' var pos = 0.0, val = 0.0;\n'\ 5091 var htmlline !! 5067 ' for (var j = 0; j < divTotal; j++) {\n'\ 5092 var mode = li !! 5068 ' var htmlline = "";\n'\ 5093 if(mode == "s !! 5069 ' var mode = list[i].id[5];\n'\ 5094 pos = !! 5070 ' if(mode == "s") {\n'\ 5095 val = !! 5071 ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\ 5096 if(j !! 5072 ' val = (j-divTotal+1)*tS;\n'\ 5097 !! 5073 ' if(j == divTotal - 1)\n'\ 5098 else !! 5074 ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S→</cS></div>\';\n'\ 5099 !! 5075 ' else\n'\ 5100 } else { !! 5076 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 5101 pos = !! 5077 ' } else {\n'\ 5102 val = !! 5078 ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ 5103 htmll !! 5079 ' val = (j)*tS;\n'\ 5104 if(j !! 5080 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 5105 !! 5081 ' if(j == 0)\n'\ 5106 !! 5082 ' if(mode == "r")\n'\ 5107 !! 5083 ' htmlline = rline+"<cS>←R</cS></div>";\n'\ 5108 !! 5084 ' else\n'\ 5109 } !! 5085 ' htmlline = rline+"<cS>0ms</div>";\n'\ 5110 html += htmll !! 5086 ' }\n'\ 5111 } !! 5087 ' html += htmlline;\n'\ 5112 timescale.innerHTML = !! 5088 ' }\n'\ 5113 } !! 5089 ' timescale.innerHTML = html;\n'\ 5114 } !! 5090 ' }\n'\ 5115 function zoomTimeline() { !! 5091 ' }\n'\ 5116 var dmesg = document.getEleme !! 5092 ' function zoomTimeline() {\n'\ 5117 var zoombox = document.getEle !! 5093 ' var dmesg = document.getElementById("dmesg");\n'\ 5118 var left = zoombox.scrollLeft !! 5094 ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 5119 var val = parseFloat(dmesg.st !! 5095 ' var left = zoombox.scrollLeft;\n'\ 5120 var newval = 100; !! 5096 ' var val = parseFloat(dmesg.style.width);\n'\ 5121 var sh = window.outerWidth / !! 5097 ' var newval = 100;\n'\ 5122 if(this.id == "zoomin") { !! 5098 ' var sh = window.outerWidth / 2;\n'\ 5123 newval = val * 1.2; !! 5099 ' if(this.id == "zoomin") {\n'\ 5124 if(newval > 910034) n !! 5100 ' newval = val * 1.2;\n'\ 5125 dmesg.style.width = n !! 5101 ' if(newval > 910034) newval = 910034;\n'\ 5126 zoombox.scrollLeft = !! 5102 ' dmesg.style.width = newval+"%";\n'\ 5127 } else if (this.id == "zoomou !! 5103 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 5128 newval = val / 1.2; !! 5104 ' } else if (this.id == "zoomout") {\n'\ 5129 if(newval < 100) newv !! 5105 ' newval = val / 1.2;\n'\ 5130 dmesg.style.width = n !! 5106 ' if(newval < 100) newval = 100;\n'\ 5131 zoombox.scrollLeft = !! 5107 ' dmesg.style.width = newval+"%";\n'\ 5132 } else { !! 5108 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 5133 zoombox.scrollLeft = !! 5109 ' } else {\n'\ 5134 dmesg.style.width = " !! 5110 ' zoombox.scrollLeft = 0;\n'\ 5135 } !! 5111 ' dmesg.style.width = "100%";\n'\ 5136 var tS = [10000, 5000, 2000, !! 5112 ' }\n'\ 5137 var t0 = bounds[0]; !! 5113 ' var tS = [10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1];\n'\ 5138 var tMax = bounds[1]; !! 5114 ' var t0 = bounds[0];\n'\ 5139 var tTotal = tMax - t0; !! 5115 ' var tMax = bounds[1];\n'\ 5140 var wTotal = tTotal * 100.0 / !! 5116 ' var tTotal = tMax - t0;\n'\ 5141 var idx = 7*window.innerWidth !! 5117 ' var wTotal = tTotal * 100.0 / newval;\n'\ 5142 for(var i = 0; (i < tS.length !! 5118 ' var idx = 7*window.innerWidth/1100;\n'\ 5143 if(i >= tS.length) i = tS.len !! 5119 ' for(var i = 0; (i < tS.length)&&((wTotal / tS[i]) < idx); i++);\n'\ 5144 if(tS[i] == resolution) retur !! 5120 ' if(i >= tS.length) i = tS.length - 1;\n'\ 5145 resolution = tS[i]; !! 5121 ' if(tS[i] == resolution) return;\n'\ 5146 redrawTimescale(t0, tMax, tS[ !! 5122 ' resolution = tS[i];\n'\ 5147 } !! 5123 ' redrawTimescale(t0, tMax, tS[i]);\n'\ 5148 function deviceName(title) { !! 5124 ' }\n'\ 5149 var name = title.slice(0, tit !! 5125 ' function deviceName(title) {\n'\ 5150 return name; !! 5126 ' var name = title.slice(0, title.indexOf(" ("));\n'\ 5151 } !! 5127 ' return name;\n'\ 5152 function deviceHover() { !! 5128 ' }\n'\ 5153 var name = deviceName(this.ti !! 5129 ' function deviceHover() {\n'\ 5154 var dmesg = document.getEleme !! 5130 ' var name = deviceName(this.title);\n'\ 5155 var dev = dmesg.getElementsBy !! 5131 ' var dmesg = document.getElementById("dmesg");\n'\ 5156 var cpu = -1; !! 5132 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5157 if(name.match("CPU_ON\[[0-9]* !! 5133 ' var cpu = -1;\n'\ 5158 cpu = parseInt(name.s !! 5134 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 5159 else if(name.match("CPU_OFF\[ !! 5135 ' cpu = parseInt(name.slice(7));\n'\ 5160 cpu = parseInt(name.s !! 5136 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 5161 for (var i = 0; i < dev.lengt !! 5137 ' cpu = parseInt(name.slice(8));\n'\ 5162 dname = deviceName(de !! 5138 ' for (var i = 0; i < dev.length; i++) {\n'\ 5163 var cname = dev[i].cl !! 5139 ' dname = deviceName(dev[i].title);\n'\ 5164 if((cpu >= 0 && dname !! 5140 ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 5165 (name == dnam !! 5141 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 5166 { !! 5142 ' (name == dname))\n'\ 5167 dev[i].classN !! 5143 ' {\n'\ 5168 } else { !! 5144 ' dev[i].className = "hover "+cname;\n'\ 5169 dev[i].classN !! 5145 ' } else {\n'\ 5170 } !! 5146 ' dev[i].className = cname;\n'\ 5171 } !! 5147 ' }\n'\ 5172 } !! 5148 ' }\n'\ 5173 function deviceUnhover() { !! 5149 ' }\n'\ 5174 var dmesg = document.getEleme !! 5150 ' function deviceUnhover() {\n'\ 5175 var dev = dmesg.getElementsBy !! 5151 ' var dmesg = document.getElementById("dmesg");\n'\ 5176 for (var i = 0; i < dev.lengt !! 5152 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5177 dev[i].className = de !! 5153 ' for (var i = 0; i < dev.length; i++) {\n'\ 5178 } !! 5154 ' dev[i].className = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 5179 } !! 5155 ' }\n'\ 5180 function deviceTitle(title, total, cp !! 5156 ' }\n'\ 5181 var prefix = "Total"; !! 5157 ' function deviceTitle(title, total, cpu) {\n'\ 5182 if(total.length > 3) { !! 5158 ' var prefix = "Total";\n'\ 5183 prefix = "Average"; !! 5159 ' if(total.length > 3) {\n'\ 5184 total[1] = (total[1]+ !! 5160 ' prefix = "Average";\n'\ 5185 total[2] = (total[2]+ !! 5161 ' total[1] = (total[1]+total[3])/2;\n'\ 5186 } !! 5162 ' total[2] = (total[2]+total[4])/2;\n'\ 5187 var devtitle = document.getEl !! 5163 ' }\n'\ 5188 var name = deviceName(title); !! 5164 ' var devtitle = document.getElementById("devicedetailtitle");\n'\ 5189 if(cpu >= 0) name = "CPU"+cpu !! 5165 ' var name = deviceName(title);\n'\ 5190 var driver = ""; !! 5166 ' if(cpu >= 0) name = "CPU"+cpu;\n'\ 5191 var tS = "<t2>(</t2>"; !! 5167 ' var driver = "";\n'\ 5192 var tR = "<t2>)</t2>"; !! 5168 ' var tS = "<t2>(</t2>";\n'\ 5193 if(total[1] > 0) !! 5169 ' var tR = "<t2>)</t2>";\n'\ 5194 tS = "<t2>("+prefix+" !! 5170 ' if(total[1] > 0)\n'\ 5195 if(total[2] > 0) !! 5171 ' tS = "<t2>("+prefix+" Suspend:</t2><t0> "+total[1].toFixed(3)+" ms</t0> ";\n'\ 5196 tR = " <t2>"+prefix+" !! 5172 ' if(total[2] > 0)\n'\ 5197 var s = title.indexOf("{"); !! 5173 ' tR = " <t2>"+prefix+" Resume:</t2><t0> "+total[2].toFixed(3)+" ms<t2>)</t2></t0>";\n'\ 5198 var e = title.indexOf("}"); !! 5174 ' var s = title.indexOf("{");\n'\ 5199 if((s >= 0) && (e >= 0)) !! 5175 ' var e = title.indexOf("}");\n'\ 5200 driver = title.slice(< !! 5176 ' if((s >= 0) && (e >= 0))\n'\ 5201 if(total[1] > 0 && total[2] > !! 5177 ' driver = title.slice(s+1, e) + " <t1>@</t1> ";\n'\ 5202 devtitle.innerHTML = !! 5178 ' if(total[1] > 0 && total[2] > 0)\n'\ 5203 else !! 5179 ' devtitle.innerHTML = "<t0>"+driver+name+"</t0> "+tS+tR;\n'\ 5204 devtitle.innerHTML = !! 5180 ' else\n'\ 5205 return name; !! 5181 ' devtitle.innerHTML = "<t0>"+title+"</t0>";\n'\ 5206 } !! 5182 ' return name;\n'\ 5207 function deviceDetail() { !! 5183 ' }\n'\ 5208 var devinfo = document.getEle !! 5184 ' function deviceDetail() {\n'\ 5209 devinfo.style.display = "bloc !! 5185 ' var devinfo = document.getElementById("devicedetail");\n'\ 5210 var name = deviceName(this.ti !! 5186 ' devinfo.style.display = "block";\n'\ 5211 var cpu = -1; !! 5187 ' var name = deviceName(this.title);\n'\ 5212 if(name.match("CPU_ON\[[0-9]* !! 5188 ' var cpu = -1;\n'\ 5213 cpu = parseInt(name.s !! 5189 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 5214 else if(name.match("CPU_OFF\[ !! 5190 ' cpu = parseInt(name.slice(7));\n'\ 5215 cpu = parseInt(name.s !! 5191 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 5216 var dmesg = document.getEleme !! 5192 ' cpu = parseInt(name.slice(8));\n'\ 5217 var dev = dmesg.getElementsBy !! 5193 ' var dmesg = document.getElementById("dmesg");\n'\ 5218 var idlist = []; !! 5194 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5219 var pdata = [[]]; !! 5195 ' var idlist = [];\n'\ 5220 if(document.getElementById("d !! 5196 ' var pdata = [[]];\n'\ 5221 pdata = [[], []]; !! 5197 ' if(document.getElementById("devicedetail1"))\n'\ 5222 var pd = pdata[0]; !! 5198 ' pdata = [[], []];\n'\ 5223 var total = [0.0, 0.0, 0.0]; !! 5199 ' var pd = pdata[0];\n'\ 5224 for (var i = 0; i < dev.lengt !! 5200 ' var total = [0.0, 0.0, 0.0];\n'\ 5225 dname = deviceName(de !! 5201 ' for (var i = 0; i < dev.length; i++) {\n'\ 5226 if((cpu >= 0 && dname !! 5202 ' dname = deviceName(dev[i].title);\n'\ 5227 (name == dnam !! 5203 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 5228 { !! 5204 ' (name == dname))\n'\ 5229 idlist[idlist !! 5205 ' {\n'\ 5230 var tidx = 1; !! 5206 ' idlist[idlist.length] = dev[i].id;\n'\ 5231 if(dev[i].id[ !! 5207 ' var tidx = 1;\n'\ 5232 pd = !! 5208 ' if(dev[i].id[0] == "a") {\n'\ 5233 } else { !! 5209 ' pd = pdata[0];\n'\ 5234 if(pd !! 5210 ' } else {\n'\ 5235 if(to !! 5211 ' if(pdata.length == 1) pdata[1] = [];\n'\ 5236 pd = !! 5212 ' if(total.length == 3) total[3]=total[4]=0.0;\n'\ 5237 tidx !! 5213 ' pd = pdata[1];\n'\ 5238 } !! 5214 ' tidx = 3;\n'\ 5239 var info = de !! 5215 ' }\n'\ 5240 var pname = i !! 5216 ' var info = dev[i].title.split(" ");\n'\ 5241 pd[pname] = p !! 5217 ' var pname = info[info.length-1];\n'\ 5242 total[0] += p !! 5218 ' pd[pname] = parseFloat(info[info.length-3].slice(1));\n'\ 5243 if(pname.inde !! 5219 ' total[0] += pd[pname];\n'\ 5244 total !! 5220 ' if(pname.indexOf("suspend") >= 0)\n'\ 5245 else !! 5221 ' total[tidx] += pd[pname];\n'\ 5246 total !! 5222 ' else\n'\ 5247 } !! 5223 ' total[tidx+1] += pd[pname];\n'\ 5248 } !! 5224 ' }\n'\ 5249 var devname = deviceTitle(thi !! 5225 ' }\n'\ 5250 var left = 0.0; !! 5226 ' var devname = deviceTitle(this.title, total, cpu);\n'\ 5251 for (var t = 0; t < pdata.len !! 5227 ' var left = 0.0;\n'\ 5252 pd = pdata[t]; !! 5228 ' for (var t = 0; t < pdata.length; t++) {\n'\ 5253 devinfo = document.ge !! 5229 ' pd = pdata[t];\n'\ 5254 var phases = devinfo. !! 5230 ' devinfo = document.getElementById("devicedetail"+t);\n'\ 5255 for (var i = 0; i < p !! 5231 ' var phases = devinfo.getElementsByClassName("phaselet");\n'\ 5256 if(phases[i]. !! 5232 ' for (var i = 0; i < phases.length; i++) {\n'\ 5257 var w !! 5233 ' if(phases[i].id in pd) {\n'\ 5258 var f !! 5234 ' var w = 100.0*pd[phases[i].id]/total[0];\n'\ 5259 if(w !! 5235 ' var fs = 32;\n'\ 5260 var f !! 5236 ' if(w < 8) fs = 4*w | 0;\n'\ 5261 phase !! 5237 ' var fs2 = fs*3/4;\n'\ 5262 phase !! 5238 ' phases[i].style.width = w+"%";\n'\ 5263 phase !! 5239 ' phases[i].style.left = left+"%";\n'\ 5264 left !! 5240 ' phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\ 5265 var t !! 5241 ' left += w;\n'\ 5266 var p !! 5242 ' var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\ 5267 phase !! 5243 ' var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";\n'\ 5268 } else { !! 5244 ' phases[i].innerHTML = time+pname;\n'\ 5269 phase !! 5245 ' } else {\n'\ 5270 phase !! 5246 ' phases[i].style.width = "0%";\n'\ 5271 } !! 5247 ' phases[i].style.left = left+"%";\n'\ 5272 } !! 5248 ' }\n'\ 5273 } !! 5249 ' }\n'\ 5274 if(typeof devstats !== 'undef !! 5250 ' }\n'\ 5275 callDetail(this.id, t !! 5251 ' if(typeof devstats !== \'undefined\')\n'\ 5276 var cglist = document.getElem !! 5252 ' callDetail(this.id, this.title);\n'\ 5277 if(!cglist) return; !! 5253 ' var cglist = document.getElementById("callgraphs");\n'\ 5278 var cg = cglist.getElementsBy !! 5254 ' if(!cglist) return;\n'\ 5279 if(cg.length < 10) return; !! 5255 ' var cg = cglist.getElementsByClassName("atop");\n'\ 5280 for (var i = 0; i < cg.length !! 5256 ' if(cg.length < 10) return;\n'\ 5281 cgid = cg[i].id.split !! 5257 ' for (var i = 0; i < cg.length; i++) {\n'\ 5282 if(idlist.indexOf(cgi !! 5258 ' cgid = cg[i].id.split("x")[0]\n'\ 5283 cg[i].style.d !! 5259 ' if(idlist.indexOf(cgid) >= 0) {\n'\ 5284 } else { !! 5260 ' cg[i].style.display = "block";\n'\ 5285 cg[i].style.d !! 5261 ' } else {\n'\ 5286 } !! 5262 ' cg[i].style.display = "none";\n'\ 5287 } !! 5263 ' }\n'\ 5288 } !! 5264 ' }\n'\ 5289 function callDetail(devid, devtitle) !! 5265 ' }\n'\ 5290 if(!(devid in devstats) || de !! 5266 ' function callDetail(devid, devtitle) {\n'\ 5291 return; !! 5267 ' if(!(devid in devstats) || devstats[devid].length < 1)\n'\ 5292 var list = devstats[devid]; !! 5268 ' return;\n'\ 5293 var tmp = devtitle.split(" ") !! 5269 ' var list = devstats[devid];\n'\ 5294 var name = tmp[0], phase = tm !! 5270 ' var tmp = devtitle.split(" ");\n'\ 5295 var dd = document.getElementB !! 5271 ' var name = tmp[0], phase = tmp[tmp.length-1];\n'\ 5296 var total = parseFloat(tmp[1] !! 5272 ' var dd = document.getElementById(phase);\n'\ 5297 var mlist = []; !! 5273 ' var total = parseFloat(tmp[1].slice(1));\n'\ 5298 var maxlen = 0; !! 5274 ' var mlist = [];\n'\ 5299 var info = [] !! 5275 ' var maxlen = 0;\n'\ 5300 for(var i in list) { !! 5276 ' var info = []\n'\ 5301 if(list[i][0] == "@") !! 5277 ' for(var i in list) {\n'\ 5302 info = list[i !! 5278 ' if(list[i][0] == "@") {\n'\ 5303 continue; !! 5279 ' info = list[i].split("|");\n'\ 5304 } !! 5280 ' continue;\n'\ 5305 var tmp = list[i].spl !! 5281 ' }\n'\ 5306 var t = parseFloat(tm !! 5282 ' var tmp = list[i].split("|");\n'\ 5307 var p = (t*100.0/tota !! 5283 ' var t = parseFloat(tmp[0]), f = tmp[1], c = parseInt(tmp[2]);\n'\ 5308 mlist[mlist.length] = !! 5284 ' var p = (t*100.0/total).toFixed(2);\n'\ 5309 if(f.length > maxlen) !! 5285 ' mlist[mlist.length] = [f, c, t.toFixed(2), p+"%"];\n'\ 5310 maxlen = f.le !! 5286 ' if(f.length > maxlen)\n'\ 5311 } !! 5287 ' maxlen = f.length;\n'\ 5312 var pad = 5; !! 5288 ' }\n'\ 5313 if(mlist.length == 0) pad = 3 !! 5289 ' var pad = 5;\n'\ 5314 var html = '<div style="paddi !! 5290 ' if(mlist.length == 0) pad = 30;\n'\ 5315 if(info.length > 2) !! 5291 ' var html = \'<div style="padding-top:\'+pad+\'px"><t3> <b>\'+name+\':</b>\';\n'\ 5316 html += " start=<b>"+ !! 5292 ' if(info.length > 2)\n'\ 5317 if(info.length > 3) !! 5293 ' html += " start=<b>"+info[1]+"</b>, end=<b>"+info[2]+"</b>";\n'\ 5318 html += ", length<i>( !! 5294 ' if(info.length > 3)\n'\ 5319 if(info.length > 4) !! 5295 ' html += ", length<i>(w/o overhead)</i>=<b>"+info[3]+" ms</b>";\n'\ 5320 html += ", return=<b> !! 5296 ' if(info.length > 4)\n'\ 5321 html += "</t3></div>"; !! 5297 ' html += ", return=<b>"+info[4]+"</b>";\n'\ 5322 if(mlist.length > 0) { !! 5298 ' html += "</t3></div>";\n'\ 5323 html += '<table class !! 5299 ' if(mlist.length > 0) {\n'\ 5324 for(var i in mlist) !! 5300 ' html += \'<table class=fstat style="padding-top:\'+(maxlen*5)+\'px;"><tr><th>Function</th>\';\n'\ 5325 html += "<td !! 5301 ' for(var i in mlist)\n'\ 5326 html += "</tr><tr><th !! 5302 ' html += "<td class=vt>"+mlist[i][0]+"</td>";\n'\ 5327 for(var i in mlist) !! 5303 ' html += "</tr><tr><th>Calls</th>";\n'\ 5328 html += "<td> !! 5304 ' for(var i in mlist)\n'\ 5329 html += "</tr><tr><th !! 5305 ' html += "<td>"+mlist[i][1]+"</td>";\n'\ 5330 for(var i in mlist) !! 5306 ' html += "</tr><tr><th>Time(ms)</th>";\n'\ 5331 html += "<td> !! 5307 ' for(var i in mlist)\n'\ 5332 html += "</tr><tr><th !! 5308 ' html += "<td>"+mlist[i][2]+"</td>";\n'\ 5333 for(var i in mlist) !! 5309 ' html += "</tr><tr><th>Percent</th>";\n'\ 5334 html += "<td> !! 5310 ' for(var i in mlist)\n'\ 5335 html += "</tr></table !! 5311 ' html += "<td>"+mlist[i][3]+"</td>";\n'\ 5336 } !! 5312 ' html += "</tr></table>";\n'\ 5337 dd.innerHTML = html; !! 5313 ' }\n'\ 5338 var height = (maxlen*5)+100; !! 5314 ' dd.innerHTML = html;\n'\ 5339 dd.style.height = height+"px" !! 5315 ' var height = (maxlen*5)+100;\n'\ 5340 document.getElementById("devi !! 5316 ' dd.style.height = height+"px";\n'\ 5341 } !! 5317 ' document.getElementById("devicedetail").style.height = height+"px";\n'\ 5342 function callSelect() { !! 5318 ' }\n'\ 5343 var cglist = document.getElem !! 5319 ' function callSelect() {\n'\ 5344 if(!cglist) return; !! 5320 ' var cglist = document.getElementById("callgraphs");\n'\ 5345 var cg = cglist.getElementsBy !! 5321 ' if(!cglist) return;\n'\ 5346 for (var i = 0; i < cg.length !! 5322 ' var cg = cglist.getElementsByClassName("atop");\n'\ 5347 if(this.id == cg[i].i !! 5323 ' for (var i = 0; i < cg.length; i++) {\n'\ 5348 cg[i].style.d !! 5324 ' if(this.id == cg[i].id) {\n'\ 5349 } else { !! 5325 ' cg[i].style.display = "block";\n'\ 5350 cg[i].style.d !! 5326 ' } else {\n'\ 5351 } !! 5327 ' cg[i].style.display = "none";\n'\ 5352 } !! 5328 ' }\n'\ 5353 } !! 5329 ' }\n'\ 5354 function devListWindow(e) { !! 5330 ' }\n'\ 5355 var win = window.open(); !! 5331 ' function devListWindow(e) {\n'\ 5356 var html = "<title>"+e.target !! 5332 ' var win = window.open();\n'\ 5357 "<style type=\"text/c !! 5333 ' var html = "<title>"+e.target.innerHTML+"</title>"+\n'\ 5358 " ul {list-style-ty !! 5334 ' "<style type=\\"text/css\\">"+\n'\ 5359 "</style>" !! 5335 ' " ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\ 5360 var dt = devtable[0]; !! 5336 ' "</style>"\n'\ 5361 if(e.target.id != "devlist1") !! 5337 ' var dt = devtable[0];\n'\ 5362 dt = devtable[1]; !! 5338 ' if(e.target.id != "devlist1")\n'\ 5363 win.document.write(html+dt); !! 5339 ' dt = devtable[1];\n'\ 5364 } !! 5340 ' win.document.write(html+dt);\n'\ 5365 function errWindow() { !! 5341 ' }\n'\ 5366 var range = this.id.split("_" !! 5342 ' function errWindow() {\n'\ 5367 var idx1 = parseInt(range[0]) !! 5343 ' var range = this.id.split("_");\n'\ 5368 var idx2 = parseInt(range[1]) !! 5344 ' var idx1 = parseInt(range[0]);\n'\ 5369 var win = window.open(); !! 5345 ' var idx2 = parseInt(range[1]);\n'\ 5370 var log = document.getElement !! 5346 ' var win = window.open();\n'\ 5371 var title = "<title>dmesg log !! 5347 ' var log = document.getElementById("dmesglog");\n'\ 5372 var text = log.innerHTML.spli !! 5348 ' var title = "<title>dmesg log</title>";\n'\ 5373 var html = ""; !! 5349 ' var text = log.innerHTML.split("\\n");\n'\ 5374 for(var i = 0; i < text.lengt !! 5350 ' var html = "";\n'\ 5375 if(i == idx1) { !! 5351 ' for(var i = 0; i < text.length; i++) {\n'\ 5376 html += "<e i !! 5352 ' if(i == idx1) {\n'\ 5377 } else if(i > idx1 && !! 5353 ' html += "<e id=target>"+text[i]+"</e>\\n";\n'\ 5378 html += "<e>" !! 5354 ' } else if(i > idx1 && i <= idx2) {\n'\ 5379 } else { !! 5355 ' html += "<e>"+text[i]+"</e>\\n";\n'\ 5380 html += text[ !! 5356 ' } else {\n'\ 5381 } !! 5357 ' html += text[i]+"\\n";\n'\ 5382 } !! 5358 ' }\n'\ 5383 win.document.write("<style>e{ !! 5359 ' }\n'\ 5384 win.location.hash = "#target" !! 5360 ' win.document.write("<style>e{color:red}</style>"+title+"<pre>"+html+"</pre>");\n'\ 5385 win.document.close(); !! 5361 ' win.location.hash = "#target";\n'\ 5386 } !! 5362 ' win.document.close();\n'\ 5387 function logWindow(e) { !! 5363 ' }\n'\ 5388 var name = e.target.id.slice( !! 5364 ' function logWindow(e) {\n'\ 5389 var win = window.open(); !! 5365 ' var name = e.target.id.slice(4);\n'\ 5390 var log = document.getElement !! 5366 ' var win = window.open();\n'\ 5391 var title = "<title>"+documen !! 5367 ' var log = document.getElementById(name+"log");\n'\ 5392 win.document.write(title+"<pr !! 5368 ' var title = "<title>"+document.title.split(" ")[0]+" "+name+" log</title>";\n'\ 5393 win.document.close(); !! 5369 ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ 5394 } !! 5370 ' win.document.close();\n'\ 5395 function onMouseDown(e) { !! 5371 ' }\n'\ 5396 dragval[0] = e.clientX; !! 5372 ' function onMouseDown(e) {\n'\ 5397 dragval[1] = document.getElem !! 5373 ' dragval[0] = e.clientX;\n'\ 5398 document.onmousemove = onMous !! 5374 ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ 5399 } !! 5375 ' document.onmousemove = onMouseMove;\n'\ 5400 function onMouseMove(e) { !! 5376 ' }\n'\ 5401 var zoombox = document.getEle !! 5377 ' function onMouseMove(e) {\n'\ 5402 zoombox.scrollLeft = dragval[ !! 5378 ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 5403 } !! 5379 ' zoombox.scrollLeft = dragval[1] + dragval[0] - e.clientX;\n'\ 5404 function onMouseUp(e) { !! 5380 ' }\n'\ 5405 document.onmousemove = null; !! 5381 ' function onMouseUp(e) {\n'\ 5406 } !! 5382 ' document.onmousemove = null;\n'\ 5407 function onKeyPress(e) { !! 5383 ' }\n'\ 5408 var c = e.charCode; !! 5384 ' function onKeyPress(e) {\n'\ 5409 if(c != 42 && c != 43 && c != !! 5385 ' var c = e.charCode;\n'\ 5410 var click = document.createEv !! 5386 ' if(c != 42 && c != 43 && c != 45) return;\n'\ 5411 click.initEvent("click", true !! 5387 ' var click = document.createEvent("Events");\n'\ 5412 if(c == 43) !! 5388 ' click.initEvent("click", true, false);\n'\ 5413 document.getElementBy !! 5389 ' if(c == 43) \n'\ 5414 else if(c == 45) !! 5390 ' document.getElementById("zoomin").dispatchEvent(click);\n'\ 5415 document.getElementBy !! 5391 ' else if(c == 45)\n'\ 5416 else if(c == 42) !! 5392 ' document.getElementById("zoomout").dispatchEvent(click);\n'\ 5417 document.getElementBy !! 5393 ' else if(c == 42)\n'\ 5418 } !! 5394 ' document.getElementById("zoomdef").dispatchEvent(click);\n'\ 5419 window.addEventListener("resize", fun !! 5395 ' }\n'\ 5420 window.addEventListener("load", funct !! 5396 ' window.addEventListener("resize", function () {zoomTimeline();});\n'\ 5421 var dmesg = document.getEleme !! 5397 ' window.addEventListener("load", function () {\n'\ 5422 dmesg.style.width = "100%" !! 5398 ' var dmesg = document.getElementById("dmesg");\n'\ 5423 dmesg.onmousedown = onMouseDo !! 5399 ' dmesg.style.width = "100%"\n'\ 5424 document.onmouseup = onMouseU !! 5400 ' dmesg.onmousedown = onMouseDown;\n'\ 5425 document.onkeypress = onKeyPr !! 5401 ' document.onmouseup = onMouseUp;\n'\ 5426 document.getElementById("zoom !! 5402 ' document.onkeypress = onKeyPress;\n'\ 5427 document.getElementById("zoom !! 5403 ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ 5428 document.getElementById("zoom !! 5404 ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ 5429 var list = document.getElemen !! 5405 ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ 5430 for (var i = 0; i < list.leng !! 5406 ' var list = document.getElementsByClassName("err");\n'\ 5431 list[i].onclick = err !! 5407 ' for (var i = 0; i < list.length; i++)\n'\ 5432 var list = document.getElemen !! 5408 ' list[i].onclick = errWindow;\n'\ 5433 for (var i = 0; i < list.leng !! 5409 ' var list = document.getElementsByClassName("logbtn");\n'\ 5434 list[i].onclick = log !! 5410 ' for (var i = 0; i < list.length; i++)\n'\ 5435 list = document.getElementsBy !! 5411 ' list[i].onclick = logWindow;\n'\ 5436 for (var i = 0; i < list.leng !! 5412 ' list = document.getElementsByClassName("devlist");\n'\ 5437 list[i].onclick = dev !! 5413 ' for (var i = 0; i < list.length; i++)\n'\ 5438 var dev = dmesg.getElementsBy !! 5414 ' list[i].onclick = devListWindow;\n'\ 5439 for (var i = 0; i < dev.lengt !! 5415 ' var dev = dmesg.getElementsByClassName("thread");\n'\ 5440 dev[i].onclick = devi !! 5416 ' for (var i = 0; i < dev.length; i++) {\n'\ 5441 dev[i].onmouseover = !! 5417 ' dev[i].onclick = deviceDetail;\n'\ 5442 dev[i].onmouseout = d !! 5418 ' dev[i].onmouseover = deviceHover;\n'\ 5443 } !! 5419 ' dev[i].onmouseout = deviceUnhover;\n'\ 5444 var dev = dmesg.getElementsBy !! 5420 ' }\n'\ 5445 for (var i = 0; i < dev.lengt !! 5421 ' var dev = dmesg.getElementsByClassName("srccall");\n'\ 5446 dev[i].onclick = call !! 5422 ' for (var i = 0; i < dev.length; i++)\n'\ 5447 zoomTimeline(); !! 5423 ' dev[i].onclick = callSelect;\n'\ 5448 }); !! 5424 ' zoomTimeline();\n'\ 5449 </script> """ !! 5425 ' });\n'\ >> 5426 '</script>\n' 5450 hf.write(script_code); 5427 hf.write(script_code); 5451 5428 5452 # Function: executeSuspend 5429 # Function: executeSuspend 5453 # Description: 5430 # Description: 5454 # Execute system suspend through the s 5431 # Execute system suspend through the sysfs interface, then copy the output 5455 # dmesg and ftrace files to the test o 5432 # dmesg and ftrace files to the test output directory. 5456 def executeSuspend(quiet=False): 5433 def executeSuspend(quiet=False): 5457 sv, tp, pm = sysvals, sysvals.tpath, 5434 sv, tp, pm = sysvals, sysvals.tpath, ProcessMonitor() 5458 if sv.wifi: 5435 if sv.wifi: 5459 wifi = sv.checkWifi() 5436 wifi = sv.checkWifi() 5460 sv.dlog('wifi check, connecte 5437 sv.dlog('wifi check, connected device is "%s"' % wifi) 5461 testdata = [] 5438 testdata = [] 5462 # run these commands to prepare the s 5439 # run these commands to prepare the system for suspend 5463 if sv.display: 5440 if sv.display: 5464 if not quiet: 5441 if not quiet: 5465 pprint('SET DISPLAY T 5442 pprint('SET DISPLAY TO %s' % sv.display.upper()) 5466 ret = sv.displayControl(sv.di 5443 ret = sv.displayControl(sv.display) 5467 sv.dlog('xset display %s, ret 5444 sv.dlog('xset display %s, ret = %d' % (sv.display, ret)) 5468 time.sleep(1) 5445 time.sleep(1) 5469 if sv.sync: 5446 if sv.sync: 5470 if not quiet: 5447 if not quiet: 5471 pprint('SYNCING FILES 5448 pprint('SYNCING FILESYSTEMS') 5472 sv.dlog('syncing filesystems' 5449 sv.dlog('syncing filesystems') 5473 call('sync', shell=True) 5450 call('sync', shell=True) 5474 sv.dlog('read dmesg') 5451 sv.dlog('read dmesg') 5475 sv.initdmesg() 5452 sv.initdmesg() 5476 sv.dlog('cmdinfo before') 5453 sv.dlog('cmdinfo before') 5477 sv.cmdinfo(True) 5454 sv.cmdinfo(True) 5478 sv.start(pm) 5455 sv.start(pm) 5479 # execute however many s/r runs reque 5456 # execute however many s/r runs requested 5480 for count in range(1,sv.execcount+1): 5457 for count in range(1,sv.execcount+1): 5481 # x2delay in between test run 5458 # x2delay in between test runs 5482 if(count > 1 and sv.x2delay > 5459 if(count > 1 and sv.x2delay > 0): 5483 sv.fsetVal('WAIT %d' 5460 sv.fsetVal('WAIT %d' % sv.x2delay, 'trace_marker') 5484 time.sleep(sv.x2delay 5461 time.sleep(sv.x2delay/1000.0) 5485 sv.fsetVal('WAIT END' 5462 sv.fsetVal('WAIT END', 'trace_marker') 5486 # start message 5463 # start message 5487 if sv.testcommand != '': 5464 if sv.testcommand != '': 5488 pprint('COMMAND START 5465 pprint('COMMAND START') 5489 else: 5466 else: 5490 if(sv.rtcwake): 5467 if(sv.rtcwake): 5491 pprint('SUSPE 5468 pprint('SUSPEND START') 5492 else: 5469 else: 5493 pprint('SUSPE 5470 pprint('SUSPEND START (press a key to resume)') 5494 # set rtcwake 5471 # set rtcwake 5495 if(sv.rtcwake): 5472 if(sv.rtcwake): 5496 if not quiet: 5473 if not quiet: 5497 pprint('will 5474 pprint('will issue an rtcwake in %d seconds' % sv.rtcwaketime) 5498 sv.dlog('enable RTC w 5475 sv.dlog('enable RTC wake alarm') 5499 sv.rtcWakeAlarmOn() 5476 sv.rtcWakeAlarmOn() 5500 # start of suspend trace mark 5477 # start of suspend trace marker 5501 sv.fsetVal(datetime.now().str 5478 sv.fsetVal(datetime.now().strftime(sv.tmstart), 'trace_marker') 5502 # predelay delay 5479 # predelay delay 5503 if(count == 1 and sv.predelay 5480 if(count == 1 and sv.predelay > 0): 5504 sv.fsetVal('WAIT %d' 5481 sv.fsetVal('WAIT %d' % sv.predelay, 'trace_marker') 5505 time.sleep(sv.predela 5482 time.sleep(sv.predelay/1000.0) 5506 sv.fsetVal('WAIT END' 5483 sv.fsetVal('WAIT END', 'trace_marker') 5507 # initiate suspend or command 5484 # initiate suspend or command 5508 sv.dlog('system executing a s 5485 sv.dlog('system executing a suspend') 5509 tdata = {'error': ''} 5486 tdata = {'error': ''} 5510 if sv.testcommand != '': 5487 if sv.testcommand != '': 5511 res = call(sv.testcom 5488 res = call(sv.testcommand+' 2>&1', shell=True); 5512 if res != 0: 5489 if res != 0: 5513 tdata['error' 5490 tdata['error'] = 'cmd returned %d' % res 5514 else: 5491 else: 5515 s0ixready = sv.s0ixSu 5492 s0ixready = sv.s0ixSupport() 5516 mode = sv.suspendmode 5493 mode = sv.suspendmode 5517 if sv.memmode and os. 5494 if sv.memmode and os.path.exists(sv.mempowerfile): 5518 mode = 'mem' 5495 mode = 'mem' 5519 sv.testVal(sv 5496 sv.testVal(sv.mempowerfile, 'radio', sv.memmode) 5520 if sv.diskmode and os 5497 if sv.diskmode and os.path.exists(sv.diskpowerfile): 5521 mode = 'disk' 5498 mode = 'disk' 5522 sv.testVal(sv 5499 sv.testVal(sv.diskpowerfile, 'radio', sv.diskmode) 5523 if sv.acpidebug: 5500 if sv.acpidebug: 5524 sv.testVal(sv 5501 sv.testVal(sv.acpipath, 'acpi', '0xe') 5525 if ((mode == 'freeze' 5502 if ((mode == 'freeze') or (sv.memmode == 's2idle')) \ 5526 and sv.haveTu 5503 and sv.haveTurbostat(): 5527 # execution w 5504 # execution will pause here 5528 retval, turbo !! 5505 turbo = sv.turbostat(s0ixready) 5529 if retval != << 5530 tdata << 5531 if turbo: 5506 if turbo: 5532 tdata 5507 tdata['turbo'] = turbo 5533 else: 5508 else: 5534 pf = open(sv. 5509 pf = open(sv.powerfile, 'w') 5535 pf.write(mode 5510 pf.write(mode) 5536 # execution w 5511 # execution will pause here 5537 try: 5512 try: 5538 pf.fl << 5539 pf.cl 5513 pf.close() 5540 except Except 5514 except Exception as e: 5541 tdata 5515 tdata['error'] = str(e) 5542 sv.fsetVal('CMD COMPLETE', 't 5516 sv.fsetVal('CMD COMPLETE', 'trace_marker') 5543 sv.dlog('system returned') 5517 sv.dlog('system returned') 5544 # reset everything 5518 # reset everything 5545 sv.testVal('restoreall') 5519 sv.testVal('restoreall') 5546 if(sv.rtcwake): 5520 if(sv.rtcwake): 5547 sv.dlog('disable RTC 5521 sv.dlog('disable RTC wake alarm') 5548 sv.rtcWakeAlarmOff() 5522 sv.rtcWakeAlarmOff() 5549 # postdelay delay 5523 # postdelay delay 5550 if(count == sv.execcount and 5524 if(count == sv.execcount and sv.postdelay > 0): 5551 sv.fsetVal('WAIT %d' 5525 sv.fsetVal('WAIT %d' % sv.postdelay, 'trace_marker') 5552 time.sleep(sv.postdel 5526 time.sleep(sv.postdelay/1000.0) 5553 sv.fsetVal('WAIT END' 5527 sv.fsetVal('WAIT END', 'trace_marker') 5554 # return from suspend 5528 # return from suspend 5555 pprint('RESUME COMPLETE') 5529 pprint('RESUME COMPLETE') 5556 if(count < sv.execcount): 5530 if(count < sv.execcount): 5557 sv.fsetVal(datetime.n 5531 sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker') 5558 elif(not sv.wifitrace): 5532 elif(not sv.wifitrace): 5559 sv.fsetVal(datetime.n 5533 sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker') 5560 sv.stop(pm) 5534 sv.stop(pm) 5561 if sv.wifi and wifi: 5535 if sv.wifi and wifi: 5562 tdata['wifi'] = sv.po 5536 tdata['wifi'] = sv.pollWifi(wifi) 5563 sv.dlog('wifi check, 5537 sv.dlog('wifi check, %s' % tdata['wifi']) 5564 if(count == sv.execcount and 5538 if(count == sv.execcount and sv.wifitrace): 5565 sv.fsetVal(datetime.n 5539 sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker') 5566 sv.stop(pm) 5540 sv.stop(pm) 5567 if sv.netfix: 5541 if sv.netfix: 5568 tdata['netfix'] = sv. 5542 tdata['netfix'] = sv.netfixon() 5569 sv.dlog('netfix, %s' 5543 sv.dlog('netfix, %s' % tdata['netfix']) 5570 if(sv.suspendmode == 'mem' or 5544 if(sv.suspendmode == 'mem' or sv.suspendmode == 'command'): 5571 sv.dlog('read the ACP 5545 sv.dlog('read the ACPI FPDT') 5572 tdata['fw'] = getFPDT 5546 tdata['fw'] = getFPDT(False) 5573 testdata.append(tdata) 5547 testdata.append(tdata) 5574 sv.dlog('cmdinfo after') 5548 sv.dlog('cmdinfo after') 5575 cmdafter = sv.cmdinfo(False) 5549 cmdafter = sv.cmdinfo(False) 5576 # grab a copy of the dmesg output 5550 # grab a copy of the dmesg output 5577 if not quiet: 5551 if not quiet: 5578 pprint('CAPTURING DMESG') 5552 pprint('CAPTURING DMESG') 5579 sv.getdmesg(testdata) 5553 sv.getdmesg(testdata) 5580 # grab a copy of the ftrace output 5554 # grab a copy of the ftrace output 5581 if sv.useftrace: 5555 if sv.useftrace: 5582 if not quiet: 5556 if not quiet: 5583 pprint('CAPTURING TRA 5557 pprint('CAPTURING TRACE') 5584 op = sv.writeDatafileHeader(s 5558 op = sv.writeDatafileHeader(sv.ftracefile, testdata) 5585 fp = open(tp+'trace', 'rb') 5559 fp = open(tp+'trace', 'rb') 5586 op.write(ascii(fp.read())) 5560 op.write(ascii(fp.read())) 5587 op.close() 5561 op.close() 5588 sv.fsetVal('', 'trace') 5562 sv.fsetVal('', 'trace') 5589 sv.platforminfo(cmdafter) 5563 sv.platforminfo(cmdafter) 5590 5564 5591 def readFile(file): 5565 def readFile(file): 5592 if os.path.islink(file): 5566 if os.path.islink(file): 5593 return os.readlink(file).spli 5567 return os.readlink(file).split('/')[-1] 5594 else: 5568 else: 5595 return sysvals.getVal(file).s 5569 return sysvals.getVal(file).strip() 5596 5570 5597 # Function: ms2nice 5571 # Function: ms2nice 5598 # Description: 5572 # Description: 5599 # Print out a very concise time string 5573 # Print out a very concise time string in minutes and seconds 5600 # Output: 5574 # Output: 5601 # The time string, e.g. "1901m16s" 5575 # The time string, e.g. "1901m16s" 5602 def ms2nice(val): 5576 def ms2nice(val): 5603 val = int(val) 5577 val = int(val) 5604 h = val // 3600000 5578 h = val // 3600000 5605 m = (val // 60000) % 60 5579 m = (val // 60000) % 60 5606 s = (val // 1000) % 60 5580 s = (val // 1000) % 60 5607 if h > 0: 5581 if h > 0: 5608 return '%d:%02d:%02d' % (h, m 5582 return '%d:%02d:%02d' % (h, m, s) 5609 if m > 0: 5583 if m > 0: 5610 return '%02d:%02d' % (m, s) 5584 return '%02d:%02d' % (m, s) 5611 return '%ds' % s 5585 return '%ds' % s 5612 5586 5613 def yesno(val): 5587 def yesno(val): 5614 list = {'enabled':'A', 'disabled':'S' 5588 list = {'enabled':'A', 'disabled':'S', 'auto':'E', 'on':'D', 5615 'active':'A', 'suspended':'S' 5589 'active':'A', 'suspended':'S', 'suspending':'S'} 5616 if val not in list: 5590 if val not in list: 5617 return ' ' 5591 return ' ' 5618 return list[val] 5592 return list[val] 5619 5593 5620 # Function: deviceInfo 5594 # Function: deviceInfo 5621 # Description: 5595 # Description: 5622 # Detect all the USB hosts and devices 5596 # Detect all the USB hosts and devices currently connected and add 5623 # a list of USB device names to sysval 5597 # a list of USB device names to sysvals for better timeline readability 5624 def deviceInfo(output=''): 5598 def deviceInfo(output=''): 5625 if not output: 5599 if not output: 5626 pprint('LEGEND\n'\ 5600 pprint('LEGEND\n'\ 5627 '---------------------------- 5601 '---------------------------------------------------------------------------------------------\n'\ 5628 ' A = async/sync PM queue (A 5602 ' A = async/sync PM queue (A/S) C = runtime active children\n'\ 5629 ' R = runtime suspend enable 5603 ' R = runtime suspend enabled/disabled (E/D) rACTIVE = runtime active (min/sec)\n'\ 5630 ' S = runtime status active/ 5604 ' S = runtime status active/suspended (A/S) rSUSPEND = runtime suspend (min/sec)\n'\ 5631 ' U = runtime usage count\n' 5605 ' U = runtime usage count\n'\ 5632 '---------------------------- 5606 '---------------------------------------------------------------------------------------------\n'\ 5633 'DEVICE N 5607 'DEVICE NAME A R S U C rACTIVE rSUSPEND\n'\ 5634 '---------------------------- 5608 '---------------------------------------------------------------------------------------------') 5635 5609 5636 res = [] 5610 res = [] 5637 tgtval = 'runtime_status' 5611 tgtval = 'runtime_status' 5638 lines = dict() 5612 lines = dict() 5639 for dirname, dirnames, filenames in o 5613 for dirname, dirnames, filenames in os.walk('/sys/devices'): 5640 if(not re.match(r'.*/power', !! 5614 if(not re.match('.*/power', dirname) or 5641 'control' not in file 5615 'control' not in filenames or 5642 tgtval not in filenam 5616 tgtval not in filenames): 5643 continue 5617 continue 5644 name = '' 5618 name = '' 5645 dirname = dirname[:-6] 5619 dirname = dirname[:-6] 5646 device = dirname.split('/')[- 5620 device = dirname.split('/')[-1] 5647 power = dict() 5621 power = dict() 5648 power[tgtval] = readFile('%s/ 5622 power[tgtval] = readFile('%s/power/%s' % (dirname, tgtval)) 5649 # only list devices which sup 5623 # only list devices which support runtime suspend 5650 if power[tgtval] not in ['act 5624 if power[tgtval] not in ['active', 'suspended', 'suspending']: 5651 continue 5625 continue 5652 for i in ['product', 'driver' 5626 for i in ['product', 'driver', 'subsystem']: 5653 file = '%s/%s' % (dir 5627 file = '%s/%s' % (dirname, i) 5654 if os.path.exists(fil 5628 if os.path.exists(file): 5655 name = readFi 5629 name = readFile(file) 5656 break 5630 break 5657 for i in ['async', 'control', 5631 for i in ['async', 'control', 'runtime_status', 'runtime_usage', 5658 'runtime_active_kids' 5632 'runtime_active_kids', 'runtime_active_time', 5659 'runtime_suspended_ti 5633 'runtime_suspended_time']: 5660 if i in filenames: 5634 if i in filenames: 5661 power[i] = re 5635 power[i] = readFile('%s/power/%s' % (dirname, i)) 5662 if output: 5636 if output: 5663 if power['control'] = 5637 if power['control'] == output: 5664 res.append('% 5638 res.append('%s/power/control' % dirname) 5665 continue 5639 continue 5666 lines[dirname] = '%-26s %-26s 5640 lines[dirname] = '%-26s %-26s %1s %1s %1s %1s %1s %10s %10s' % \ 5667 (device[:26], name[:2 5641 (device[:26], name[:26], 5668 yesno(power['async']) 5642 yesno(power['async']), \ 5669 yesno(power['control' 5643 yesno(power['control']), \ 5670 yesno(power['runtime_ 5644 yesno(power['runtime_status']), \ 5671 power['runtime_usage' 5645 power['runtime_usage'], \ 5672 power['runtime_active 5646 power['runtime_active_kids'], \ 5673 ms2nice(power['runtim 5647 ms2nice(power['runtime_active_time']), \ 5674 ms2nice(power['runtim 5648 ms2nice(power['runtime_suspended_time'])) 5675 for i in sorted(lines): 5649 for i in sorted(lines): 5676 print(lines[i]) 5650 print(lines[i]) 5677 return res 5651 return res 5678 5652 5679 # Function: getModes 5653 # Function: getModes 5680 # Description: 5654 # Description: 5681 # Determine the supported power modes 5655 # Determine the supported power modes on this system 5682 # Output: 5656 # Output: 5683 # A string list of the available modes 5657 # A string list of the available modes 5684 def getModes(): 5658 def getModes(): 5685 modes = [] 5659 modes = [] 5686 if(os.path.exists(sysvals.powerfile)) 5660 if(os.path.exists(sysvals.powerfile)): 5687 fp = open(sysvals.powerfile, 5661 fp = open(sysvals.powerfile, 'r') 5688 modes = fp.read().split() 5662 modes = fp.read().split() 5689 fp.close() 5663 fp.close() 5690 if(os.path.exists(sysvals.mempowerfil 5664 if(os.path.exists(sysvals.mempowerfile)): 5691 deep = False 5665 deep = False 5692 fp = open(sysvals.mempowerfil 5666 fp = open(sysvals.mempowerfile, 'r') 5693 for m in fp.read().split(): 5667 for m in fp.read().split(): 5694 memmode = m.strip('[] 5668 memmode = m.strip('[]') 5695 if memmode == 'deep': 5669 if memmode == 'deep': 5696 deep = True 5670 deep = True 5697 else: 5671 else: 5698 modes.append( 5672 modes.append('mem-%s' % memmode) 5699 fp.close() 5673 fp.close() 5700 if 'mem' in modes and not dee 5674 if 'mem' in modes and not deep: 5701 modes.remove('mem') 5675 modes.remove('mem') 5702 if('disk' in modes and os.path.exists 5676 if('disk' in modes and os.path.exists(sysvals.diskpowerfile)): 5703 fp = open(sysvals.diskpowerfi 5677 fp = open(sysvals.diskpowerfile, 'r') 5704 for m in fp.read().split(): 5678 for m in fp.read().split(): 5705 modes.append('disk-%s 5679 modes.append('disk-%s' % m.strip('[]')) 5706 fp.close() 5680 fp.close() 5707 return modes 5681 return modes 5708 5682 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 5683 # Function: dmidecode 5744 # Description: 5684 # Description: 5745 # Read the bios tables and pull out sy 5685 # Read the bios tables and pull out system info 5746 # Arguments: 5686 # Arguments: 5747 # mempath: /dev/mem or custom mem path 5687 # mempath: /dev/mem or custom mem path 5748 # fatal: True to exit on error, False 5688 # fatal: True to exit on error, False to return empty dict 5749 # Output: 5689 # Output: 5750 # A dict object with all available key 5690 # A dict object with all available key/values 5751 def dmidecode(mempath, fatal=False): 5691 def dmidecode(mempath, fatal=False): 5752 out = dict() 5692 out = dict() 5753 if(not (os.path.exists(mempath) and o << 5754 return dmidecode_backup(out, << 5755 5693 5756 # the list of values to retrieve, wit 5694 # the list of values to retrieve, with hardcoded (type, idx) 5757 info = { 5695 info = { 5758 'bios-vendor': (0, 4), 5696 'bios-vendor': (0, 4), 5759 'bios-version': (0, 5), 5697 'bios-version': (0, 5), 5760 'bios-release-date': (0, 8), 5698 'bios-release-date': (0, 8), 5761 'system-manufacturer': (1, 4) 5699 'system-manufacturer': (1, 4), 5762 'system-product-name': (1, 5) 5700 'system-product-name': (1, 5), 5763 'system-version': (1, 6), 5701 'system-version': (1, 6), 5764 'system-serial-number': (1, 7 5702 'system-serial-number': (1, 7), 5765 'baseboard-manufacturer': (2, 5703 'baseboard-manufacturer': (2, 4), 5766 'baseboard-product-name': (2, 5704 'baseboard-product-name': (2, 5), 5767 'baseboard-version': (2, 6), 5705 'baseboard-version': (2, 6), 5768 'baseboard-serial-number': (2 5706 'baseboard-serial-number': (2, 7), 5769 'chassis-manufacturer': (3, 4 5707 'chassis-manufacturer': (3, 4), >> 5708 'chassis-type': (3, 5), 5770 'chassis-version': (3, 6), 5709 'chassis-version': (3, 6), 5771 'chassis-serial-number': (3, 5710 'chassis-serial-number': (3, 7), 5772 'processor-manufacturer': (4, 5711 'processor-manufacturer': (4, 7), 5773 'processor-version': (4, 16), 5712 'processor-version': (4, 16), 5774 } 5713 } >> 5714 if(not os.path.exists(mempath)): >> 5715 if(fatal): >> 5716 doError('file does not exist: %s' % mempath) >> 5717 return out >> 5718 if(not os.access(mempath, os.R_OK)): >> 5719 if(fatal): >> 5720 doError('file is not readable: %s' % mempath) >> 5721 return out 5775 5722 5776 # by default use legacy scan, but try 5723 # by default use legacy scan, but try to use EFI first 5777 memaddr, memsize = 0xf0000, 0x10000 !! 5724 memaddr = 0xf0000 >> 5725 memsize = 0x10000 5778 for ep in ['/sys/firmware/efi/systab' 5726 for ep in ['/sys/firmware/efi/systab', '/proc/efi/systab']: 5779 if not os.path.exists(ep) or 5727 if not os.path.exists(ep) or not os.access(ep, os.R_OK): 5780 continue 5728 continue 5781 fp = open(ep, 'r') 5729 fp = open(ep, 'r') 5782 buf = fp.read() 5730 buf = fp.read() 5783 fp.close() 5731 fp.close() 5784 i = buf.find('SMBIOS=') 5732 i = buf.find('SMBIOS=') 5785 if i >= 0: 5733 if i >= 0: 5786 try: 5734 try: 5787 memaddr = int 5735 memaddr = int(buf[i+7:], 16) 5788 memsize = 0x2 5736 memsize = 0x20 5789 except: 5737 except: 5790 continue 5738 continue 5791 5739 5792 # read in the memory for scanning 5740 # read in the memory for scanning 5793 try: 5741 try: 5794 fp = open(mempath, 'rb') 5742 fp = open(mempath, 'rb') 5795 fp.seek(memaddr) 5743 fp.seek(memaddr) 5796 buf = fp.read(memsize) 5744 buf = fp.read(memsize) 5797 except: 5745 except: 5798 return dmidecode_backup(out, !! 5746 if(fatal): >> 5747 doError('DMI table is unreachable, sorry') >> 5748 else: >> 5749 pprint('WARNING: /dev/mem is not readable, ignoring DMI data') >> 5750 return out 5799 fp.close() 5751 fp.close() 5800 5752 5801 # search for either an SM table or DM 5753 # search for either an SM table or DMI table 5802 i = base = length = num = 0 5754 i = base = length = num = 0 5803 while(i < memsize): 5755 while(i < memsize): 5804 if buf[i:i+4] == b'_SM_' and 5756 if buf[i:i+4] == b'_SM_' and i < memsize - 16: 5805 length = struct.unpac 5757 length = struct.unpack('H', buf[i+22:i+24])[0] 5806 base, num = struct.un 5758 base, num = struct.unpack('IH', buf[i+24:i+30]) 5807 break 5759 break 5808 elif buf[i:i+5] == b'_DMI_': 5760 elif buf[i:i+5] == b'_DMI_': 5809 length = struct.unpac 5761 length = struct.unpack('H', buf[i+6:i+8])[0] 5810 base, num = struct.un 5762 base, num = struct.unpack('IH', buf[i+8:i+14]) 5811 break 5763 break 5812 i += 16 5764 i += 16 5813 if base == 0 and length == 0 and num 5765 if base == 0 and length == 0 and num == 0: 5814 return dmidecode_backup(out, !! 5766 if(fatal): >> 5767 doError('Neither SMBIOS nor DMI were found') >> 5768 else: >> 5769 return out 5815 5770 5816 # read in the SM or DMI table 5771 # read in the SM or DMI table 5817 try: 5772 try: 5818 fp = open(mempath, 'rb') 5773 fp = open(mempath, 'rb') 5819 fp.seek(base) 5774 fp.seek(base) 5820 buf = fp.read(length) 5775 buf = fp.read(length) 5821 except: 5776 except: 5822 return dmidecode_backup(out, !! 5777 if(fatal): >> 5778 doError('DMI table is unreachable, sorry') >> 5779 else: >> 5780 pprint('WARNING: /dev/mem is not readable, ignoring DMI data') >> 5781 return out 5823 fp.close() 5782 fp.close() 5824 5783 5825 # scan the table for the values we wa 5784 # scan the table for the values we want 5826 count = i = 0 5785 count = i = 0 5827 while(count < num and i <= len(buf) - 5786 while(count < num and i <= len(buf) - 4): 5828 type, size, handle = struct.u 5787 type, size, handle = struct.unpack('BBH', buf[i:i+4]) 5829 n = i + size 5788 n = i + size 5830 while n < len(buf) - 1: 5789 while n < len(buf) - 1: 5831 if 0 == struct.unpack 5790 if 0 == struct.unpack('H', buf[n:n+2])[0]: 5832 break 5791 break 5833 n += 1 5792 n += 1 5834 data = buf[i+size:n+2].split( 5793 data = buf[i+size:n+2].split(b'\0') 5835 for name in info: 5794 for name in info: 5836 itype, idxadr = info[ 5795 itype, idxadr = info[name] 5837 if itype == type: 5796 if itype == type: 5838 idx = struct. 5797 idx = struct.unpack('B', buf[i+idxadr:i+idxadr+1])[0] 5839 if idx > 0 an 5798 if idx > 0 and idx < len(data) - 1: 5840 s = d 5799 s = data[idx-1].decode('utf-8') 5841 if s. 5800 if s.strip() and s.strip().lower() != 'to be filled by o.e.m.': 5842 5801 out[name] = s 5843 i = n + 2 5802 i = n + 2 5844 count += 1 5803 count += 1 5845 return out 5804 return out 5846 5805 5847 # Function: getFPDT 5806 # Function: getFPDT 5848 # Description: 5807 # Description: 5849 # Read the acpi bios tables and pull o 5808 # Read the acpi bios tables and pull out FPDT, the firmware data 5850 # Arguments: 5809 # Arguments: 5851 # output: True to output the info to s 5810 # output: True to output the info to stdout, False otherwise 5852 def getFPDT(output): 5811 def getFPDT(output): 5853 rectype = {} 5812 rectype = {} 5854 rectype[0] = 'Firmware Basic Boot Per 5813 rectype[0] = 'Firmware Basic Boot Performance Record' 5855 rectype[1] = 'S3 Performance Table Re 5814 rectype[1] = 'S3 Performance Table Record' 5856 prectype = {} 5815 prectype = {} 5857 prectype[0] = 'Basic S3 Resume Perfor 5816 prectype[0] = 'Basic S3 Resume Performance Record' 5858 prectype[1] = 'Basic S3 Suspend Perfo 5817 prectype[1] = 'Basic S3 Suspend Performance Record' 5859 5818 5860 sysvals.rootCheck(True) 5819 sysvals.rootCheck(True) 5861 if(not os.path.exists(sysvals.fpdtpat 5820 if(not os.path.exists(sysvals.fpdtpath)): 5862 if(output): 5821 if(output): 5863 doError('file does no 5822 doError('file does not exist: %s' % sysvals.fpdtpath) 5864 return False 5823 return False 5865 if(not os.access(sysvals.fpdtpath, os 5824 if(not os.access(sysvals.fpdtpath, os.R_OK)): 5866 if(output): 5825 if(output): 5867 doError('file is not 5826 doError('file is not readable: %s' % sysvals.fpdtpath) 5868 return False 5827 return False 5869 if(not os.path.exists(sysvals.mempath 5828 if(not os.path.exists(sysvals.mempath)): 5870 if(output): 5829 if(output): 5871 doError('file does no 5830 doError('file does not exist: %s' % sysvals.mempath) 5872 return False 5831 return False 5873 if(not os.access(sysvals.mempath, os. 5832 if(not os.access(sysvals.mempath, os.R_OK)): 5874 if(output): 5833 if(output): 5875 doError('file is not 5834 doError('file is not readable: %s' % sysvals.mempath) 5876 return False 5835 return False 5877 5836 5878 fp = open(sysvals.fpdtpath, 'rb') 5837 fp = open(sysvals.fpdtpath, 'rb') 5879 buf = fp.read() 5838 buf = fp.read() 5880 fp.close() 5839 fp.close() 5881 5840 5882 if(len(buf) < 36): 5841 if(len(buf) < 36): 5883 if(output): 5842 if(output): 5884 doError('Invalid FPDT 5843 doError('Invalid FPDT table data, should '+\ 5885 'be at least 5844 'be at least 36 bytes') 5886 return False 5845 return False 5887 5846 5888 table = struct.unpack('4sIBB6s8sI4sI' 5847 table = struct.unpack('4sIBB6s8sI4sI', buf[0:36]) 5889 if(output): 5848 if(output): 5890 pprint('\n'\ 5849 pprint('\n'\ 5891 'Firmware Performance Data Ta 5850 'Firmware Performance Data Table (%s)\n'\ 5892 ' Signature 5851 ' Signature : %s\n'\ 5893 ' Table Length 5852 ' Table Length : %u\n'\ 5894 ' Revision 5853 ' Revision : %u\n'\ 5895 ' Checksum 5854 ' Checksum : 0x%x\n'\ 5896 ' OEM ID 5855 ' OEM ID : %s\n'\ 5897 ' OEM Table ID 5856 ' OEM Table ID : %s\n'\ 5898 ' OEM Revision 5857 ' OEM Revision : %u\n'\ 5899 ' Creator ID 5858 ' Creator ID : %s\n'\ 5900 ' Creator Revision 5859 ' Creator Revision : 0x%x\n'\ 5901 '' % (ascii(table[0]), ascii( 5860 '' % (ascii(table[0]), ascii(table[0]), table[1], table[2], 5902 table[3], ascii(table 5861 table[3], ascii(table[4]), ascii(table[5]), table[6], 5903 ascii(table[7]), tabl 5862 ascii(table[7]), table[8])) 5904 5863 5905 if(table[0] != b'FPDT'): 5864 if(table[0] != b'FPDT'): 5906 if(output): 5865 if(output): 5907 doError('Invalid FPDT 5866 doError('Invalid FPDT table') 5908 return False 5867 return False 5909 if(len(buf) <= 36): 5868 if(len(buf) <= 36): 5910 return False 5869 return False 5911 i = 0 5870 i = 0 5912 fwData = [0, 0] 5871 fwData = [0, 0] 5913 records = buf[36:] 5872 records = buf[36:] 5914 try: 5873 try: 5915 fp = open(sysvals.mempath, 'r 5874 fp = open(sysvals.mempath, 'rb') 5916 except: 5875 except: 5917 pprint('WARNING: /dev/mem is 5876 pprint('WARNING: /dev/mem is not readable, ignoring the FPDT data') 5918 return False 5877 return False 5919 while(i < len(records)): 5878 while(i < len(records)): 5920 header = struct.unpack('HBB', 5879 header = struct.unpack('HBB', records[i:i+4]) 5921 if(header[0] not in rectype): 5880 if(header[0] not in rectype): 5922 i += header[1] 5881 i += header[1] 5923 continue 5882 continue 5924 if(header[1] != 16): 5883 if(header[1] != 16): 5925 i += header[1] 5884 i += header[1] 5926 continue 5885 continue 5927 addr = struct.unpack('Q', rec 5886 addr = struct.unpack('Q', records[i+8:i+16])[0] 5928 try: 5887 try: 5929 fp.seek(addr) 5888 fp.seek(addr) 5930 first = fp.read(8) 5889 first = fp.read(8) 5931 except: 5890 except: 5932 if(output): 5891 if(output): 5933 pprint('Bad a 5892 pprint('Bad address 0x%x in %s' % (addr, sysvals.mempath)) 5934 return [0, 0] 5893 return [0, 0] 5935 rechead = struct.unpack('4sI' 5894 rechead = struct.unpack('4sI', first) 5936 recdata = fp.read(rechead[1]- 5895 recdata = fp.read(rechead[1]-8) 5937 if(rechead[0] == b'FBPT'): 5896 if(rechead[0] == b'FBPT'): 5938 record = struct.unpac 5897 record = struct.unpack('HBBIQQQQQ', recdata[:48]) 5939 if(output): 5898 if(output): 5940 pprint('%s (% 5899 pprint('%s (%s)\n'\ 5941 ' 5900 ' Reset END : %u ns\n'\ 5942 ' OS Loader 5901 ' OS Loader LoadImage Start : %u ns\n'\ 5943 ' OS Loader S 5902 ' OS Loader StartImage Start : %u ns\n'\ 5944 ' ExitBoo 5903 ' ExitBootServices Entry : %u ns\n'\ 5945 ' ExitBo 5904 ' ExitBootServices Exit : %u ns'\ 5946 '' % (rectype 5905 '' % (rectype[header[0]], ascii(rechead[0]), record[4], record[5], 5947 recor 5906 record[6], record[7], record[8])) 5948 elif(rechead[0] == b'S3PT'): 5907 elif(rechead[0] == b'S3PT'): 5949 if(output): 5908 if(output): 5950 pprint('%s (% 5909 pprint('%s (%s)' % (rectype[header[0]], ascii(rechead[0]))) 5951 j = 0 5910 j = 0 5952 while(j < len(recdata 5911 while(j < len(recdata)): 5953 prechead = st 5912 prechead = struct.unpack('HBB', recdata[j:j+4]) 5954 if(prechead[0 5913 if(prechead[0] not in prectype): 5955 conti 5914 continue 5956 if(prechead[0 5915 if(prechead[0] == 0): 5957 recor 5916 record = struct.unpack('IIQQ', recdata[j:j+prechead[1]]) 5958 fwDat 5917 fwData[1] = record[2] 5959 if(ou 5918 if(output): 5960 5919 pprint(' %s\n'\ 5961 5920 ' Resume Count : %u\n'\ 5962 5921 ' FullResume : %u ns\n'\ 5963 5922 ' AverageResume : %u ns'\ 5964 5923 '' % (prectype[prechead[0]], record[1], 5965 5924 record[2], record[3])) 5966 elif(prechead 5925 elif(prechead[0] == 1): 5967 recor 5926 record = struct.unpack('QQ', recdata[j+4:j+prechead[1]]) 5968 fwDat 5927 fwData[0] = record[1] - record[0] 5969 if(ou 5928 if(output): 5970 5929 pprint(' %s\n'\ 5971 5930 ' SuspendStart : %u ns\n'\ 5972 5931 ' SuspendEnd : %u ns\n'\ 5973 5932 ' SuspendTime : %u ns'\ 5974 5933 '' % (prectype[prechead[0]], record[0], 5975 5934 record[1], fwData[0])) 5976 5935 5977 j += prechead 5936 j += prechead[1] 5978 if(output): 5937 if(output): 5979 pprint('') 5938 pprint('') 5980 i += header[1] 5939 i += header[1] 5981 fp.close() 5940 fp.close() 5982 return fwData 5941 return fwData 5983 5942 5984 # Function: statusCheck 5943 # Function: statusCheck 5985 # Description: 5944 # Description: 5986 # Verify that the requested command an 5945 # Verify that the requested command and options will work, and 5987 # print the results to the terminal 5946 # print the results to the terminal 5988 # Output: 5947 # Output: 5989 # True if the test will work, False if 5948 # True if the test will work, False if not 5990 def statusCheck(probecheck=False): 5949 def statusCheck(probecheck=False): 5991 status = '' 5950 status = '' 5992 5951 5993 pprint('Checking this system (%s)...' 5952 pprint('Checking this system (%s)...' % platform.node()) 5994 5953 5995 # check we have root access 5954 # check we have root access 5996 res = sysvals.colorText('NO (No featu 5955 res = sysvals.colorText('NO (No features of this tool will work!)') 5997 if(sysvals.rootCheck(False)): 5956 if(sysvals.rootCheck(False)): 5998 res = 'YES' 5957 res = 'YES' 5999 pprint(' have root access: %s' % r 5958 pprint(' have root access: %s' % res) 6000 if(res != 'YES'): 5959 if(res != 'YES'): 6001 pprint(' Try running this 5960 pprint(' Try running this script with sudo') 6002 return 'missing root access' 5961 return 'missing root access' 6003 5962 6004 # check sysfs is mounted 5963 # check sysfs is mounted 6005 res = sysvals.colorText('NO (No featu 5964 res = sysvals.colorText('NO (No features of this tool will work!)') 6006 if(os.path.exists(sysvals.powerfile)) 5965 if(os.path.exists(sysvals.powerfile)): 6007 res = 'YES' 5966 res = 'YES' 6008 pprint(' is sysfs mounted: %s' % r 5967 pprint(' is sysfs mounted: %s' % res) 6009 if(res != 'YES'): 5968 if(res != 'YES'): 6010 return 'sysfs is missing' 5969 return 'sysfs is missing' 6011 5970 6012 # check target mode is a valid mode 5971 # check target mode is a valid mode 6013 if sysvals.suspendmode != 'command': 5972 if sysvals.suspendmode != 'command': 6014 res = sysvals.colorText('NO') 5973 res = sysvals.colorText('NO') 6015 modes = getModes() 5974 modes = getModes() 6016 if(sysvals.suspendmode in mod 5975 if(sysvals.suspendmode in modes): 6017 res = 'YES' 5976 res = 'YES' 6018 else: 5977 else: 6019 status = '%s mode is 5978 status = '%s mode is not supported' % sysvals.suspendmode 6020 pprint(' is "%s" a valid p 5979 pprint(' is "%s" a valid power mode: %s' % (sysvals.suspendmode, res)) 6021 if(res == 'NO'): 5980 if(res == 'NO'): 6022 pprint(' valid p 5981 pprint(' valid power modes are: %s' % modes) 6023 pprint(' please 5982 pprint(' please choose one with -m') 6024 5983 6025 # check if ftrace is available 5984 # check if ftrace is available 6026 if sysvals.useftrace: 5985 if sysvals.useftrace: 6027 res = sysvals.colorText('NO') 5986 res = sysvals.colorText('NO') 6028 sysvals.useftrace = sysvals.v 5987 sysvals.useftrace = sysvals.verifyFtrace() 6029 efmt = '"{0}" uses ftrace, an 5988 efmt = '"{0}" uses ftrace, and it is not properly supported' 6030 if sysvals.useftrace: 5989 if sysvals.useftrace: 6031 res = 'YES' 5990 res = 'YES' 6032 elif sysvals.usecallgraph: 5991 elif sysvals.usecallgraph: 6033 status = efmt.format( 5992 status = efmt.format('-f') 6034 elif sysvals.usedevsrc: 5993 elif sysvals.usedevsrc: 6035 status = efmt.format( 5994 status = efmt.format('-dev') 6036 elif sysvals.useprocmon: 5995 elif sysvals.useprocmon: 6037 status = efmt.format( 5996 status = efmt.format('-proc') 6038 pprint(' is ftrace support 5997 pprint(' is ftrace supported: %s' % res) 6039 5998 6040 # check if kprobes are available 5999 # check if kprobes are available 6041 if sysvals.usekprobes: 6000 if sysvals.usekprobes: 6042 res = sysvals.colorText('NO') 6001 res = sysvals.colorText('NO') 6043 sysvals.usekprobes = sysvals. 6002 sysvals.usekprobes = sysvals.verifyKprobes() 6044 if(sysvals.usekprobes): 6003 if(sysvals.usekprobes): 6045 res = 'YES' 6004 res = 'YES' 6046 else: 6005 else: 6047 sysvals.usedevsrc = F 6006 sysvals.usedevsrc = False 6048 pprint(' are kprobes suppo 6007 pprint(' are kprobes supported: %s' % res) 6049 6008 6050 # what data source are we using 6009 # what data source are we using 6051 res = 'DMESG (very limited, ftrace is 6010 res = 'DMESG (very limited, ftrace is preferred)' 6052 if sysvals.useftrace: 6011 if sysvals.useftrace: 6053 sysvals.usetraceevents = True 6012 sysvals.usetraceevents = True 6054 for e in sysvals.traceevents: 6013 for e in sysvals.traceevents: 6055 if not os.path.exists 6014 if not os.path.exists(sysvals.epath+e): 6056 sysvals.usetr 6015 sysvals.usetraceevents = False 6057 if(sysvals.usetraceevents): 6016 if(sysvals.usetraceevents): 6058 res = 'FTRACE (all tr 6017 res = 'FTRACE (all trace events found)' 6059 pprint(' timeline data source: %s' 6018 pprint(' timeline data source: %s' % res) 6060 6019 6061 # check if rtcwake 6020 # check if rtcwake 6062 res = sysvals.colorText('NO') 6021 res = sysvals.colorText('NO') 6063 if(sysvals.rtcpath != ''): 6022 if(sysvals.rtcpath != ''): 6064 res = 'YES' 6023 res = 'YES' 6065 elif(sysvals.rtcwake): 6024 elif(sysvals.rtcwake): 6066 status = 'rtcwake is not prop 6025 status = 'rtcwake is not properly supported' 6067 pprint(' is rtcwake supported: %s' 6026 pprint(' is rtcwake supported: %s' % res) 6068 6027 6069 # check info commands 6028 # check info commands 6070 pprint(' optional commands this to 6029 pprint(' optional commands this tool may use for info:') 6071 no = sysvals.colorText('MISSING') 6030 no = sysvals.colorText('MISSING') 6072 yes = sysvals.colorText('FOUND', 32) 6031 yes = sysvals.colorText('FOUND', 32) 6073 for c in ['turbostat', 'mcelog', 'lsp 6032 for c in ['turbostat', 'mcelog', 'lspci', 'lsusb', 'netfix']: 6074 if c == 'turbostat': 6033 if c == 'turbostat': 6075 res = yes if sysvals. 6034 res = yes if sysvals.haveTurbostat() else no 6076 else: 6035 else: 6077 res = yes if sysvals. 6036 res = yes if sysvals.getExec(c) else no 6078 pprint(' %s: %s' % (c, 6037 pprint(' %s: %s' % (c, res)) 6079 6038 6080 if not probecheck: 6039 if not probecheck: 6081 return status 6040 return status 6082 6041 6083 # verify kprobes 6042 # verify kprobes 6084 if sysvals.usekprobes: 6043 if sysvals.usekprobes: 6085 for name in sysvals.tracefunc 6044 for name in sysvals.tracefuncs: 6086 sysvals.defaultKprobe 6045 sysvals.defaultKprobe(name, sysvals.tracefuncs[name]) 6087 if sysvals.usedevsrc: 6046 if sysvals.usedevsrc: 6088 for name in sysvals.d 6047 for name in sysvals.dev_tracefuncs: 6089 sysvals.defau 6048 sysvals.defaultKprobe(name, sysvals.dev_tracefuncs[name]) 6090 sysvals.addKprobes(True) 6049 sysvals.addKprobes(True) 6091 6050 6092 return status 6051 return status 6093 6052 6094 # Function: doError 6053 # Function: doError 6095 # Description: 6054 # Description: 6096 # generic error function for catastrph 6055 # generic error function for catastrphic failures 6097 # Arguments: 6056 # Arguments: 6098 # msg: the error message to print 6057 # msg: the error message to print 6099 # help: True if printHelp should be ca 6058 # help: True if printHelp should be called after, False otherwise 6100 def doError(msg, help=False): 6059 def doError(msg, help=False): 6101 if(help == True): 6060 if(help == True): 6102 printHelp() 6061 printHelp() 6103 pprint('ERROR: %s\n' % msg) 6062 pprint('ERROR: %s\n' % msg) 6104 sysvals.outputResult({'error':msg}) 6063 sysvals.outputResult({'error':msg}) 6105 sys.exit(1) 6064 sys.exit(1) 6106 6065 6107 # Function: getArgInt 6066 # Function: getArgInt 6108 # Description: 6067 # Description: 6109 # pull out an integer argument from th 6068 # pull out an integer argument from the command line with checks 6110 def getArgInt(name, args, min, max, main=True 6069 def getArgInt(name, args, min, max, main=True): 6111 if main: 6070 if main: 6112 try: 6071 try: 6113 arg = next(args) 6072 arg = next(args) 6114 except: 6073 except: 6115 doError(name+': no ar 6074 doError(name+': no argument supplied', True) 6116 else: 6075 else: 6117 arg = args 6076 arg = args 6118 try: 6077 try: 6119 val = int(arg) 6078 val = int(arg) 6120 except: 6079 except: 6121 doError(name+': non-integer v 6080 doError(name+': non-integer value given', True) 6122 if(val < min or val > max): 6081 if(val < min or val > max): 6123 doError(name+': value should 6082 doError(name+': value should be between %d and %d' % (min, max), True) 6124 return val 6083 return val 6125 6084 6126 # Function: getArgFloat 6085 # Function: getArgFloat 6127 # Description: 6086 # Description: 6128 # pull out a float argument from the c 6087 # pull out a float argument from the command line with checks 6129 def getArgFloat(name, args, min, max, main=Tr 6088 def getArgFloat(name, args, min, max, main=True): 6130 if main: 6089 if main: 6131 try: 6090 try: 6132 arg = next(args) 6091 arg = next(args) 6133 except: 6092 except: 6134 doError(name+': no ar 6093 doError(name+': no argument supplied', True) 6135 else: 6094 else: 6136 arg = args 6095 arg = args 6137 try: 6096 try: 6138 val = float(arg) 6097 val = float(arg) 6139 except: 6098 except: 6140 doError(name+': non-numerical 6099 doError(name+': non-numerical value given', True) 6141 if(val < min or val > max): 6100 if(val < min or val > max): 6142 doError(name+': value should 6101 doError(name+': value should be between %f and %f' % (min, max), True) 6143 return val 6102 return val 6144 6103 6145 def processData(live=False, quiet=False): 6104 def processData(live=False, quiet=False): 6146 if not quiet: 6105 if not quiet: 6147 pprint('PROCESSING: %s' % sys 6106 pprint('PROCESSING: %s' % sysvals.htmlfile) 6148 sysvals.vprint('usetraceevents=%s, us 6107 sysvals.vprint('usetraceevents=%s, usetracemarkers=%s, usekprobes=%s' % \ 6149 (sysvals.usetraceevents, sysv 6108 (sysvals.usetraceevents, sysvals.usetracemarkers, sysvals.usekprobes)) 6150 error = '' 6109 error = '' 6151 if(sysvals.usetraceevents): 6110 if(sysvals.usetraceevents): 6152 testruns, error = parseTraceL 6111 testruns, error = parseTraceLog(live) 6153 if sysvals.dmesgfile: 6112 if sysvals.dmesgfile: 6154 for data in testruns: 6113 for data in testruns: 6155 data.extractE 6114 data.extractErrorInfo() 6156 else: 6115 else: 6157 testruns = loadKernelLog() 6116 testruns = loadKernelLog() 6158 for data in testruns: 6117 for data in testruns: 6159 parseKernelLog(data) 6118 parseKernelLog(data) 6160 if(sysvals.ftracefile and (sy 6119 if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): 6161 appendIncompleteTrace 6120 appendIncompleteTraceLog(testruns) 6162 if not sysvals.stamp: 6121 if not sysvals.stamp: 6163 pprint('ERROR: data does not 6122 pprint('ERROR: data does not include the expected stamp') 6164 return (testruns, {'error': ' 6123 return (testruns, {'error': 'timeline generation failed'}) 6165 shown = ['os', 'bios', 'biosdate', 'c 6124 shown = ['os', 'bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr', 6166 'memsz', 'mode', 'num 6125 'memsz', 'mode', 'numcpu', 'plat', 'time', 'wifi'] 6167 sysvals.vprint('System Info:') 6126 sysvals.vprint('System Info:') 6168 for key in sorted(sysvals.stamp): 6127 for key in sorted(sysvals.stamp): 6169 if key in shown: 6128 if key in shown: 6170 sysvals.vprint(' % 6129 sysvals.vprint(' %-8s : %s' % (key.upper(), sysvals.stamp[key])) 6171 sysvals.vprint('Command:\n %s' % s 6130 sysvals.vprint('Command:\n %s' % sysvals.cmdline) 6172 for data in testruns: 6131 for data in testruns: 6173 if data.turbostat: 6132 if data.turbostat: 6174 idx, s = 0, 'Turbosta 6133 idx, s = 0, 'Turbostat:\n ' 6175 for val in data.turbo 6134 for val in data.turbostat.split('|'): 6176 idx += len(va 6135 idx += len(val) + 1 6177 if idx >= 80: 6136 if idx >= 80: 6178 idx = 6137 idx = 0 6179 s += 6138 s += '\n ' 6180 s += val + ' 6139 s += val + ' ' 6181 sysvals.vprint(s) 6140 sysvals.vprint(s) 6182 data.printDetails() 6141 data.printDetails() 6183 if len(sysvals.platinfo) > 0: 6142 if len(sysvals.platinfo) > 0: 6184 sysvals.vprint('\nPlatform In 6143 sysvals.vprint('\nPlatform Info:') 6185 for info in sysvals.platinfo: 6144 for info in sysvals.platinfo: 6186 sysvals.vprint('[%s - 6145 sysvals.vprint('[%s - %s]' % (info[0], info[1])) 6187 sysvals.vprint(info[2 6146 sysvals.vprint(info[2]) 6188 sysvals.vprint('') 6147 sysvals.vprint('') 6189 if sysvals.cgdump: 6148 if sysvals.cgdump: 6190 for data in testruns: 6149 for data in testruns: 6191 data.debugPrint() 6150 data.debugPrint() 6192 sys.exit(0) 6151 sys.exit(0) 6193 if len(testruns) < 1: 6152 if len(testruns) < 1: 6194 pprint('ERROR: Not enough tes 6153 pprint('ERROR: Not enough test data to build a timeline') 6195 return (testruns, {'error': ' 6154 return (testruns, {'error': 'timeline generation failed'}) 6196 sysvals.vprint('Creating the html tim 6155 sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile) 6197 createHTML(testruns, error) 6156 createHTML(testruns, error) 6198 if not quiet: 6157 if not quiet: 6199 pprint('DONE: %s' % sys 6158 pprint('DONE: %s' % sysvals.htmlfile) 6200 data = testruns[0] 6159 data = testruns[0] 6201 stamp = data.stamp 6160 stamp = data.stamp 6202 stamp['suspend'], stamp['resume'] = d 6161 stamp['suspend'], stamp['resume'] = data.getTimeValues() 6203 if data.fwValid: 6162 if data.fwValid: 6204 stamp['fwsuspend'], stamp['fw 6163 stamp['fwsuspend'], stamp['fwresume'] = data.fwSuspend, data.fwResume 6205 if error: 6164 if error: 6206 stamp['error'] = error 6165 stamp['error'] = error 6207 return (testruns, stamp) 6166 return (testruns, stamp) 6208 6167 6209 # Function: rerunTest 6168 # Function: rerunTest 6210 # Description: 6169 # Description: 6211 # generate an output from an existing 6170 # generate an output from an existing set of ftrace/dmesg logs 6212 def rerunTest(htmlfile=''): 6171 def rerunTest(htmlfile=''): 6213 if sysvals.ftracefile: 6172 if sysvals.ftracefile: 6214 doesTraceLogHaveTraceEvents() 6173 doesTraceLogHaveTraceEvents() 6215 if not sysvals.dmesgfile and not sysv 6174 if not sysvals.dmesgfile and not sysvals.usetraceevents: 6216 doError('recreating this html 6175 doError('recreating this html output requires a dmesg file') 6217 if htmlfile: 6176 if htmlfile: 6218 sysvals.htmlfile = htmlfile 6177 sysvals.htmlfile = htmlfile 6219 else: 6178 else: 6220 sysvals.setOutputFile() 6179 sysvals.setOutputFile() 6221 if os.path.exists(sysvals.htmlfile): 6180 if os.path.exists(sysvals.htmlfile): 6222 if not os.path.isfile(sysvals 6181 if not os.path.isfile(sysvals.htmlfile): 6223 doError('a directory 6182 doError('a directory already exists with this name: %s' % sysvals.htmlfile) 6224 elif not os.access(sysvals.ht 6183 elif not os.access(sysvals.htmlfile, os.W_OK): 6225 doError('missing perm 6184 doError('missing permission to write to %s' % sysvals.htmlfile) 6226 testruns, stamp = processData() 6185 testruns, stamp = processData() 6227 sysvals.resetlog() 6186 sysvals.resetlog() 6228 return stamp 6187 return stamp 6229 6188 6230 # Function: runTest 6189 # Function: runTest 6231 # Description: 6190 # Description: 6232 # execute a suspend/resume, gather the 6191 # execute a suspend/resume, gather the logs, and generate the output 6233 def runTest(n=0, quiet=False): 6192 def runTest(n=0, quiet=False): 6234 # prepare for the test 6193 # prepare for the test 6235 sysvals.initTestOutput('suspend') 6194 sysvals.initTestOutput('suspend') 6236 op = sysvals.writeDatafileHeader(sysv 6195 op = sysvals.writeDatafileHeader(sysvals.dmesgfile, []) 6237 op.write('# EXECUTION TRACE START\n') 6196 op.write('# EXECUTION TRACE START\n') 6238 op.close() 6197 op.close() 6239 if n <= 1: 6198 if n <= 1: 6240 if sysvals.rs != 0: 6199 if sysvals.rs != 0: 6241 sysvals.dlog('%sablin 6200 sysvals.dlog('%sabling runtime suspend' % ('en' if sysvals.rs > 0 else 'dis')) 6242 sysvals.setRuntimeSus 6201 sysvals.setRuntimeSuspend(True) 6243 if sysvals.display: 6202 if sysvals.display: 6244 ret = sysvals.display 6203 ret = sysvals.displayControl('init') 6245 sysvals.dlog('xset di 6204 sysvals.dlog('xset display init, ret = %d' % ret) 6246 sysvals.testVal(sysvals.pmdpath, 'bas 6205 sysvals.testVal(sysvals.pmdpath, 'basic', '1') 6247 sysvals.testVal(sysvals.s0ixpath, 'ba 6206 sysvals.testVal(sysvals.s0ixpath, 'basic', 'Y') 6248 sysvals.dlog('initialize ftrace') 6207 sysvals.dlog('initialize ftrace') 6249 sysvals.initFtrace(quiet) 6208 sysvals.initFtrace(quiet) 6250 6209 6251 # execute the test 6210 # execute the test 6252 executeSuspend(quiet) 6211 executeSuspend(quiet) 6253 sysvals.cleanupFtrace() 6212 sysvals.cleanupFtrace() 6254 if sysvals.skiphtml: 6213 if sysvals.skiphtml: 6255 sysvals.outputResult({}, n) 6214 sysvals.outputResult({}, n) 6256 sysvals.sudoUserchown(sysvals 6215 sysvals.sudoUserchown(sysvals.testdir) 6257 return 6216 return 6258 testruns, stamp = processData(True, q 6217 testruns, stamp = processData(True, quiet) 6259 for data in testruns: 6218 for data in testruns: 6260 del data 6219 del data 6261 sysvals.sudoUserchown(sysvals.testdir 6220 sysvals.sudoUserchown(sysvals.testdir) 6262 sysvals.outputResult(stamp, n) 6221 sysvals.outputResult(stamp, n) 6263 if 'error' in stamp: 6222 if 'error' in stamp: 6264 return 2 6223 return 2 6265 return 0 6224 return 0 6266 6225 6267 def find_in_html(html, start, end, firstonly= 6226 def find_in_html(html, start, end, firstonly=True): 6268 cnt, out, list = len(html), [], [] 6227 cnt, out, list = len(html), [], [] 6269 if firstonly: 6228 if firstonly: 6270 m = re.search(start, html) 6229 m = re.search(start, html) 6271 if m: 6230 if m: 6272 list.append(m) 6231 list.append(m) 6273 else: 6232 else: 6274 list = re.finditer(start, htm 6233 list = re.finditer(start, html) 6275 for match in list: 6234 for match in list: 6276 s = match.end() 6235 s = match.end() 6277 e = cnt if (len(out) < 1 or s 6236 e = cnt if (len(out) < 1 or s + 10000 > cnt) else s + 10000 6278 m = re.search(end, html[s:e]) 6237 m = re.search(end, html[s:e]) 6279 if not m: 6238 if not m: 6280 break 6239 break 6281 e = s + m.start() 6240 e = s + m.start() 6282 str = html[s:e] 6241 str = html[s:e] 6283 if end == 'ms': 6242 if end == 'ms': 6284 num = re.search(r'[-+ 6243 num = re.search(r'[-+]?\d*\.\d+|\d+', str) 6285 str = num.group() if 6244 str = num.group() if num else 'NaN' 6286 if firstonly: 6245 if firstonly: 6287 return str 6246 return str 6288 out.append(str) 6247 out.append(str) 6289 if firstonly: 6248 if firstonly: 6290 return '' 6249 return '' 6291 return out 6250 return out 6292 6251 6293 def data_from_html(file, outpath, issues, ful 6252 def data_from_html(file, outpath, issues, fulldetail=False): 6294 try: !! 6253 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 6254 sysvals.htmlfile = os.path.relpath(file, outpath) 6299 # extract general info 6255 # extract general info 6300 suspend = find_in_html(html, 'Kernel 6256 suspend = find_in_html(html, 'Kernel Suspend', 'ms') 6301 resume = find_in_html(html, 'Kernel R 6257 resume = find_in_html(html, 'Kernel Resume', 'ms') 6302 sysinfo = find_in_html(html, '<div cl 6258 sysinfo = find_in_html(html, '<div class="stamp sysinfo">', '</div>') 6303 line = find_in_html(html, '<div class 6259 line = find_in_html(html, '<div class="stamp">', '</div>') 6304 stmp = line.split() 6260 stmp = line.split() 6305 if not suspend or not resume or len(s 6261 if not suspend or not resume or len(stmp) != 8: 6306 return False 6262 return False 6307 try: 6263 try: 6308 dt = datetime.strptime(' '.jo 6264 dt = datetime.strptime(' '.join(stmp[3:]), '%B %d %Y, %I:%M:%S %p') 6309 except: 6265 except: 6310 return False 6266 return False 6311 sysvals.hostname = stmp[0] 6267 sysvals.hostname = stmp[0] 6312 tstr = dt.strftime('%Y/%m/%d %H:%M:%S 6268 tstr = dt.strftime('%Y/%m/%d %H:%M:%S') 6313 error = find_in_html(html, '<table cl 6269 error = find_in_html(html, '<table class="testfail"><tr><td>', '</td>') 6314 if error: 6270 if error: 6315 m = re.match(r'[a-z0-9]* fail !! 6271 m = re.match('[a-z0-9]* failed in (?P<p>\S*).*', error) 6316 if m: 6272 if m: 6317 result = 'fail in %s' 6273 result = 'fail in %s' % m.group('p') 6318 else: 6274 else: 6319 result = 'fail' 6275 result = 'fail' 6320 else: 6276 else: 6321 result = 'pass' 6277 result = 'pass' 6322 # extract error info 6278 # extract error info 6323 tp, ilist = False, [] 6279 tp, ilist = False, [] 6324 extra = dict() 6280 extra = dict() 6325 log = find_in_html(html, '<div id="dm 6281 log = find_in_html(html, '<div id="dmesglog" style="display:none;">', 6326 '</div>').strip() 6282 '</div>').strip() 6327 if log: 6283 if log: 6328 d = Data(0) 6284 d = Data(0) 6329 d.end = 999999999 6285 d.end = 999999999 6330 d.dmesgtext = log.split('\n') 6286 d.dmesgtext = log.split('\n') 6331 tp = d.extractErrorInfo() 6287 tp = d.extractErrorInfo() 6332 if len(issues) < 100: !! 6288 for msg in tp.msglist: 6333 for msg in tp.msglist !! 6289 sysvals.errorSummary(issues, msg) 6334 sysvals.error << 6335 if stmp[2] == 'freeze': 6290 if stmp[2] == 'freeze': 6336 extra = d.turbostatIn 6291 extra = d.turbostatInfo() 6337 elist = dict() 6292 elist = dict() 6338 for dir in d.errorinfo: 6293 for dir in d.errorinfo: 6339 for err in d.errorinf 6294 for err in d.errorinfo[dir]: 6340 if err[0] not 6295 if err[0] not in elist: 6341 elist 6296 elist[err[0]] = 0 6342 elist[err[0]] 6297 elist[err[0]] += 1 6343 for i in elist: 6298 for i in elist: 6344 ilist.append('%sx%d' 6299 ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i) 6345 line = find_in_html(log, '# w 6300 line = find_in_html(log, '# wifi ', '\n') 6346 if line: 6301 if line: 6347 extra['wifi'] = line 6302 extra['wifi'] = line 6348 line = find_in_html(log, '# n 6303 line = find_in_html(log, '# netfix ', '\n') 6349 if line: 6304 if line: 6350 extra['netfix'] = lin 6305 extra['netfix'] = line 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 6306 low = find_in_html(html, 'freeze time: <b>', ' ms</b>') 6357 for lowstr in ['waking', '+']: 6307 for lowstr in ['waking', '+']: 6358 if not low: 6308 if not low: 6359 break 6309 break 6360 if lowstr not in low: 6310 if lowstr not in low: 6361 continue 6311 continue 6362 if lowstr == '+': 6312 if lowstr == '+': 6363 issue = 'S2LOOPx%d' % 6313 issue = 'S2LOOPx%d' % len(low.split('+')) 6364 else: 6314 else: 6365 m = re.match(r'.*waki !! 6315 m = re.match('.*waking *(?P<n>[0-9]*) *times.*', low) 6366 issue = 'S2WAKEx%s' % 6316 issue = 'S2WAKEx%s' % m.group('n') if m else 'S2WAKExNaN' 6367 match = [i for i in issues if 6317 match = [i for i in issues if i['match'] == issue] 6368 if len(match) > 0: 6318 if len(match) > 0: 6369 match[0]['count'] += 6319 match[0]['count'] += 1 6370 if sysvals.hostname n 6320 if sysvals.hostname not in match[0]['urls']: 6371 match[0]['url 6321 match[0]['urls'][sysvals.hostname] = [sysvals.htmlfile] 6372 elif sysvals.htmlfile 6322 elif sysvals.htmlfile not in match[0]['urls'][sysvals.hostname]: 6373 match[0]['url 6323 match[0]['urls'][sysvals.hostname].append(sysvals.htmlfile) 6374 else: 6324 else: 6375 issues.append({ 6325 issues.append({ 6376 'match': issu 6326 'match': issue, 'count': 1, 'line': issue, 6377 'urls': {sysv 6327 'urls': {sysvals.hostname: [sysvals.htmlfile]}, 6378 }) 6328 }) 6379 ilist.append(issue) 6329 ilist.append(issue) 6380 # extract device info 6330 # extract device info 6381 devices = dict() 6331 devices = dict() 6382 for line in html.split('\n'): 6332 for line in html.split('\n'): 6383 m = re.match(r' *<div id=\"[a !! 6333 m = re.match(' *<div id=\"[a,0-9]*\" *title=\"(?P<title>.*)\" class=\"thread.*', line) 6384 if not m or 'thread kth' in l 6334 if not m or 'thread kth' in line or 'thread sec' in line: 6385 continue 6335 continue 6386 m = re.match(r'(?P<n>.*) \((? !! 6336 m = re.match('(?P<n>.*) \((?P<t>[0-9,\.]*) ms\) (?P<p>.*)', m.group('title')) 6387 if not m: 6337 if not m: 6388 continue 6338 continue 6389 name, time, phase = m.group(' 6339 name, time, phase = m.group('n'), m.group('t'), m.group('p') 6390 if name == 'async_synchronize 6340 if name == 'async_synchronize_full': 6391 continue 6341 continue 6392 if ' async' in name or ' sync 6342 if ' async' in name or ' sync' in name: 6393 name = ' '.join(name. 6343 name = ' '.join(name.split(' ')[:-1]) 6394 if phase.startswith('suspend' 6344 if phase.startswith('suspend'): 6395 d = 'suspend' 6345 d = 'suspend' 6396 elif phase.startswith('resume 6346 elif phase.startswith('resume'): 6397 d = 'resume' 6347 d = 'resume' 6398 else: 6348 else: 6399 continue 6349 continue 6400 if d not in devices: 6350 if d not in devices: 6401 devices[d] = dict() 6351 devices[d] = dict() 6402 if name not in devices[d]: 6352 if name not in devices[d]: 6403 devices[d][name] = 0. 6353 devices[d][name] = 0.0 6404 devices[d][name] += float(tim 6354 devices[d][name] += float(time) 6405 # create worst device info 6355 # create worst device info 6406 worst = dict() 6356 worst = dict() 6407 for d in ['suspend', 'resume']: 6357 for d in ['suspend', 'resume']: 6408 worst[d] = {'name':'', 'time' 6358 worst[d] = {'name':'', 'time': 0.0} 6409 dev = devices[d] if d in devi 6359 dev = devices[d] if d in devices else 0 6410 if dev and len(dev.keys()) > 6360 if dev and len(dev.keys()) > 0: 6411 n = sorted(dev, key=l 6361 n = sorted(dev, key=lambda k:(dev[k], k), reverse=True)[0] 6412 worst[d]['name'], wor 6362 worst[d]['name'], worst[d]['time'] = n, dev[n] 6413 data = { 6363 data = { 6414 'mode': stmp[2], 6364 'mode': stmp[2], 6415 'host': stmp[0], 6365 'host': stmp[0], 6416 'kernel': stmp[1], 6366 'kernel': stmp[1], 6417 'sysinfo': sysinfo, 6367 'sysinfo': sysinfo, 6418 'time': tstr, 6368 'time': tstr, 6419 'result': result, 6369 'result': result, 6420 'issues': ' '.join(ilist), 6370 'issues': ' '.join(ilist), 6421 'suspend': suspend, 6371 'suspend': suspend, 6422 'resume': resume, 6372 'resume': resume, 6423 'devlist': devices, 6373 'devlist': devices, 6424 'sus_worst': worst['suspend'] 6374 'sus_worst': worst['suspend']['name'], 6425 'sus_worsttime': worst['suspe 6375 'sus_worsttime': worst['suspend']['time'], 6426 'res_worst': worst['resume'][ 6376 'res_worst': worst['resume']['name'], 6427 'res_worsttime': worst['resum 6377 'res_worsttime': worst['resume']['time'], 6428 'url': sysvals.htmlfile, 6378 'url': sysvals.htmlfile, 6429 } 6379 } 6430 for key in extra: 6380 for key in extra: 6431 data[key] = extra[key] 6381 data[key] = extra[key] 6432 if fulldetail: 6382 if fulldetail: 6433 data['funclist'] = find_in_ht 6383 data['funclist'] = find_in_html(html, '<div title="', '" class="traceevent"', False) 6434 if tp: 6384 if tp: 6435 for arg in ['-multi ', '-info 6385 for arg in ['-multi ', '-info ']: 6436 if arg in tp.cmdline: 6386 if arg in tp.cmdline: 6437 data['target' 6387 data['target'] = tp.cmdline[tp.cmdline.find(arg):].split()[1] 6438 break 6388 break 6439 return data 6389 return data 6440 6390 6441 def genHtml(subdir, force=False): 6391 def genHtml(subdir, force=False): 6442 for dirname, dirnames, filenames in o 6392 for dirname, dirnames, filenames in os.walk(subdir): 6443 sysvals.dmesgfile = sysvals.f 6393 sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = '' 6444 for filename in filenames: 6394 for filename in filenames: 6445 file = os.path.join(d 6395 file = os.path.join(dirname, filename) 6446 if sysvals.usable(fil 6396 if sysvals.usable(file): 6447 if(re.match(r !! 6397 if(re.match('.*_dmesg.txt', filename)): 6448 sysva 6398 sysvals.dmesgfile = file 6449 elif(re.match !! 6399 elif(re.match('.*_ftrace.txt', filename)): 6450 sysva 6400 sysvals.ftracefile = file 6451 sysvals.setOutputFile() 6401 sysvals.setOutputFile() 6452 if (sysvals.dmesgfile or sysv 6402 if (sysvals.dmesgfile or sysvals.ftracefile) and sysvals.htmlfile and \ 6453 (force or not sysvals 6403 (force or not sysvals.usable(sysvals.htmlfile, True)): 6454 pprint('FTRACE: %s' % 6404 pprint('FTRACE: %s' % sysvals.ftracefile) 6455 if sysvals.dmesgfile: 6405 if sysvals.dmesgfile: 6456 pprint('DMESG 6406 pprint('DMESG : %s' % sysvals.dmesgfile) 6457 rerunTest() 6407 rerunTest() 6458 6408 6459 # Function: runSummary 6409 # Function: runSummary 6460 # Description: 6410 # Description: 6461 # create a summary of tests in a sub-d 6411 # create a summary of tests in a sub-directory 6462 def runSummary(subdir, local=True, genhtml=Fa 6412 def runSummary(subdir, local=True, genhtml=False): 6463 inpath = os.path.abspath(subdir) 6413 inpath = os.path.abspath(subdir) 6464 outpath = os.path.abspath('.') if loc 6414 outpath = os.path.abspath('.') if local else inpath 6465 pprint('Generating a summary of folde 6415 pprint('Generating a summary of folder:\n %s' % inpath) 6466 if genhtml: 6416 if genhtml: 6467 genHtml(subdir) 6417 genHtml(subdir) 6468 target, issues, testruns = '', [], [] 6418 target, issues, testruns = '', [], [] 6469 desc = {'host':[],'mode':[],'kernel': 6419 desc = {'host':[],'mode':[],'kernel':[]} 6470 for dirname, dirnames, filenames in o 6420 for dirname, dirnames, filenames in os.walk(subdir): 6471 for filename in filenames: 6421 for filename in filenames: 6472 if(not re.match(r'.*. !! 6422 if(not re.match('.*.html', filename)): 6473 continue 6423 continue 6474 data = data_from_html 6424 data = data_from_html(os.path.join(dirname, filename), outpath, issues) 6475 if(not data): 6425 if(not data): 6476 continue 6426 continue 6477 if 'target' in data: 6427 if 'target' in data: 6478 target = data 6428 target = data['target'] 6479 testruns.append(data) 6429 testruns.append(data) 6480 for key in desc: 6430 for key in desc: 6481 if data[key] 6431 if data[key] not in desc[key]: 6482 desc[ 6432 desc[key].append(data[key]) 6483 pprint('Summary files:') 6433 pprint('Summary files:') 6484 if len(desc['host']) == len(desc['mod 6434 if len(desc['host']) == len(desc['mode']) == len(desc['kernel']) == 1: 6485 title = '%s %s %s' % (desc['h 6435 title = '%s %s %s' % (desc['host'][0], desc['kernel'][0], desc['mode'][0]) 6486 if target: 6436 if target: 6487 title += ' %s' % targ 6437 title += ' %s' % target 6488 else: 6438 else: 6489 title = inpath 6439 title = inpath 6490 createHTMLSummarySimple(testruns, os. 6440 createHTMLSummarySimple(testruns, os.path.join(outpath, 'summary.html'), title) 6491 pprint(' summary.html - tab 6441 pprint(' summary.html - tabular list of test data found') 6492 createHTMLDeviceSummary(testruns, os. 6442 createHTMLDeviceSummary(testruns, os.path.join(outpath, 'summary-devices.html'), title) 6493 pprint(' summary-devices.html - ker 6443 pprint(' summary-devices.html - kernel device list sorted by total execution time') 6494 createHTMLIssuesSummary(testruns, iss 6444 createHTMLIssuesSummary(testruns, issues, os.path.join(outpath, 'summary-issues.html'), title) 6495 pprint(' summary-issues.html - ker 6445 pprint(' summary-issues.html - kernel issues found sorted by frequency') 6496 6446 6497 # Function: checkArgBool 6447 # Function: checkArgBool 6498 # Description: 6448 # Description: 6499 # check if a boolean string value is t 6449 # check if a boolean string value is true or false 6500 def checkArgBool(name, value): 6450 def checkArgBool(name, value): 6501 if value in switchvalues: 6451 if value in switchvalues: 6502 if value in switchoff: 6452 if value in switchoff: 6503 return False 6453 return False 6504 return True 6454 return True 6505 doError('invalid boolean --> (%s: %s) 6455 doError('invalid boolean --> (%s: %s), use "true/false" or "1/0"' % (name, value), True) 6506 return False 6456 return False 6507 6457 6508 # Function: configFromFile 6458 # Function: configFromFile 6509 # Description: 6459 # Description: 6510 # Configure the script via the info in 6460 # Configure the script via the info in a config file 6511 def configFromFile(file): 6461 def configFromFile(file): 6512 Config = configparser.ConfigParser() 6462 Config = configparser.ConfigParser() 6513 6463 6514 Config.read(file) 6464 Config.read(file) 6515 sections = Config.sections() 6465 sections = Config.sections() 6516 overridekprobes = False 6466 overridekprobes = False 6517 overridedevkprobes = False 6467 overridedevkprobes = False 6518 if 'Settings' in sections: 6468 if 'Settings' in sections: 6519 for opt in Config.options('Se 6469 for opt in Config.options('Settings'): 6520 value = Config.get('S 6470 value = Config.get('Settings', opt).lower() 6521 option = opt.lower() 6471 option = opt.lower() 6522 if(option == 'verbose 6472 if(option == 'verbose'): 6523 sysvals.verbo 6473 sysvals.verbose = checkArgBool(option, value) 6524 elif(option == 'addlo 6474 elif(option == 'addlogs'): 6525 sysvals.dmesg 6475 sysvals.dmesglog = sysvals.ftracelog = checkArgBool(option, value) 6526 elif(option == 'dev') 6476 elif(option == 'dev'): 6527 sysvals.usede 6477 sysvals.usedevsrc = checkArgBool(option, value) 6528 elif(option == 'proc' 6478 elif(option == 'proc'): 6529 sysvals.usepr 6479 sysvals.useprocmon = checkArgBool(option, value) 6530 elif(option == 'x2'): 6480 elif(option == 'x2'): 6531 if checkArgBo 6481 if checkArgBool(option, value): 6532 sysva 6482 sysvals.execcount = 2 6533 elif(option == 'callg 6483 elif(option == 'callgraph'): 6534 sysvals.useca 6484 sysvals.usecallgraph = checkArgBool(option, value) 6535 elif(option == 'overr 6485 elif(option == 'override-timeline-functions'): 6536 overridekprob 6486 overridekprobes = checkArgBool(option, value) 6537 elif(option == 'overr 6487 elif(option == 'override-dev-timeline-functions'): 6538 overridedevkp 6488 overridedevkprobes = checkArgBool(option, value) 6539 elif(option == 'skiph 6489 elif(option == 'skiphtml'): 6540 sysvals.skiph 6490 sysvals.skiphtml = checkArgBool(option, value) 6541 elif(option == 'sync' 6491 elif(option == 'sync'): 6542 sysvals.sync 6492 sysvals.sync = checkArgBool(option, value) 6543 elif(option == 'rs' o 6493 elif(option == 'rs' or option == 'runtimesuspend'): 6544 if value in s 6494 if value in switchvalues: 6545 if va 6495 if value in switchoff: 6546 6496 sysvals.rs = -1 6547 else: 6497 else: 6548 6498 sysvals.rs = 1 6549 else: 6499 else: 6550 doErr 6500 doError('invalid value --> (%s: %s), use "enable/disable"' % (option, value), True) 6551 elif(option == 'displ 6501 elif(option == 'display'): 6552 disopt = ['on 6502 disopt = ['on', 'off', 'standby', 'suspend'] 6553 if value not 6503 if value not in disopt: 6554 doErr 6504 doError('invalid value --> (%s: %s), use %s' % (option, value, disopt), True) 6555 sysvals.displ 6505 sysvals.display = value 6556 elif(option == 'gzip' 6506 elif(option == 'gzip'): 6557 sysvals.gzip 6507 sysvals.gzip = checkArgBool(option, value) 6558 elif(option == 'cgfil 6508 elif(option == 'cgfilter'): 6559 sysvals.setCa 6509 sysvals.setCallgraphFilter(value) 6560 elif(option == 'cgski 6510 elif(option == 'cgskip'): 6561 if value in s 6511 if value in switchoff: 6562 sysva 6512 sysvals.cgskip = '' 6563 else: 6513 else: 6564 sysva 6514 sysvals.cgskip = sysvals.configFile(val) 6565 if(no 6515 if(not sysvals.cgskip): 6566 6516 doError('%s does not exist' % sysvals.cgskip) 6567 elif(option == 'cgtes 6517 elif(option == 'cgtest'): 6568 sysvals.cgtes 6518 sysvals.cgtest = getArgInt('cgtest', value, 0, 1, False) 6569 elif(option == 'cgpha 6519 elif(option == 'cgphase'): 6570 d = Data(0) 6520 d = Data(0) 6571 if value not 6521 if value not in d.phasedef: 6572 doErr 6522 doError('invalid phase --> (%s: %s), valid phases are %s'\ 6573 6523 % (option, value, d.phasedef.keys()), True) 6574 sysvals.cgpha 6524 sysvals.cgphase = value 6575 elif(option == 'fadd' 6525 elif(option == 'fadd'): 6576 file = sysval 6526 file = sysvals.configFile(value) 6577 if(not file): 6527 if(not file): 6578 doErr 6528 doError('%s does not exist' % value) 6579 sysvals.addFt 6529 sysvals.addFtraceFilterFunctions(file) 6580 elif(option == 'resul 6530 elif(option == 'result'): 6581 sysvals.resul 6531 sysvals.result = value 6582 elif(option == 'multi 6532 elif(option == 'multi'): 6583 nums = value. 6533 nums = value.split() 6584 if len(nums) 6534 if len(nums) != 2: 6585 doErr 6535 doError('multi requires 2 integers (exec_count and delay)', True) 6586 sysvals.multi 6536 sysvals.multiinit(nums[0], nums[1]) 6587 elif(option == 'devic 6537 elif(option == 'devicefilter'): 6588 sysvals.setDe 6538 sysvals.setDeviceFilter(value) 6589 elif(option == 'expan 6539 elif(option == 'expandcg'): 6590 sysvals.cgexp 6540 sysvals.cgexp = checkArgBool(option, value) 6591 elif(option == 'srgap 6541 elif(option == 'srgap'): 6592 if checkArgBo 6542 if checkArgBool(option, value): 6593 sysva 6543 sysvals.srgap = 5 6594 elif(option == 'mode' 6544 elif(option == 'mode'): 6595 sysvals.suspe 6545 sysvals.suspendmode = value 6596 elif(option == 'comma 6546 elif(option == 'command' or option == 'cmd'): 6597 sysvals.testc 6547 sysvals.testcommand = value 6598 elif(option == 'x2del 6548 elif(option == 'x2delay'): 6599 sysvals.x2del 6549 sysvals.x2delay = getArgInt('x2delay', value, 0, 60000, False) 6600 elif(option == 'prede 6550 elif(option == 'predelay'): 6601 sysvals.prede 6551 sysvals.predelay = getArgInt('predelay', value, 0, 60000, False) 6602 elif(option == 'postd 6552 elif(option == 'postdelay'): 6603 sysvals.postd 6553 sysvals.postdelay = getArgInt('postdelay', value, 0, 60000, False) 6604 elif(option == 'maxde 6554 elif(option == 'maxdepth'): 6605 sysvals.max_g 6555 sysvals.max_graph_depth = getArgInt('maxdepth', value, 0, 1000, False) 6606 elif(option == 'rtcwa 6556 elif(option == 'rtcwake'): 6607 if value in s 6557 if value in switchoff: 6608 sysva 6558 sysvals.rtcwake = False 6609 else: 6559 else: 6610 sysva 6560 sysvals.rtcwake = True 6611 sysva 6561 sysvals.rtcwaketime = getArgInt('rtcwake', value, 0, 3600, False) 6612 elif(option == 'timep 6562 elif(option == 'timeprec'): 6613 sysvals.setPr 6563 sysvals.setPrecision(getArgInt('timeprec', value, 0, 6, False)) 6614 elif(option == 'minde 6564 elif(option == 'mindev'): 6615 sysvals.minde 6565 sysvals.mindevlen = getArgFloat('mindev', value, 0.0, 10000.0, False) 6616 elif(option == 'calll 6566 elif(option == 'callloop-maxgap'): 6617 sysvals.calll 6567 sysvals.callloopmaxgap = getArgFloat('callloop-maxgap', value, 0.0, 1.0, False) 6618 elif(option == 'calll 6568 elif(option == 'callloop-maxlen'): 6619 sysvals.calll 6569 sysvals.callloopmaxgap = getArgFloat('callloop-maxlen', value, 0.0, 1.0, False) 6620 elif(option == 'mincg 6570 elif(option == 'mincg'): 6621 sysvals.mincg 6571 sysvals.mincglen = getArgFloat('mincg', value, 0.0, 10000.0, False) 6622 elif(option == 'bufsi 6572 elif(option == 'bufsize'): 6623 sysvals.bufsi 6573 sysvals.bufsize = getArgInt('bufsize', value, 1, 1024*1024*8, False) 6624 elif(option == 'outpu 6574 elif(option == 'output-dir'): 6625 sysvals.outdi 6575 sysvals.outdir = sysvals.setOutputFolder(value) 6626 6576 6627 if sysvals.suspendmode == 'command' a 6577 if sysvals.suspendmode == 'command' and not sysvals.testcommand: 6628 doError('No command supplied 6578 doError('No command supplied for mode "command"') 6629 6579 6630 # compatibility errors 6580 # compatibility errors 6631 if sysvals.usedevsrc and sysvals.usec 6581 if sysvals.usedevsrc and sysvals.usecallgraph: 6632 doError('-dev is not compatib 6582 doError('-dev is not compatible with -f') 6633 if sysvals.usecallgraph and sysvals.u 6583 if sysvals.usecallgraph and sysvals.useprocmon: 6634 doError('-proc is not compati 6584 doError('-proc is not compatible with -f') 6635 6585 6636 if overridekprobes: 6586 if overridekprobes: 6637 sysvals.tracefuncs = dict() 6587 sysvals.tracefuncs = dict() 6638 if overridedevkprobes: 6588 if overridedevkprobes: 6639 sysvals.dev_tracefuncs = dict 6589 sysvals.dev_tracefuncs = dict() 6640 6590 6641 kprobes = dict() 6591 kprobes = dict() 6642 kprobesec = 'dev_timeline_functions_' 6592 kprobesec = 'dev_timeline_functions_'+platform.machine() 6643 if kprobesec in sections: 6593 if kprobesec in sections: 6644 for name in Config.options(kp 6594 for name in Config.options(kprobesec): 6645 text = Config.get(kpr 6595 text = Config.get(kprobesec, name) 6646 kprobes[name] = (text 6596 kprobes[name] = (text, True) 6647 kprobesec = 'timeline_functions_'+pla 6597 kprobesec = 'timeline_functions_'+platform.machine() 6648 if kprobesec in sections: 6598 if kprobesec in sections: 6649 for name in Config.options(kp 6599 for name in Config.options(kprobesec): 6650 if name in kprobes: 6600 if name in kprobes: 6651 doError('Dupl 6601 doError('Duplicate timeline function found "%s"' % (name)) 6652 text = Config.get(kpr 6602 text = Config.get(kprobesec, name) 6653 kprobes[name] = (text 6603 kprobes[name] = (text, False) 6654 6604 6655 for name in kprobes: 6605 for name in kprobes: 6656 function = name 6606 function = name 6657 format = name 6607 format = name 6658 color = '' 6608 color = '' 6659 args = dict() 6609 args = dict() 6660 text, dev = kprobes[name] 6610 text, dev = kprobes[name] 6661 data = text.split() 6611 data = text.split() 6662 i = 0 6612 i = 0 6663 for val in data: 6613 for val in data: 6664 # bracketted strings 6614 # bracketted strings are special formatting, read them separately 6665 if val[0] == '[' and 6615 if val[0] == '[' and val[-1] == ']': 6666 for prop in v 6616 for prop in val[1:-1].split(','): 6667 p = p 6617 p = prop.split('=') 6668 if p[ 6618 if p[0] == 'color': 6669 6619 try: 6670 6620 color = int(p[1], 16) 6671 6621 color = '#'+p[1] 6672 6622 except: 6673 6623 color = p[1] 6674 continue 6624 continue 6675 # first real arg shou 6625 # first real arg should be the format string 6676 if i == 0: 6626 if i == 0: 6677 format = val 6627 format = val 6678 # all other args are 6628 # all other args are actual function args 6679 else: 6629 else: 6680 d = val.split 6630 d = val.split('=') 6681 args[d[0]] = 6631 args[d[0]] = d[1] 6682 i += 1 6632 i += 1 6683 if not function or not format 6633 if not function or not format: 6684 doError('Invalid kpro 6634 doError('Invalid kprobe: %s' % name) 6685 for arg in re.findall('{(?P<n 6635 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format): 6686 if arg not in args: 6636 if arg not in args: 6687 doError('Kpro 6637 doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 6688 if (dev and name in sysvals.d 6638 if (dev and name in sysvals.dev_tracefuncs) or (not dev and name in sysvals.tracefuncs): 6689 doError('Duplicate ti 6639 doError('Duplicate timeline function found "%s"' % (name)) 6690 6640 6691 kp = { 6641 kp = { 6692 'name': name, 6642 'name': name, 6693 'func': function, 6643 'func': function, 6694 'format': format, 6644 'format': format, 6695 sysvals.archargs: arg 6645 sysvals.archargs: args 6696 } 6646 } 6697 if color: 6647 if color: 6698 kp['color'] = color 6648 kp['color'] = color 6699 if dev: 6649 if dev: 6700 sysvals.dev_tracefunc 6650 sysvals.dev_tracefuncs[name] = kp 6701 else: 6651 else: 6702 sysvals.tracefuncs[na 6652 sysvals.tracefuncs[name] = kp 6703 6653 6704 # Function: printHelp 6654 # Function: printHelp 6705 # Description: 6655 # Description: 6706 # print out the help text 6656 # print out the help text 6707 def printHelp(): 6657 def printHelp(): 6708 pprint('\n%s v%s\n'\ 6658 pprint('\n%s v%s\n'\ 6709 'Usage: sudo sleepgraph <options> <co 6659 'Usage: sudo sleepgraph <options> <commands>\n'\ 6710 '\n'\ 6660 '\n'\ 6711 'Description:\n'\ 6661 'Description:\n'\ 6712 ' This tool is designed to assist ke 6662 ' This tool is designed to assist kernel and OS developers in optimizing\n'\ 6713 ' their linux stack\'s suspend/resum 6663 ' their linux stack\'s suspend/resume time. Using a kernel image built\n'\ 6714 ' with a few extra options enabled, 6664 ' with a few extra options enabled, the tool will execute a suspend and\n'\ 6715 ' capture dmesg and ftrace data unti 6665 ' capture dmesg and ftrace data until resume is complete. This data is\n'\ 6716 ' transformed into a device timeline 6666 ' transformed into a device timeline and an optional callgraph to give\n'\ 6717 ' a detailed view of which devices/s 6667 ' a detailed view of which devices/subsystems are taking the most\n'\ 6718 ' time in suspend/resume.\n'\ 6668 ' time in suspend/resume.\n'\ 6719 '\n'\ 6669 '\n'\ 6720 ' If no specific command is given, t 6670 ' If no specific command is given, the default behavior is to initiate\n'\ 6721 ' a suspend/resume and capture the d 6671 ' a suspend/resume and capture the dmesg/ftrace output as an html timeline.\n'\ 6722 '\n'\ 6672 '\n'\ 6723 ' Generates output files in subdirec 6673 ' Generates output files in subdirectory: suspend-yymmdd-HHMMSS\n'\ 6724 ' HTML output: < 6674 ' HTML output: <hostname>_<mode>.html\n'\ 6725 ' raw dmesg output: < 6675 ' raw dmesg output: <hostname>_<mode>_dmesg.txt\n'\ 6726 ' raw ftrace output: < 6676 ' raw ftrace output: <hostname>_<mode>_ftrace.txt\n'\ 6727 '\n'\ 6677 '\n'\ 6728 'Options:\n'\ 6678 'Options:\n'\ 6729 ' -h Print this help text 6679 ' -h Print this help text\n'\ 6730 ' -v Print the current to 6680 ' -v Print the current tool version\n'\ 6731 ' -config fn Pull arguments and c 6681 ' -config fn Pull arguments and config options from file fn\n'\ 6732 ' -verbose Print extra informat 6682 ' -verbose Print extra information during execution and analysis\n'\ 6733 ' -m mode Mode to initiate for 6683 ' -m mode Mode to initiate for suspend (default: %s)\n'\ 6734 ' -o name Overrides the output 6684 ' -o name Overrides the output subdirectory name when running a new test\n'\ 6735 ' default: suspend-{da 6685 ' default: suspend-{date}-{time}\n'\ 6736 ' -rtcwake t Wakeup t seconds aft 6686 ' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)\n'\ 6737 ' -addlogs Add the dmesg and ft 6687 ' -addlogs Add the dmesg and ftrace logs to the html output\n'\ 6738 ' -noturbostat Dont use turbostat i 6688 ' -noturbostat Dont use turbostat in freeze mode (default: disabled)\n'\ 6739 ' -srgap Add a visible gap in 6689 ' -srgap Add a visible gap in the timeline between sus/res (default: disabled)\n'\ 6740 ' -skiphtml Run the test and cap 6690 ' -skiphtml Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\ 6741 ' -result fn Export a results tab 6691 ' -result fn Export a results table to a text file for parsing.\n'\ 6742 ' -wifi If a wifi connection 6692 ' -wifi If a wifi connection is available, check that it reconnects after resume.\n'\ 6743 ' -wifitrace Trace kernel executi 6693 ' -wifitrace Trace kernel execution through wifi reconnect.\n'\ 6744 ' -netfix Use netfix to reset 6694 ' -netfix Use netfix to reset the network in the event it fails to resume.\n'\ 6745 ' [testprep]\n'\ 6695 ' [testprep]\n'\ 6746 ' -sync Sync the filesystems 6696 ' -sync Sync the filesystems before starting the test\n'\ 6747 ' -rs on/off Enable/disable runti 6697 ' -rs on/off Enable/disable runtime suspend for all devices, restore all after test\n'\ 6748 ' -display m Change the display m 6698 ' -display m Change the display mode to m for the test (on/off/standby/suspend)\n'\ 6749 ' [advanced]\n'\ 6699 ' [advanced]\n'\ 6750 ' -gzip Gzip the trace and d 6700 ' -gzip Gzip the trace and dmesg logs to save space\n'\ 6751 ' -cmd {s} Run the timeline ove 6701 ' -cmd {s} Run the timeline over a custom command, e.g. "sync -d"\n'\ 6752 ' -proc Add usermode process 6702 ' -proc Add usermode process info into the timeline (default: disabled)\n'\ 6753 ' -dev Add kernel function 6703 ' -dev Add kernel function calls and threads to the timeline (default: disabled)\n'\ 6754 ' -x2 Run two suspend/resu 6704 ' -x2 Run two suspend/resumes back to back (default: disabled)\n'\ 6755 ' -x2delay t Include t ms delay b 6705 ' -x2delay t Include t ms delay between multiple test runs (default: 0 ms)\n'\ 6756 ' -predelay t Include t ms delay b 6706 ' -predelay t Include t ms delay before 1st suspend (default: 0 ms)\n'\ 6757 ' -postdelay t Include t ms delay a 6707 ' -postdelay t Include t ms delay after last resume (default: 0 ms)\n'\ 6758 ' -mindev ms Discard all device b 6708 ' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 6759 ' -multi n d Execute <n> consecut 6709 ' -multi n d Execute <n> consecutive tests at <d> seconds intervals. If <n> is followed\n'\ 6760 ' by a "d", "h", or "m 6710 ' by a "d", "h", or "m" execute for <n> days, hours, or mins instead.\n'\ 6761 ' The outputs will be 6711 ' The outputs will be created in a new subdirectory with a summary page.\n'\ 6762 ' -maxfail n Abort a -multi run a 6712 ' -maxfail n Abort a -multi run after n consecutive fails (default is 0 = never abort)\n'\ 6763 ' [debug]\n'\ 6713 ' [debug]\n'\ 6764 ' -f Use ftrace to create 6714 ' -f Use ftrace to create device callgraphs (default: disabled)\n'\ 6765 ' -ftop Use ftrace on the to 6715 ' -ftop Use ftrace on the top level call: "%s" (default: disabled)\n'\ 6766 ' -maxdepth N limit the callgraph 6716 ' -maxdepth N limit the callgraph data to N call levels (default: 0=all)\n'\ 6767 ' -expandcg pre-expand the callg 6717 ' -expandcg pre-expand the callgraph data in the html output (default: disabled)\n'\ 6768 ' -fadd file Add functions to be 6718 ' -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 6719 ' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names\n'\ 6770 ' -mincg ms Discard all callgrap 6720 ' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 6771 ' -cgphase P Only show callgraph 6721 ' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)\n'\ 6772 ' -cgtest N Only show callgraph 6722 ' -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 6723 ' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)\n'\ 6774 ' -cgfilter S Filter the callgraph 6724 ' -cgfilter S Filter the callgraph output in the timeline\n'\ 6775 ' -cgskip file Callgraph functions 6725 ' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\ 6776 ' -bufsize N Set trace buffer siz 6726 ' -bufsize N Set trace buffer size to N kilo-bytes (default: all of free memory)\n'\ 6777 ' -devdump Print out all the ra 6727 ' -devdump Print out all the raw device data for each phase\n'\ 6778 ' -cgdump Print out all the ra 6728 ' -cgdump Print out all the raw callgraph data\n'\ 6779 '\n'\ 6729 '\n'\ 6780 'Other commands:\n'\ 6730 'Other commands:\n'\ 6781 ' -modes List available suspe 6731 ' -modes List available suspend modes\n'\ 6782 ' -status Test to see if the s 6732 ' -status Test to see if the system is enabled to run this tool\n'\ 6783 ' -fpdt Print out the conten 6733 ' -fpdt Print out the contents of the ACPI Firmware Performance Data Table\n'\ 6784 ' -wificheck Print out wifi conne 6734 ' -wificheck Print out wifi connection info\n'\ 6785 ' -x<mode> Test xset by togglin 6735 ' -x<mode> Test xset by toggling the given mode (on/off/standby/suspend)\n'\ 6786 ' -sysinfo Print out system inf 6736 ' -sysinfo Print out system info extracted from BIOS\n'\ 6787 ' -devinfo Print out the pm set 6737 ' -devinfo Print out the pm settings of all devices which support runtime suspend\n'\ 6788 ' -cmdinfo Print out all the pl 6738 ' -cmdinfo Print out all the platform info collected before and after suspend/resume\n'\ 6789 ' -flist Print the list of fu 6739 ' -flist Print the list of functions currently being captured in ftrace\n'\ 6790 ' -flistall Print all functions 6740 ' -flistall Print all functions capable of being captured in ftrace\n'\ 6791 ' -summary dir Create a summary of 6741 ' -summary dir Create a summary of tests in this dir [-genhtml builds missing html]\n'\ 6792 ' [redo]\n'\ 6742 ' [redo]\n'\ 6793 ' -ftrace ftracefile Create HTML o 6743 ' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)\n'\ 6794 ' -dmesg dmesgfile Create HTML o 6744 ' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)\n'\ 6795 '' % (sysvals.title, sysvals.version, 6745 '' % (sysvals.title, sysvals.version, sysvals.suspendmode, sysvals.ftopfunc)) 6796 return True 6746 return True 6797 6747 6798 # ----------------- MAIN -------------------- 6748 # ----------------- MAIN -------------------- 6799 # exec start (skipped if script is loaded as 6749 # exec start (skipped if script is loaded as library) 6800 if __name__ == '__main__': 6750 if __name__ == '__main__': 6801 genhtml = False 6751 genhtml = False 6802 cmd = '' 6752 cmd = '' 6803 simplecmds = ['-sysinfo', '-modes', ' 6753 simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall', 6804 '-devinfo', '-status', '-xon' 6754 '-devinfo', '-status', '-xon', '-xoff', '-xstandby', '-xsuspend', 6805 '-xinit', '-xreset', '-xstat' 6755 '-xinit', '-xreset', '-xstat', '-wificheck', '-cmdinfo'] 6806 if '-f' in sys.argv: 6756 if '-f' in sys.argv: 6807 sysvals.cgskip = sysvals.conf 6757 sysvals.cgskip = sysvals.configFile('cgskip.txt') 6808 # loop through the command line argum 6758 # loop through the command line arguments 6809 args = iter(sys.argv[1:]) 6759 args = iter(sys.argv[1:]) 6810 for arg in args: 6760 for arg in args: 6811 if(arg == '-m'): 6761 if(arg == '-m'): 6812 try: 6762 try: 6813 val = next(ar 6763 val = next(args) 6814 except: 6764 except: 6815 doError('No m 6765 doError('No mode supplied', True) 6816 if val == 'command' a 6766 if val == 'command' and not sysvals.testcommand: 6817 doError('No c 6767 doError('No command supplied for mode "command"', True) 6818 sysvals.suspendmode = 6768 sysvals.suspendmode = val 6819 elif(arg in simplecmds): 6769 elif(arg in simplecmds): 6820 cmd = arg[1:] 6770 cmd = arg[1:] 6821 elif(arg == '-h'): 6771 elif(arg == '-h'): 6822 printHelp() 6772 printHelp() 6823 sys.exit(0) 6773 sys.exit(0) 6824 elif(arg == '-v'): 6774 elif(arg == '-v'): 6825 pprint("Version %s" % 6775 pprint("Version %s" % sysvals.version) 6826 sys.exit(0) 6776 sys.exit(0) 6827 elif(arg == '-debugtiming'): 6777 elif(arg == '-debugtiming'): 6828 debugtiming = True 6778 debugtiming = True 6829 elif(arg == '-x2'): 6779 elif(arg == '-x2'): 6830 sysvals.execcount = 2 6780 sysvals.execcount = 2 6831 elif(arg == '-x2delay'): 6781 elif(arg == '-x2delay'): 6832 sysvals.x2delay = get 6782 sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000) 6833 elif(arg == '-predelay'): 6783 elif(arg == '-predelay'): 6834 sysvals.predelay = ge 6784 sysvals.predelay = getArgInt('-predelay', args, 0, 60000) 6835 elif(arg == '-postdelay'): 6785 elif(arg == '-postdelay'): 6836 sysvals.postdelay = g 6786 sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000) 6837 elif(arg == '-f'): 6787 elif(arg == '-f'): 6838 sysvals.usecallgraph 6788 sysvals.usecallgraph = True 6839 elif(arg == '-ftop'): 6789 elif(arg == '-ftop'): 6840 sysvals.usecallgraph 6790 sysvals.usecallgraph = True 6841 sysvals.ftop = True 6791 sysvals.ftop = True 6842 sysvals.usekprobes = 6792 sysvals.usekprobes = False 6843 elif(arg == '-skiphtml'): 6793 elif(arg == '-skiphtml'): 6844 sysvals.skiphtml = Tr 6794 sysvals.skiphtml = True 6845 elif(arg == '-cgdump'): 6795 elif(arg == '-cgdump'): 6846 sysvals.cgdump = True 6796 sysvals.cgdump = True 6847 elif(arg == '-devdump'): 6797 elif(arg == '-devdump'): 6848 sysvals.devdump = Tru 6798 sysvals.devdump = True 6849 elif(arg == '-genhtml'): 6799 elif(arg == '-genhtml'): 6850 genhtml = True 6800 genhtml = True 6851 elif(arg == '-addlogs'): 6801 elif(arg == '-addlogs'): 6852 sysvals.dmesglog = sy 6802 sysvals.dmesglog = sysvals.ftracelog = True 6853 elif(arg == '-nologs'): 6803 elif(arg == '-nologs'): 6854 sysvals.dmesglog = sy 6804 sysvals.dmesglog = sysvals.ftracelog = False 6855 elif(arg == '-addlogdmesg'): 6805 elif(arg == '-addlogdmesg'): 6856 sysvals.dmesglog = Tr 6806 sysvals.dmesglog = True 6857 elif(arg == '-addlogftrace'): 6807 elif(arg == '-addlogftrace'): 6858 sysvals.ftracelog = T 6808 sysvals.ftracelog = True 6859 elif(arg == '-noturbostat'): 6809 elif(arg == '-noturbostat'): 6860 sysvals.tstat = False 6810 sysvals.tstat = False 6861 elif(arg == '-verbose'): 6811 elif(arg == '-verbose'): 6862 sysvals.verbose = Tru 6812 sysvals.verbose = True 6863 elif(arg == '-proc'): 6813 elif(arg == '-proc'): 6864 sysvals.useprocmon = 6814 sysvals.useprocmon = True 6865 elif(arg == '-dev'): 6815 elif(arg == '-dev'): 6866 sysvals.usedevsrc = T 6816 sysvals.usedevsrc = True 6867 elif(arg == '-sync'): 6817 elif(arg == '-sync'): 6868 sysvals.sync = True 6818 sysvals.sync = True 6869 elif(arg == '-wifi'): 6819 elif(arg == '-wifi'): 6870 sysvals.wifi = True 6820 sysvals.wifi = True 6871 elif(arg == '-wifitrace'): 6821 elif(arg == '-wifitrace'): 6872 sysvals.wifitrace = T 6822 sysvals.wifitrace = True 6873 elif(arg == '-netfix'): 6823 elif(arg == '-netfix'): 6874 sysvals.netfix = True 6824 sysvals.netfix = True 6875 elif(arg == '-gzip'): 6825 elif(arg == '-gzip'): 6876 sysvals.gzip = True 6826 sysvals.gzip = True 6877 elif(arg == '-info'): 6827 elif(arg == '-info'): 6878 try: 6828 try: 6879 val = next(ar 6829 val = next(args) 6880 except: 6830 except: 6881 doError('-inf 6831 doError('-info requires one string argument', True) 6882 elif(arg == '-desc'): 6832 elif(arg == '-desc'): 6883 try: 6833 try: 6884 val = next(ar 6834 val = next(args) 6885 except: 6835 except: 6886 doError('-des 6836 doError('-desc requires one string argument', True) 6887 elif(arg == '-rs'): 6837 elif(arg == '-rs'): 6888 try: 6838 try: 6889 val = next(ar 6839 val = next(args) 6890 except: 6840 except: 6891 doError('-rs 6841 doError('-rs requires "enable" or "disable"', True) 6892 if val.lower() in swi 6842 if val.lower() in switchvalues: 6893 if val.lower( 6843 if val.lower() in switchoff: 6894 sysva 6844 sysvals.rs = -1 6895 else: 6845 else: 6896 sysva 6846 sysvals.rs = 1 6897 else: 6847 else: 6898 doError('inva 6848 doError('invalid option: %s, use "enable/disable" or "on/off"' % val, True) 6899 elif(arg == '-display'): 6849 elif(arg == '-display'): 6900 try: 6850 try: 6901 val = next(ar 6851 val = next(args) 6902 except: 6852 except: 6903 doError('-dis 6853 doError('-display requires an mode value', True) 6904 disopt = ['on', 'off' 6854 disopt = ['on', 'off', 'standby', 'suspend'] 6905 if val.lower() not in 6855 if val.lower() not in disopt: 6906 doError('vali 6856 doError('valid display mode values are %s' % disopt, True) 6907 sysvals.display = val 6857 sysvals.display = val.lower() 6908 elif(arg == '-maxdepth'): 6858 elif(arg == '-maxdepth'): 6909 sysvals.max_graph_dep 6859 sysvals.max_graph_depth = getArgInt('-maxdepth', args, 0, 1000) 6910 elif(arg == '-rtcwake'): 6860 elif(arg == '-rtcwake'): 6911 try: 6861 try: 6912 val = next(ar 6862 val = next(args) 6913 except: 6863 except: 6914 doError('No r 6864 doError('No rtcwake time supplied', True) 6915 if val.lower() in swi 6865 if val.lower() in switchoff: 6916 sysvals.rtcwa 6866 sysvals.rtcwake = False 6917 else: 6867 else: 6918 sysvals.rtcwa 6868 sysvals.rtcwake = True 6919 sysvals.rtcwa 6869 sysvals.rtcwaketime = getArgInt('-rtcwake', val, 0, 3600, False) 6920 elif(arg == '-timeprec'): 6870 elif(arg == '-timeprec'): 6921 sysvals.setPrecision( 6871 sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6)) 6922 elif(arg == '-mindev'): 6872 elif(arg == '-mindev'): 6923 sysvals.mindevlen = g 6873 sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0) 6924 elif(arg == '-mincg'): 6874 elif(arg == '-mincg'): 6925 sysvals.mincglen = ge 6875 sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0) 6926 elif(arg == '-bufsize'): 6876 elif(arg == '-bufsize'): 6927 sysvals.bufsize = get 6877 sysvals.bufsize = getArgInt('-bufsize', args, 1, 1024*1024*8) 6928 elif(arg == '-cgtest'): 6878 elif(arg == '-cgtest'): 6929 sysvals.cgtest = getA 6879 sysvals.cgtest = getArgInt('-cgtest', args, 0, 1) 6930 elif(arg == '-cgphase'): 6880 elif(arg == '-cgphase'): 6931 try: 6881 try: 6932 val = next(ar 6882 val = next(args) 6933 except: 6883 except: 6934 doError('No p 6884 doError('No phase name supplied', True) 6935 d = Data(0) 6885 d = Data(0) 6936 if val not in d.phase 6886 if val not in d.phasedef: 6937 doError('inva 6887 doError('invalid phase --> (%s: %s), valid phases are %s'\ 6938 % (ar 6888 % (arg, val, d.phasedef.keys()), True) 6939 sysvals.cgphase = val 6889 sysvals.cgphase = val 6940 elif(arg == '-cgfilter'): 6890 elif(arg == '-cgfilter'): 6941 try: 6891 try: 6942 val = next(ar 6892 val = next(args) 6943 except: 6893 except: 6944 doError('No c 6894 doError('No callgraph functions supplied', True) 6945 sysvals.setCallgraphF 6895 sysvals.setCallgraphFilter(val) 6946 elif(arg == '-skipkprobe'): 6896 elif(arg == '-skipkprobe'): 6947 try: 6897 try: 6948 val = next(ar 6898 val = next(args) 6949 except: 6899 except: 6950 doError('No k 6900 doError('No kprobe functions supplied', True) 6951 sysvals.skipKprobes(v 6901 sysvals.skipKprobes(val) 6952 elif(arg == '-cgskip'): 6902 elif(arg == '-cgskip'): 6953 try: 6903 try: 6954 val = next(ar 6904 val = next(args) 6955 except: 6905 except: 6956 doError('No f 6906 doError('No file supplied', True) 6957 if val.lower() in swi 6907 if val.lower() in switchoff: 6958 sysvals.cgski 6908 sysvals.cgskip = '' 6959 else: 6909 else: 6960 sysvals.cgski 6910 sysvals.cgskip = sysvals.configFile(val) 6961 if(not sysval 6911 if(not sysvals.cgskip): 6962 doErr 6912 doError('%s does not exist' % sysvals.cgskip) 6963 elif(arg == '-callloop-maxgap 6913 elif(arg == '-callloop-maxgap'): 6964 sysvals.callloopmaxga 6914 sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', args, 0.0, 1.0) 6965 elif(arg == '-callloop-maxlen 6915 elif(arg == '-callloop-maxlen'): 6966 sysvals.callloopmaxle 6916 sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0) 6967 elif(arg == '-cmd'): 6917 elif(arg == '-cmd'): 6968 try: 6918 try: 6969 val = next(ar 6919 val = next(args) 6970 except: 6920 except: 6971 doError('No c 6921 doError('No command string supplied', True) 6972 sysvals.testcommand = 6922 sysvals.testcommand = val 6973 sysvals.suspendmode = 6923 sysvals.suspendmode = 'command' 6974 elif(arg == '-expandcg'): 6924 elif(arg == '-expandcg'): 6975 sysvals.cgexp = True 6925 sysvals.cgexp = True 6976 elif(arg == '-srgap'): 6926 elif(arg == '-srgap'): 6977 sysvals.srgap = 5 6927 sysvals.srgap = 5 6978 elif(arg == '-maxfail'): 6928 elif(arg == '-maxfail'): 6979 sysvals.maxfail = get 6929 sysvals.maxfail = getArgInt('-maxfail', args, 0, 1000000) 6980 elif(arg == '-multi'): 6930 elif(arg == '-multi'): 6981 try: 6931 try: 6982 c, d = next(a 6932 c, d = next(args), next(args) 6983 except: 6933 except: 6984 doError('-mul 6934 doError('-multi requires two values', True) 6985 sysvals.multiinit(c, 6935 sysvals.multiinit(c, d) 6986 elif(arg == '-o'): 6936 elif(arg == '-o'): 6987 try: 6937 try: 6988 val = next(ar 6938 val = next(args) 6989 except: 6939 except: 6990 doError('No s 6940 doError('No subdirectory name supplied', True) 6991 sysvals.outdir = sysv 6941 sysvals.outdir = sysvals.setOutputFolder(val) 6992 elif(arg == '-config'): 6942 elif(arg == '-config'): 6993 try: 6943 try: 6994 val = next(ar 6944 val = next(args) 6995 except: 6945 except: 6996 doError('No t 6946 doError('No text file supplied', True) 6997 file = sysvals.config 6947 file = sysvals.configFile(val) 6998 if(not file): 6948 if(not file): 6999 doError('%s d 6949 doError('%s does not exist' % val) 7000 configFromFile(file) 6950 configFromFile(file) 7001 elif(arg == '-fadd'): 6951 elif(arg == '-fadd'): 7002 try: 6952 try: 7003 val = next(ar 6953 val = next(args) 7004 except: 6954 except: 7005 doError('No t 6955 doError('No text file supplied', True) 7006 file = sysvals.config 6956 file = sysvals.configFile(val) 7007 if(not file): 6957 if(not file): 7008 doError('%s d 6958 doError('%s does not exist' % val) 7009 sysvals.addFtraceFilt 6959 sysvals.addFtraceFilterFunctions(file) 7010 elif(arg == '-dmesg'): 6960 elif(arg == '-dmesg'): 7011 try: 6961 try: 7012 val = next(ar 6962 val = next(args) 7013 except: 6963 except: 7014 doError('No d 6964 doError('No dmesg file supplied', True) 7015 sysvals.notestrun = T 6965 sysvals.notestrun = True 7016 sysvals.dmesgfile = v 6966 sysvals.dmesgfile = val 7017 if(os.path.exists(sys 6967 if(os.path.exists(sysvals.dmesgfile) == False): 7018 doError('%s d 6968 doError('%s does not exist' % sysvals.dmesgfile) 7019 elif(arg == '-ftrace'): 6969 elif(arg == '-ftrace'): 7020 try: 6970 try: 7021 val = next(ar 6971 val = next(args) 7022 except: 6972 except: 7023 doError('No f 6973 doError('No ftrace file supplied', True) 7024 sysvals.notestrun = T 6974 sysvals.notestrun = True 7025 sysvals.ftracefile = 6975 sysvals.ftracefile = val 7026 if(os.path.exists(sys 6976 if(os.path.exists(sysvals.ftracefile) == False): 7027 doError('%s d 6977 doError('%s does not exist' % sysvals.ftracefile) 7028 elif(arg == '-summary'): 6978 elif(arg == '-summary'): 7029 try: 6979 try: 7030 val = next(ar 6980 val = next(args) 7031 except: 6981 except: 7032 doError('No d 6982 doError('No directory supplied', True) 7033 cmd = 'summary' 6983 cmd = 'summary' 7034 sysvals.outdir = val 6984 sysvals.outdir = val 7035 sysvals.notestrun = T 6985 sysvals.notestrun = True 7036 if(os.path.isdir(val) 6986 if(os.path.isdir(val) == False): 7037 doError('%s i 6987 doError('%s is not accesible' % val) 7038 elif(arg == '-filter'): 6988 elif(arg == '-filter'): 7039 try: 6989 try: 7040 val = next(ar 6990 val = next(args) 7041 except: 6991 except: 7042 doError('No d 6992 doError('No devnames supplied', True) 7043 sysvals.setDeviceFilt 6993 sysvals.setDeviceFilter(val) 7044 elif(arg == '-result'): 6994 elif(arg == '-result'): 7045 try: 6995 try: 7046 val = next(ar 6996 val = next(args) 7047 except: 6997 except: 7048 doError('No r 6998 doError('No result file supplied', True) 7049 sysvals.result = val 6999 sysvals.result = val 7050 sysvals.signalHandler 7000 sysvals.signalHandlerInit() 7051 else: 7001 else: 7052 doError('Invalid argu 7002 doError('Invalid argument: '+arg, True) 7053 7003 7054 # compatibility errors 7004 # compatibility errors 7055 if(sysvals.usecallgraph and sysvals.u 7005 if(sysvals.usecallgraph and sysvals.usedevsrc): 7056 doError('-dev is not compatib 7006 doError('-dev is not compatible with -f') 7057 if(sysvals.usecallgraph and sysvals.u 7007 if(sysvals.usecallgraph and sysvals.useprocmon): 7058 doError('-proc is not compati 7008 doError('-proc is not compatible with -f') 7059 7009 7060 if sysvals.usecallgraph and sysvals.c 7010 if sysvals.usecallgraph and sysvals.cgskip: 7061 sysvals.vprint('Using cgskip 7011 sysvals.vprint('Using cgskip file: %s' % sysvals.cgskip) 7062 sysvals.setCallgraphBlacklist 7012 sysvals.setCallgraphBlacklist(sysvals.cgskip) 7063 7013 7064 # callgraph size cannot exceed device 7014 # callgraph size cannot exceed device size 7065 if sysvals.mincglen < sysvals.mindevl 7015 if sysvals.mincglen < sysvals.mindevlen: 7066 sysvals.mincglen = sysvals.mi 7016 sysvals.mincglen = sysvals.mindevlen 7067 7017 7068 # remove existing buffers before calc 7018 # remove existing buffers before calculating memory 7069 if(sysvals.usecallgraph or sysvals.us 7019 if(sysvals.usecallgraph or sysvals.usedevsrc): 7070 sysvals.fsetVal('16', 'buffer 7020 sysvals.fsetVal('16', 'buffer_size_kb') 7071 sysvals.cpuInfo() 7021 sysvals.cpuInfo() 7072 7022 7073 # just run a utility command and exit 7023 # just run a utility command and exit 7074 if(cmd != ''): 7024 if(cmd != ''): 7075 ret = 0 7025 ret = 0 7076 if(cmd == 'status'): 7026 if(cmd == 'status'): 7077 if not statusCheck(Tr 7027 if not statusCheck(True): 7078 ret = 1 7028 ret = 1 7079 elif(cmd == 'fpdt'): 7029 elif(cmd == 'fpdt'): 7080 if not getFPDT(True): 7030 if not getFPDT(True): 7081 ret = 1 7031 ret = 1 7082 elif(cmd == 'sysinfo'): 7032 elif(cmd == 'sysinfo'): 7083 sysvals.printSystemIn 7033 sysvals.printSystemInfo(True) 7084 elif(cmd == 'devinfo'): 7034 elif(cmd == 'devinfo'): 7085 deviceInfo() 7035 deviceInfo() 7086 elif(cmd == 'modes'): 7036 elif(cmd == 'modes'): 7087 pprint(getModes()) 7037 pprint(getModes()) 7088 elif(cmd == 'flist'): 7038 elif(cmd == 'flist'): 7089 sysvals.getFtraceFilt 7039 sysvals.getFtraceFilterFunctions(True) 7090 elif(cmd == 'flistall'): 7040 elif(cmd == 'flistall'): 7091 sysvals.getFtraceFilt 7041 sysvals.getFtraceFilterFunctions(False) 7092 elif(cmd == 'summary'): 7042 elif(cmd == 'summary'): 7093 runSummary(sysvals.ou 7043 runSummary(sysvals.outdir, True, genhtml) 7094 elif(cmd in ['xon', 'xoff', ' 7044 elif(cmd in ['xon', 'xoff', 'xstandby', 'xsuspend', 'xinit', 'xreset']): 7095 sysvals.verbose = Tru 7045 sysvals.verbose = True 7096 ret = sysvals.display 7046 ret = sysvals.displayControl(cmd[1:]) 7097 elif(cmd == 'xstat'): 7047 elif(cmd == 'xstat'): 7098 pprint('Display Statu 7048 pprint('Display Status: %s' % sysvals.displayControl('stat').upper()) 7099 elif(cmd == 'wificheck'): 7049 elif(cmd == 'wificheck'): 7100 dev = sysvals.checkWi 7050 dev = sysvals.checkWifi() 7101 if dev: 7051 if dev: 7102 print('%s is 7052 print('%s is connected' % sysvals.wifiDetails(dev)) 7103 else: 7053 else: 7104 print('No wif 7054 print('No wifi connection found') 7105 elif(cmd == 'cmdinfo'): 7055 elif(cmd == 'cmdinfo'): 7106 for out in sysvals.cm 7056 for out in sysvals.cmdinfo(False, True): 7107 print('[%s - 7057 print('[%s - %s]\n%s\n' % out) 7108 sys.exit(ret) 7058 sys.exit(ret) 7109 7059 7110 # if instructed, re-analyze existing 7060 # if instructed, re-analyze existing data files 7111 if(sysvals.notestrun): 7061 if(sysvals.notestrun): 7112 stamp = rerunTest(sysvals.out 7062 stamp = rerunTest(sysvals.outdir) 7113 sysvals.outputResult(stamp) 7063 sysvals.outputResult(stamp) 7114 sys.exit(0) 7064 sys.exit(0) 7115 7065 7116 # verify that we can run a test 7066 # verify that we can run a test 7117 error = statusCheck() 7067 error = statusCheck() 7118 if(error): 7068 if(error): 7119 doError(error) 7069 doError(error) 7120 7070 7121 # extract mem/disk extra modes and co 7071 # extract mem/disk extra modes and convert 7122 mode = sysvals.suspendmode 7072 mode = sysvals.suspendmode 7123 if mode.startswith('mem'): 7073 if mode.startswith('mem'): 7124 memmode = mode.split('-', 1)[ 7074 memmode = mode.split('-', 1)[-1] if '-' in mode else 'deep' 7125 if memmode == 'shallow': 7075 if memmode == 'shallow': 7126 mode = 'standby' 7076 mode = 'standby' 7127 elif memmode == 's2idle': 7077 elif memmode == 's2idle': 7128 mode = 'freeze' 7078 mode = 'freeze' 7129 else: 7079 else: 7130 mode = 'mem' 7080 mode = 'mem' 7131 sysvals.memmode = memmode 7081 sysvals.memmode = memmode 7132 sysvals.suspendmode = mode 7082 sysvals.suspendmode = mode 7133 if mode.startswith('disk-'): 7083 if mode.startswith('disk-'): 7134 sysvals.diskmode = mode.split 7084 sysvals.diskmode = mode.split('-', 1)[-1] 7135 sysvals.suspendmode = 'disk' 7085 sysvals.suspendmode = 'disk' 7136 sysvals.systemInfo(dmidecode(sysvals. 7086 sysvals.systemInfo(dmidecode(sysvals.mempath)) 7137 7087 7138 failcnt, ret = 0, 0 7088 failcnt, ret = 0, 0 7139 if sysvals.multitest['run']: 7089 if sysvals.multitest['run']: 7140 # run multiple tests in a sep 7090 # run multiple tests in a separate subdirectory 7141 if not sysvals.outdir: 7091 if not sysvals.outdir: 7142 if 'time' in sysvals. 7092 if 'time' in sysvals.multitest: 7143 s = '-%dm' % 7093 s = '-%dm' % sysvals.multitest['time'] 7144 else: 7094 else: 7145 s = '-x%d' % 7095 s = '-x%d' % sysvals.multitest['count'] 7146 sysvals.outdir = date 7096 sysvals.outdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S'+s) 7147 if not os.path.isdir(sysvals. 7097 if not os.path.isdir(sysvals.outdir): 7148 os.makedirs(sysvals.o 7098 os.makedirs(sysvals.outdir) 7149 sysvals.sudoUserchown(sysvals 7099 sysvals.sudoUserchown(sysvals.outdir) 7150 finish = datetime.now() 7100 finish = datetime.now() 7151 if 'time' in sysvals.multites 7101 if 'time' in sysvals.multitest: 7152 finish += timedelta(m 7102 finish += timedelta(minutes=sysvals.multitest['time']) 7153 for i in range(sysvals.multit 7103 for i in range(sysvals.multitest['count']): 7154 sysvals.multistat(Tru 7104 sysvals.multistat(True, i, finish) 7155 if i != 0 and sysvals 7105 if i != 0 and sysvals.multitest['delay'] > 0: 7156 pprint('Waiti 7106 pprint('Waiting %d seconds...' % (sysvals.multitest['delay'])) 7157 time.sleep(sy 7107 time.sleep(sysvals.multitest['delay']) 7158 fmt = 'suspend-%y%m%d 7108 fmt = 'suspend-%y%m%d-%H%M%S' 7159 sysvals.testdir = os. 7109 sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt)) 7160 ret = runTest(i+1, no 7110 ret = runTest(i+1, not sysvals.verbose) 7161 failcnt = 0 if not re 7111 failcnt = 0 if not ret else failcnt + 1 7162 if sysvals.maxfail > 7112 if sysvals.maxfail > 0 and failcnt >= sysvals.maxfail: 7163 pprint('Maxim 7113 pprint('Maximum fail count of %d reached, aborting multitest' % (sysvals.maxfail)) 7164 break 7114 break 7165 sysvals.resetlog() 7115 sysvals.resetlog() 7166 sysvals.multistat(Fal 7116 sysvals.multistat(False, i, finish) 7167 if 'time' in sysvals. 7117 if 'time' in sysvals.multitest and datetime.now() >= finish: 7168 break 7118 break 7169 if not sysvals.skiphtml: 7119 if not sysvals.skiphtml: 7170 runSummary(sysvals.ou 7120 runSummary(sysvals.outdir, False, False) 7171 sysvals.sudoUserchown(sysvals 7121 sysvals.sudoUserchown(sysvals.outdir) 7172 else: 7122 else: 7173 if sysvals.outdir: 7123 if sysvals.outdir: 7174 sysvals.testdir = sys 7124 sysvals.testdir = sysvals.outdir 7175 # run the test in the current 7125 # run the test in the current directory 7176 ret = runTest() 7126 ret = runTest() 7177 7127 7178 # reset to default values after testi 7128 # reset to default values after testing 7179 if sysvals.display: 7129 if sysvals.display: 7180 sysvals.displayControl('reset 7130 sysvals.displayControl('reset') 7181 if sysvals.rs != 0: 7131 if sysvals.rs != 0: 7182 sysvals.setRuntimeSuspend(Fal 7132 sysvals.setRuntimeSuspend(False) 7183 sys.exit(ret) 7133 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.