162306a36Sopenharmony_ci#!/usr/bin/env python3 262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-only 362306a36Sopenharmony_ci# 462306a36Sopenharmony_ci# Tool for analyzing suspend/resume timing 562306a36Sopenharmony_ci# Copyright (c) 2013, Intel Corporation. 662306a36Sopenharmony_ci# 762306a36Sopenharmony_ci# This program is free software; you can redistribute it and/or modify it 862306a36Sopenharmony_ci# under the terms and conditions of the GNU General Public License, 962306a36Sopenharmony_ci# version 2, as published by the Free Software Foundation. 1062306a36Sopenharmony_ci# 1162306a36Sopenharmony_ci# This program is distributed in the hope it will be useful, but WITHOUT 1262306a36Sopenharmony_ci# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1362306a36Sopenharmony_ci# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1462306a36Sopenharmony_ci# more details. 1562306a36Sopenharmony_ci# 1662306a36Sopenharmony_ci# Authors: 1762306a36Sopenharmony_ci# Todd Brandt <todd.e.brandt@linux.intel.com> 1862306a36Sopenharmony_ci# 1962306a36Sopenharmony_ci# Links: 2062306a36Sopenharmony_ci# Home Page 2162306a36Sopenharmony_ci# https://01.org/pm-graph 2262306a36Sopenharmony_ci# Source repo 2362306a36Sopenharmony_ci# git@github.com:intel/pm-graph 2462306a36Sopenharmony_ci# 2562306a36Sopenharmony_ci# Description: 2662306a36Sopenharmony_ci# This tool is designed to assist kernel and OS developers in optimizing 2762306a36Sopenharmony_ci# their linux stack's suspend/resume time. Using a kernel image built 2862306a36Sopenharmony_ci# with a few extra options enabled, the tool will execute a suspend and 2962306a36Sopenharmony_ci# will capture dmesg and ftrace data until resume is complete. This data 3062306a36Sopenharmony_ci# is transformed into a device timeline and a callgraph to give a quick 3162306a36Sopenharmony_ci# and detailed view of which devices and callbacks are taking the most 3262306a36Sopenharmony_ci# time in suspend/resume. The output is a single html file which can be 3362306a36Sopenharmony_ci# viewed in firefox or chrome. 3462306a36Sopenharmony_ci# 3562306a36Sopenharmony_ci# The following kernel build options are required: 3662306a36Sopenharmony_ci# CONFIG_DEVMEM=y 3762306a36Sopenharmony_ci# CONFIG_PM_DEBUG=y 3862306a36Sopenharmony_ci# CONFIG_PM_SLEEP_DEBUG=y 3962306a36Sopenharmony_ci# CONFIG_FTRACE=y 4062306a36Sopenharmony_ci# CONFIG_FUNCTION_TRACER=y 4162306a36Sopenharmony_ci# CONFIG_FUNCTION_GRAPH_TRACER=y 4262306a36Sopenharmony_ci# CONFIG_KPROBES=y 4362306a36Sopenharmony_ci# CONFIG_KPROBES_ON_FTRACE=y 4462306a36Sopenharmony_ci# 4562306a36Sopenharmony_ci# For kernel versions older than 3.15: 4662306a36Sopenharmony_ci# The following additional kernel parameters are required: 4762306a36Sopenharmony_ci# (e.g. in file /etc/default/grub) 4862306a36Sopenharmony_ci# GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=16M ..." 4962306a36Sopenharmony_ci# 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci# ----------------- LIBRARIES -------------------- 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciimport sys 5462306a36Sopenharmony_ciimport time 5562306a36Sopenharmony_ciimport os 5662306a36Sopenharmony_ciimport string 5762306a36Sopenharmony_ciimport re 5862306a36Sopenharmony_ciimport platform 5962306a36Sopenharmony_ciimport signal 6062306a36Sopenharmony_ciimport codecs 6162306a36Sopenharmony_cifrom datetime import datetime, timedelta 6262306a36Sopenharmony_ciimport struct 6362306a36Sopenharmony_ciimport configparser 6462306a36Sopenharmony_ciimport gzip 6562306a36Sopenharmony_cifrom threading import Thread 6662306a36Sopenharmony_cifrom subprocess import call, Popen, PIPE 6762306a36Sopenharmony_ciimport base64 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cidebugtiming = False 7062306a36Sopenharmony_cimystarttime = time.time() 7162306a36Sopenharmony_cidef pprint(msg): 7262306a36Sopenharmony_ci if debugtiming: 7362306a36Sopenharmony_ci print('[%09.3f] %s' % (time.time()-mystarttime, msg)) 7462306a36Sopenharmony_ci else: 7562306a36Sopenharmony_ci print(msg) 7662306a36Sopenharmony_ci sys.stdout.flush() 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cidef ascii(text): 7962306a36Sopenharmony_ci return text.decode('ascii', 'ignore') 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci# ----------------- CLASSES -------------------- 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci# Class: SystemValues 8462306a36Sopenharmony_ci# Description: 8562306a36Sopenharmony_ci# A global, single-instance container used to 8662306a36Sopenharmony_ci# store system values and test parameters 8762306a36Sopenharmony_ciclass SystemValues: 8862306a36Sopenharmony_ci title = 'SleepGraph' 8962306a36Sopenharmony_ci version = '5.11' 9062306a36Sopenharmony_ci ansi = False 9162306a36Sopenharmony_ci rs = 0 9262306a36Sopenharmony_ci display = '' 9362306a36Sopenharmony_ci gzip = False 9462306a36Sopenharmony_ci sync = False 9562306a36Sopenharmony_ci wifi = False 9662306a36Sopenharmony_ci netfix = False 9762306a36Sopenharmony_ci verbose = False 9862306a36Sopenharmony_ci testlog = True 9962306a36Sopenharmony_ci dmesglog = True 10062306a36Sopenharmony_ci ftracelog = False 10162306a36Sopenharmony_ci acpidebug = True 10262306a36Sopenharmony_ci tstat = True 10362306a36Sopenharmony_ci wifitrace = False 10462306a36Sopenharmony_ci mindevlen = 0.0001 10562306a36Sopenharmony_ci mincglen = 0.0 10662306a36Sopenharmony_ci cgphase = '' 10762306a36Sopenharmony_ci cgtest = -1 10862306a36Sopenharmony_ci cgskip = '' 10962306a36Sopenharmony_ci maxfail = 0 11062306a36Sopenharmony_ci multitest = {'run': False, 'count': 1000000, 'delay': 0} 11162306a36Sopenharmony_ci max_graph_depth = 0 11262306a36Sopenharmony_ci callloopmaxgap = 0.0001 11362306a36Sopenharmony_ci callloopmaxlen = 0.005 11462306a36Sopenharmony_ci bufsize = 0 11562306a36Sopenharmony_ci cpucount = 0 11662306a36Sopenharmony_ci memtotal = 204800 11762306a36Sopenharmony_ci memfree = 204800 11862306a36Sopenharmony_ci osversion = '' 11962306a36Sopenharmony_ci srgap = 0 12062306a36Sopenharmony_ci cgexp = False 12162306a36Sopenharmony_ci testdir = '' 12262306a36Sopenharmony_ci outdir = '' 12362306a36Sopenharmony_ci tpath = '/sys/kernel/tracing/' 12462306a36Sopenharmony_ci fpdtpath = '/sys/firmware/acpi/tables/FPDT' 12562306a36Sopenharmony_ci epath = '/sys/kernel/tracing/events/power/' 12662306a36Sopenharmony_ci pmdpath = '/sys/power/pm_debug_messages' 12762306a36Sopenharmony_ci s0ixpath = '/sys/module/intel_pmc_core/parameters/warn_on_s0ix_failures' 12862306a36Sopenharmony_ci s0ixres = '/sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us' 12962306a36Sopenharmony_ci acpipath='/sys/module/acpi/parameters/debug_level' 13062306a36Sopenharmony_ci traceevents = [ 13162306a36Sopenharmony_ci 'suspend_resume', 13262306a36Sopenharmony_ci 'wakeup_source_activate', 13362306a36Sopenharmony_ci 'wakeup_source_deactivate', 13462306a36Sopenharmony_ci 'device_pm_callback_end', 13562306a36Sopenharmony_ci 'device_pm_callback_start' 13662306a36Sopenharmony_ci ] 13762306a36Sopenharmony_ci logmsg = '' 13862306a36Sopenharmony_ci testcommand = '' 13962306a36Sopenharmony_ci mempath = '/dev/mem' 14062306a36Sopenharmony_ci powerfile = '/sys/power/state' 14162306a36Sopenharmony_ci mempowerfile = '/sys/power/mem_sleep' 14262306a36Sopenharmony_ci diskpowerfile = '/sys/power/disk' 14362306a36Sopenharmony_ci suspendmode = 'mem' 14462306a36Sopenharmony_ci memmode = '' 14562306a36Sopenharmony_ci diskmode = '' 14662306a36Sopenharmony_ci hostname = 'localhost' 14762306a36Sopenharmony_ci prefix = 'test' 14862306a36Sopenharmony_ci teststamp = '' 14962306a36Sopenharmony_ci sysstamp = '' 15062306a36Sopenharmony_ci dmesgstart = 0.0 15162306a36Sopenharmony_ci dmesgfile = '' 15262306a36Sopenharmony_ci ftracefile = '' 15362306a36Sopenharmony_ci htmlfile = 'output.html' 15462306a36Sopenharmony_ci result = '' 15562306a36Sopenharmony_ci rtcwake = True 15662306a36Sopenharmony_ci rtcwaketime = 15 15762306a36Sopenharmony_ci rtcpath = '' 15862306a36Sopenharmony_ci devicefilter = [] 15962306a36Sopenharmony_ci cgfilter = [] 16062306a36Sopenharmony_ci stamp = 0 16162306a36Sopenharmony_ci execcount = 1 16262306a36Sopenharmony_ci x2delay = 0 16362306a36Sopenharmony_ci skiphtml = False 16462306a36Sopenharmony_ci usecallgraph = False 16562306a36Sopenharmony_ci ftopfunc = 'pm_suspend' 16662306a36Sopenharmony_ci ftop = False 16762306a36Sopenharmony_ci usetraceevents = False 16862306a36Sopenharmony_ci usetracemarkers = True 16962306a36Sopenharmony_ci useftrace = True 17062306a36Sopenharmony_ci usekprobes = True 17162306a36Sopenharmony_ci usedevsrc = False 17262306a36Sopenharmony_ci useprocmon = False 17362306a36Sopenharmony_ci notestrun = False 17462306a36Sopenharmony_ci cgdump = False 17562306a36Sopenharmony_ci devdump = False 17662306a36Sopenharmony_ci mixedphaseheight = True 17762306a36Sopenharmony_ci devprops = dict() 17862306a36Sopenharmony_ci cfgdef = dict() 17962306a36Sopenharmony_ci platinfo = [] 18062306a36Sopenharmony_ci predelay = 0 18162306a36Sopenharmony_ci postdelay = 0 18262306a36Sopenharmony_ci tmstart = 'SUSPEND START %Y%m%d-%H:%M:%S.%f' 18362306a36Sopenharmony_ci tmend = 'RESUME COMPLETE %Y%m%d-%H:%M:%S.%f' 18462306a36Sopenharmony_ci tracefuncs = { 18562306a36Sopenharmony_ci 'async_synchronize_full': {}, 18662306a36Sopenharmony_ci 'sys_sync': {}, 18762306a36Sopenharmony_ci 'ksys_sync': {}, 18862306a36Sopenharmony_ci '__pm_notifier_call_chain': {}, 18962306a36Sopenharmony_ci 'pm_prepare_console': {}, 19062306a36Sopenharmony_ci 'pm_notifier_call_chain': {}, 19162306a36Sopenharmony_ci 'freeze_processes': {}, 19262306a36Sopenharmony_ci 'freeze_kernel_threads': {}, 19362306a36Sopenharmony_ci 'pm_restrict_gfp_mask': {}, 19462306a36Sopenharmony_ci 'acpi_suspend_begin': {}, 19562306a36Sopenharmony_ci 'acpi_hibernation_begin': {}, 19662306a36Sopenharmony_ci 'acpi_hibernation_enter': {}, 19762306a36Sopenharmony_ci 'acpi_hibernation_leave': {}, 19862306a36Sopenharmony_ci 'acpi_pm_freeze': {}, 19962306a36Sopenharmony_ci 'acpi_pm_thaw': {}, 20062306a36Sopenharmony_ci 'acpi_s2idle_end': {}, 20162306a36Sopenharmony_ci 'acpi_s2idle_sync': {}, 20262306a36Sopenharmony_ci 'acpi_s2idle_begin': {}, 20362306a36Sopenharmony_ci 'acpi_s2idle_prepare': {}, 20462306a36Sopenharmony_ci 'acpi_s2idle_prepare_late': {}, 20562306a36Sopenharmony_ci 'acpi_s2idle_wake': {}, 20662306a36Sopenharmony_ci 'acpi_s2idle_wakeup': {}, 20762306a36Sopenharmony_ci 'acpi_s2idle_restore': {}, 20862306a36Sopenharmony_ci 'acpi_s2idle_restore_early': {}, 20962306a36Sopenharmony_ci 'hibernate_preallocate_memory': {}, 21062306a36Sopenharmony_ci 'create_basic_memory_bitmaps': {}, 21162306a36Sopenharmony_ci 'swsusp_write': {}, 21262306a36Sopenharmony_ci 'suspend_console': {}, 21362306a36Sopenharmony_ci 'acpi_pm_prepare': {}, 21462306a36Sopenharmony_ci 'syscore_suspend': {}, 21562306a36Sopenharmony_ci 'arch_enable_nonboot_cpus_end': {}, 21662306a36Sopenharmony_ci 'syscore_resume': {}, 21762306a36Sopenharmony_ci 'acpi_pm_finish': {}, 21862306a36Sopenharmony_ci 'resume_console': {}, 21962306a36Sopenharmony_ci 'acpi_pm_end': {}, 22062306a36Sopenharmony_ci 'pm_restore_gfp_mask': {}, 22162306a36Sopenharmony_ci 'thaw_processes': {}, 22262306a36Sopenharmony_ci 'pm_restore_console': {}, 22362306a36Sopenharmony_ci 'CPU_OFF': { 22462306a36Sopenharmony_ci 'func':'_cpu_down', 22562306a36Sopenharmony_ci 'args_x86_64': {'cpu':'%di:s32'}, 22662306a36Sopenharmony_ci 'format': 'CPU_OFF[{cpu}]' 22762306a36Sopenharmony_ci }, 22862306a36Sopenharmony_ci 'CPU_ON': { 22962306a36Sopenharmony_ci 'func':'_cpu_up', 23062306a36Sopenharmony_ci 'args_x86_64': {'cpu':'%di:s32'}, 23162306a36Sopenharmony_ci 'format': 'CPU_ON[{cpu}]' 23262306a36Sopenharmony_ci }, 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci dev_tracefuncs = { 23562306a36Sopenharmony_ci # general wait/delay/sleep 23662306a36Sopenharmony_ci 'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 }, 23762306a36Sopenharmony_ci 'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 }, 23862306a36Sopenharmony_ci 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 }, 23962306a36Sopenharmony_ci 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 }, 24062306a36Sopenharmony_ci 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 }, 24162306a36Sopenharmony_ci 'acpi_os_stall': {'ub': 1}, 24262306a36Sopenharmony_ci 'rt_mutex_slowlock': {'ub': 1}, 24362306a36Sopenharmony_ci # ACPI 24462306a36Sopenharmony_ci 'acpi_resume_power_resources': {}, 24562306a36Sopenharmony_ci 'acpi_ps_execute_method': { 'args_x86_64': { 24662306a36Sopenharmony_ci 'fullpath':'+0(+40(%di)):string', 24762306a36Sopenharmony_ci }}, 24862306a36Sopenharmony_ci # mei_me 24962306a36Sopenharmony_ci 'mei_reset': {}, 25062306a36Sopenharmony_ci # filesystem 25162306a36Sopenharmony_ci 'ext4_sync_fs': {}, 25262306a36Sopenharmony_ci # 80211 25362306a36Sopenharmony_ci 'ath10k_bmi_read_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 25462306a36Sopenharmony_ci 'ath10k_bmi_write_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 25562306a36Sopenharmony_ci 'ath10k_bmi_fast_download': { 'args_x86_64': {'length':'%cx:s32'} }, 25662306a36Sopenharmony_ci 'iwlagn_mac_start': {}, 25762306a36Sopenharmony_ci 'iwlagn_alloc_bcast_station': {}, 25862306a36Sopenharmony_ci 'iwl_trans_pcie_start_hw': {}, 25962306a36Sopenharmony_ci 'iwl_trans_pcie_start_fw': {}, 26062306a36Sopenharmony_ci 'iwl_run_init_ucode': {}, 26162306a36Sopenharmony_ci 'iwl_load_ucode_wait_alive': {}, 26262306a36Sopenharmony_ci 'iwl_alive_start': {}, 26362306a36Sopenharmony_ci 'iwlagn_mac_stop': {}, 26462306a36Sopenharmony_ci 'iwlagn_mac_suspend': {}, 26562306a36Sopenharmony_ci 'iwlagn_mac_resume': {}, 26662306a36Sopenharmony_ci 'iwlagn_mac_add_interface': {}, 26762306a36Sopenharmony_ci 'iwlagn_mac_remove_interface': {}, 26862306a36Sopenharmony_ci 'iwlagn_mac_change_interface': {}, 26962306a36Sopenharmony_ci 'iwlagn_mac_config': {}, 27062306a36Sopenharmony_ci 'iwlagn_configure_filter': {}, 27162306a36Sopenharmony_ci 'iwlagn_mac_hw_scan': {}, 27262306a36Sopenharmony_ci 'iwlagn_bss_info_changed': {}, 27362306a36Sopenharmony_ci 'iwlagn_mac_channel_switch': {}, 27462306a36Sopenharmony_ci 'iwlagn_mac_flush': {}, 27562306a36Sopenharmony_ci # ATA 27662306a36Sopenharmony_ci 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} }, 27762306a36Sopenharmony_ci # i915 27862306a36Sopenharmony_ci 'i915_gem_resume': {}, 27962306a36Sopenharmony_ci 'i915_restore_state': {}, 28062306a36Sopenharmony_ci 'intel_opregion_setup': {}, 28162306a36Sopenharmony_ci 'g4x_pre_enable_dp': {}, 28262306a36Sopenharmony_ci 'vlv_pre_enable_dp': {}, 28362306a36Sopenharmony_ci 'chv_pre_enable_dp': {}, 28462306a36Sopenharmony_ci 'g4x_enable_dp': {}, 28562306a36Sopenharmony_ci 'vlv_enable_dp': {}, 28662306a36Sopenharmony_ci 'intel_hpd_init': {}, 28762306a36Sopenharmony_ci 'intel_opregion_register': {}, 28862306a36Sopenharmony_ci 'intel_dp_detect': {}, 28962306a36Sopenharmony_ci 'intel_hdmi_detect': {}, 29062306a36Sopenharmony_ci 'intel_opregion_init': {}, 29162306a36Sopenharmony_ci 'intel_fbdev_set_suspend': {}, 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci infocmds = [ 29462306a36Sopenharmony_ci [0, 'sysinfo', 'uname', '-a'], 29562306a36Sopenharmony_ci [0, 'cpuinfo', 'head', '-7', '/proc/cpuinfo'], 29662306a36Sopenharmony_ci [0, 'kparams', 'cat', '/proc/cmdline'], 29762306a36Sopenharmony_ci [0, 'mcelog', 'mcelog'], 29862306a36Sopenharmony_ci [0, 'pcidevices', 'lspci', '-tv'], 29962306a36Sopenharmony_ci [0, 'usbdevices', 'lsusb', '-tv'], 30062306a36Sopenharmony_ci [0, 'acpidevices', 'sh', '-c', 'ls -l /sys/bus/acpi/devices/*/physical_node'], 30162306a36Sopenharmony_ci [0, 's0ix_require', 'cat', '/sys/kernel/debug/pmc_core/substate_requirements'], 30262306a36Sopenharmony_ci [0, 's0ix_debug', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_debug_status'], 30362306a36Sopenharmony_ci [0, 'ethtool', 'ethtool', '{ethdev}'], 30462306a36Sopenharmony_ci [1, 's0ix_residency', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_residency_usec'], 30562306a36Sopenharmony_ci [1, 'interrupts', 'cat', '/proc/interrupts'], 30662306a36Sopenharmony_ci [1, 'wakeups', 'cat', '/sys/kernel/debug/wakeup_sources'], 30762306a36Sopenharmony_ci [2, 'gpecounts', 'sh', '-c', 'grep -v invalid /sys/firmware/acpi/interrupts/*'], 30862306a36Sopenharmony_ci [2, 'suspendstats', 'sh', '-c', 'grep -v invalid /sys/power/suspend_stats/*'], 30962306a36Sopenharmony_ci [2, 'cpuidle', 'sh', '-c', 'grep -v invalid /sys/devices/system/cpu/cpu*/cpuidle/state*/s2idle/*'], 31062306a36Sopenharmony_ci [2, 'battery', 'sh', '-c', 'grep -v invalid /sys/class/power_supply/*/*'], 31162306a36Sopenharmony_ci [2, 'thermal', 'sh', '-c', 'grep . /sys/class/thermal/thermal_zone*/temp'], 31262306a36Sopenharmony_ci ] 31362306a36Sopenharmony_ci cgblacklist = [] 31462306a36Sopenharmony_ci kprobes = dict() 31562306a36Sopenharmony_ci timeformat = '%.3f' 31662306a36Sopenharmony_ci cmdline = '%s %s' % \ 31762306a36Sopenharmony_ci (os.path.basename(sys.argv[0]), ' '.join(sys.argv[1:])) 31862306a36Sopenharmony_ci sudouser = '' 31962306a36Sopenharmony_ci def __init__(self): 32062306a36Sopenharmony_ci self.archargs = 'args_'+platform.machine() 32162306a36Sopenharmony_ci self.hostname = platform.node() 32262306a36Sopenharmony_ci if(self.hostname == ''): 32362306a36Sopenharmony_ci self.hostname = 'localhost' 32462306a36Sopenharmony_ci rtc = "rtc0" 32562306a36Sopenharmony_ci if os.path.exists('/dev/rtc'): 32662306a36Sopenharmony_ci rtc = os.readlink('/dev/rtc') 32762306a36Sopenharmony_ci rtc = '/sys/class/rtc/'+rtc 32862306a36Sopenharmony_ci if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \ 32962306a36Sopenharmony_ci os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'): 33062306a36Sopenharmony_ci self.rtcpath = rtc 33162306a36Sopenharmony_ci if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): 33262306a36Sopenharmony_ci self.ansi = True 33362306a36Sopenharmony_ci self.testdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S') 33462306a36Sopenharmony_ci if os.getuid() == 0 and 'SUDO_USER' in os.environ and \ 33562306a36Sopenharmony_ci os.environ['SUDO_USER']: 33662306a36Sopenharmony_ci self.sudouser = os.environ['SUDO_USER'] 33762306a36Sopenharmony_ci def resetlog(self): 33862306a36Sopenharmony_ci self.logmsg = '' 33962306a36Sopenharmony_ci self.platinfo = [] 34062306a36Sopenharmony_ci def vprint(self, msg): 34162306a36Sopenharmony_ci self.logmsg += msg+'\n' 34262306a36Sopenharmony_ci if self.verbose or msg.startswith('WARNING:'): 34362306a36Sopenharmony_ci pprint(msg) 34462306a36Sopenharmony_ci def signalHandler(self, signum, frame): 34562306a36Sopenharmony_ci if not self.result: 34662306a36Sopenharmony_ci return 34762306a36Sopenharmony_ci signame = self.signames[signum] if signum in self.signames else 'UNKNOWN' 34862306a36Sopenharmony_ci msg = 'Signal %s caused a tool exit, line %d' % (signame, frame.f_lineno) 34962306a36Sopenharmony_ci self.outputResult({'error':msg}) 35062306a36Sopenharmony_ci sys.exit(3) 35162306a36Sopenharmony_ci def signalHandlerInit(self): 35262306a36Sopenharmony_ci capture = ['BUS', 'SYS', 'XCPU', 'XFSZ', 'PWR', 'HUP', 'INT', 'QUIT', 35362306a36Sopenharmony_ci 'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM'] 35462306a36Sopenharmony_ci self.signames = dict() 35562306a36Sopenharmony_ci for i in capture: 35662306a36Sopenharmony_ci s = 'SIG'+i 35762306a36Sopenharmony_ci try: 35862306a36Sopenharmony_ci signum = getattr(signal, s) 35962306a36Sopenharmony_ci signal.signal(signum, self.signalHandler) 36062306a36Sopenharmony_ci except: 36162306a36Sopenharmony_ci continue 36262306a36Sopenharmony_ci self.signames[signum] = s 36362306a36Sopenharmony_ci def rootCheck(self, fatal=True): 36462306a36Sopenharmony_ci if(os.access(self.powerfile, os.W_OK)): 36562306a36Sopenharmony_ci return True 36662306a36Sopenharmony_ci if fatal: 36762306a36Sopenharmony_ci msg = 'This command requires sysfs mount and root access' 36862306a36Sopenharmony_ci pprint('ERROR: %s\n' % msg) 36962306a36Sopenharmony_ci self.outputResult({'error':msg}) 37062306a36Sopenharmony_ci sys.exit(1) 37162306a36Sopenharmony_ci return False 37262306a36Sopenharmony_ci def rootUser(self, fatal=False): 37362306a36Sopenharmony_ci if 'USER' in os.environ and os.environ['USER'] == 'root': 37462306a36Sopenharmony_ci return True 37562306a36Sopenharmony_ci if fatal: 37662306a36Sopenharmony_ci msg = 'This command must be run as root' 37762306a36Sopenharmony_ci pprint('ERROR: %s\n' % msg) 37862306a36Sopenharmony_ci self.outputResult({'error':msg}) 37962306a36Sopenharmony_ci sys.exit(1) 38062306a36Sopenharmony_ci return False 38162306a36Sopenharmony_ci def usable(self, file, ishtml=False): 38262306a36Sopenharmony_ci if not os.path.exists(file) or os.path.getsize(file) < 1: 38362306a36Sopenharmony_ci return False 38462306a36Sopenharmony_ci if ishtml: 38562306a36Sopenharmony_ci try: 38662306a36Sopenharmony_ci fp = open(file, 'r') 38762306a36Sopenharmony_ci res = fp.read(1000) 38862306a36Sopenharmony_ci fp.close() 38962306a36Sopenharmony_ci except: 39062306a36Sopenharmony_ci return False 39162306a36Sopenharmony_ci if '<html>' not in res: 39262306a36Sopenharmony_ci return False 39362306a36Sopenharmony_ci return True 39462306a36Sopenharmony_ci def getExec(self, cmd): 39562306a36Sopenharmony_ci try: 39662306a36Sopenharmony_ci fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout 39762306a36Sopenharmony_ci out = ascii(fp.read()).strip() 39862306a36Sopenharmony_ci fp.close() 39962306a36Sopenharmony_ci except: 40062306a36Sopenharmony_ci out = '' 40162306a36Sopenharmony_ci if out: 40262306a36Sopenharmony_ci return out 40362306a36Sopenharmony_ci for path in ['/sbin', '/bin', '/usr/sbin', '/usr/bin', 40462306a36Sopenharmony_ci '/usr/local/sbin', '/usr/local/bin']: 40562306a36Sopenharmony_ci cmdfull = os.path.join(path, cmd) 40662306a36Sopenharmony_ci if os.path.exists(cmdfull): 40762306a36Sopenharmony_ci return cmdfull 40862306a36Sopenharmony_ci return out 40962306a36Sopenharmony_ci def setPrecision(self, num): 41062306a36Sopenharmony_ci if num < 0 or num > 6: 41162306a36Sopenharmony_ci return 41262306a36Sopenharmony_ci self.timeformat = '%.{0}f'.format(num) 41362306a36Sopenharmony_ci def setOutputFolder(self, value): 41462306a36Sopenharmony_ci args = dict() 41562306a36Sopenharmony_ci n = datetime.now() 41662306a36Sopenharmony_ci args['date'] = n.strftime('%y%m%d') 41762306a36Sopenharmony_ci args['time'] = n.strftime('%H%M%S') 41862306a36Sopenharmony_ci args['hostname'] = args['host'] = self.hostname 41962306a36Sopenharmony_ci args['mode'] = self.suspendmode 42062306a36Sopenharmony_ci return value.format(**args) 42162306a36Sopenharmony_ci def setOutputFile(self): 42262306a36Sopenharmony_ci if self.dmesgfile != '': 42362306a36Sopenharmony_ci m = re.match('(?P<name>.*)_dmesg\.txt.*', self.dmesgfile) 42462306a36Sopenharmony_ci if(m): 42562306a36Sopenharmony_ci self.htmlfile = m.group('name')+'.html' 42662306a36Sopenharmony_ci if self.ftracefile != '': 42762306a36Sopenharmony_ci m = re.match('(?P<name>.*)_ftrace\.txt.*', self.ftracefile) 42862306a36Sopenharmony_ci if(m): 42962306a36Sopenharmony_ci self.htmlfile = m.group('name')+'.html' 43062306a36Sopenharmony_ci def systemInfo(self, info): 43162306a36Sopenharmony_ci p = m = '' 43262306a36Sopenharmony_ci if 'baseboard-manufacturer' in info: 43362306a36Sopenharmony_ci m = info['baseboard-manufacturer'] 43462306a36Sopenharmony_ci elif 'system-manufacturer' in info: 43562306a36Sopenharmony_ci m = info['system-manufacturer'] 43662306a36Sopenharmony_ci if 'system-product-name' in info: 43762306a36Sopenharmony_ci p = info['system-product-name'] 43862306a36Sopenharmony_ci elif 'baseboard-product-name' in info: 43962306a36Sopenharmony_ci p = info['baseboard-product-name'] 44062306a36Sopenharmony_ci if m[:5].lower() == 'intel' and 'baseboard-product-name' in info: 44162306a36Sopenharmony_ci p = info['baseboard-product-name'] 44262306a36Sopenharmony_ci c = info['processor-version'] if 'processor-version' in info else '' 44362306a36Sopenharmony_ci b = info['bios-version'] if 'bios-version' in info else '' 44462306a36Sopenharmony_ci r = info['bios-release-date'] if 'bios-release-date' in info else '' 44562306a36Sopenharmony_ci self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | biosdate:%s | numcpu:%d | memsz:%d | memfr:%d' % \ 44662306a36Sopenharmony_ci (m, p, c, b, r, self.cpucount, self.memtotal, self.memfree) 44762306a36Sopenharmony_ci if self.osversion: 44862306a36Sopenharmony_ci self.sysstamp += ' | os:%s' % self.osversion 44962306a36Sopenharmony_ci def printSystemInfo(self, fatal=False): 45062306a36Sopenharmony_ci self.rootCheck(True) 45162306a36Sopenharmony_ci out = dmidecode(self.mempath, fatal) 45262306a36Sopenharmony_ci if len(out) < 1: 45362306a36Sopenharmony_ci return 45462306a36Sopenharmony_ci fmt = '%-24s: %s' 45562306a36Sopenharmony_ci if self.osversion: 45662306a36Sopenharmony_ci print(fmt % ('os-version', self.osversion)) 45762306a36Sopenharmony_ci for name in sorted(out): 45862306a36Sopenharmony_ci print(fmt % (name, out[name])) 45962306a36Sopenharmony_ci print(fmt % ('cpucount', ('%d' % self.cpucount))) 46062306a36Sopenharmony_ci print(fmt % ('memtotal', ('%d kB' % self.memtotal))) 46162306a36Sopenharmony_ci print(fmt % ('memfree', ('%d kB' % self.memfree))) 46262306a36Sopenharmony_ci def cpuInfo(self): 46362306a36Sopenharmony_ci self.cpucount = 0 46462306a36Sopenharmony_ci if os.path.exists('/proc/cpuinfo'): 46562306a36Sopenharmony_ci with open('/proc/cpuinfo', 'r') as fp: 46662306a36Sopenharmony_ci for line in fp: 46762306a36Sopenharmony_ci if re.match('^processor[ \t]*:[ \t]*[0-9]*', line): 46862306a36Sopenharmony_ci self.cpucount += 1 46962306a36Sopenharmony_ci if os.path.exists('/proc/meminfo'): 47062306a36Sopenharmony_ci with open('/proc/meminfo', 'r') as fp: 47162306a36Sopenharmony_ci for line in fp: 47262306a36Sopenharmony_ci m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line) 47362306a36Sopenharmony_ci if m: 47462306a36Sopenharmony_ci self.memtotal = int(m.group('sz')) 47562306a36Sopenharmony_ci m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line) 47662306a36Sopenharmony_ci if m: 47762306a36Sopenharmony_ci self.memfree = int(m.group('sz')) 47862306a36Sopenharmony_ci if os.path.exists('/etc/os-release'): 47962306a36Sopenharmony_ci with open('/etc/os-release', 'r') as fp: 48062306a36Sopenharmony_ci for line in fp: 48162306a36Sopenharmony_ci if line.startswith('PRETTY_NAME='): 48262306a36Sopenharmony_ci self.osversion = line[12:].strip().replace('"', '') 48362306a36Sopenharmony_ci def initTestOutput(self, name): 48462306a36Sopenharmony_ci self.prefix = self.hostname 48562306a36Sopenharmony_ci v = open('/proc/version', 'r').read().strip() 48662306a36Sopenharmony_ci kver = v.split()[2] 48762306a36Sopenharmony_ci fmt = name+'-%m%d%y-%H%M%S' 48862306a36Sopenharmony_ci testtime = datetime.now().strftime(fmt) 48962306a36Sopenharmony_ci self.teststamp = \ 49062306a36Sopenharmony_ci '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver 49162306a36Sopenharmony_ci ext = '' 49262306a36Sopenharmony_ci if self.gzip: 49362306a36Sopenharmony_ci ext = '.gz' 49462306a36Sopenharmony_ci self.dmesgfile = \ 49562306a36Sopenharmony_ci self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt'+ext 49662306a36Sopenharmony_ci self.ftracefile = \ 49762306a36Sopenharmony_ci self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt'+ext 49862306a36Sopenharmony_ci self.htmlfile = \ 49962306a36Sopenharmony_ci self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' 50062306a36Sopenharmony_ci if not os.path.isdir(self.testdir): 50162306a36Sopenharmony_ci os.makedirs(self.testdir) 50262306a36Sopenharmony_ci self.sudoUserchown(self.testdir) 50362306a36Sopenharmony_ci def getValueList(self, value): 50462306a36Sopenharmony_ci out = [] 50562306a36Sopenharmony_ci for i in value.split(','): 50662306a36Sopenharmony_ci if i.strip(): 50762306a36Sopenharmony_ci out.append(i.strip()) 50862306a36Sopenharmony_ci return out 50962306a36Sopenharmony_ci def setDeviceFilter(self, value): 51062306a36Sopenharmony_ci self.devicefilter = self.getValueList(value) 51162306a36Sopenharmony_ci def setCallgraphFilter(self, value): 51262306a36Sopenharmony_ci self.cgfilter = self.getValueList(value) 51362306a36Sopenharmony_ci def skipKprobes(self, value): 51462306a36Sopenharmony_ci for k in self.getValueList(value): 51562306a36Sopenharmony_ci if k in self.tracefuncs: 51662306a36Sopenharmony_ci del self.tracefuncs[k] 51762306a36Sopenharmony_ci if k in self.dev_tracefuncs: 51862306a36Sopenharmony_ci del self.dev_tracefuncs[k] 51962306a36Sopenharmony_ci def setCallgraphBlacklist(self, file): 52062306a36Sopenharmony_ci self.cgblacklist = self.listFromFile(file) 52162306a36Sopenharmony_ci def rtcWakeAlarmOn(self): 52262306a36Sopenharmony_ci call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True) 52362306a36Sopenharmony_ci nowtime = open(self.rtcpath+'/since_epoch', 'r').read().strip() 52462306a36Sopenharmony_ci if nowtime: 52562306a36Sopenharmony_ci nowtime = int(nowtime) 52662306a36Sopenharmony_ci else: 52762306a36Sopenharmony_ci # if hardware time fails, use the software time 52862306a36Sopenharmony_ci nowtime = int(datetime.now().strftime('%s')) 52962306a36Sopenharmony_ci alarm = nowtime + self.rtcwaketime 53062306a36Sopenharmony_ci call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True) 53162306a36Sopenharmony_ci def rtcWakeAlarmOff(self): 53262306a36Sopenharmony_ci call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True) 53362306a36Sopenharmony_ci def initdmesg(self): 53462306a36Sopenharmony_ci # get the latest time stamp from the dmesg log 53562306a36Sopenharmony_ci lines = Popen('dmesg', stdout=PIPE).stdout.readlines() 53662306a36Sopenharmony_ci ktime = '0' 53762306a36Sopenharmony_ci for line in reversed(lines): 53862306a36Sopenharmony_ci line = ascii(line).replace('\r\n', '') 53962306a36Sopenharmony_ci idx = line.find('[') 54062306a36Sopenharmony_ci if idx > 1: 54162306a36Sopenharmony_ci line = line[idx:] 54262306a36Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 54362306a36Sopenharmony_ci if(m): 54462306a36Sopenharmony_ci ktime = m.group('ktime') 54562306a36Sopenharmony_ci break 54662306a36Sopenharmony_ci self.dmesgstart = float(ktime) 54762306a36Sopenharmony_ci def getdmesg(self, testdata): 54862306a36Sopenharmony_ci op = self.writeDatafileHeader(self.dmesgfile, testdata) 54962306a36Sopenharmony_ci # store all new dmesg lines since initdmesg was called 55062306a36Sopenharmony_ci fp = Popen('dmesg', stdout=PIPE).stdout 55162306a36Sopenharmony_ci for line in fp: 55262306a36Sopenharmony_ci line = ascii(line).replace('\r\n', '') 55362306a36Sopenharmony_ci idx = line.find('[') 55462306a36Sopenharmony_ci if idx > 1: 55562306a36Sopenharmony_ci line = line[idx:] 55662306a36Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 55762306a36Sopenharmony_ci if(not m): 55862306a36Sopenharmony_ci continue 55962306a36Sopenharmony_ci ktime = float(m.group('ktime')) 56062306a36Sopenharmony_ci if ktime > self.dmesgstart: 56162306a36Sopenharmony_ci op.write(line) 56262306a36Sopenharmony_ci fp.close() 56362306a36Sopenharmony_ci op.close() 56462306a36Sopenharmony_ci def listFromFile(self, file): 56562306a36Sopenharmony_ci list = [] 56662306a36Sopenharmony_ci fp = open(file) 56762306a36Sopenharmony_ci for i in fp.read().split('\n'): 56862306a36Sopenharmony_ci i = i.strip() 56962306a36Sopenharmony_ci if i and i[0] != '#': 57062306a36Sopenharmony_ci list.append(i) 57162306a36Sopenharmony_ci fp.close() 57262306a36Sopenharmony_ci return list 57362306a36Sopenharmony_ci def addFtraceFilterFunctions(self, file): 57462306a36Sopenharmony_ci for i in self.listFromFile(file): 57562306a36Sopenharmony_ci if len(i) < 2: 57662306a36Sopenharmony_ci continue 57762306a36Sopenharmony_ci self.tracefuncs[i] = dict() 57862306a36Sopenharmony_ci def getFtraceFilterFunctions(self, current): 57962306a36Sopenharmony_ci self.rootCheck(True) 58062306a36Sopenharmony_ci if not current: 58162306a36Sopenharmony_ci call('cat '+self.tpath+'available_filter_functions', shell=True) 58262306a36Sopenharmony_ci return 58362306a36Sopenharmony_ci master = self.listFromFile(self.tpath+'available_filter_functions') 58462306a36Sopenharmony_ci for i in sorted(self.tracefuncs): 58562306a36Sopenharmony_ci if 'func' in self.tracefuncs[i]: 58662306a36Sopenharmony_ci i = self.tracefuncs[i]['func'] 58762306a36Sopenharmony_ci if i in master: 58862306a36Sopenharmony_ci print(i) 58962306a36Sopenharmony_ci else: 59062306a36Sopenharmony_ci print(self.colorText(i)) 59162306a36Sopenharmony_ci def setFtraceFilterFunctions(self, list): 59262306a36Sopenharmony_ci master = self.listFromFile(self.tpath+'available_filter_functions') 59362306a36Sopenharmony_ci flist = '' 59462306a36Sopenharmony_ci for i in list: 59562306a36Sopenharmony_ci if i not in master: 59662306a36Sopenharmony_ci continue 59762306a36Sopenharmony_ci if ' [' in i: 59862306a36Sopenharmony_ci flist += i.split(' ')[0]+'\n' 59962306a36Sopenharmony_ci else: 60062306a36Sopenharmony_ci flist += i+'\n' 60162306a36Sopenharmony_ci fp = open(self.tpath+'set_graph_function', 'w') 60262306a36Sopenharmony_ci fp.write(flist) 60362306a36Sopenharmony_ci fp.close() 60462306a36Sopenharmony_ci def basicKprobe(self, name): 60562306a36Sopenharmony_ci self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name} 60662306a36Sopenharmony_ci def defaultKprobe(self, name, kdata): 60762306a36Sopenharmony_ci k = kdata 60862306a36Sopenharmony_ci for field in ['name', 'format', 'func']: 60962306a36Sopenharmony_ci if field not in k: 61062306a36Sopenharmony_ci k[field] = name 61162306a36Sopenharmony_ci if self.archargs in k: 61262306a36Sopenharmony_ci k['args'] = k[self.archargs] 61362306a36Sopenharmony_ci else: 61462306a36Sopenharmony_ci k['args'] = dict() 61562306a36Sopenharmony_ci k['format'] = name 61662306a36Sopenharmony_ci self.kprobes[name] = k 61762306a36Sopenharmony_ci def kprobeColor(self, name): 61862306a36Sopenharmony_ci if name not in self.kprobes or 'color' not in self.kprobes[name]: 61962306a36Sopenharmony_ci return '' 62062306a36Sopenharmony_ci return self.kprobes[name]['color'] 62162306a36Sopenharmony_ci def kprobeDisplayName(self, name, dataraw): 62262306a36Sopenharmony_ci if name not in self.kprobes: 62362306a36Sopenharmony_ci self.basicKprobe(name) 62462306a36Sopenharmony_ci data = '' 62562306a36Sopenharmony_ci quote=0 62662306a36Sopenharmony_ci # first remvoe any spaces inside quotes, and the quotes 62762306a36Sopenharmony_ci for c in dataraw: 62862306a36Sopenharmony_ci if c == '"': 62962306a36Sopenharmony_ci quote = (quote + 1) % 2 63062306a36Sopenharmony_ci if quote and c == ' ': 63162306a36Sopenharmony_ci data += '_' 63262306a36Sopenharmony_ci elif c != '"': 63362306a36Sopenharmony_ci data += c 63462306a36Sopenharmony_ci fmt, args = self.kprobes[name]['format'], self.kprobes[name]['args'] 63562306a36Sopenharmony_ci arglist = dict() 63662306a36Sopenharmony_ci # now process the args 63762306a36Sopenharmony_ci for arg in sorted(args): 63862306a36Sopenharmony_ci arglist[arg] = '' 63962306a36Sopenharmony_ci m = re.match('.* '+arg+'=(?P<arg>.*) ', data); 64062306a36Sopenharmony_ci if m: 64162306a36Sopenharmony_ci arglist[arg] = m.group('arg') 64262306a36Sopenharmony_ci else: 64362306a36Sopenharmony_ci m = re.match('.* '+arg+'=(?P<arg>.*)', data); 64462306a36Sopenharmony_ci if m: 64562306a36Sopenharmony_ci arglist[arg] = m.group('arg') 64662306a36Sopenharmony_ci out = fmt.format(**arglist) 64762306a36Sopenharmony_ci out = out.replace(' ', '_').replace('"', '') 64862306a36Sopenharmony_ci return out 64962306a36Sopenharmony_ci def kprobeText(self, kname, kprobe): 65062306a36Sopenharmony_ci name = fmt = func = kname 65162306a36Sopenharmony_ci args = dict() 65262306a36Sopenharmony_ci if 'name' in kprobe: 65362306a36Sopenharmony_ci name = kprobe['name'] 65462306a36Sopenharmony_ci if 'format' in kprobe: 65562306a36Sopenharmony_ci fmt = kprobe['format'] 65662306a36Sopenharmony_ci if 'func' in kprobe: 65762306a36Sopenharmony_ci func = kprobe['func'] 65862306a36Sopenharmony_ci if self.archargs in kprobe: 65962306a36Sopenharmony_ci args = kprobe[self.archargs] 66062306a36Sopenharmony_ci if 'args' in kprobe: 66162306a36Sopenharmony_ci args = kprobe['args'] 66262306a36Sopenharmony_ci if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func): 66362306a36Sopenharmony_ci doError('Kprobe "%s" has format info in the function name "%s"' % (name, func)) 66462306a36Sopenharmony_ci for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt): 66562306a36Sopenharmony_ci if arg not in args: 66662306a36Sopenharmony_ci doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 66762306a36Sopenharmony_ci val = 'p:%s_cal %s' % (name, func) 66862306a36Sopenharmony_ci for i in sorted(args): 66962306a36Sopenharmony_ci val += ' %s=%s' % (i, args[i]) 67062306a36Sopenharmony_ci val += '\nr:%s_ret %s $retval\n' % (name, func) 67162306a36Sopenharmony_ci return val 67262306a36Sopenharmony_ci def addKprobes(self, output=False): 67362306a36Sopenharmony_ci if len(self.kprobes) < 1: 67462306a36Sopenharmony_ci return 67562306a36Sopenharmony_ci if output: 67662306a36Sopenharmony_ci pprint(' kprobe functions in this kernel:') 67762306a36Sopenharmony_ci # first test each kprobe 67862306a36Sopenharmony_ci rejects = [] 67962306a36Sopenharmony_ci # sort kprobes: trace, ub-dev, custom, dev 68062306a36Sopenharmony_ci kpl = [[], [], [], []] 68162306a36Sopenharmony_ci linesout = len(self.kprobes) 68262306a36Sopenharmony_ci for name in sorted(self.kprobes): 68362306a36Sopenharmony_ci res = self.colorText('YES', 32) 68462306a36Sopenharmony_ci if not self.testKprobe(name, self.kprobes[name]): 68562306a36Sopenharmony_ci res = self.colorText('NO') 68662306a36Sopenharmony_ci rejects.append(name) 68762306a36Sopenharmony_ci else: 68862306a36Sopenharmony_ci if name in self.tracefuncs: 68962306a36Sopenharmony_ci kpl[0].append(name) 69062306a36Sopenharmony_ci elif name in self.dev_tracefuncs: 69162306a36Sopenharmony_ci if 'ub' in self.dev_tracefuncs[name]: 69262306a36Sopenharmony_ci kpl[1].append(name) 69362306a36Sopenharmony_ci else: 69462306a36Sopenharmony_ci kpl[3].append(name) 69562306a36Sopenharmony_ci else: 69662306a36Sopenharmony_ci kpl[2].append(name) 69762306a36Sopenharmony_ci if output: 69862306a36Sopenharmony_ci pprint(' %s: %s' % (name, res)) 69962306a36Sopenharmony_ci kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3] 70062306a36Sopenharmony_ci # remove all failed ones from the list 70162306a36Sopenharmony_ci for name in rejects: 70262306a36Sopenharmony_ci self.kprobes.pop(name) 70362306a36Sopenharmony_ci # set the kprobes all at once 70462306a36Sopenharmony_ci self.fsetVal('', 'kprobe_events') 70562306a36Sopenharmony_ci kprobeevents = '' 70662306a36Sopenharmony_ci for kp in kplist: 70762306a36Sopenharmony_ci kprobeevents += self.kprobeText(kp, self.kprobes[kp]) 70862306a36Sopenharmony_ci self.fsetVal(kprobeevents, 'kprobe_events') 70962306a36Sopenharmony_ci if output: 71062306a36Sopenharmony_ci check = self.fgetVal('kprobe_events') 71162306a36Sopenharmony_ci linesack = (len(check.split('\n')) - 1) // 2 71262306a36Sopenharmony_ci pprint(' kprobe functions enabled: %d/%d' % (linesack, linesout)) 71362306a36Sopenharmony_ci self.fsetVal('1', 'events/kprobes/enable') 71462306a36Sopenharmony_ci def testKprobe(self, kname, kprobe): 71562306a36Sopenharmony_ci self.fsetVal('0', 'events/kprobes/enable') 71662306a36Sopenharmony_ci kprobeevents = self.kprobeText(kname, kprobe) 71762306a36Sopenharmony_ci if not kprobeevents: 71862306a36Sopenharmony_ci return False 71962306a36Sopenharmony_ci try: 72062306a36Sopenharmony_ci self.fsetVal(kprobeevents, 'kprobe_events') 72162306a36Sopenharmony_ci check = self.fgetVal('kprobe_events') 72262306a36Sopenharmony_ci except: 72362306a36Sopenharmony_ci return False 72462306a36Sopenharmony_ci linesout = len(kprobeevents.split('\n')) 72562306a36Sopenharmony_ci linesack = len(check.split('\n')) 72662306a36Sopenharmony_ci if linesack < linesout: 72762306a36Sopenharmony_ci return False 72862306a36Sopenharmony_ci return True 72962306a36Sopenharmony_ci def setVal(self, val, file): 73062306a36Sopenharmony_ci if not os.path.exists(file): 73162306a36Sopenharmony_ci return False 73262306a36Sopenharmony_ci try: 73362306a36Sopenharmony_ci fp = open(file, 'wb', 0) 73462306a36Sopenharmony_ci fp.write(val.encode()) 73562306a36Sopenharmony_ci fp.flush() 73662306a36Sopenharmony_ci fp.close() 73762306a36Sopenharmony_ci except: 73862306a36Sopenharmony_ci return False 73962306a36Sopenharmony_ci return True 74062306a36Sopenharmony_ci def fsetVal(self, val, path): 74162306a36Sopenharmony_ci if not self.useftrace: 74262306a36Sopenharmony_ci return False 74362306a36Sopenharmony_ci return self.setVal(val, self.tpath+path) 74462306a36Sopenharmony_ci def getVal(self, file): 74562306a36Sopenharmony_ci res = '' 74662306a36Sopenharmony_ci if not os.path.exists(file): 74762306a36Sopenharmony_ci return res 74862306a36Sopenharmony_ci try: 74962306a36Sopenharmony_ci fp = open(file, 'r') 75062306a36Sopenharmony_ci res = fp.read() 75162306a36Sopenharmony_ci fp.close() 75262306a36Sopenharmony_ci except: 75362306a36Sopenharmony_ci pass 75462306a36Sopenharmony_ci return res 75562306a36Sopenharmony_ci def fgetVal(self, path): 75662306a36Sopenharmony_ci if not self.useftrace: 75762306a36Sopenharmony_ci return '' 75862306a36Sopenharmony_ci return self.getVal(self.tpath+path) 75962306a36Sopenharmony_ci def cleanupFtrace(self): 76062306a36Sopenharmony_ci if self.useftrace: 76162306a36Sopenharmony_ci self.fsetVal('0', 'events/kprobes/enable') 76262306a36Sopenharmony_ci self.fsetVal('', 'kprobe_events') 76362306a36Sopenharmony_ci self.fsetVal('1024', 'buffer_size_kb') 76462306a36Sopenharmony_ci def setupAllKprobes(self): 76562306a36Sopenharmony_ci for name in self.tracefuncs: 76662306a36Sopenharmony_ci self.defaultKprobe(name, self.tracefuncs[name]) 76762306a36Sopenharmony_ci for name in self.dev_tracefuncs: 76862306a36Sopenharmony_ci self.defaultKprobe(name, self.dev_tracefuncs[name]) 76962306a36Sopenharmony_ci def isCallgraphFunc(self, name): 77062306a36Sopenharmony_ci if len(self.tracefuncs) < 1 and self.suspendmode == 'command': 77162306a36Sopenharmony_ci return True 77262306a36Sopenharmony_ci for i in self.tracefuncs: 77362306a36Sopenharmony_ci if 'func' in self.tracefuncs[i]: 77462306a36Sopenharmony_ci f = self.tracefuncs[i]['func'] 77562306a36Sopenharmony_ci else: 77662306a36Sopenharmony_ci f = i 77762306a36Sopenharmony_ci if name == f: 77862306a36Sopenharmony_ci return True 77962306a36Sopenharmony_ci return False 78062306a36Sopenharmony_ci def initFtrace(self, quiet=False): 78162306a36Sopenharmony_ci if not self.useftrace: 78262306a36Sopenharmony_ci return 78362306a36Sopenharmony_ci if not quiet: 78462306a36Sopenharmony_ci sysvals.printSystemInfo(False) 78562306a36Sopenharmony_ci pprint('INITIALIZING FTRACE') 78662306a36Sopenharmony_ci # turn trace off 78762306a36Sopenharmony_ci self.fsetVal('0', 'tracing_on') 78862306a36Sopenharmony_ci self.cleanupFtrace() 78962306a36Sopenharmony_ci # set the trace clock to global 79062306a36Sopenharmony_ci self.fsetVal('global', 'trace_clock') 79162306a36Sopenharmony_ci self.fsetVal('nop', 'current_tracer') 79262306a36Sopenharmony_ci # set trace buffer to an appropriate value 79362306a36Sopenharmony_ci cpus = max(1, self.cpucount) 79462306a36Sopenharmony_ci if self.bufsize > 0: 79562306a36Sopenharmony_ci tgtsize = self.bufsize 79662306a36Sopenharmony_ci elif self.usecallgraph or self.usedevsrc: 79762306a36Sopenharmony_ci bmax = (1*1024*1024) if self.suspendmode in ['disk', 'command'] \ 79862306a36Sopenharmony_ci else (3*1024*1024) 79962306a36Sopenharmony_ci tgtsize = min(self.memfree, bmax) 80062306a36Sopenharmony_ci else: 80162306a36Sopenharmony_ci tgtsize = 65536 80262306a36Sopenharmony_ci while not self.fsetVal('%d' % (tgtsize // cpus), 'buffer_size_kb'): 80362306a36Sopenharmony_ci # if the size failed to set, lower it and keep trying 80462306a36Sopenharmony_ci tgtsize -= 65536 80562306a36Sopenharmony_ci if tgtsize < 65536: 80662306a36Sopenharmony_ci tgtsize = int(self.fgetVal('buffer_size_kb')) * cpus 80762306a36Sopenharmony_ci break 80862306a36Sopenharmony_ci self.vprint('Setting trace buffers to %d kB (%d kB per cpu)' % (tgtsize, tgtsize/cpus)) 80962306a36Sopenharmony_ci # initialize the callgraph trace 81062306a36Sopenharmony_ci if(self.usecallgraph): 81162306a36Sopenharmony_ci # set trace type 81262306a36Sopenharmony_ci self.fsetVal('function_graph', 'current_tracer') 81362306a36Sopenharmony_ci self.fsetVal('', 'set_ftrace_filter') 81462306a36Sopenharmony_ci # temporary hack to fix https://bugzilla.kernel.org/show_bug.cgi?id=212761 81562306a36Sopenharmony_ci fp = open(self.tpath+'set_ftrace_notrace', 'w') 81662306a36Sopenharmony_ci fp.write('native_queued_spin_lock_slowpath\ndev_driver_string') 81762306a36Sopenharmony_ci fp.close() 81862306a36Sopenharmony_ci # set trace format options 81962306a36Sopenharmony_ci self.fsetVal('print-parent', 'trace_options') 82062306a36Sopenharmony_ci self.fsetVal('funcgraph-abstime', 'trace_options') 82162306a36Sopenharmony_ci self.fsetVal('funcgraph-cpu', 'trace_options') 82262306a36Sopenharmony_ci self.fsetVal('funcgraph-duration', 'trace_options') 82362306a36Sopenharmony_ci self.fsetVal('funcgraph-proc', 'trace_options') 82462306a36Sopenharmony_ci self.fsetVal('funcgraph-tail', 'trace_options') 82562306a36Sopenharmony_ci self.fsetVal('nofuncgraph-overhead', 'trace_options') 82662306a36Sopenharmony_ci self.fsetVal('context-info', 'trace_options') 82762306a36Sopenharmony_ci self.fsetVal('graph-time', 'trace_options') 82862306a36Sopenharmony_ci self.fsetVal('%d' % self.max_graph_depth, 'max_graph_depth') 82962306a36Sopenharmony_ci cf = ['dpm_run_callback'] 83062306a36Sopenharmony_ci if(self.usetraceevents): 83162306a36Sopenharmony_ci cf += ['dpm_prepare', 'dpm_complete'] 83262306a36Sopenharmony_ci for fn in self.tracefuncs: 83362306a36Sopenharmony_ci if 'func' in self.tracefuncs[fn]: 83462306a36Sopenharmony_ci cf.append(self.tracefuncs[fn]['func']) 83562306a36Sopenharmony_ci else: 83662306a36Sopenharmony_ci cf.append(fn) 83762306a36Sopenharmony_ci if self.ftop: 83862306a36Sopenharmony_ci self.setFtraceFilterFunctions([self.ftopfunc]) 83962306a36Sopenharmony_ci else: 84062306a36Sopenharmony_ci self.setFtraceFilterFunctions(cf) 84162306a36Sopenharmony_ci # initialize the kprobe trace 84262306a36Sopenharmony_ci elif self.usekprobes: 84362306a36Sopenharmony_ci for name in self.tracefuncs: 84462306a36Sopenharmony_ci self.defaultKprobe(name, self.tracefuncs[name]) 84562306a36Sopenharmony_ci if self.usedevsrc: 84662306a36Sopenharmony_ci for name in self.dev_tracefuncs: 84762306a36Sopenharmony_ci self.defaultKprobe(name, self.dev_tracefuncs[name]) 84862306a36Sopenharmony_ci if not quiet: 84962306a36Sopenharmony_ci pprint('INITIALIZING KPROBES') 85062306a36Sopenharmony_ci self.addKprobes(self.verbose) 85162306a36Sopenharmony_ci if(self.usetraceevents): 85262306a36Sopenharmony_ci # turn trace events on 85362306a36Sopenharmony_ci events = iter(self.traceevents) 85462306a36Sopenharmony_ci for e in events: 85562306a36Sopenharmony_ci self.fsetVal('1', 'events/power/'+e+'/enable') 85662306a36Sopenharmony_ci # clear the trace buffer 85762306a36Sopenharmony_ci self.fsetVal('', 'trace') 85862306a36Sopenharmony_ci def verifyFtrace(self): 85962306a36Sopenharmony_ci # files needed for any trace data 86062306a36Sopenharmony_ci files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock', 86162306a36Sopenharmony_ci 'trace_marker', 'trace_options', 'tracing_on'] 86262306a36Sopenharmony_ci # files needed for callgraph trace data 86362306a36Sopenharmony_ci tp = self.tpath 86462306a36Sopenharmony_ci if(self.usecallgraph): 86562306a36Sopenharmony_ci files += [ 86662306a36Sopenharmony_ci 'available_filter_functions', 86762306a36Sopenharmony_ci 'set_ftrace_filter', 86862306a36Sopenharmony_ci 'set_graph_function' 86962306a36Sopenharmony_ci ] 87062306a36Sopenharmony_ci for f in files: 87162306a36Sopenharmony_ci if(os.path.exists(tp+f) == False): 87262306a36Sopenharmony_ci return False 87362306a36Sopenharmony_ci return True 87462306a36Sopenharmony_ci def verifyKprobes(self): 87562306a36Sopenharmony_ci # files needed for kprobes to work 87662306a36Sopenharmony_ci files = ['kprobe_events', 'events'] 87762306a36Sopenharmony_ci tp = self.tpath 87862306a36Sopenharmony_ci for f in files: 87962306a36Sopenharmony_ci if(os.path.exists(tp+f) == False): 88062306a36Sopenharmony_ci return False 88162306a36Sopenharmony_ci return True 88262306a36Sopenharmony_ci def colorText(self, str, color=31): 88362306a36Sopenharmony_ci if not self.ansi: 88462306a36Sopenharmony_ci return str 88562306a36Sopenharmony_ci return '\x1B[%d;40m%s\x1B[m' % (color, str) 88662306a36Sopenharmony_ci def writeDatafileHeader(self, filename, testdata): 88762306a36Sopenharmony_ci fp = self.openlog(filename, 'w') 88862306a36Sopenharmony_ci fp.write('%s\n%s\n# command | %s\n' % (self.teststamp, self.sysstamp, self.cmdline)) 88962306a36Sopenharmony_ci for test in testdata: 89062306a36Sopenharmony_ci if 'fw' in test: 89162306a36Sopenharmony_ci fw = test['fw'] 89262306a36Sopenharmony_ci if(fw): 89362306a36Sopenharmony_ci fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) 89462306a36Sopenharmony_ci if 'turbo' in test: 89562306a36Sopenharmony_ci fp.write('# turbostat %s\n' % test['turbo']) 89662306a36Sopenharmony_ci if 'wifi' in test: 89762306a36Sopenharmony_ci fp.write('# wifi %s\n' % test['wifi']) 89862306a36Sopenharmony_ci if 'netfix' in test: 89962306a36Sopenharmony_ci fp.write('# netfix %s\n' % test['netfix']) 90062306a36Sopenharmony_ci if test['error'] or len(testdata) > 1: 90162306a36Sopenharmony_ci fp.write('# enter_sleep_error %s\n' % test['error']) 90262306a36Sopenharmony_ci return fp 90362306a36Sopenharmony_ci def sudoUserchown(self, dir): 90462306a36Sopenharmony_ci if os.path.exists(dir) and self.sudouser: 90562306a36Sopenharmony_ci cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' 90662306a36Sopenharmony_ci call(cmd.format(self.sudouser, dir), shell=True) 90762306a36Sopenharmony_ci def outputResult(self, testdata, num=0): 90862306a36Sopenharmony_ci if not self.result: 90962306a36Sopenharmony_ci return 91062306a36Sopenharmony_ci n = '' 91162306a36Sopenharmony_ci if num > 0: 91262306a36Sopenharmony_ci n = '%d' % num 91362306a36Sopenharmony_ci fp = open(self.result, 'a') 91462306a36Sopenharmony_ci if 'error' in testdata: 91562306a36Sopenharmony_ci fp.write('result%s: fail\n' % n) 91662306a36Sopenharmony_ci fp.write('error%s: %s\n' % (n, testdata['error'])) 91762306a36Sopenharmony_ci else: 91862306a36Sopenharmony_ci fp.write('result%s: pass\n' % n) 91962306a36Sopenharmony_ci if 'mode' in testdata: 92062306a36Sopenharmony_ci fp.write('mode%s: %s\n' % (n, testdata['mode'])) 92162306a36Sopenharmony_ci for v in ['suspend', 'resume', 'boot', 'lastinit']: 92262306a36Sopenharmony_ci if v in testdata: 92362306a36Sopenharmony_ci fp.write('%s%s: %.3f\n' % (v, n, testdata[v])) 92462306a36Sopenharmony_ci for v in ['fwsuspend', 'fwresume']: 92562306a36Sopenharmony_ci if v in testdata: 92662306a36Sopenharmony_ci fp.write('%s%s: %.3f\n' % (v, n, testdata[v] / 1000000.0)) 92762306a36Sopenharmony_ci if 'bugurl' in testdata: 92862306a36Sopenharmony_ci fp.write('url%s: %s\n' % (n, testdata['bugurl'])) 92962306a36Sopenharmony_ci fp.close() 93062306a36Sopenharmony_ci self.sudoUserchown(self.result) 93162306a36Sopenharmony_ci def configFile(self, file): 93262306a36Sopenharmony_ci dir = os.path.dirname(os.path.realpath(__file__)) 93362306a36Sopenharmony_ci if os.path.exists(file): 93462306a36Sopenharmony_ci return file 93562306a36Sopenharmony_ci elif os.path.exists(dir+'/'+file): 93662306a36Sopenharmony_ci return dir+'/'+file 93762306a36Sopenharmony_ci elif os.path.exists(dir+'/config/'+file): 93862306a36Sopenharmony_ci return dir+'/config/'+file 93962306a36Sopenharmony_ci return '' 94062306a36Sopenharmony_ci def openlog(self, filename, mode): 94162306a36Sopenharmony_ci isgz = self.gzip 94262306a36Sopenharmony_ci if mode == 'r': 94362306a36Sopenharmony_ci try: 94462306a36Sopenharmony_ci with gzip.open(filename, mode+'t') as fp: 94562306a36Sopenharmony_ci test = fp.read(64) 94662306a36Sopenharmony_ci isgz = True 94762306a36Sopenharmony_ci except: 94862306a36Sopenharmony_ci isgz = False 94962306a36Sopenharmony_ci if isgz: 95062306a36Sopenharmony_ci return gzip.open(filename, mode+'t') 95162306a36Sopenharmony_ci return open(filename, mode) 95262306a36Sopenharmony_ci def putlog(self, filename, text): 95362306a36Sopenharmony_ci with self.openlog(filename, 'a') as fp: 95462306a36Sopenharmony_ci fp.write(text) 95562306a36Sopenharmony_ci fp.close() 95662306a36Sopenharmony_ci def dlog(self, text): 95762306a36Sopenharmony_ci if not self.dmesgfile: 95862306a36Sopenharmony_ci return 95962306a36Sopenharmony_ci self.putlog(self.dmesgfile, '# %s\n' % text) 96062306a36Sopenharmony_ci def flog(self, text): 96162306a36Sopenharmony_ci self.putlog(self.ftracefile, text) 96262306a36Sopenharmony_ci def b64unzip(self, data): 96362306a36Sopenharmony_ci try: 96462306a36Sopenharmony_ci out = codecs.decode(base64.b64decode(data), 'zlib').decode() 96562306a36Sopenharmony_ci except: 96662306a36Sopenharmony_ci out = data 96762306a36Sopenharmony_ci return out 96862306a36Sopenharmony_ci def b64zip(self, data): 96962306a36Sopenharmony_ci out = base64.b64encode(codecs.encode(data.encode(), 'zlib')).decode() 97062306a36Sopenharmony_ci return out 97162306a36Sopenharmony_ci def platforminfo(self, cmdafter): 97262306a36Sopenharmony_ci # add platform info on to a completed ftrace file 97362306a36Sopenharmony_ci if not os.path.exists(self.ftracefile): 97462306a36Sopenharmony_ci return False 97562306a36Sopenharmony_ci footer = '#\n' 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci # add test command string line if need be 97862306a36Sopenharmony_ci if self.suspendmode == 'command' and self.testcommand: 97962306a36Sopenharmony_ci footer += '# platform-testcmd: %s\n' % (self.testcommand) 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci # get a list of target devices from the ftrace file 98262306a36Sopenharmony_ci props = dict() 98362306a36Sopenharmony_ci tp = TestProps() 98462306a36Sopenharmony_ci tf = self.openlog(self.ftracefile, 'r') 98562306a36Sopenharmony_ci for line in tf: 98662306a36Sopenharmony_ci if tp.stampInfo(line, self): 98762306a36Sopenharmony_ci continue 98862306a36Sopenharmony_ci # parse only valid lines, if this is not one move on 98962306a36Sopenharmony_ci m = re.match(tp.ftrace_line_fmt, line) 99062306a36Sopenharmony_ci if(not m or 'device_pm_callback_start' not in line): 99162306a36Sopenharmony_ci continue 99262306a36Sopenharmony_ci m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg')); 99362306a36Sopenharmony_ci if(not m): 99462306a36Sopenharmony_ci continue 99562306a36Sopenharmony_ci dev = m.group('d') 99662306a36Sopenharmony_ci if dev not in props: 99762306a36Sopenharmony_ci props[dev] = DevProps() 99862306a36Sopenharmony_ci tf.close() 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci # now get the syspath for each target device 100162306a36Sopenharmony_ci for dirname, dirnames, filenames in os.walk('/sys/devices'): 100262306a36Sopenharmony_ci if(re.match('.*/power', dirname) and 'async' in filenames): 100362306a36Sopenharmony_ci dev = dirname.split('/')[-2] 100462306a36Sopenharmony_ci if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)): 100562306a36Sopenharmony_ci props[dev].syspath = dirname[:-6] 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci # now fill in the properties for our target devices 100862306a36Sopenharmony_ci for dev in sorted(props): 100962306a36Sopenharmony_ci dirname = props[dev].syspath 101062306a36Sopenharmony_ci if not dirname or not os.path.exists(dirname): 101162306a36Sopenharmony_ci continue 101262306a36Sopenharmony_ci props[dev].isasync = False 101362306a36Sopenharmony_ci if os.path.exists(dirname+'/power/async'): 101462306a36Sopenharmony_ci fp = open(dirname+'/power/async') 101562306a36Sopenharmony_ci if 'enabled' in fp.read(): 101662306a36Sopenharmony_ci props[dev].isasync = True 101762306a36Sopenharmony_ci fp.close() 101862306a36Sopenharmony_ci fields = os.listdir(dirname) 101962306a36Sopenharmony_ci for file in ['product', 'name', 'model', 'description', 'id', 'idVendor']: 102062306a36Sopenharmony_ci if file not in fields: 102162306a36Sopenharmony_ci continue 102262306a36Sopenharmony_ci try: 102362306a36Sopenharmony_ci with open(os.path.join(dirname, file), 'rb') as fp: 102462306a36Sopenharmony_ci props[dev].altname = ascii(fp.read()) 102562306a36Sopenharmony_ci except: 102662306a36Sopenharmony_ci continue 102762306a36Sopenharmony_ci if file == 'idVendor': 102862306a36Sopenharmony_ci idv, idp = props[dev].altname.strip(), '' 102962306a36Sopenharmony_ci try: 103062306a36Sopenharmony_ci with open(os.path.join(dirname, 'idProduct'), 'rb') as fp: 103162306a36Sopenharmony_ci idp = ascii(fp.read()).strip() 103262306a36Sopenharmony_ci except: 103362306a36Sopenharmony_ci props[dev].altname = '' 103462306a36Sopenharmony_ci break 103562306a36Sopenharmony_ci props[dev].altname = '%s:%s' % (idv, idp) 103662306a36Sopenharmony_ci break 103762306a36Sopenharmony_ci if props[dev].altname: 103862306a36Sopenharmony_ci out = props[dev].altname.strip().replace('\n', ' ')\ 103962306a36Sopenharmony_ci .replace(',', ' ').replace(';', ' ') 104062306a36Sopenharmony_ci props[dev].altname = out 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci # add a devinfo line to the bottom of ftrace 104362306a36Sopenharmony_ci out = '' 104462306a36Sopenharmony_ci for dev in sorted(props): 104562306a36Sopenharmony_ci out += props[dev].out(dev) 104662306a36Sopenharmony_ci footer += '# platform-devinfo: %s\n' % self.b64zip(out) 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci # add a line for each of these commands with their outputs 104962306a36Sopenharmony_ci for name, cmdline, info in cmdafter: 105062306a36Sopenharmony_ci footer += '# platform-%s: %s | %s\n' % (name, cmdline, self.b64zip(info)) 105162306a36Sopenharmony_ci self.flog(footer) 105262306a36Sopenharmony_ci return True 105362306a36Sopenharmony_ci def commonPrefix(self, list): 105462306a36Sopenharmony_ci if len(list) < 2: 105562306a36Sopenharmony_ci return '' 105662306a36Sopenharmony_ci prefix = list[0] 105762306a36Sopenharmony_ci for s in list[1:]: 105862306a36Sopenharmony_ci while s[:len(prefix)] != prefix and prefix: 105962306a36Sopenharmony_ci prefix = prefix[:len(prefix)-1] 106062306a36Sopenharmony_ci if not prefix: 106162306a36Sopenharmony_ci break 106262306a36Sopenharmony_ci if '/' in prefix and prefix[-1] != '/': 106362306a36Sopenharmony_ci prefix = prefix[0:prefix.rfind('/')+1] 106462306a36Sopenharmony_ci return prefix 106562306a36Sopenharmony_ci def dictify(self, text, format): 106662306a36Sopenharmony_ci out = dict() 106762306a36Sopenharmony_ci header = True if format == 1 else False 106862306a36Sopenharmony_ci delim = ' ' if format == 1 else ':' 106962306a36Sopenharmony_ci for line in text.split('\n'): 107062306a36Sopenharmony_ci if header: 107162306a36Sopenharmony_ci header, out['@'] = False, line 107262306a36Sopenharmony_ci continue 107362306a36Sopenharmony_ci line = line.strip() 107462306a36Sopenharmony_ci if delim in line: 107562306a36Sopenharmony_ci data = line.split(delim, 1) 107662306a36Sopenharmony_ci num = re.search(r'[\d]+', data[1]) 107762306a36Sopenharmony_ci if format == 2 and num: 107862306a36Sopenharmony_ci out[data[0].strip()] = num.group() 107962306a36Sopenharmony_ci else: 108062306a36Sopenharmony_ci out[data[0].strip()] = data[1] 108162306a36Sopenharmony_ci return out 108262306a36Sopenharmony_ci def cmdinfovar(self, arg): 108362306a36Sopenharmony_ci if arg == 'ethdev': 108462306a36Sopenharmony_ci try: 108562306a36Sopenharmony_ci cmd = [self.getExec('ip'), '-4', '-o', '-br', 'addr'] 108662306a36Sopenharmony_ci fp = Popen(cmd, stdout=PIPE, stderr=PIPE).stdout 108762306a36Sopenharmony_ci info = ascii(fp.read()).strip() 108862306a36Sopenharmony_ci fp.close() 108962306a36Sopenharmony_ci except: 109062306a36Sopenharmony_ci return 'iptoolcrash' 109162306a36Sopenharmony_ci for line in info.split('\n'): 109262306a36Sopenharmony_ci if line[0] == 'e' and 'UP' in line: 109362306a36Sopenharmony_ci return line.split()[0] 109462306a36Sopenharmony_ci return 'nodevicefound' 109562306a36Sopenharmony_ci return 'unknown' 109662306a36Sopenharmony_ci def cmdinfo(self, begin, debug=False): 109762306a36Sopenharmony_ci out = [] 109862306a36Sopenharmony_ci if begin: 109962306a36Sopenharmony_ci self.cmd1 = dict() 110062306a36Sopenharmony_ci for cargs in self.infocmds: 110162306a36Sopenharmony_ci delta, name, args = cargs[0], cargs[1], cargs[2:] 110262306a36Sopenharmony_ci for i in range(len(args)): 110362306a36Sopenharmony_ci if args[i][0] == '{' and args[i][-1] == '}': 110462306a36Sopenharmony_ci args[i] = self.cmdinfovar(args[i][1:-1]) 110562306a36Sopenharmony_ci cmdline, cmdpath = ' '.join(args[0:]), self.getExec(args[0]) 110662306a36Sopenharmony_ci if not cmdpath or (begin and not delta): 110762306a36Sopenharmony_ci continue 110862306a36Sopenharmony_ci self.dlog('[%s]' % cmdline) 110962306a36Sopenharmony_ci try: 111062306a36Sopenharmony_ci fp = Popen([cmdpath]+args[1:], stdout=PIPE, stderr=PIPE).stdout 111162306a36Sopenharmony_ci info = ascii(fp.read()).strip() 111262306a36Sopenharmony_ci fp.close() 111362306a36Sopenharmony_ci except: 111462306a36Sopenharmony_ci continue 111562306a36Sopenharmony_ci if not debug and begin: 111662306a36Sopenharmony_ci self.cmd1[name] = self.dictify(info, delta) 111762306a36Sopenharmony_ci elif not debug and delta and name in self.cmd1: 111862306a36Sopenharmony_ci before, after = self.cmd1[name], self.dictify(info, delta) 111962306a36Sopenharmony_ci dinfo = ('\t%s\n' % before['@']) if '@' in before and len(before) > 1 else '' 112062306a36Sopenharmony_ci prefix = self.commonPrefix(list(before.keys())) 112162306a36Sopenharmony_ci for key in sorted(before): 112262306a36Sopenharmony_ci if key in after and before[key] != after[key]: 112362306a36Sopenharmony_ci title = key.replace(prefix, '') 112462306a36Sopenharmony_ci if delta == 2: 112562306a36Sopenharmony_ci dinfo += '\t%s : %s -> %s\n' % \ 112662306a36Sopenharmony_ci (title, before[key].strip(), after[key].strip()) 112762306a36Sopenharmony_ci else: 112862306a36Sopenharmony_ci dinfo += '%10s (start) : %s\n%10s (after) : %s\n' % \ 112962306a36Sopenharmony_ci (title, before[key], title, after[key]) 113062306a36Sopenharmony_ci dinfo = '\tnothing changed' if not dinfo else dinfo.rstrip() 113162306a36Sopenharmony_ci out.append((name, cmdline, dinfo)) 113262306a36Sopenharmony_ci else: 113362306a36Sopenharmony_ci out.append((name, cmdline, '\tnothing' if not info else info)) 113462306a36Sopenharmony_ci return out 113562306a36Sopenharmony_ci def testVal(self, file, fmt='basic', value=''): 113662306a36Sopenharmony_ci if file == 'restoreall': 113762306a36Sopenharmony_ci for f in self.cfgdef: 113862306a36Sopenharmony_ci if os.path.exists(f): 113962306a36Sopenharmony_ci fp = open(f, 'w') 114062306a36Sopenharmony_ci fp.write(self.cfgdef[f]) 114162306a36Sopenharmony_ci fp.close() 114262306a36Sopenharmony_ci self.cfgdef = dict() 114362306a36Sopenharmony_ci elif value and os.path.exists(file): 114462306a36Sopenharmony_ci fp = open(file, 'r+') 114562306a36Sopenharmony_ci if fmt == 'radio': 114662306a36Sopenharmony_ci m = re.match('.*\[(?P<v>.*)\].*', fp.read()) 114762306a36Sopenharmony_ci if m: 114862306a36Sopenharmony_ci self.cfgdef[file] = m.group('v') 114962306a36Sopenharmony_ci elif fmt == 'acpi': 115062306a36Sopenharmony_ci line = fp.read().strip().split('\n')[-1] 115162306a36Sopenharmony_ci m = re.match('.* (?P<v>[0-9A-Fx]*) .*', line) 115262306a36Sopenharmony_ci if m: 115362306a36Sopenharmony_ci self.cfgdef[file] = m.group('v') 115462306a36Sopenharmony_ci else: 115562306a36Sopenharmony_ci self.cfgdef[file] = fp.read().strip() 115662306a36Sopenharmony_ci fp.write(value) 115762306a36Sopenharmony_ci fp.close() 115862306a36Sopenharmony_ci def s0ixSupport(self): 115962306a36Sopenharmony_ci if not os.path.exists(self.s0ixres) or not os.path.exists(self.mempowerfile): 116062306a36Sopenharmony_ci return False 116162306a36Sopenharmony_ci fp = open(sysvals.mempowerfile, 'r') 116262306a36Sopenharmony_ci data = fp.read().strip() 116362306a36Sopenharmony_ci fp.close() 116462306a36Sopenharmony_ci if '[s2idle]' in data: 116562306a36Sopenharmony_ci return True 116662306a36Sopenharmony_ci return False 116762306a36Sopenharmony_ci def haveTurbostat(self): 116862306a36Sopenharmony_ci if not self.tstat: 116962306a36Sopenharmony_ci return False 117062306a36Sopenharmony_ci cmd = self.getExec('turbostat') 117162306a36Sopenharmony_ci if not cmd: 117262306a36Sopenharmony_ci return False 117362306a36Sopenharmony_ci fp = Popen([cmd, '-v'], stdout=PIPE, stderr=PIPE).stderr 117462306a36Sopenharmony_ci out = ascii(fp.read()).strip() 117562306a36Sopenharmony_ci fp.close() 117662306a36Sopenharmony_ci if re.match('turbostat version .*', out): 117762306a36Sopenharmony_ci self.vprint(out) 117862306a36Sopenharmony_ci return True 117962306a36Sopenharmony_ci return False 118062306a36Sopenharmony_ci def turbostat(self, s0ixready): 118162306a36Sopenharmony_ci cmd = self.getExec('turbostat') 118262306a36Sopenharmony_ci rawout = keyline = valline = '' 118362306a36Sopenharmony_ci fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile) 118462306a36Sopenharmony_ci fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE).stderr 118562306a36Sopenharmony_ci for line in fp: 118662306a36Sopenharmony_ci line = ascii(line) 118762306a36Sopenharmony_ci rawout += line 118862306a36Sopenharmony_ci if keyline and valline: 118962306a36Sopenharmony_ci continue 119062306a36Sopenharmony_ci if re.match('(?i)Avg_MHz.*', line): 119162306a36Sopenharmony_ci keyline = line.strip().split() 119262306a36Sopenharmony_ci elif keyline: 119362306a36Sopenharmony_ci valline = line.strip().split() 119462306a36Sopenharmony_ci fp.close() 119562306a36Sopenharmony_ci if not keyline or not valline or len(keyline) != len(valline): 119662306a36Sopenharmony_ci errmsg = 'unrecognized turbostat output:\n'+rawout.strip() 119762306a36Sopenharmony_ci self.vprint(errmsg) 119862306a36Sopenharmony_ci if not self.verbose: 119962306a36Sopenharmony_ci pprint(errmsg) 120062306a36Sopenharmony_ci return '' 120162306a36Sopenharmony_ci if self.verbose: 120262306a36Sopenharmony_ci pprint(rawout.strip()) 120362306a36Sopenharmony_ci out = [] 120462306a36Sopenharmony_ci for key in keyline: 120562306a36Sopenharmony_ci idx = keyline.index(key) 120662306a36Sopenharmony_ci val = valline[idx] 120762306a36Sopenharmony_ci if key == 'SYS%LPI' and not s0ixready and re.match('^[0\.]*$', val): 120862306a36Sopenharmony_ci continue 120962306a36Sopenharmony_ci out.append('%s=%s' % (key, val)) 121062306a36Sopenharmony_ci return '|'.join(out) 121162306a36Sopenharmony_ci def netfixon(self, net='both'): 121262306a36Sopenharmony_ci cmd = self.getExec('netfix') 121362306a36Sopenharmony_ci if not cmd: 121462306a36Sopenharmony_ci return '' 121562306a36Sopenharmony_ci fp = Popen([cmd, '-s', net, 'on'], stdout=PIPE, stderr=PIPE).stdout 121662306a36Sopenharmony_ci out = ascii(fp.read()).strip() 121762306a36Sopenharmony_ci fp.close() 121862306a36Sopenharmony_ci return out 121962306a36Sopenharmony_ci def wifiDetails(self, dev): 122062306a36Sopenharmony_ci try: 122162306a36Sopenharmony_ci info = open('/sys/class/net/%s/device/uevent' % dev, 'r').read().strip() 122262306a36Sopenharmony_ci except: 122362306a36Sopenharmony_ci return dev 122462306a36Sopenharmony_ci vals = [dev] 122562306a36Sopenharmony_ci for prop in info.split('\n'): 122662306a36Sopenharmony_ci if prop.startswith('DRIVER=') or prop.startswith('PCI_ID='): 122762306a36Sopenharmony_ci vals.append(prop.split('=')[-1]) 122862306a36Sopenharmony_ci return ':'.join(vals) 122962306a36Sopenharmony_ci def checkWifi(self, dev=''): 123062306a36Sopenharmony_ci try: 123162306a36Sopenharmony_ci w = open('/proc/net/wireless', 'r').read().strip() 123262306a36Sopenharmony_ci except: 123362306a36Sopenharmony_ci return '' 123462306a36Sopenharmony_ci for line in reversed(w.split('\n')): 123562306a36Sopenharmony_ci m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', line) 123662306a36Sopenharmony_ci if not m or (dev and dev != m.group('dev')): 123762306a36Sopenharmony_ci continue 123862306a36Sopenharmony_ci return m.group('dev') 123962306a36Sopenharmony_ci return '' 124062306a36Sopenharmony_ci def pollWifi(self, dev, timeout=10): 124162306a36Sopenharmony_ci start = time.time() 124262306a36Sopenharmony_ci while (time.time() - start) < timeout: 124362306a36Sopenharmony_ci w = self.checkWifi(dev) 124462306a36Sopenharmony_ci if w: 124562306a36Sopenharmony_ci return '%s reconnected %.2f' % \ 124662306a36Sopenharmony_ci (self.wifiDetails(dev), max(0, time.time() - start)) 124762306a36Sopenharmony_ci time.sleep(0.01) 124862306a36Sopenharmony_ci return '%s timeout %d' % (self.wifiDetails(dev), timeout) 124962306a36Sopenharmony_ci def errorSummary(self, errinfo, msg): 125062306a36Sopenharmony_ci found = False 125162306a36Sopenharmony_ci for entry in errinfo: 125262306a36Sopenharmony_ci if re.match(entry['match'], msg): 125362306a36Sopenharmony_ci entry['count'] += 1 125462306a36Sopenharmony_ci if self.hostname not in entry['urls']: 125562306a36Sopenharmony_ci entry['urls'][self.hostname] = [self.htmlfile] 125662306a36Sopenharmony_ci elif self.htmlfile not in entry['urls'][self.hostname]: 125762306a36Sopenharmony_ci entry['urls'][self.hostname].append(self.htmlfile) 125862306a36Sopenharmony_ci found = True 125962306a36Sopenharmony_ci break 126062306a36Sopenharmony_ci if found: 126162306a36Sopenharmony_ci return 126262306a36Sopenharmony_ci arr = msg.split() 126362306a36Sopenharmony_ci for j in range(len(arr)): 126462306a36Sopenharmony_ci if re.match('^[0-9,\-\.]*$', arr[j]): 126562306a36Sopenharmony_ci arr[j] = '[0-9,\-\.]*' 126662306a36Sopenharmony_ci else: 126762306a36Sopenharmony_ci arr[j] = arr[j]\ 126862306a36Sopenharmony_ci .replace('\\', '\\\\').replace(']', '\]').replace('[', '\[')\ 126962306a36Sopenharmony_ci .replace('.', '\.').replace('+', '\+').replace('*', '\*')\ 127062306a36Sopenharmony_ci .replace('(', '\(').replace(')', '\)').replace('}', '\}')\ 127162306a36Sopenharmony_ci .replace('{', '\{') 127262306a36Sopenharmony_ci mstr = ' *'.join(arr) 127362306a36Sopenharmony_ci entry = { 127462306a36Sopenharmony_ci 'line': msg, 127562306a36Sopenharmony_ci 'match': mstr, 127662306a36Sopenharmony_ci 'count': 1, 127762306a36Sopenharmony_ci 'urls': {self.hostname: [self.htmlfile]} 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci errinfo.append(entry) 128062306a36Sopenharmony_ci def multistat(self, start, idx, finish): 128162306a36Sopenharmony_ci if 'time' in self.multitest: 128262306a36Sopenharmony_ci id = '%d Duration=%dmin' % (idx+1, self.multitest['time']) 128362306a36Sopenharmony_ci else: 128462306a36Sopenharmony_ci id = '%d/%d' % (idx+1, self.multitest['count']) 128562306a36Sopenharmony_ci t = time.time() 128662306a36Sopenharmony_ci if 'start' not in self.multitest: 128762306a36Sopenharmony_ci self.multitest['start'] = self.multitest['last'] = t 128862306a36Sopenharmony_ci self.multitest['total'] = 0.0 128962306a36Sopenharmony_ci pprint('TEST (%s) START' % id) 129062306a36Sopenharmony_ci return 129162306a36Sopenharmony_ci dt = t - self.multitest['last'] 129262306a36Sopenharmony_ci if not start: 129362306a36Sopenharmony_ci if idx == 0 and self.multitest['delay'] > 0: 129462306a36Sopenharmony_ci self.multitest['total'] += self.multitest['delay'] 129562306a36Sopenharmony_ci pprint('TEST (%s) COMPLETE -- Duration %.1fs' % (id, dt)) 129662306a36Sopenharmony_ci return 129762306a36Sopenharmony_ci self.multitest['total'] += dt 129862306a36Sopenharmony_ci self.multitest['last'] = t 129962306a36Sopenharmony_ci avg = self.multitest['total'] / idx 130062306a36Sopenharmony_ci if 'time' in self.multitest: 130162306a36Sopenharmony_ci left = finish - datetime.now() 130262306a36Sopenharmony_ci left -= timedelta(microseconds=left.microseconds) 130362306a36Sopenharmony_ci else: 130462306a36Sopenharmony_ci left = timedelta(seconds=((self.multitest['count'] - idx) * int(avg))) 130562306a36Sopenharmony_ci pprint('TEST (%s) START - Avg Duration %.1fs, Time left %s' % \ 130662306a36Sopenharmony_ci (id, avg, str(left))) 130762306a36Sopenharmony_ci def multiinit(self, c, d): 130862306a36Sopenharmony_ci sz, unit = 'count', 'm' 130962306a36Sopenharmony_ci if c.endswith('d') or c.endswith('h') or c.endswith('m'): 131062306a36Sopenharmony_ci sz, unit, c = 'time', c[-1], c[:-1] 131162306a36Sopenharmony_ci self.multitest['run'] = True 131262306a36Sopenharmony_ci self.multitest[sz] = getArgInt('multi: n d (exec count)', c, 1, 1000000, False) 131362306a36Sopenharmony_ci self.multitest['delay'] = getArgInt('multi: n d (delay between tests)', d, 0, 3600, False) 131462306a36Sopenharmony_ci if unit == 'd': 131562306a36Sopenharmony_ci self.multitest[sz] *= 1440 131662306a36Sopenharmony_ci elif unit == 'h': 131762306a36Sopenharmony_ci self.multitest[sz] *= 60 131862306a36Sopenharmony_ci def displayControl(self, cmd): 131962306a36Sopenharmony_ci xset, ret = 'timeout 10 xset -d :0.0 {0}', 0 132062306a36Sopenharmony_ci if self.sudouser: 132162306a36Sopenharmony_ci xset = 'sudo -u %s %s' % (self.sudouser, xset) 132262306a36Sopenharmony_ci if cmd == 'init': 132362306a36Sopenharmony_ci ret = call(xset.format('dpms 0 0 0'), shell=True) 132462306a36Sopenharmony_ci if not ret: 132562306a36Sopenharmony_ci ret = call(xset.format('s off'), shell=True) 132662306a36Sopenharmony_ci elif cmd == 'reset': 132762306a36Sopenharmony_ci ret = call(xset.format('s reset'), shell=True) 132862306a36Sopenharmony_ci elif cmd in ['on', 'off', 'standby', 'suspend']: 132962306a36Sopenharmony_ci b4 = self.displayControl('stat') 133062306a36Sopenharmony_ci ret = call(xset.format('dpms force %s' % cmd), shell=True) 133162306a36Sopenharmony_ci if not ret: 133262306a36Sopenharmony_ci curr = self.displayControl('stat') 133362306a36Sopenharmony_ci self.vprint('Display Switched: %s -> %s' % (b4, curr)) 133462306a36Sopenharmony_ci if curr != cmd: 133562306a36Sopenharmony_ci self.vprint('WARNING: Display failed to change to %s' % cmd) 133662306a36Sopenharmony_ci if ret: 133762306a36Sopenharmony_ci self.vprint('WARNING: Display failed to change to %s with xset' % cmd) 133862306a36Sopenharmony_ci return ret 133962306a36Sopenharmony_ci elif cmd == 'stat': 134062306a36Sopenharmony_ci fp = Popen(xset.format('q').split(' '), stdout=PIPE).stdout 134162306a36Sopenharmony_ci ret = 'unknown' 134262306a36Sopenharmony_ci for line in fp: 134362306a36Sopenharmony_ci m = re.match('[\s]*Monitor is (?P<m>.*)', ascii(line)) 134462306a36Sopenharmony_ci if(m and len(m.group('m')) >= 2): 134562306a36Sopenharmony_ci out = m.group('m').lower() 134662306a36Sopenharmony_ci ret = out[3:] if out[0:2] == 'in' else out 134762306a36Sopenharmony_ci break 134862306a36Sopenharmony_ci fp.close() 134962306a36Sopenharmony_ci return ret 135062306a36Sopenharmony_ci def setRuntimeSuspend(self, before=True): 135162306a36Sopenharmony_ci if before: 135262306a36Sopenharmony_ci # runtime suspend disable or enable 135362306a36Sopenharmony_ci if self.rs > 0: 135462306a36Sopenharmony_ci self.rstgt, self.rsval, self.rsdir = 'on', 'auto', 'enabled' 135562306a36Sopenharmony_ci else: 135662306a36Sopenharmony_ci self.rstgt, self.rsval, self.rsdir = 'auto', 'on', 'disabled' 135762306a36Sopenharmony_ci pprint('CONFIGURING RUNTIME SUSPEND...') 135862306a36Sopenharmony_ci self.rslist = deviceInfo(self.rstgt) 135962306a36Sopenharmony_ci for i in self.rslist: 136062306a36Sopenharmony_ci self.setVal(self.rsval, i) 136162306a36Sopenharmony_ci pprint('runtime suspend %s on all devices (%d changed)' % (self.rsdir, len(self.rslist))) 136262306a36Sopenharmony_ci pprint('waiting 5 seconds...') 136362306a36Sopenharmony_ci time.sleep(5) 136462306a36Sopenharmony_ci else: 136562306a36Sopenharmony_ci # runtime suspend re-enable or re-disable 136662306a36Sopenharmony_ci for i in self.rslist: 136762306a36Sopenharmony_ci self.setVal(self.rstgt, i) 136862306a36Sopenharmony_ci pprint('runtime suspend settings restored on %d devices' % len(self.rslist)) 136962306a36Sopenharmony_ci def start(self, pm): 137062306a36Sopenharmony_ci if self.useftrace: 137162306a36Sopenharmony_ci self.dlog('start ftrace tracing') 137262306a36Sopenharmony_ci self.fsetVal('1', 'tracing_on') 137362306a36Sopenharmony_ci if self.useprocmon: 137462306a36Sopenharmony_ci self.dlog('start the process monitor') 137562306a36Sopenharmony_ci pm.start() 137662306a36Sopenharmony_ci def stop(self, pm): 137762306a36Sopenharmony_ci if self.useftrace: 137862306a36Sopenharmony_ci if self.useprocmon: 137962306a36Sopenharmony_ci self.dlog('stop the process monitor') 138062306a36Sopenharmony_ci pm.stop() 138162306a36Sopenharmony_ci self.dlog('stop ftrace tracing') 138262306a36Sopenharmony_ci self.fsetVal('0', 'tracing_on') 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_cisysvals = SystemValues() 138562306a36Sopenharmony_ciswitchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0'] 138662306a36Sopenharmony_ciswitchoff = ['disable', 'off', 'false', '0'] 138762306a36Sopenharmony_cisuspendmodename = { 138862306a36Sopenharmony_ci 'standby': 'standby (S1)', 138962306a36Sopenharmony_ci 'freeze': 'freeze (S2idle)', 139062306a36Sopenharmony_ci 'mem': 'suspend (S3)', 139162306a36Sopenharmony_ci 'disk': 'hibernate (S4)' 139262306a36Sopenharmony_ci} 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci# Class: DevProps 139562306a36Sopenharmony_ci# Description: 139662306a36Sopenharmony_ci# Simple class which holds property values collected 139762306a36Sopenharmony_ci# for all the devices used in the timeline. 139862306a36Sopenharmony_ciclass DevProps: 139962306a36Sopenharmony_ci def __init__(self): 140062306a36Sopenharmony_ci self.syspath = '' 140162306a36Sopenharmony_ci self.altname = '' 140262306a36Sopenharmony_ci self.isasync = True 140362306a36Sopenharmony_ci self.xtraclass = '' 140462306a36Sopenharmony_ci self.xtrainfo = '' 140562306a36Sopenharmony_ci def out(self, dev): 140662306a36Sopenharmony_ci return '%s,%s,%d;' % (dev, self.altname, self.isasync) 140762306a36Sopenharmony_ci def debug(self, dev): 140862306a36Sopenharmony_ci pprint('%s:\n\taltname = %s\n\t async = %s' % (dev, self.altname, self.isasync)) 140962306a36Sopenharmony_ci def altName(self, dev): 141062306a36Sopenharmony_ci if not self.altname or self.altname == dev: 141162306a36Sopenharmony_ci return dev 141262306a36Sopenharmony_ci return '%s [%s]' % (self.altname, dev) 141362306a36Sopenharmony_ci def xtraClass(self): 141462306a36Sopenharmony_ci if self.xtraclass: 141562306a36Sopenharmony_ci return ' '+self.xtraclass 141662306a36Sopenharmony_ci if not self.isasync: 141762306a36Sopenharmony_ci return ' sync' 141862306a36Sopenharmony_ci return '' 141962306a36Sopenharmony_ci def xtraInfo(self): 142062306a36Sopenharmony_ci if self.xtraclass: 142162306a36Sopenharmony_ci return ' '+self.xtraclass 142262306a36Sopenharmony_ci if self.isasync: 142362306a36Sopenharmony_ci return ' (async)' 142462306a36Sopenharmony_ci return ' (sync)' 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci# Class: DeviceNode 142762306a36Sopenharmony_ci# Description: 142862306a36Sopenharmony_ci# A container used to create a device hierachy, with a single root node 142962306a36Sopenharmony_ci# and a tree of child nodes. Used by Data.deviceTopology() 143062306a36Sopenharmony_ciclass DeviceNode: 143162306a36Sopenharmony_ci def __init__(self, nodename, nodedepth): 143262306a36Sopenharmony_ci self.name = nodename 143362306a36Sopenharmony_ci self.children = [] 143462306a36Sopenharmony_ci self.depth = nodedepth 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci# Class: Data 143762306a36Sopenharmony_ci# Description: 143862306a36Sopenharmony_ci# The primary container for suspend/resume test data. There is one for 143962306a36Sopenharmony_ci# each test run. The data is organized into a cronological hierarchy: 144062306a36Sopenharmony_ci# Data.dmesg { 144162306a36Sopenharmony_ci# phases { 144262306a36Sopenharmony_ci# 10 sequential, non-overlapping phases of S/R 144362306a36Sopenharmony_ci# contents: times for phase start/end, order/color data for html 144462306a36Sopenharmony_ci# devlist { 144562306a36Sopenharmony_ci# device callback or action list for this phase 144662306a36Sopenharmony_ci# device { 144762306a36Sopenharmony_ci# a single device callback or generic action 144862306a36Sopenharmony_ci# contents: start/stop times, pid/cpu/driver info 144962306a36Sopenharmony_ci# parents/children, html id for timeline/callgraph 145062306a36Sopenharmony_ci# optionally includes an ftrace callgraph 145162306a36Sopenharmony_ci# optionally includes dev/ps data 145262306a36Sopenharmony_ci# } 145362306a36Sopenharmony_ci# } 145462306a36Sopenharmony_ci# } 145562306a36Sopenharmony_ci# } 145662306a36Sopenharmony_ci# 145762306a36Sopenharmony_ciclass Data: 145862306a36Sopenharmony_ci phasedef = { 145962306a36Sopenharmony_ci 'suspend_prepare': {'order': 0, 'color': '#CCFFCC'}, 146062306a36Sopenharmony_ci 'suspend': {'order': 1, 'color': '#88FF88'}, 146162306a36Sopenharmony_ci 'suspend_late': {'order': 2, 'color': '#00AA00'}, 146262306a36Sopenharmony_ci 'suspend_noirq': {'order': 3, 'color': '#008888'}, 146362306a36Sopenharmony_ci 'suspend_machine': {'order': 4, 'color': '#0000FF'}, 146462306a36Sopenharmony_ci 'resume_machine': {'order': 5, 'color': '#FF0000'}, 146562306a36Sopenharmony_ci 'resume_noirq': {'order': 6, 'color': '#FF9900'}, 146662306a36Sopenharmony_ci 'resume_early': {'order': 7, 'color': '#FFCC00'}, 146762306a36Sopenharmony_ci 'resume': {'order': 8, 'color': '#FFFF88'}, 146862306a36Sopenharmony_ci 'resume_complete': {'order': 9, 'color': '#FFFFCC'}, 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci errlist = { 147162306a36Sopenharmony_ci 'HWERROR' : r'.*\[ *Hardware Error *\].*', 147262306a36Sopenharmony_ci 'FWBUG' : r'.*\[ *Firmware Bug *\].*', 147362306a36Sopenharmony_ci 'TASKFAIL': r'.*Freezing .*after *.*', 147462306a36Sopenharmony_ci 'BUG' : r'(?i).*\bBUG\b.*', 147562306a36Sopenharmony_ci 'ERROR' : r'(?i).*\bERROR\b.*', 147662306a36Sopenharmony_ci 'WARNING' : r'(?i).*\bWARNING\b.*', 147762306a36Sopenharmony_ci 'FAULT' : r'(?i).*\bFAULT\b.*', 147862306a36Sopenharmony_ci 'FAIL' : r'(?i).*\bFAILED\b.*', 147962306a36Sopenharmony_ci 'INVALID' : r'(?i).*\bINVALID\b.*', 148062306a36Sopenharmony_ci 'CRASH' : r'(?i).*\bCRASHED\b.*', 148162306a36Sopenharmony_ci 'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*', 148262306a36Sopenharmony_ci 'ABORT' : r'(?i).*\bABORT\b.*', 148362306a36Sopenharmony_ci 'IRQ' : r'.*\bgenirq: .*', 148462306a36Sopenharmony_ci 'ACPI' : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*', 148562306a36Sopenharmony_ci 'DISKFULL': r'.*\bNo space left on device.*', 148662306a36Sopenharmony_ci 'USBERR' : r'.*usb .*device .*, error [0-9-]*', 148762306a36Sopenharmony_ci 'ATAERR' : r' *ata[0-9\.]*: .*failed.*', 148862306a36Sopenharmony_ci 'MEIERR' : r' *mei.*: .*failed.*', 148962306a36Sopenharmony_ci 'TPMERR' : r'(?i) *tpm *tpm[0-9]*: .*error.*', 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci def __init__(self, num): 149262306a36Sopenharmony_ci idchar = 'abcdefghij' 149362306a36Sopenharmony_ci self.start = 0.0 # test start 149462306a36Sopenharmony_ci self.end = 0.0 # test end 149562306a36Sopenharmony_ci self.hwstart = 0 # rtc test start 149662306a36Sopenharmony_ci self.hwend = 0 # rtc test end 149762306a36Sopenharmony_ci self.tSuspended = 0.0 # low-level suspend start 149862306a36Sopenharmony_ci self.tResumed = 0.0 # low-level resume start 149962306a36Sopenharmony_ci self.tKernSus = 0.0 # kernel level suspend start 150062306a36Sopenharmony_ci self.tKernRes = 0.0 # kernel level resume end 150162306a36Sopenharmony_ci self.fwValid = False # is firmware data available 150262306a36Sopenharmony_ci self.fwSuspend = 0 # time spent in firmware suspend 150362306a36Sopenharmony_ci self.fwResume = 0 # time spent in firmware resume 150462306a36Sopenharmony_ci self.html_device_id = 0 150562306a36Sopenharmony_ci self.stamp = 0 150662306a36Sopenharmony_ci self.outfile = '' 150762306a36Sopenharmony_ci self.kerror = False 150862306a36Sopenharmony_ci self.wifi = dict() 150962306a36Sopenharmony_ci self.turbostat = 0 151062306a36Sopenharmony_ci self.enterfail = '' 151162306a36Sopenharmony_ci self.currphase = '' 151262306a36Sopenharmony_ci self.pstl = dict() # process timeline 151362306a36Sopenharmony_ci self.testnumber = num 151462306a36Sopenharmony_ci self.idstr = idchar[num] 151562306a36Sopenharmony_ci self.dmesgtext = [] # dmesg text file in memory 151662306a36Sopenharmony_ci self.dmesg = dict() # root data structure 151762306a36Sopenharmony_ci self.errorinfo = {'suspend':[],'resume':[]} 151862306a36Sopenharmony_ci self.tLow = [] # time spent in low-level suspends (standby/freeze) 151962306a36Sopenharmony_ci self.devpids = [] 152062306a36Sopenharmony_ci self.devicegroups = 0 152162306a36Sopenharmony_ci def sortedPhases(self): 152262306a36Sopenharmony_ci return sorted(self.dmesg, key=lambda k:self.dmesg[k]['order']) 152362306a36Sopenharmony_ci def initDevicegroups(self): 152462306a36Sopenharmony_ci # called when phases are all finished being added 152562306a36Sopenharmony_ci for phase in sorted(self.dmesg.keys()): 152662306a36Sopenharmony_ci if '*' in phase: 152762306a36Sopenharmony_ci p = phase.split('*') 152862306a36Sopenharmony_ci pnew = '%s%d' % (p[0], len(p)) 152962306a36Sopenharmony_ci self.dmesg[pnew] = self.dmesg.pop(phase) 153062306a36Sopenharmony_ci self.devicegroups = [] 153162306a36Sopenharmony_ci for phase in self.sortedPhases(): 153262306a36Sopenharmony_ci self.devicegroups.append([phase]) 153362306a36Sopenharmony_ci def nextPhase(self, phase, offset): 153462306a36Sopenharmony_ci order = self.dmesg[phase]['order'] + offset 153562306a36Sopenharmony_ci for p in self.dmesg: 153662306a36Sopenharmony_ci if self.dmesg[p]['order'] == order: 153762306a36Sopenharmony_ci return p 153862306a36Sopenharmony_ci return '' 153962306a36Sopenharmony_ci def lastPhase(self, depth=1): 154062306a36Sopenharmony_ci plist = self.sortedPhases() 154162306a36Sopenharmony_ci if len(plist) < depth: 154262306a36Sopenharmony_ci return '' 154362306a36Sopenharmony_ci return plist[-1*depth] 154462306a36Sopenharmony_ci def turbostatInfo(self): 154562306a36Sopenharmony_ci tp = TestProps() 154662306a36Sopenharmony_ci out = {'syslpi':'N/A','pkgpc10':'N/A'} 154762306a36Sopenharmony_ci for line in self.dmesgtext: 154862306a36Sopenharmony_ci m = re.match(tp.tstatfmt, line) 154962306a36Sopenharmony_ci if not m: 155062306a36Sopenharmony_ci continue 155162306a36Sopenharmony_ci for i in m.group('t').split('|'): 155262306a36Sopenharmony_ci if 'SYS%LPI' in i: 155362306a36Sopenharmony_ci out['syslpi'] = i.split('=')[-1]+'%' 155462306a36Sopenharmony_ci elif 'pc10' in i: 155562306a36Sopenharmony_ci out['pkgpc10'] = i.split('=')[-1]+'%' 155662306a36Sopenharmony_ci break 155762306a36Sopenharmony_ci return out 155862306a36Sopenharmony_ci def extractErrorInfo(self): 155962306a36Sopenharmony_ci lf = self.dmesgtext 156062306a36Sopenharmony_ci if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 156162306a36Sopenharmony_ci lf = sysvals.openlog(sysvals.dmesgfile, 'r') 156262306a36Sopenharmony_ci i = 0 156362306a36Sopenharmony_ci tp = TestProps() 156462306a36Sopenharmony_ci list = [] 156562306a36Sopenharmony_ci for line in lf: 156662306a36Sopenharmony_ci i += 1 156762306a36Sopenharmony_ci if tp.stampInfo(line, sysvals): 156862306a36Sopenharmony_ci continue 156962306a36Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 157062306a36Sopenharmony_ci if not m: 157162306a36Sopenharmony_ci continue 157262306a36Sopenharmony_ci t = float(m.group('ktime')) 157362306a36Sopenharmony_ci if t < self.start or t > self.end: 157462306a36Sopenharmony_ci continue 157562306a36Sopenharmony_ci dir = 'suspend' if t < self.tSuspended else 'resume' 157662306a36Sopenharmony_ci msg = m.group('msg') 157762306a36Sopenharmony_ci if re.match('capability: warning: .*', msg): 157862306a36Sopenharmony_ci continue 157962306a36Sopenharmony_ci for err in self.errlist: 158062306a36Sopenharmony_ci if re.match(self.errlist[err], msg): 158162306a36Sopenharmony_ci list.append((msg, err, dir, t, i, i)) 158262306a36Sopenharmony_ci self.kerror = True 158362306a36Sopenharmony_ci break 158462306a36Sopenharmony_ci tp.msglist = [] 158562306a36Sopenharmony_ci for msg, type, dir, t, idx1, idx2 in list: 158662306a36Sopenharmony_ci tp.msglist.append(msg) 158762306a36Sopenharmony_ci self.errorinfo[dir].append((type, t, idx1, idx2)) 158862306a36Sopenharmony_ci if self.kerror: 158962306a36Sopenharmony_ci sysvals.dmesglog = True 159062306a36Sopenharmony_ci if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 159162306a36Sopenharmony_ci lf.close() 159262306a36Sopenharmony_ci return tp 159362306a36Sopenharmony_ci def setStart(self, time, msg=''): 159462306a36Sopenharmony_ci self.start = time 159562306a36Sopenharmony_ci if msg: 159662306a36Sopenharmony_ci try: 159762306a36Sopenharmony_ci self.hwstart = datetime.strptime(msg, sysvals.tmstart) 159862306a36Sopenharmony_ci except: 159962306a36Sopenharmony_ci self.hwstart = 0 160062306a36Sopenharmony_ci def setEnd(self, time, msg=''): 160162306a36Sopenharmony_ci self.end = time 160262306a36Sopenharmony_ci if msg: 160362306a36Sopenharmony_ci try: 160462306a36Sopenharmony_ci self.hwend = datetime.strptime(msg, sysvals.tmend) 160562306a36Sopenharmony_ci except: 160662306a36Sopenharmony_ci self.hwend = 0 160762306a36Sopenharmony_ci def isTraceEventOutsideDeviceCalls(self, pid, time): 160862306a36Sopenharmony_ci for phase in self.sortedPhases(): 160962306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 161062306a36Sopenharmony_ci for dev in list: 161162306a36Sopenharmony_ci d = list[dev] 161262306a36Sopenharmony_ci if(d['pid'] == pid and time >= d['start'] and 161362306a36Sopenharmony_ci time < d['end']): 161462306a36Sopenharmony_ci return False 161562306a36Sopenharmony_ci return True 161662306a36Sopenharmony_ci def sourcePhase(self, start): 161762306a36Sopenharmony_ci for phase in self.sortedPhases(): 161862306a36Sopenharmony_ci if 'machine' in phase: 161962306a36Sopenharmony_ci continue 162062306a36Sopenharmony_ci pend = self.dmesg[phase]['end'] 162162306a36Sopenharmony_ci if start <= pend: 162262306a36Sopenharmony_ci return phase 162362306a36Sopenharmony_ci return 'resume_complete' if 'resume_complete' in self.dmesg else '' 162462306a36Sopenharmony_ci def sourceDevice(self, phaselist, start, end, pid, type): 162562306a36Sopenharmony_ci tgtdev = '' 162662306a36Sopenharmony_ci for phase in phaselist: 162762306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 162862306a36Sopenharmony_ci for devname in list: 162962306a36Sopenharmony_ci dev = list[devname] 163062306a36Sopenharmony_ci # pid must match 163162306a36Sopenharmony_ci if dev['pid'] != pid: 163262306a36Sopenharmony_ci continue 163362306a36Sopenharmony_ci devS = dev['start'] 163462306a36Sopenharmony_ci devE = dev['end'] 163562306a36Sopenharmony_ci if type == 'device': 163662306a36Sopenharmony_ci # device target event is entirely inside the source boundary 163762306a36Sopenharmony_ci if(start < devS or start >= devE or end <= devS or end > devE): 163862306a36Sopenharmony_ci continue 163962306a36Sopenharmony_ci elif type == 'thread': 164062306a36Sopenharmony_ci # thread target event will expand the source boundary 164162306a36Sopenharmony_ci if start < devS: 164262306a36Sopenharmony_ci dev['start'] = start 164362306a36Sopenharmony_ci if end > devE: 164462306a36Sopenharmony_ci dev['end'] = end 164562306a36Sopenharmony_ci tgtdev = dev 164662306a36Sopenharmony_ci break 164762306a36Sopenharmony_ci return tgtdev 164862306a36Sopenharmony_ci def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata): 164962306a36Sopenharmony_ci # try to place the call in a device 165062306a36Sopenharmony_ci phases = self.sortedPhases() 165162306a36Sopenharmony_ci tgtdev = self.sourceDevice(phases, start, end, pid, 'device') 165262306a36Sopenharmony_ci # calls with device pids that occur outside device bounds are dropped 165362306a36Sopenharmony_ci # TODO: include these somehow 165462306a36Sopenharmony_ci if not tgtdev and pid in self.devpids: 165562306a36Sopenharmony_ci return False 165662306a36Sopenharmony_ci # try to place the call in a thread 165762306a36Sopenharmony_ci if not tgtdev: 165862306a36Sopenharmony_ci tgtdev = self.sourceDevice(phases, start, end, pid, 'thread') 165962306a36Sopenharmony_ci # create new thread blocks, expand as new calls are found 166062306a36Sopenharmony_ci if not tgtdev: 166162306a36Sopenharmony_ci if proc == '<...>': 166262306a36Sopenharmony_ci threadname = 'kthread-%d' % (pid) 166362306a36Sopenharmony_ci else: 166462306a36Sopenharmony_ci threadname = '%s-%d' % (proc, pid) 166562306a36Sopenharmony_ci tgtphase = self.sourcePhase(start) 166662306a36Sopenharmony_ci if not tgtphase: 166762306a36Sopenharmony_ci return False 166862306a36Sopenharmony_ci self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '') 166962306a36Sopenharmony_ci return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata) 167062306a36Sopenharmony_ci # this should not happen 167162306a36Sopenharmony_ci if not tgtdev: 167262306a36Sopenharmony_ci sysvals.vprint('[%f - %f] %s-%d %s %s %s' % \ 167362306a36Sopenharmony_ci (start, end, proc, pid, kprobename, cdata, rdata)) 167462306a36Sopenharmony_ci return False 167562306a36Sopenharmony_ci # place the call data inside the src element of the tgtdev 167662306a36Sopenharmony_ci if('src' not in tgtdev): 167762306a36Sopenharmony_ci tgtdev['src'] = [] 167862306a36Sopenharmony_ci dtf = sysvals.dev_tracefuncs 167962306a36Sopenharmony_ci ubiquitous = False 168062306a36Sopenharmony_ci if kprobename in dtf and 'ub' in dtf[kprobename]: 168162306a36Sopenharmony_ci ubiquitous = True 168262306a36Sopenharmony_ci mc = re.match('\(.*\) *(?P<args>.*)', cdata) 168362306a36Sopenharmony_ci mr = re.match('\((?P<caller>\S*).* arg1=(?P<ret>.*)', rdata) 168462306a36Sopenharmony_ci if mc and mr: 168562306a36Sopenharmony_ci c = mr.group('caller').split('+')[0] 168662306a36Sopenharmony_ci a = mc.group('args').strip() 168762306a36Sopenharmony_ci r = mr.group('ret') 168862306a36Sopenharmony_ci if len(r) > 6: 168962306a36Sopenharmony_ci r = '' 169062306a36Sopenharmony_ci else: 169162306a36Sopenharmony_ci r = 'ret=%s ' % r 169262306a36Sopenharmony_ci if ubiquitous and c in dtf and 'ub' in dtf[c]: 169362306a36Sopenharmony_ci return False 169462306a36Sopenharmony_ci else: 169562306a36Sopenharmony_ci return False 169662306a36Sopenharmony_ci color = sysvals.kprobeColor(kprobename) 169762306a36Sopenharmony_ci e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color) 169862306a36Sopenharmony_ci tgtdev['src'].append(e) 169962306a36Sopenharmony_ci return True 170062306a36Sopenharmony_ci def overflowDevices(self): 170162306a36Sopenharmony_ci # get a list of devices that extend beyond the end of this test run 170262306a36Sopenharmony_ci devlist = [] 170362306a36Sopenharmony_ci for phase in self.sortedPhases(): 170462306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 170562306a36Sopenharmony_ci for devname in list: 170662306a36Sopenharmony_ci dev = list[devname] 170762306a36Sopenharmony_ci if dev['end'] > self.end: 170862306a36Sopenharmony_ci devlist.append(dev) 170962306a36Sopenharmony_ci return devlist 171062306a36Sopenharmony_ci def mergeOverlapDevices(self, devlist): 171162306a36Sopenharmony_ci # merge any devices that overlap devlist 171262306a36Sopenharmony_ci for dev in devlist: 171362306a36Sopenharmony_ci devname = dev['name'] 171462306a36Sopenharmony_ci for phase in self.sortedPhases(): 171562306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 171662306a36Sopenharmony_ci if devname not in list: 171762306a36Sopenharmony_ci continue 171862306a36Sopenharmony_ci tdev = list[devname] 171962306a36Sopenharmony_ci o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start']) 172062306a36Sopenharmony_ci if o <= 0: 172162306a36Sopenharmony_ci continue 172262306a36Sopenharmony_ci dev['end'] = tdev['end'] 172362306a36Sopenharmony_ci if 'src' not in dev or 'src' not in tdev: 172462306a36Sopenharmony_ci continue 172562306a36Sopenharmony_ci dev['src'] += tdev['src'] 172662306a36Sopenharmony_ci del list[devname] 172762306a36Sopenharmony_ci def usurpTouchingThread(self, name, dev): 172862306a36Sopenharmony_ci # the caller test has priority of this thread, give it to him 172962306a36Sopenharmony_ci for phase in self.sortedPhases(): 173062306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 173162306a36Sopenharmony_ci if name in list: 173262306a36Sopenharmony_ci tdev = list[name] 173362306a36Sopenharmony_ci if tdev['start'] - dev['end'] < 0.1: 173462306a36Sopenharmony_ci dev['end'] = tdev['end'] 173562306a36Sopenharmony_ci if 'src' not in dev: 173662306a36Sopenharmony_ci dev['src'] = [] 173762306a36Sopenharmony_ci if 'src' in tdev: 173862306a36Sopenharmony_ci dev['src'] += tdev['src'] 173962306a36Sopenharmony_ci del list[name] 174062306a36Sopenharmony_ci break 174162306a36Sopenharmony_ci def stitchTouchingThreads(self, testlist): 174262306a36Sopenharmony_ci # merge any threads between tests that touch 174362306a36Sopenharmony_ci for phase in self.sortedPhases(): 174462306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 174562306a36Sopenharmony_ci for devname in list: 174662306a36Sopenharmony_ci dev = list[devname] 174762306a36Sopenharmony_ci if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']: 174862306a36Sopenharmony_ci continue 174962306a36Sopenharmony_ci for data in testlist: 175062306a36Sopenharmony_ci data.usurpTouchingThread(devname, dev) 175162306a36Sopenharmony_ci def optimizeDevSrc(self): 175262306a36Sopenharmony_ci # merge any src call loops to reduce timeline size 175362306a36Sopenharmony_ci for phase in self.sortedPhases(): 175462306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 175562306a36Sopenharmony_ci for dev in list: 175662306a36Sopenharmony_ci if 'src' not in list[dev]: 175762306a36Sopenharmony_ci continue 175862306a36Sopenharmony_ci src = list[dev]['src'] 175962306a36Sopenharmony_ci p = 0 176062306a36Sopenharmony_ci for e in sorted(src, key=lambda event: event.time): 176162306a36Sopenharmony_ci if not p or not e.repeat(p): 176262306a36Sopenharmony_ci p = e 176362306a36Sopenharmony_ci continue 176462306a36Sopenharmony_ci # e is another iteration of p, move it into p 176562306a36Sopenharmony_ci p.end = e.end 176662306a36Sopenharmony_ci p.length = p.end - p.time 176762306a36Sopenharmony_ci p.count += 1 176862306a36Sopenharmony_ci src.remove(e) 176962306a36Sopenharmony_ci def trimTimeVal(self, t, t0, dT, left): 177062306a36Sopenharmony_ci if left: 177162306a36Sopenharmony_ci if(t > t0): 177262306a36Sopenharmony_ci if(t - dT < t0): 177362306a36Sopenharmony_ci return t0 177462306a36Sopenharmony_ci return t - dT 177562306a36Sopenharmony_ci else: 177662306a36Sopenharmony_ci return t 177762306a36Sopenharmony_ci else: 177862306a36Sopenharmony_ci if(t < t0 + dT): 177962306a36Sopenharmony_ci if(t > t0): 178062306a36Sopenharmony_ci return t0 + dT 178162306a36Sopenharmony_ci return t + dT 178262306a36Sopenharmony_ci else: 178362306a36Sopenharmony_ci return t 178462306a36Sopenharmony_ci def trimTime(self, t0, dT, left): 178562306a36Sopenharmony_ci self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left) 178662306a36Sopenharmony_ci self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left) 178762306a36Sopenharmony_ci self.start = self.trimTimeVal(self.start, t0, dT, left) 178862306a36Sopenharmony_ci self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left) 178962306a36Sopenharmony_ci self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left) 179062306a36Sopenharmony_ci self.end = self.trimTimeVal(self.end, t0, dT, left) 179162306a36Sopenharmony_ci for phase in self.sortedPhases(): 179262306a36Sopenharmony_ci p = self.dmesg[phase] 179362306a36Sopenharmony_ci p['start'] = self.trimTimeVal(p['start'], t0, dT, left) 179462306a36Sopenharmony_ci p['end'] = self.trimTimeVal(p['end'], t0, dT, left) 179562306a36Sopenharmony_ci list = p['list'] 179662306a36Sopenharmony_ci for name in list: 179762306a36Sopenharmony_ci d = list[name] 179862306a36Sopenharmony_ci d['start'] = self.trimTimeVal(d['start'], t0, dT, left) 179962306a36Sopenharmony_ci d['end'] = self.trimTimeVal(d['end'], t0, dT, left) 180062306a36Sopenharmony_ci d['length'] = d['end'] - d['start'] 180162306a36Sopenharmony_ci if('ftrace' in d): 180262306a36Sopenharmony_ci cg = d['ftrace'] 180362306a36Sopenharmony_ci cg.start = self.trimTimeVal(cg.start, t0, dT, left) 180462306a36Sopenharmony_ci cg.end = self.trimTimeVal(cg.end, t0, dT, left) 180562306a36Sopenharmony_ci for line in cg.list: 180662306a36Sopenharmony_ci line.time = self.trimTimeVal(line.time, t0, dT, left) 180762306a36Sopenharmony_ci if('src' in d): 180862306a36Sopenharmony_ci for e in d['src']: 180962306a36Sopenharmony_ci e.time = self.trimTimeVal(e.time, t0, dT, left) 181062306a36Sopenharmony_ci e.end = self.trimTimeVal(e.end, t0, dT, left) 181162306a36Sopenharmony_ci e.length = e.end - e.time 181262306a36Sopenharmony_ci if('cpuexec' in d): 181362306a36Sopenharmony_ci cpuexec = dict() 181462306a36Sopenharmony_ci for e in d['cpuexec']: 181562306a36Sopenharmony_ci c0, cN = e 181662306a36Sopenharmony_ci c0 = self.trimTimeVal(c0, t0, dT, left) 181762306a36Sopenharmony_ci cN = self.trimTimeVal(cN, t0, dT, left) 181862306a36Sopenharmony_ci cpuexec[(c0, cN)] = d['cpuexec'][e] 181962306a36Sopenharmony_ci d['cpuexec'] = cpuexec 182062306a36Sopenharmony_ci for dir in ['suspend', 'resume']: 182162306a36Sopenharmony_ci list = [] 182262306a36Sopenharmony_ci for e in self.errorinfo[dir]: 182362306a36Sopenharmony_ci type, tm, idx1, idx2 = e 182462306a36Sopenharmony_ci tm = self.trimTimeVal(tm, t0, dT, left) 182562306a36Sopenharmony_ci list.append((type, tm, idx1, idx2)) 182662306a36Sopenharmony_ci self.errorinfo[dir] = list 182762306a36Sopenharmony_ci def trimFreezeTime(self, tZero): 182862306a36Sopenharmony_ci # trim out any standby or freeze clock time 182962306a36Sopenharmony_ci lp = '' 183062306a36Sopenharmony_ci for phase in self.sortedPhases(): 183162306a36Sopenharmony_ci if 'resume_machine' in phase and 'suspend_machine' in lp: 183262306a36Sopenharmony_ci tS, tR = self.dmesg[lp]['end'], self.dmesg[phase]['start'] 183362306a36Sopenharmony_ci tL = tR - tS 183462306a36Sopenharmony_ci if tL <= 0: 183562306a36Sopenharmony_ci continue 183662306a36Sopenharmony_ci left = True if tR > tZero else False 183762306a36Sopenharmony_ci self.trimTime(tS, tL, left) 183862306a36Sopenharmony_ci if 'waking' in self.dmesg[lp]: 183962306a36Sopenharmony_ci tCnt = self.dmesg[lp]['waking'][0] 184062306a36Sopenharmony_ci if self.dmesg[lp]['waking'][1] >= 0.001: 184162306a36Sopenharmony_ci tTry = '%.0f' % (round(self.dmesg[lp]['waking'][1] * 1000)) 184262306a36Sopenharmony_ci else: 184362306a36Sopenharmony_ci tTry = '%.3f' % (self.dmesg[lp]['waking'][1] * 1000) 184462306a36Sopenharmony_ci text = '%.0f (%s ms waking %d times)' % (tL * 1000, tTry, tCnt) 184562306a36Sopenharmony_ci else: 184662306a36Sopenharmony_ci text = '%.0f' % (tL * 1000) 184762306a36Sopenharmony_ci self.tLow.append(text) 184862306a36Sopenharmony_ci lp = phase 184962306a36Sopenharmony_ci def getMemTime(self): 185062306a36Sopenharmony_ci if not self.hwstart or not self.hwend: 185162306a36Sopenharmony_ci return 185262306a36Sopenharmony_ci stime = (self.tSuspended - self.start) * 1000000 185362306a36Sopenharmony_ci rtime = (self.end - self.tResumed) * 1000000 185462306a36Sopenharmony_ci hws = self.hwstart + timedelta(microseconds=stime) 185562306a36Sopenharmony_ci hwr = self.hwend - timedelta(microseconds=rtime) 185662306a36Sopenharmony_ci self.tLow.append('%.0f'%((hwr - hws).total_seconds() * 1000)) 185762306a36Sopenharmony_ci def getTimeValues(self): 185862306a36Sopenharmony_ci s = (self.tSuspended - self.tKernSus) * 1000 185962306a36Sopenharmony_ci r = (self.tKernRes - self.tResumed) * 1000 186062306a36Sopenharmony_ci return (max(s, 0), max(r, 0)) 186162306a36Sopenharmony_ci def setPhase(self, phase, ktime, isbegin, order=-1): 186262306a36Sopenharmony_ci if(isbegin): 186362306a36Sopenharmony_ci # phase start over current phase 186462306a36Sopenharmony_ci if self.currphase: 186562306a36Sopenharmony_ci if 'resume_machine' not in self.currphase: 186662306a36Sopenharmony_ci sysvals.vprint('WARNING: phase %s failed to end' % self.currphase) 186762306a36Sopenharmony_ci self.dmesg[self.currphase]['end'] = ktime 186862306a36Sopenharmony_ci phases = self.dmesg.keys() 186962306a36Sopenharmony_ci color = self.phasedef[phase]['color'] 187062306a36Sopenharmony_ci count = len(phases) if order < 0 else order 187162306a36Sopenharmony_ci # create unique name for every new phase 187262306a36Sopenharmony_ci while phase in phases: 187362306a36Sopenharmony_ci phase += '*' 187462306a36Sopenharmony_ci self.dmesg[phase] = {'list': dict(), 'start': -1.0, 'end': -1.0, 187562306a36Sopenharmony_ci 'row': 0, 'color': color, 'order': count} 187662306a36Sopenharmony_ci self.dmesg[phase]['start'] = ktime 187762306a36Sopenharmony_ci self.currphase = phase 187862306a36Sopenharmony_ci else: 187962306a36Sopenharmony_ci # phase end without a start 188062306a36Sopenharmony_ci if phase not in self.currphase: 188162306a36Sopenharmony_ci if self.currphase: 188262306a36Sopenharmony_ci sysvals.vprint('WARNING: %s ended instead of %s, ftrace corruption?' % (phase, self.currphase)) 188362306a36Sopenharmony_ci else: 188462306a36Sopenharmony_ci sysvals.vprint('WARNING: %s ended without a start, ftrace corruption?' % phase) 188562306a36Sopenharmony_ci return phase 188662306a36Sopenharmony_ci phase = self.currphase 188762306a36Sopenharmony_ci self.dmesg[phase]['end'] = ktime 188862306a36Sopenharmony_ci self.currphase = '' 188962306a36Sopenharmony_ci return phase 189062306a36Sopenharmony_ci def sortedDevices(self, phase): 189162306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 189262306a36Sopenharmony_ci return sorted(list, key=lambda k:list[k]['start']) 189362306a36Sopenharmony_ci def fixupInitcalls(self, phase): 189462306a36Sopenharmony_ci # if any calls never returned, clip them at system resume end 189562306a36Sopenharmony_ci phaselist = self.dmesg[phase]['list'] 189662306a36Sopenharmony_ci for devname in phaselist: 189762306a36Sopenharmony_ci dev = phaselist[devname] 189862306a36Sopenharmony_ci if(dev['end'] < 0): 189962306a36Sopenharmony_ci for p in self.sortedPhases(): 190062306a36Sopenharmony_ci if self.dmesg[p]['end'] > dev['start']: 190162306a36Sopenharmony_ci dev['end'] = self.dmesg[p]['end'] 190262306a36Sopenharmony_ci break 190362306a36Sopenharmony_ci sysvals.vprint('%s (%s): callback didnt return' % (devname, phase)) 190462306a36Sopenharmony_ci def deviceFilter(self, devicefilter): 190562306a36Sopenharmony_ci for phase in self.sortedPhases(): 190662306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 190762306a36Sopenharmony_ci rmlist = [] 190862306a36Sopenharmony_ci for name in list: 190962306a36Sopenharmony_ci keep = False 191062306a36Sopenharmony_ci for filter in devicefilter: 191162306a36Sopenharmony_ci if filter in name or \ 191262306a36Sopenharmony_ci ('drv' in list[name] and filter in list[name]['drv']): 191362306a36Sopenharmony_ci keep = True 191462306a36Sopenharmony_ci if not keep: 191562306a36Sopenharmony_ci rmlist.append(name) 191662306a36Sopenharmony_ci for name in rmlist: 191762306a36Sopenharmony_ci del list[name] 191862306a36Sopenharmony_ci def fixupInitcallsThatDidntReturn(self): 191962306a36Sopenharmony_ci # if any calls never returned, clip them at system resume end 192062306a36Sopenharmony_ci for phase in self.sortedPhases(): 192162306a36Sopenharmony_ci self.fixupInitcalls(phase) 192262306a36Sopenharmony_ci def phaseOverlap(self, phases): 192362306a36Sopenharmony_ci rmgroups = [] 192462306a36Sopenharmony_ci newgroup = [] 192562306a36Sopenharmony_ci for group in self.devicegroups: 192662306a36Sopenharmony_ci for phase in phases: 192762306a36Sopenharmony_ci if phase not in group: 192862306a36Sopenharmony_ci continue 192962306a36Sopenharmony_ci for p in group: 193062306a36Sopenharmony_ci if p not in newgroup: 193162306a36Sopenharmony_ci newgroup.append(p) 193262306a36Sopenharmony_ci if group not in rmgroups: 193362306a36Sopenharmony_ci rmgroups.append(group) 193462306a36Sopenharmony_ci for group in rmgroups: 193562306a36Sopenharmony_ci self.devicegroups.remove(group) 193662306a36Sopenharmony_ci self.devicegroups.append(newgroup) 193762306a36Sopenharmony_ci def newActionGlobal(self, name, start, end, pid=-1, color=''): 193862306a36Sopenharmony_ci # which phase is this device callback or action in 193962306a36Sopenharmony_ci phases = self.sortedPhases() 194062306a36Sopenharmony_ci targetphase = 'none' 194162306a36Sopenharmony_ci htmlclass = '' 194262306a36Sopenharmony_ci overlap = 0.0 194362306a36Sopenharmony_ci myphases = [] 194462306a36Sopenharmony_ci for phase in phases: 194562306a36Sopenharmony_ci pstart = self.dmesg[phase]['start'] 194662306a36Sopenharmony_ci pend = self.dmesg[phase]['end'] 194762306a36Sopenharmony_ci # see if the action overlaps this phase 194862306a36Sopenharmony_ci o = max(0, min(end, pend) - max(start, pstart)) 194962306a36Sopenharmony_ci if o > 0: 195062306a36Sopenharmony_ci myphases.append(phase) 195162306a36Sopenharmony_ci # set the target phase to the one that overlaps most 195262306a36Sopenharmony_ci if o > overlap: 195362306a36Sopenharmony_ci if overlap > 0 and phase == 'post_resume': 195462306a36Sopenharmony_ci continue 195562306a36Sopenharmony_ci targetphase = phase 195662306a36Sopenharmony_ci overlap = o 195762306a36Sopenharmony_ci # if no target phase was found, pin it to the edge 195862306a36Sopenharmony_ci if targetphase == 'none': 195962306a36Sopenharmony_ci p0start = self.dmesg[phases[0]]['start'] 196062306a36Sopenharmony_ci if start <= p0start: 196162306a36Sopenharmony_ci targetphase = phases[0] 196262306a36Sopenharmony_ci else: 196362306a36Sopenharmony_ci targetphase = phases[-1] 196462306a36Sopenharmony_ci if pid == -2: 196562306a36Sopenharmony_ci htmlclass = ' bg' 196662306a36Sopenharmony_ci elif pid == -3: 196762306a36Sopenharmony_ci htmlclass = ' ps' 196862306a36Sopenharmony_ci if len(myphases) > 1: 196962306a36Sopenharmony_ci htmlclass = ' bg' 197062306a36Sopenharmony_ci self.phaseOverlap(myphases) 197162306a36Sopenharmony_ci if targetphase in phases: 197262306a36Sopenharmony_ci newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color) 197362306a36Sopenharmony_ci return (targetphase, newname) 197462306a36Sopenharmony_ci return False 197562306a36Sopenharmony_ci def newAction(self, phase, name, pid, parent, start, end, drv, htmlclass='', color=''): 197662306a36Sopenharmony_ci # new device callback for a specific phase 197762306a36Sopenharmony_ci self.html_device_id += 1 197862306a36Sopenharmony_ci devid = '%s%d' % (self.idstr, self.html_device_id) 197962306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 198062306a36Sopenharmony_ci length = -1.0 198162306a36Sopenharmony_ci if(start >= 0 and end >= 0): 198262306a36Sopenharmony_ci length = end - start 198362306a36Sopenharmony_ci if pid == -2 or name not in sysvals.tracefuncs.keys(): 198462306a36Sopenharmony_ci i = 2 198562306a36Sopenharmony_ci origname = name 198662306a36Sopenharmony_ci while(name in list): 198762306a36Sopenharmony_ci name = '%s[%d]' % (origname, i) 198862306a36Sopenharmony_ci i += 1 198962306a36Sopenharmony_ci list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid, 199062306a36Sopenharmony_ci 'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv } 199162306a36Sopenharmony_ci if htmlclass: 199262306a36Sopenharmony_ci list[name]['htmlclass'] = htmlclass 199362306a36Sopenharmony_ci if color: 199462306a36Sopenharmony_ci list[name]['color'] = color 199562306a36Sopenharmony_ci return name 199662306a36Sopenharmony_ci def findDevice(self, phase, name): 199762306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 199862306a36Sopenharmony_ci mydev = '' 199962306a36Sopenharmony_ci for devname in sorted(list): 200062306a36Sopenharmony_ci if name == devname or re.match('^%s\[(?P<num>[0-9]*)\]$' % name, devname): 200162306a36Sopenharmony_ci mydev = devname 200262306a36Sopenharmony_ci if mydev: 200362306a36Sopenharmony_ci return list[mydev] 200462306a36Sopenharmony_ci return False 200562306a36Sopenharmony_ci def deviceChildren(self, devname, phase): 200662306a36Sopenharmony_ci devlist = [] 200762306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 200862306a36Sopenharmony_ci for child in list: 200962306a36Sopenharmony_ci if(list[child]['par'] == devname): 201062306a36Sopenharmony_ci devlist.append(child) 201162306a36Sopenharmony_ci return devlist 201262306a36Sopenharmony_ci def maxDeviceNameSize(self, phase): 201362306a36Sopenharmony_ci size = 0 201462306a36Sopenharmony_ci for name in self.dmesg[phase]['list']: 201562306a36Sopenharmony_ci if len(name) > size: 201662306a36Sopenharmony_ci size = len(name) 201762306a36Sopenharmony_ci return size 201862306a36Sopenharmony_ci def printDetails(self): 201962306a36Sopenharmony_ci sysvals.vprint('Timeline Details:') 202062306a36Sopenharmony_ci sysvals.vprint(' test start: %f' % self.start) 202162306a36Sopenharmony_ci sysvals.vprint('kernel suspend start: %f' % self.tKernSus) 202262306a36Sopenharmony_ci tS = tR = False 202362306a36Sopenharmony_ci for phase in self.sortedPhases(): 202462306a36Sopenharmony_ci devlist = self.dmesg[phase]['list'] 202562306a36Sopenharmony_ci dc, ps, pe = len(devlist), self.dmesg[phase]['start'], self.dmesg[phase]['end'] 202662306a36Sopenharmony_ci if not tS and ps >= self.tSuspended: 202762306a36Sopenharmony_ci sysvals.vprint(' machine suspended: %f' % self.tSuspended) 202862306a36Sopenharmony_ci tS = True 202962306a36Sopenharmony_ci if not tR and ps >= self.tResumed: 203062306a36Sopenharmony_ci sysvals.vprint(' machine resumed: %f' % self.tResumed) 203162306a36Sopenharmony_ci tR = True 203262306a36Sopenharmony_ci sysvals.vprint('%20s: %f - %f (%d devices)' % (phase, ps, pe, dc)) 203362306a36Sopenharmony_ci if sysvals.devdump: 203462306a36Sopenharmony_ci sysvals.vprint(''.join('-' for i in range(80))) 203562306a36Sopenharmony_ci maxname = '%d' % self.maxDeviceNameSize(phase) 203662306a36Sopenharmony_ci fmt = '%3d) %'+maxname+'s - %f - %f' 203762306a36Sopenharmony_ci c = 1 203862306a36Sopenharmony_ci for name in sorted(devlist): 203962306a36Sopenharmony_ci s = devlist[name]['start'] 204062306a36Sopenharmony_ci e = devlist[name]['end'] 204162306a36Sopenharmony_ci sysvals.vprint(fmt % (c, name, s, e)) 204262306a36Sopenharmony_ci c += 1 204362306a36Sopenharmony_ci sysvals.vprint(''.join('-' for i in range(80))) 204462306a36Sopenharmony_ci sysvals.vprint(' kernel resume end: %f' % self.tKernRes) 204562306a36Sopenharmony_ci sysvals.vprint(' test end: %f' % self.end) 204662306a36Sopenharmony_ci def deviceChildrenAllPhases(self, devname): 204762306a36Sopenharmony_ci devlist = [] 204862306a36Sopenharmony_ci for phase in self.sortedPhases(): 204962306a36Sopenharmony_ci list = self.deviceChildren(devname, phase) 205062306a36Sopenharmony_ci for dev in sorted(list): 205162306a36Sopenharmony_ci if dev not in devlist: 205262306a36Sopenharmony_ci devlist.append(dev) 205362306a36Sopenharmony_ci return devlist 205462306a36Sopenharmony_ci def masterTopology(self, name, list, depth): 205562306a36Sopenharmony_ci node = DeviceNode(name, depth) 205662306a36Sopenharmony_ci for cname in list: 205762306a36Sopenharmony_ci # avoid recursions 205862306a36Sopenharmony_ci if name == cname: 205962306a36Sopenharmony_ci continue 206062306a36Sopenharmony_ci clist = self.deviceChildrenAllPhases(cname) 206162306a36Sopenharmony_ci cnode = self.masterTopology(cname, clist, depth+1) 206262306a36Sopenharmony_ci node.children.append(cnode) 206362306a36Sopenharmony_ci return node 206462306a36Sopenharmony_ci def printTopology(self, node): 206562306a36Sopenharmony_ci html = '' 206662306a36Sopenharmony_ci if node.name: 206762306a36Sopenharmony_ci info = '' 206862306a36Sopenharmony_ci drv = '' 206962306a36Sopenharmony_ci for phase in self.sortedPhases(): 207062306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 207162306a36Sopenharmony_ci if node.name in list: 207262306a36Sopenharmony_ci s = list[node.name]['start'] 207362306a36Sopenharmony_ci e = list[node.name]['end'] 207462306a36Sopenharmony_ci if list[node.name]['drv']: 207562306a36Sopenharmony_ci drv = ' {'+list[node.name]['drv']+'}' 207662306a36Sopenharmony_ci info += ('<li>%s: %.3fms</li>' % (phase, (e-s)*1000)) 207762306a36Sopenharmony_ci html += '<li><b>'+node.name+drv+'</b>' 207862306a36Sopenharmony_ci if info: 207962306a36Sopenharmony_ci html += '<ul>'+info+'</ul>' 208062306a36Sopenharmony_ci html += '</li>' 208162306a36Sopenharmony_ci if len(node.children) > 0: 208262306a36Sopenharmony_ci html += '<ul>' 208362306a36Sopenharmony_ci for cnode in node.children: 208462306a36Sopenharmony_ci html += self.printTopology(cnode) 208562306a36Sopenharmony_ci html += '</ul>' 208662306a36Sopenharmony_ci return html 208762306a36Sopenharmony_ci def rootDeviceList(self): 208862306a36Sopenharmony_ci # list of devices graphed 208962306a36Sopenharmony_ci real = [] 209062306a36Sopenharmony_ci for phase in self.sortedPhases(): 209162306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 209262306a36Sopenharmony_ci for dev in sorted(list): 209362306a36Sopenharmony_ci if list[dev]['pid'] >= 0 and dev not in real: 209462306a36Sopenharmony_ci real.append(dev) 209562306a36Sopenharmony_ci # list of top-most root devices 209662306a36Sopenharmony_ci rootlist = [] 209762306a36Sopenharmony_ci for phase in self.sortedPhases(): 209862306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 209962306a36Sopenharmony_ci for dev in sorted(list): 210062306a36Sopenharmony_ci pdev = list[dev]['par'] 210162306a36Sopenharmony_ci pid = list[dev]['pid'] 210262306a36Sopenharmony_ci if(pid < 0 or re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)): 210362306a36Sopenharmony_ci continue 210462306a36Sopenharmony_ci if pdev and pdev not in real and pdev not in rootlist: 210562306a36Sopenharmony_ci rootlist.append(pdev) 210662306a36Sopenharmony_ci return rootlist 210762306a36Sopenharmony_ci def deviceTopology(self): 210862306a36Sopenharmony_ci rootlist = self.rootDeviceList() 210962306a36Sopenharmony_ci master = self.masterTopology('', rootlist, 0) 211062306a36Sopenharmony_ci return self.printTopology(master) 211162306a36Sopenharmony_ci def selectTimelineDevices(self, widfmt, tTotal, mindevlen): 211262306a36Sopenharmony_ci # only select devices that will actually show up in html 211362306a36Sopenharmony_ci self.tdevlist = dict() 211462306a36Sopenharmony_ci for phase in self.dmesg: 211562306a36Sopenharmony_ci devlist = [] 211662306a36Sopenharmony_ci list = self.dmesg[phase]['list'] 211762306a36Sopenharmony_ci for dev in list: 211862306a36Sopenharmony_ci length = (list[dev]['end'] - list[dev]['start']) * 1000 211962306a36Sopenharmony_ci width = widfmt % (((list[dev]['end']-list[dev]['start'])*100)/tTotal) 212062306a36Sopenharmony_ci if length >= mindevlen: 212162306a36Sopenharmony_ci devlist.append(dev) 212262306a36Sopenharmony_ci self.tdevlist[phase] = devlist 212362306a36Sopenharmony_ci def addHorizontalDivider(self, devname, devend): 212462306a36Sopenharmony_ci phase = 'suspend_prepare' 212562306a36Sopenharmony_ci self.newAction(phase, devname, -2, '', \ 212662306a36Sopenharmony_ci self.start, devend, '', ' sec', '') 212762306a36Sopenharmony_ci if phase not in self.tdevlist: 212862306a36Sopenharmony_ci self.tdevlist[phase] = [] 212962306a36Sopenharmony_ci self.tdevlist[phase].append(devname) 213062306a36Sopenharmony_ci d = DevItem(0, phase, self.dmesg[phase]['list'][devname]) 213162306a36Sopenharmony_ci return d 213262306a36Sopenharmony_ci def addProcessUsageEvent(self, name, times): 213362306a36Sopenharmony_ci # get the start and end times for this process 213462306a36Sopenharmony_ci cpuexec = dict() 213562306a36Sopenharmony_ci tlast = start = end = -1 213662306a36Sopenharmony_ci for t in sorted(times): 213762306a36Sopenharmony_ci if tlast < 0: 213862306a36Sopenharmony_ci tlast = t 213962306a36Sopenharmony_ci continue 214062306a36Sopenharmony_ci if name in self.pstl[t] and self.pstl[t][name] > 0: 214162306a36Sopenharmony_ci if start < 0: 214262306a36Sopenharmony_ci start = tlast 214362306a36Sopenharmony_ci end, key = t, (tlast, t) 214462306a36Sopenharmony_ci maxj = (t - tlast) * 1024.0 214562306a36Sopenharmony_ci cpuexec[key] = min(1.0, float(self.pstl[t][name]) / maxj) 214662306a36Sopenharmony_ci tlast = t 214762306a36Sopenharmony_ci if start < 0 or end < 0: 214862306a36Sopenharmony_ci return 214962306a36Sopenharmony_ci # add a new action for this process and get the object 215062306a36Sopenharmony_ci out = self.newActionGlobal(name, start, end, -3) 215162306a36Sopenharmony_ci if out: 215262306a36Sopenharmony_ci phase, devname = out 215362306a36Sopenharmony_ci dev = self.dmesg[phase]['list'][devname] 215462306a36Sopenharmony_ci dev['cpuexec'] = cpuexec 215562306a36Sopenharmony_ci def createProcessUsageEvents(self): 215662306a36Sopenharmony_ci # get an array of process names and times 215762306a36Sopenharmony_ci proclist = {'sus': dict(), 'res': dict()} 215862306a36Sopenharmony_ci tdata = {'sus': [], 'res': []} 215962306a36Sopenharmony_ci for t in sorted(self.pstl): 216062306a36Sopenharmony_ci dir = 'sus' if t < self.tSuspended else 'res' 216162306a36Sopenharmony_ci for ps in sorted(self.pstl[t]): 216262306a36Sopenharmony_ci if ps not in proclist[dir]: 216362306a36Sopenharmony_ci proclist[dir][ps] = 0 216462306a36Sopenharmony_ci tdata[dir].append(t) 216562306a36Sopenharmony_ci # process the events for suspend and resume 216662306a36Sopenharmony_ci if len(proclist['sus']) > 0 or len(proclist['res']) > 0: 216762306a36Sopenharmony_ci sysvals.vprint('Process Execution:') 216862306a36Sopenharmony_ci for dir in ['sus', 'res']: 216962306a36Sopenharmony_ci for ps in sorted(proclist[dir]): 217062306a36Sopenharmony_ci self.addProcessUsageEvent(ps, tdata[dir]) 217162306a36Sopenharmony_ci def handleEndMarker(self, time, msg=''): 217262306a36Sopenharmony_ci dm = self.dmesg 217362306a36Sopenharmony_ci self.setEnd(time, msg) 217462306a36Sopenharmony_ci self.initDevicegroups() 217562306a36Sopenharmony_ci # give suspend_prepare an end if needed 217662306a36Sopenharmony_ci if 'suspend_prepare' in dm and dm['suspend_prepare']['end'] < 0: 217762306a36Sopenharmony_ci dm['suspend_prepare']['end'] = time 217862306a36Sopenharmony_ci # assume resume machine ends at next phase start 217962306a36Sopenharmony_ci if 'resume_machine' in dm and dm['resume_machine']['end'] < 0: 218062306a36Sopenharmony_ci np = self.nextPhase('resume_machine', 1) 218162306a36Sopenharmony_ci if np: 218262306a36Sopenharmony_ci dm['resume_machine']['end'] = dm[np]['start'] 218362306a36Sopenharmony_ci # if kernel resume end not found, assume its the end marker 218462306a36Sopenharmony_ci if self.tKernRes == 0.0: 218562306a36Sopenharmony_ci self.tKernRes = time 218662306a36Sopenharmony_ci # if kernel suspend start not found, assume its the end marker 218762306a36Sopenharmony_ci if self.tKernSus == 0.0: 218862306a36Sopenharmony_ci self.tKernSus = time 218962306a36Sopenharmony_ci # set resume complete to end at end marker 219062306a36Sopenharmony_ci if 'resume_complete' in dm: 219162306a36Sopenharmony_ci dm['resume_complete']['end'] = time 219262306a36Sopenharmony_ci def initcall_debug_call(self, line, quick=False): 219362306a36Sopenharmony_ci m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\ 219462306a36Sopenharmony_ci 'PM: *calling .* @ (?P<n>.*), parent: (?P<p>.*)', line) 219562306a36Sopenharmony_ci if not m: 219662306a36Sopenharmony_ci m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\ 219762306a36Sopenharmony_ci 'calling .* @ (?P<n>.*), parent: (?P<p>.*)', line) 219862306a36Sopenharmony_ci if not m: 219962306a36Sopenharmony_ci m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling '+\ 220062306a36Sopenharmony_ci '(?P<f>.*)\+ @ (?P<n>.*), parent: (?P<p>.*)', line) 220162306a36Sopenharmony_ci if m: 220262306a36Sopenharmony_ci return True if quick else m.group('t', 'f', 'n', 'p') 220362306a36Sopenharmony_ci return False if quick else ('', '', '', '') 220462306a36Sopenharmony_ci def initcall_debug_return(self, line, quick=False): 220562306a36Sopenharmony_ci m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: PM: '+\ 220662306a36Sopenharmony_ci '.* returned (?P<r>[0-9]*) after (?P<dt>[0-9]*) usecs', line) 220762306a36Sopenharmony_ci if not m: 220862306a36Sopenharmony_ci m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\ 220962306a36Sopenharmony_ci '.* returned (?P<r>[0-9]*) after (?P<dt>[0-9]*) usecs', line) 221062306a36Sopenharmony_ci if not m: 221162306a36Sopenharmony_ci m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\ 221262306a36Sopenharmony_ci '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', line) 221362306a36Sopenharmony_ci if m: 221462306a36Sopenharmony_ci return True if quick else m.group('t', 'f', 'dt') 221562306a36Sopenharmony_ci return False if quick else ('', '', '') 221662306a36Sopenharmony_ci def debugPrint(self): 221762306a36Sopenharmony_ci for p in self.sortedPhases(): 221862306a36Sopenharmony_ci list = self.dmesg[p]['list'] 221962306a36Sopenharmony_ci for devname in sorted(list): 222062306a36Sopenharmony_ci dev = list[devname] 222162306a36Sopenharmony_ci if 'ftrace' in dev: 222262306a36Sopenharmony_ci dev['ftrace'].debugPrint(' [%s]' % devname) 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci# Class: DevFunction 222562306a36Sopenharmony_ci# Description: 222662306a36Sopenharmony_ci# A container for kprobe function data we want in the dev timeline 222762306a36Sopenharmony_ciclass DevFunction: 222862306a36Sopenharmony_ci def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color): 222962306a36Sopenharmony_ci self.row = 0 223062306a36Sopenharmony_ci self.count = 1 223162306a36Sopenharmony_ci self.name = name 223262306a36Sopenharmony_ci self.args = args 223362306a36Sopenharmony_ci self.caller = caller 223462306a36Sopenharmony_ci self.ret = ret 223562306a36Sopenharmony_ci self.time = start 223662306a36Sopenharmony_ci self.length = end - start 223762306a36Sopenharmony_ci self.end = end 223862306a36Sopenharmony_ci self.ubiquitous = u 223962306a36Sopenharmony_ci self.proc = proc 224062306a36Sopenharmony_ci self.pid = pid 224162306a36Sopenharmony_ci self.color = color 224262306a36Sopenharmony_ci def title(self): 224362306a36Sopenharmony_ci cnt = '' 224462306a36Sopenharmony_ci if self.count > 1: 224562306a36Sopenharmony_ci cnt = '(x%d)' % self.count 224662306a36Sopenharmony_ci l = '%0.3fms' % (self.length * 1000) 224762306a36Sopenharmony_ci if self.ubiquitous: 224862306a36Sopenharmony_ci title = '%s(%s)%s <- %s, %s(%s)' % \ 224962306a36Sopenharmony_ci (self.name, self.args, cnt, self.caller, self.ret, l) 225062306a36Sopenharmony_ci else: 225162306a36Sopenharmony_ci title = '%s(%s) %s%s(%s)' % (self.name, self.args, self.ret, cnt, l) 225262306a36Sopenharmony_ci return title.replace('"', '') 225362306a36Sopenharmony_ci def text(self): 225462306a36Sopenharmony_ci if self.count > 1: 225562306a36Sopenharmony_ci text = '%s(x%d)' % (self.name, self.count) 225662306a36Sopenharmony_ci else: 225762306a36Sopenharmony_ci text = self.name 225862306a36Sopenharmony_ci return text 225962306a36Sopenharmony_ci def repeat(self, tgt): 226062306a36Sopenharmony_ci # is the tgt call just a repeat of this call (e.g. are we in a loop) 226162306a36Sopenharmony_ci dt = self.time - tgt.end 226262306a36Sopenharmony_ci # only combine calls if -all- attributes are identical 226362306a36Sopenharmony_ci if tgt.caller == self.caller and \ 226462306a36Sopenharmony_ci tgt.name == self.name and tgt.args == self.args and \ 226562306a36Sopenharmony_ci tgt.proc == self.proc and tgt.pid == self.pid and \ 226662306a36Sopenharmony_ci tgt.ret == self.ret and dt >= 0 and \ 226762306a36Sopenharmony_ci dt <= sysvals.callloopmaxgap and \ 226862306a36Sopenharmony_ci self.length < sysvals.callloopmaxlen: 226962306a36Sopenharmony_ci return True 227062306a36Sopenharmony_ci return False 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci# Class: FTraceLine 227362306a36Sopenharmony_ci# Description: 227462306a36Sopenharmony_ci# A container for a single line of ftrace data. There are six basic types: 227562306a36Sopenharmony_ci# callgraph line: 227662306a36Sopenharmony_ci# call: " dpm_run_callback() {" 227762306a36Sopenharmony_ci# return: " }" 227862306a36Sopenharmony_ci# leaf: " dpm_run_callback();" 227962306a36Sopenharmony_ci# trace event: 228062306a36Sopenharmony_ci# tracing_mark_write: SUSPEND START or RESUME COMPLETE 228162306a36Sopenharmony_ci# suspend_resume: phase or custom exec block data 228262306a36Sopenharmony_ci# device_pm_callback: device callback info 228362306a36Sopenharmony_ciclass FTraceLine: 228462306a36Sopenharmony_ci def __init__(self, t, m='', d=''): 228562306a36Sopenharmony_ci self.length = 0.0 228662306a36Sopenharmony_ci self.fcall = False 228762306a36Sopenharmony_ci self.freturn = False 228862306a36Sopenharmony_ci self.fevent = False 228962306a36Sopenharmony_ci self.fkprobe = False 229062306a36Sopenharmony_ci self.depth = 0 229162306a36Sopenharmony_ci self.name = '' 229262306a36Sopenharmony_ci self.type = '' 229362306a36Sopenharmony_ci self.time = float(t) 229462306a36Sopenharmony_ci if not m and not d: 229562306a36Sopenharmony_ci return 229662306a36Sopenharmony_ci # is this a trace event 229762306a36Sopenharmony_ci if(d == 'traceevent' or re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m)): 229862306a36Sopenharmony_ci if(d == 'traceevent'): 229962306a36Sopenharmony_ci # nop format trace event 230062306a36Sopenharmony_ci msg = m 230162306a36Sopenharmony_ci else: 230262306a36Sopenharmony_ci # function_graph format trace event 230362306a36Sopenharmony_ci em = re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m) 230462306a36Sopenharmony_ci msg = em.group('msg') 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci emm = re.match('^(?P<call>.*?): (?P<msg>.*)', msg) 230762306a36Sopenharmony_ci if(emm): 230862306a36Sopenharmony_ci self.name = emm.group('msg') 230962306a36Sopenharmony_ci self.type = emm.group('call') 231062306a36Sopenharmony_ci else: 231162306a36Sopenharmony_ci self.name = msg 231262306a36Sopenharmony_ci km = re.match('^(?P<n>.*)_cal$', self.type) 231362306a36Sopenharmony_ci if km: 231462306a36Sopenharmony_ci self.fcall = True 231562306a36Sopenharmony_ci self.fkprobe = True 231662306a36Sopenharmony_ci self.type = km.group('n') 231762306a36Sopenharmony_ci return 231862306a36Sopenharmony_ci km = re.match('^(?P<n>.*)_ret$', self.type) 231962306a36Sopenharmony_ci if km: 232062306a36Sopenharmony_ci self.freturn = True 232162306a36Sopenharmony_ci self.fkprobe = True 232262306a36Sopenharmony_ci self.type = km.group('n') 232362306a36Sopenharmony_ci return 232462306a36Sopenharmony_ci self.fevent = True 232562306a36Sopenharmony_ci return 232662306a36Sopenharmony_ci # convert the duration to seconds 232762306a36Sopenharmony_ci if(d): 232862306a36Sopenharmony_ci self.length = float(d)/1000000 232962306a36Sopenharmony_ci # the indentation determines the depth 233062306a36Sopenharmony_ci match = re.match('^(?P<d> *)(?P<o>.*)$', m) 233162306a36Sopenharmony_ci if(not match): 233262306a36Sopenharmony_ci return 233362306a36Sopenharmony_ci self.depth = self.getDepth(match.group('d')) 233462306a36Sopenharmony_ci m = match.group('o') 233562306a36Sopenharmony_ci # function return 233662306a36Sopenharmony_ci if(m[0] == '}'): 233762306a36Sopenharmony_ci self.freturn = True 233862306a36Sopenharmony_ci if(len(m) > 1): 233962306a36Sopenharmony_ci # includes comment with function name 234062306a36Sopenharmony_ci match = re.match('^} *\/\* *(?P<n>.*) *\*\/$', m) 234162306a36Sopenharmony_ci if(match): 234262306a36Sopenharmony_ci self.name = match.group('n').strip() 234362306a36Sopenharmony_ci # function call 234462306a36Sopenharmony_ci else: 234562306a36Sopenharmony_ci self.fcall = True 234662306a36Sopenharmony_ci # function call with children 234762306a36Sopenharmony_ci if(m[-1] == '{'): 234862306a36Sopenharmony_ci match = re.match('^(?P<n>.*) *\(.*', m) 234962306a36Sopenharmony_ci if(match): 235062306a36Sopenharmony_ci self.name = match.group('n').strip() 235162306a36Sopenharmony_ci # function call with no children (leaf) 235262306a36Sopenharmony_ci elif(m[-1] == ';'): 235362306a36Sopenharmony_ci self.freturn = True 235462306a36Sopenharmony_ci match = re.match('^(?P<n>.*) *\(.*', m) 235562306a36Sopenharmony_ci if(match): 235662306a36Sopenharmony_ci self.name = match.group('n').strip() 235762306a36Sopenharmony_ci # something else (possibly a trace marker) 235862306a36Sopenharmony_ci else: 235962306a36Sopenharmony_ci self.name = m 236062306a36Sopenharmony_ci def isCall(self): 236162306a36Sopenharmony_ci return self.fcall and not self.freturn 236262306a36Sopenharmony_ci def isReturn(self): 236362306a36Sopenharmony_ci return self.freturn and not self.fcall 236462306a36Sopenharmony_ci def isLeaf(self): 236562306a36Sopenharmony_ci return self.fcall and self.freturn 236662306a36Sopenharmony_ci def getDepth(self, str): 236762306a36Sopenharmony_ci return len(str)/2 236862306a36Sopenharmony_ci def debugPrint(self, info=''): 236962306a36Sopenharmony_ci if self.isLeaf(): 237062306a36Sopenharmony_ci pprint(' -- %12.6f (depth=%02d): %s(); (%.3f us) %s' % (self.time, \ 237162306a36Sopenharmony_ci self.depth, self.name, self.length*1000000, info)) 237262306a36Sopenharmony_ci elif self.freturn: 237362306a36Sopenharmony_ci pprint(' -- %12.6f (depth=%02d): %s} (%.3f us) %s' % (self.time, \ 237462306a36Sopenharmony_ci self.depth, self.name, self.length*1000000, info)) 237562306a36Sopenharmony_ci else: 237662306a36Sopenharmony_ci pprint(' -- %12.6f (depth=%02d): %s() { (%.3f us) %s' % (self.time, \ 237762306a36Sopenharmony_ci self.depth, self.name, self.length*1000000, info)) 237862306a36Sopenharmony_ci def startMarker(self): 237962306a36Sopenharmony_ci # Is this the starting line of a suspend? 238062306a36Sopenharmony_ci if not self.fevent: 238162306a36Sopenharmony_ci return False 238262306a36Sopenharmony_ci if sysvals.usetracemarkers: 238362306a36Sopenharmony_ci if(self.name.startswith('SUSPEND START')): 238462306a36Sopenharmony_ci return True 238562306a36Sopenharmony_ci return False 238662306a36Sopenharmony_ci else: 238762306a36Sopenharmony_ci if(self.type == 'suspend_resume' and 238862306a36Sopenharmony_ci re.match('suspend_enter\[.*\] begin', self.name)): 238962306a36Sopenharmony_ci return True 239062306a36Sopenharmony_ci return False 239162306a36Sopenharmony_ci def endMarker(self): 239262306a36Sopenharmony_ci # Is this the ending line of a resume? 239362306a36Sopenharmony_ci if not self.fevent: 239462306a36Sopenharmony_ci return False 239562306a36Sopenharmony_ci if sysvals.usetracemarkers: 239662306a36Sopenharmony_ci if(self.name.startswith('RESUME COMPLETE')): 239762306a36Sopenharmony_ci return True 239862306a36Sopenharmony_ci return False 239962306a36Sopenharmony_ci else: 240062306a36Sopenharmony_ci if(self.type == 'suspend_resume' and 240162306a36Sopenharmony_ci re.match('thaw_processes\[.*\] end', self.name)): 240262306a36Sopenharmony_ci return True 240362306a36Sopenharmony_ci return False 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci# Class: FTraceCallGraph 240662306a36Sopenharmony_ci# Description: 240762306a36Sopenharmony_ci# A container for the ftrace callgraph of a single recursive function. 240862306a36Sopenharmony_ci# This can be a dpm_run_callback, dpm_prepare, or dpm_complete callgraph 240962306a36Sopenharmony_ci# Each instance is tied to a single device in a single phase, and is 241062306a36Sopenharmony_ci# comprised of an ordered list of FTraceLine objects 241162306a36Sopenharmony_ciclass FTraceCallGraph: 241262306a36Sopenharmony_ci vfname = 'missing_function_name' 241362306a36Sopenharmony_ci def __init__(self, pid, sv): 241462306a36Sopenharmony_ci self.id = '' 241562306a36Sopenharmony_ci self.invalid = False 241662306a36Sopenharmony_ci self.name = '' 241762306a36Sopenharmony_ci self.partial = False 241862306a36Sopenharmony_ci self.ignore = False 241962306a36Sopenharmony_ci self.start = -1.0 242062306a36Sopenharmony_ci self.end = -1.0 242162306a36Sopenharmony_ci self.list = [] 242262306a36Sopenharmony_ci self.depth = 0 242362306a36Sopenharmony_ci self.pid = pid 242462306a36Sopenharmony_ci self.sv = sv 242562306a36Sopenharmony_ci def addLine(self, line): 242662306a36Sopenharmony_ci # if this is already invalid, just leave 242762306a36Sopenharmony_ci if(self.invalid): 242862306a36Sopenharmony_ci if(line.depth == 0 and line.freturn): 242962306a36Sopenharmony_ci return 1 243062306a36Sopenharmony_ci return 0 243162306a36Sopenharmony_ci # invalidate on bad depth 243262306a36Sopenharmony_ci if(self.depth < 0): 243362306a36Sopenharmony_ci self.invalidate(line) 243462306a36Sopenharmony_ci return 0 243562306a36Sopenharmony_ci # ignore data til we return to the current depth 243662306a36Sopenharmony_ci if self.ignore: 243762306a36Sopenharmony_ci if line.depth > self.depth: 243862306a36Sopenharmony_ci return 0 243962306a36Sopenharmony_ci else: 244062306a36Sopenharmony_ci self.list[-1].freturn = True 244162306a36Sopenharmony_ci self.list[-1].length = line.time - self.list[-1].time 244262306a36Sopenharmony_ci self.ignore = False 244362306a36Sopenharmony_ci # if this is a return at self.depth, no more work is needed 244462306a36Sopenharmony_ci if line.depth == self.depth and line.isReturn(): 244562306a36Sopenharmony_ci if line.depth == 0: 244662306a36Sopenharmony_ci self.end = line.time 244762306a36Sopenharmony_ci return 1 244862306a36Sopenharmony_ci return 0 244962306a36Sopenharmony_ci # compare current depth with this lines pre-call depth 245062306a36Sopenharmony_ci prelinedep = line.depth 245162306a36Sopenharmony_ci if line.isReturn(): 245262306a36Sopenharmony_ci prelinedep += 1 245362306a36Sopenharmony_ci last = 0 245462306a36Sopenharmony_ci lasttime = line.time 245562306a36Sopenharmony_ci if len(self.list) > 0: 245662306a36Sopenharmony_ci last = self.list[-1] 245762306a36Sopenharmony_ci lasttime = last.time 245862306a36Sopenharmony_ci if last.isLeaf(): 245962306a36Sopenharmony_ci lasttime += last.length 246062306a36Sopenharmony_ci # handle low misalignments by inserting returns 246162306a36Sopenharmony_ci mismatch = prelinedep - self.depth 246262306a36Sopenharmony_ci warning = self.sv.verbose and abs(mismatch) > 1 246362306a36Sopenharmony_ci info = [] 246462306a36Sopenharmony_ci if mismatch < 0: 246562306a36Sopenharmony_ci idx = 0 246662306a36Sopenharmony_ci # add return calls to get the depth down 246762306a36Sopenharmony_ci while prelinedep < self.depth: 246862306a36Sopenharmony_ci self.depth -= 1 246962306a36Sopenharmony_ci if idx == 0 and last and last.isCall(): 247062306a36Sopenharmony_ci # special case, turn last call into a leaf 247162306a36Sopenharmony_ci last.depth = self.depth 247262306a36Sopenharmony_ci last.freturn = True 247362306a36Sopenharmony_ci last.length = line.time - last.time 247462306a36Sopenharmony_ci if warning: 247562306a36Sopenharmony_ci info.append(('[make leaf]', last)) 247662306a36Sopenharmony_ci else: 247762306a36Sopenharmony_ci vline = FTraceLine(lasttime) 247862306a36Sopenharmony_ci vline.depth = self.depth 247962306a36Sopenharmony_ci vline.name = self.vfname 248062306a36Sopenharmony_ci vline.freturn = True 248162306a36Sopenharmony_ci self.list.append(vline) 248262306a36Sopenharmony_ci if warning: 248362306a36Sopenharmony_ci if idx == 0: 248462306a36Sopenharmony_ci info.append(('', last)) 248562306a36Sopenharmony_ci info.append(('[add return]', vline)) 248662306a36Sopenharmony_ci idx += 1 248762306a36Sopenharmony_ci if warning: 248862306a36Sopenharmony_ci info.append(('', line)) 248962306a36Sopenharmony_ci # handle high misalignments by inserting calls 249062306a36Sopenharmony_ci elif mismatch > 0: 249162306a36Sopenharmony_ci idx = 0 249262306a36Sopenharmony_ci if warning: 249362306a36Sopenharmony_ci info.append(('', last)) 249462306a36Sopenharmony_ci # add calls to get the depth up 249562306a36Sopenharmony_ci while prelinedep > self.depth: 249662306a36Sopenharmony_ci if idx == 0 and line.isReturn(): 249762306a36Sopenharmony_ci # special case, turn this return into a leaf 249862306a36Sopenharmony_ci line.fcall = True 249962306a36Sopenharmony_ci prelinedep -= 1 250062306a36Sopenharmony_ci if warning: 250162306a36Sopenharmony_ci info.append(('[make leaf]', line)) 250262306a36Sopenharmony_ci else: 250362306a36Sopenharmony_ci vline = FTraceLine(lasttime) 250462306a36Sopenharmony_ci vline.depth = self.depth 250562306a36Sopenharmony_ci vline.name = self.vfname 250662306a36Sopenharmony_ci vline.fcall = True 250762306a36Sopenharmony_ci self.list.append(vline) 250862306a36Sopenharmony_ci self.depth += 1 250962306a36Sopenharmony_ci if not last: 251062306a36Sopenharmony_ci self.start = vline.time 251162306a36Sopenharmony_ci if warning: 251262306a36Sopenharmony_ci info.append(('[add call]', vline)) 251362306a36Sopenharmony_ci idx += 1 251462306a36Sopenharmony_ci if warning and ('[make leaf]', line) not in info: 251562306a36Sopenharmony_ci info.append(('', line)) 251662306a36Sopenharmony_ci if warning: 251762306a36Sopenharmony_ci pprint('WARNING: ftrace data missing, corrections made:') 251862306a36Sopenharmony_ci for i in info: 251962306a36Sopenharmony_ci t, obj = i 252062306a36Sopenharmony_ci if obj: 252162306a36Sopenharmony_ci obj.debugPrint(t) 252262306a36Sopenharmony_ci # process the call and set the new depth 252362306a36Sopenharmony_ci skipadd = False 252462306a36Sopenharmony_ci md = self.sv.max_graph_depth 252562306a36Sopenharmony_ci if line.isCall(): 252662306a36Sopenharmony_ci # ignore blacklisted/overdepth funcs 252762306a36Sopenharmony_ci if (md and self.depth >= md - 1) or (line.name in self.sv.cgblacklist): 252862306a36Sopenharmony_ci self.ignore = True 252962306a36Sopenharmony_ci else: 253062306a36Sopenharmony_ci self.depth += 1 253162306a36Sopenharmony_ci elif line.isReturn(): 253262306a36Sopenharmony_ci self.depth -= 1 253362306a36Sopenharmony_ci # remove blacklisted/overdepth/empty funcs that slipped through 253462306a36Sopenharmony_ci if (last and last.isCall() and last.depth == line.depth) or \ 253562306a36Sopenharmony_ci (md and last and last.depth >= md) or \ 253662306a36Sopenharmony_ci (line.name in self.sv.cgblacklist): 253762306a36Sopenharmony_ci while len(self.list) > 0 and self.list[-1].depth > line.depth: 253862306a36Sopenharmony_ci self.list.pop(-1) 253962306a36Sopenharmony_ci if len(self.list) == 0: 254062306a36Sopenharmony_ci self.invalid = True 254162306a36Sopenharmony_ci return 1 254262306a36Sopenharmony_ci self.list[-1].freturn = True 254362306a36Sopenharmony_ci self.list[-1].length = line.time - self.list[-1].time 254462306a36Sopenharmony_ci self.list[-1].name = line.name 254562306a36Sopenharmony_ci skipadd = True 254662306a36Sopenharmony_ci if len(self.list) < 1: 254762306a36Sopenharmony_ci self.start = line.time 254862306a36Sopenharmony_ci # check for a mismatch that returned all the way to callgraph end 254962306a36Sopenharmony_ci res = 1 255062306a36Sopenharmony_ci if mismatch < 0 and self.list[-1].depth == 0 and self.list[-1].freturn: 255162306a36Sopenharmony_ci line = self.list[-1] 255262306a36Sopenharmony_ci skipadd = True 255362306a36Sopenharmony_ci res = -1 255462306a36Sopenharmony_ci if not skipadd: 255562306a36Sopenharmony_ci self.list.append(line) 255662306a36Sopenharmony_ci if(line.depth == 0 and line.freturn): 255762306a36Sopenharmony_ci if(self.start < 0): 255862306a36Sopenharmony_ci self.start = line.time 255962306a36Sopenharmony_ci self.end = line.time 256062306a36Sopenharmony_ci if line.fcall: 256162306a36Sopenharmony_ci self.end += line.length 256262306a36Sopenharmony_ci if self.list[0].name == self.vfname: 256362306a36Sopenharmony_ci self.invalid = True 256462306a36Sopenharmony_ci if res == -1: 256562306a36Sopenharmony_ci self.partial = True 256662306a36Sopenharmony_ci return res 256762306a36Sopenharmony_ci return 0 256862306a36Sopenharmony_ci def invalidate(self, line): 256962306a36Sopenharmony_ci if(len(self.list) > 0): 257062306a36Sopenharmony_ci first = self.list[0] 257162306a36Sopenharmony_ci self.list = [] 257262306a36Sopenharmony_ci self.list.append(first) 257362306a36Sopenharmony_ci self.invalid = True 257462306a36Sopenharmony_ci id = 'task %s' % (self.pid) 257562306a36Sopenharmony_ci window = '(%f - %f)' % (self.start, line.time) 257662306a36Sopenharmony_ci if(self.depth < 0): 257762306a36Sopenharmony_ci pprint('Data misalignment for '+id+\ 257862306a36Sopenharmony_ci ' (buffer overflow), ignoring this callback') 257962306a36Sopenharmony_ci else: 258062306a36Sopenharmony_ci pprint('Too much data for '+id+\ 258162306a36Sopenharmony_ci ' '+window+', ignoring this callback') 258262306a36Sopenharmony_ci def slice(self, dev): 258362306a36Sopenharmony_ci minicg = FTraceCallGraph(dev['pid'], self.sv) 258462306a36Sopenharmony_ci minicg.name = self.name 258562306a36Sopenharmony_ci mydepth = -1 258662306a36Sopenharmony_ci good = False 258762306a36Sopenharmony_ci for l in self.list: 258862306a36Sopenharmony_ci if(l.time < dev['start'] or l.time > dev['end']): 258962306a36Sopenharmony_ci continue 259062306a36Sopenharmony_ci if mydepth < 0: 259162306a36Sopenharmony_ci if l.name == 'mutex_lock' and l.freturn: 259262306a36Sopenharmony_ci mydepth = l.depth 259362306a36Sopenharmony_ci continue 259462306a36Sopenharmony_ci elif l.depth == mydepth and l.name == 'mutex_unlock' and l.fcall: 259562306a36Sopenharmony_ci good = True 259662306a36Sopenharmony_ci break 259762306a36Sopenharmony_ci l.depth -= mydepth 259862306a36Sopenharmony_ci minicg.addLine(l) 259962306a36Sopenharmony_ci if not good or len(minicg.list) < 1: 260062306a36Sopenharmony_ci return 0 260162306a36Sopenharmony_ci return minicg 260262306a36Sopenharmony_ci def repair(self, enddepth): 260362306a36Sopenharmony_ci # bring the depth back to 0 with additional returns 260462306a36Sopenharmony_ci fixed = False 260562306a36Sopenharmony_ci last = self.list[-1] 260662306a36Sopenharmony_ci for i in reversed(range(enddepth)): 260762306a36Sopenharmony_ci t = FTraceLine(last.time) 260862306a36Sopenharmony_ci t.depth = i 260962306a36Sopenharmony_ci t.freturn = True 261062306a36Sopenharmony_ci fixed = self.addLine(t) 261162306a36Sopenharmony_ci if fixed != 0: 261262306a36Sopenharmony_ci self.end = last.time 261362306a36Sopenharmony_ci return True 261462306a36Sopenharmony_ci return False 261562306a36Sopenharmony_ci def postProcess(self): 261662306a36Sopenharmony_ci if len(self.list) > 0: 261762306a36Sopenharmony_ci self.name = self.list[0].name 261862306a36Sopenharmony_ci stack = dict() 261962306a36Sopenharmony_ci cnt = 0 262062306a36Sopenharmony_ci last = 0 262162306a36Sopenharmony_ci for l in self.list: 262262306a36Sopenharmony_ci # ftrace bug: reported duration is not reliable 262362306a36Sopenharmony_ci # check each leaf and clip it at max possible length 262462306a36Sopenharmony_ci if last and last.isLeaf(): 262562306a36Sopenharmony_ci if last.length > l.time - last.time: 262662306a36Sopenharmony_ci last.length = l.time - last.time 262762306a36Sopenharmony_ci if l.isCall(): 262862306a36Sopenharmony_ci stack[l.depth] = l 262962306a36Sopenharmony_ci cnt += 1 263062306a36Sopenharmony_ci elif l.isReturn(): 263162306a36Sopenharmony_ci if(l.depth not in stack): 263262306a36Sopenharmony_ci if self.sv.verbose: 263362306a36Sopenharmony_ci pprint('Post Process Error: Depth missing') 263462306a36Sopenharmony_ci l.debugPrint() 263562306a36Sopenharmony_ci return False 263662306a36Sopenharmony_ci # calculate call length from call/return lines 263762306a36Sopenharmony_ci cl = stack[l.depth] 263862306a36Sopenharmony_ci cl.length = l.time - cl.time 263962306a36Sopenharmony_ci if cl.name == self.vfname: 264062306a36Sopenharmony_ci cl.name = l.name 264162306a36Sopenharmony_ci stack.pop(l.depth) 264262306a36Sopenharmony_ci l.length = 0 264362306a36Sopenharmony_ci cnt -= 1 264462306a36Sopenharmony_ci last = l 264562306a36Sopenharmony_ci if(cnt == 0): 264662306a36Sopenharmony_ci # trace caught the whole call tree 264762306a36Sopenharmony_ci return True 264862306a36Sopenharmony_ci elif(cnt < 0): 264962306a36Sopenharmony_ci if self.sv.verbose: 265062306a36Sopenharmony_ci pprint('Post Process Error: Depth is less than 0') 265162306a36Sopenharmony_ci return False 265262306a36Sopenharmony_ci # trace ended before call tree finished 265362306a36Sopenharmony_ci return self.repair(cnt) 265462306a36Sopenharmony_ci def deviceMatch(self, pid, data): 265562306a36Sopenharmony_ci found = '' 265662306a36Sopenharmony_ci # add the callgraph data to the device hierarchy 265762306a36Sopenharmony_ci borderphase = { 265862306a36Sopenharmony_ci 'dpm_prepare': 'suspend_prepare', 265962306a36Sopenharmony_ci 'dpm_complete': 'resume_complete' 266062306a36Sopenharmony_ci } 266162306a36Sopenharmony_ci if(self.name in borderphase): 266262306a36Sopenharmony_ci p = borderphase[self.name] 266362306a36Sopenharmony_ci list = data.dmesg[p]['list'] 266462306a36Sopenharmony_ci for devname in list: 266562306a36Sopenharmony_ci dev = list[devname] 266662306a36Sopenharmony_ci if(pid == dev['pid'] and 266762306a36Sopenharmony_ci self.start <= dev['start'] and 266862306a36Sopenharmony_ci self.end >= dev['end']): 266962306a36Sopenharmony_ci cg = self.slice(dev) 267062306a36Sopenharmony_ci if cg: 267162306a36Sopenharmony_ci dev['ftrace'] = cg 267262306a36Sopenharmony_ci found = devname 267362306a36Sopenharmony_ci return found 267462306a36Sopenharmony_ci for p in data.sortedPhases(): 267562306a36Sopenharmony_ci if(data.dmesg[p]['start'] <= self.start and 267662306a36Sopenharmony_ci self.start <= data.dmesg[p]['end']): 267762306a36Sopenharmony_ci list = data.dmesg[p]['list'] 267862306a36Sopenharmony_ci for devname in sorted(list, key=lambda k:list[k]['start']): 267962306a36Sopenharmony_ci dev = list[devname] 268062306a36Sopenharmony_ci if(pid == dev['pid'] and 268162306a36Sopenharmony_ci self.start <= dev['start'] and 268262306a36Sopenharmony_ci self.end >= dev['end']): 268362306a36Sopenharmony_ci dev['ftrace'] = self 268462306a36Sopenharmony_ci found = devname 268562306a36Sopenharmony_ci break 268662306a36Sopenharmony_ci break 268762306a36Sopenharmony_ci return found 268862306a36Sopenharmony_ci def newActionFromFunction(self, data): 268962306a36Sopenharmony_ci name = self.name 269062306a36Sopenharmony_ci if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']: 269162306a36Sopenharmony_ci return 269262306a36Sopenharmony_ci fs = self.start 269362306a36Sopenharmony_ci fe = self.end 269462306a36Sopenharmony_ci if fs < data.start or fe > data.end: 269562306a36Sopenharmony_ci return 269662306a36Sopenharmony_ci phase = '' 269762306a36Sopenharmony_ci for p in data.sortedPhases(): 269862306a36Sopenharmony_ci if(data.dmesg[p]['start'] <= self.start and 269962306a36Sopenharmony_ci self.start < data.dmesg[p]['end']): 270062306a36Sopenharmony_ci phase = p 270162306a36Sopenharmony_ci break 270262306a36Sopenharmony_ci if not phase: 270362306a36Sopenharmony_ci return 270462306a36Sopenharmony_ci out = data.newActionGlobal(name, fs, fe, -2) 270562306a36Sopenharmony_ci if out: 270662306a36Sopenharmony_ci phase, myname = out 270762306a36Sopenharmony_ci data.dmesg[phase]['list'][myname]['ftrace'] = self 270862306a36Sopenharmony_ci def debugPrint(self, info=''): 270962306a36Sopenharmony_ci pprint('%s pid=%d [%f - %f] %.3f us' % \ 271062306a36Sopenharmony_ci (self.name, self.pid, self.start, self.end, 271162306a36Sopenharmony_ci (self.end - self.start)*1000000)) 271262306a36Sopenharmony_ci for l in self.list: 271362306a36Sopenharmony_ci if l.isLeaf(): 271462306a36Sopenharmony_ci pprint('%f (%02d): %s(); (%.3f us)%s' % (l.time, \ 271562306a36Sopenharmony_ci l.depth, l.name, l.length*1000000, info)) 271662306a36Sopenharmony_ci elif l.freturn: 271762306a36Sopenharmony_ci pprint('%f (%02d): %s} (%.3f us)%s' % (l.time, \ 271862306a36Sopenharmony_ci l.depth, l.name, l.length*1000000, info)) 271962306a36Sopenharmony_ci else: 272062306a36Sopenharmony_ci pprint('%f (%02d): %s() { (%.3f us)%s' % (l.time, \ 272162306a36Sopenharmony_ci l.depth, l.name, l.length*1000000, info)) 272262306a36Sopenharmony_ci pprint(' ') 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ciclass DevItem: 272562306a36Sopenharmony_ci def __init__(self, test, phase, dev): 272662306a36Sopenharmony_ci self.test = test 272762306a36Sopenharmony_ci self.phase = phase 272862306a36Sopenharmony_ci self.dev = dev 272962306a36Sopenharmony_ci def isa(self, cls): 273062306a36Sopenharmony_ci if 'htmlclass' in self.dev and cls in self.dev['htmlclass']: 273162306a36Sopenharmony_ci return True 273262306a36Sopenharmony_ci return False 273362306a36Sopenharmony_ci 273462306a36Sopenharmony_ci# Class: Timeline 273562306a36Sopenharmony_ci# Description: 273662306a36Sopenharmony_ci# A container for a device timeline which calculates 273762306a36Sopenharmony_ci# all the html properties to display it correctly 273862306a36Sopenharmony_ciclass Timeline: 273962306a36Sopenharmony_ci html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n' 274062306a36Sopenharmony_ci 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' 274162306a36Sopenharmony_ci html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n' 274262306a36Sopenharmony_ci html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' 274362306a36Sopenharmony_ci html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' 274462306a36Sopenharmony_ci def __init__(self, rowheight, scaleheight): 274562306a36Sopenharmony_ci self.html = '' 274662306a36Sopenharmony_ci self.height = 0 # total timeline height 274762306a36Sopenharmony_ci self.scaleH = scaleheight # timescale (top) row height 274862306a36Sopenharmony_ci self.rowH = rowheight # device row height 274962306a36Sopenharmony_ci self.bodyH = 0 # body height 275062306a36Sopenharmony_ci self.rows = 0 # total timeline rows 275162306a36Sopenharmony_ci self.rowlines = dict() 275262306a36Sopenharmony_ci self.rowheight = dict() 275362306a36Sopenharmony_ci def createHeader(self, sv, stamp): 275462306a36Sopenharmony_ci if(not stamp['time']): 275562306a36Sopenharmony_ci return 275662306a36Sopenharmony_ci self.html += '<div class="version"><a href="https://01.org/pm-graph">%s v%s</a></div>' \ 275762306a36Sopenharmony_ci % (sv.title, sv.version) 275862306a36Sopenharmony_ci if sv.logmsg and sv.testlog: 275962306a36Sopenharmony_ci self.html += '<button id="showtest" class="logbtn btnfmt">log</button>' 276062306a36Sopenharmony_ci if sv.dmesglog: 276162306a36Sopenharmony_ci self.html += '<button id="showdmesg" class="logbtn btnfmt">dmesg</button>' 276262306a36Sopenharmony_ci if sv.ftracelog: 276362306a36Sopenharmony_ci self.html += '<button id="showftrace" class="logbtn btnfmt">ftrace</button>' 276462306a36Sopenharmony_ci headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' 276562306a36Sopenharmony_ci self.html += headline_stamp.format(stamp['host'], stamp['kernel'], 276662306a36Sopenharmony_ci stamp['mode'], stamp['time']) 276762306a36Sopenharmony_ci if 'man' in stamp and 'plat' in stamp and 'cpu' in stamp and \ 276862306a36Sopenharmony_ci stamp['man'] and stamp['plat'] and stamp['cpu']: 276962306a36Sopenharmony_ci headline_sysinfo = '<div class="stamp sysinfo">{0} {1} <i>with</i> {2}</div>\n' 277062306a36Sopenharmony_ci self.html += headline_sysinfo.format(stamp['man'], stamp['plat'], stamp['cpu']) 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci # Function: getDeviceRows 277362306a36Sopenharmony_ci # Description: 277462306a36Sopenharmony_ci # determine how may rows the device funcs will take 277562306a36Sopenharmony_ci # Arguments: 277662306a36Sopenharmony_ci # rawlist: the list of devices/actions for a single phase 277762306a36Sopenharmony_ci # Output: 277862306a36Sopenharmony_ci # The total number of rows needed to display this phase of the timeline 277962306a36Sopenharmony_ci def getDeviceRows(self, rawlist): 278062306a36Sopenharmony_ci # clear all rows and set them to undefined 278162306a36Sopenharmony_ci sortdict = dict() 278262306a36Sopenharmony_ci for item in rawlist: 278362306a36Sopenharmony_ci item.row = -1 278462306a36Sopenharmony_ci sortdict[item] = item.length 278562306a36Sopenharmony_ci sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 278662306a36Sopenharmony_ci remaining = len(sortlist) 278762306a36Sopenharmony_ci rowdata = dict() 278862306a36Sopenharmony_ci row = 1 278962306a36Sopenharmony_ci # try to pack each row with as many ranges as possible 279062306a36Sopenharmony_ci while(remaining > 0): 279162306a36Sopenharmony_ci if(row not in rowdata): 279262306a36Sopenharmony_ci rowdata[row] = [] 279362306a36Sopenharmony_ci for i in sortlist: 279462306a36Sopenharmony_ci if(i.row >= 0): 279562306a36Sopenharmony_ci continue 279662306a36Sopenharmony_ci s = i.time 279762306a36Sopenharmony_ci e = i.time + i.length 279862306a36Sopenharmony_ci valid = True 279962306a36Sopenharmony_ci for ritem in rowdata[row]: 280062306a36Sopenharmony_ci rs = ritem.time 280162306a36Sopenharmony_ci re = ritem.time + ritem.length 280262306a36Sopenharmony_ci if(not (((s <= rs) and (e <= rs)) or 280362306a36Sopenharmony_ci ((s >= re) and (e >= re)))): 280462306a36Sopenharmony_ci valid = False 280562306a36Sopenharmony_ci break 280662306a36Sopenharmony_ci if(valid): 280762306a36Sopenharmony_ci rowdata[row].append(i) 280862306a36Sopenharmony_ci i.row = row 280962306a36Sopenharmony_ci remaining -= 1 281062306a36Sopenharmony_ci row += 1 281162306a36Sopenharmony_ci return row 281262306a36Sopenharmony_ci # Function: getPhaseRows 281362306a36Sopenharmony_ci # Description: 281462306a36Sopenharmony_ci # Organize the timeline entries into the smallest 281562306a36Sopenharmony_ci # number of rows possible, with no entry overlapping 281662306a36Sopenharmony_ci # Arguments: 281762306a36Sopenharmony_ci # devlist: the list of devices/actions in a group of contiguous phases 281862306a36Sopenharmony_ci # Output: 281962306a36Sopenharmony_ci # The total number of rows needed to display this phase of the timeline 282062306a36Sopenharmony_ci def getPhaseRows(self, devlist, row=0, sortby='length'): 282162306a36Sopenharmony_ci # clear all rows and set them to undefined 282262306a36Sopenharmony_ci remaining = len(devlist) 282362306a36Sopenharmony_ci rowdata = dict() 282462306a36Sopenharmony_ci sortdict = dict() 282562306a36Sopenharmony_ci myphases = [] 282662306a36Sopenharmony_ci # initialize all device rows to -1 and calculate devrows 282762306a36Sopenharmony_ci for item in devlist: 282862306a36Sopenharmony_ci dev = item.dev 282962306a36Sopenharmony_ci tp = (item.test, item.phase) 283062306a36Sopenharmony_ci if tp not in myphases: 283162306a36Sopenharmony_ci myphases.append(tp) 283262306a36Sopenharmony_ci dev['row'] = -1 283362306a36Sopenharmony_ci if sortby == 'start': 283462306a36Sopenharmony_ci # sort by start 1st, then length 2nd 283562306a36Sopenharmony_ci sortdict[item] = (-1*float(dev['start']), float(dev['end']) - float(dev['start'])) 283662306a36Sopenharmony_ci else: 283762306a36Sopenharmony_ci # sort by length 1st, then name 2nd 283862306a36Sopenharmony_ci sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) 283962306a36Sopenharmony_ci if 'src' in dev: 284062306a36Sopenharmony_ci dev['devrows'] = self.getDeviceRows(dev['src']) 284162306a36Sopenharmony_ci # sort the devlist by length so that large items graph on top 284262306a36Sopenharmony_ci sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 284362306a36Sopenharmony_ci orderedlist = [] 284462306a36Sopenharmony_ci for item in sortlist: 284562306a36Sopenharmony_ci if item.dev['pid'] == -2: 284662306a36Sopenharmony_ci orderedlist.append(item) 284762306a36Sopenharmony_ci for item in sortlist: 284862306a36Sopenharmony_ci if item not in orderedlist: 284962306a36Sopenharmony_ci orderedlist.append(item) 285062306a36Sopenharmony_ci # try to pack each row with as many devices as possible 285162306a36Sopenharmony_ci while(remaining > 0): 285262306a36Sopenharmony_ci rowheight = 1 285362306a36Sopenharmony_ci if(row not in rowdata): 285462306a36Sopenharmony_ci rowdata[row] = [] 285562306a36Sopenharmony_ci for item in orderedlist: 285662306a36Sopenharmony_ci dev = item.dev 285762306a36Sopenharmony_ci if(dev['row'] < 0): 285862306a36Sopenharmony_ci s = dev['start'] 285962306a36Sopenharmony_ci e = dev['end'] 286062306a36Sopenharmony_ci valid = True 286162306a36Sopenharmony_ci for ritem in rowdata[row]: 286262306a36Sopenharmony_ci rs = ritem.dev['start'] 286362306a36Sopenharmony_ci re = ritem.dev['end'] 286462306a36Sopenharmony_ci if(not (((s <= rs) and (e <= rs)) or 286562306a36Sopenharmony_ci ((s >= re) and (e >= re)))): 286662306a36Sopenharmony_ci valid = False 286762306a36Sopenharmony_ci break 286862306a36Sopenharmony_ci if(valid): 286962306a36Sopenharmony_ci rowdata[row].append(item) 287062306a36Sopenharmony_ci dev['row'] = row 287162306a36Sopenharmony_ci remaining -= 1 287262306a36Sopenharmony_ci if 'devrows' in dev and dev['devrows'] > rowheight: 287362306a36Sopenharmony_ci rowheight = dev['devrows'] 287462306a36Sopenharmony_ci for t, p in myphases: 287562306a36Sopenharmony_ci if t not in self.rowlines or t not in self.rowheight: 287662306a36Sopenharmony_ci self.rowlines[t] = dict() 287762306a36Sopenharmony_ci self.rowheight[t] = dict() 287862306a36Sopenharmony_ci if p not in self.rowlines[t] or p not in self.rowheight[t]: 287962306a36Sopenharmony_ci self.rowlines[t][p] = dict() 288062306a36Sopenharmony_ci self.rowheight[t][p] = dict() 288162306a36Sopenharmony_ci rh = self.rowH 288262306a36Sopenharmony_ci # section headers should use a different row height 288362306a36Sopenharmony_ci if len(rowdata[row]) == 1 and \ 288462306a36Sopenharmony_ci 'htmlclass' in rowdata[row][0].dev and \ 288562306a36Sopenharmony_ci 'sec' in rowdata[row][0].dev['htmlclass']: 288662306a36Sopenharmony_ci rh = 15 288762306a36Sopenharmony_ci self.rowlines[t][p][row] = rowheight 288862306a36Sopenharmony_ci self.rowheight[t][p][row] = rowheight * rh 288962306a36Sopenharmony_ci row += 1 289062306a36Sopenharmony_ci if(row > self.rows): 289162306a36Sopenharmony_ci self.rows = int(row) 289262306a36Sopenharmony_ci return row 289362306a36Sopenharmony_ci def phaseRowHeight(self, test, phase, row): 289462306a36Sopenharmony_ci return self.rowheight[test][phase][row] 289562306a36Sopenharmony_ci def phaseRowTop(self, test, phase, row): 289662306a36Sopenharmony_ci top = 0 289762306a36Sopenharmony_ci for i in sorted(self.rowheight[test][phase]): 289862306a36Sopenharmony_ci if i >= row: 289962306a36Sopenharmony_ci break 290062306a36Sopenharmony_ci top += self.rowheight[test][phase][i] 290162306a36Sopenharmony_ci return top 290262306a36Sopenharmony_ci def calcTotalRows(self): 290362306a36Sopenharmony_ci # Calculate the heights and offsets for the header and rows 290462306a36Sopenharmony_ci maxrows = 0 290562306a36Sopenharmony_ci standardphases = [] 290662306a36Sopenharmony_ci for t in self.rowlines: 290762306a36Sopenharmony_ci for p in self.rowlines[t]: 290862306a36Sopenharmony_ci total = 0 290962306a36Sopenharmony_ci for i in sorted(self.rowlines[t][p]): 291062306a36Sopenharmony_ci total += self.rowlines[t][p][i] 291162306a36Sopenharmony_ci if total > maxrows: 291262306a36Sopenharmony_ci maxrows = total 291362306a36Sopenharmony_ci if total == len(self.rowlines[t][p]): 291462306a36Sopenharmony_ci standardphases.append((t, p)) 291562306a36Sopenharmony_ci self.height = self.scaleH + (maxrows*self.rowH) 291662306a36Sopenharmony_ci self.bodyH = self.height - self.scaleH 291762306a36Sopenharmony_ci # if there is 1 line per row, draw them the standard way 291862306a36Sopenharmony_ci for t, p in standardphases: 291962306a36Sopenharmony_ci for i in sorted(self.rowheight[t][p]): 292062306a36Sopenharmony_ci self.rowheight[t][p][i] = float(self.bodyH)/len(self.rowlines[t][p]) 292162306a36Sopenharmony_ci def createZoomBox(self, mode='command', testcount=1): 292262306a36Sopenharmony_ci # Create bounding box, add buttons 292362306a36Sopenharmony_ci html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n' 292462306a36Sopenharmony_ci html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' 292562306a36Sopenharmony_ci html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail{0}</button>' 292662306a36Sopenharmony_ci html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' 292762306a36Sopenharmony_ci if mode != 'command': 292862306a36Sopenharmony_ci if testcount > 1: 292962306a36Sopenharmony_ci self.html += html_devlist2 293062306a36Sopenharmony_ci self.html += html_devlist1.format('1') 293162306a36Sopenharmony_ci else: 293262306a36Sopenharmony_ci self.html += html_devlist1.format('') 293362306a36Sopenharmony_ci self.html += html_zoombox 293462306a36Sopenharmony_ci self.html += html_timeline.format('dmesg', self.height) 293562306a36Sopenharmony_ci # Function: createTimeScale 293662306a36Sopenharmony_ci # Description: 293762306a36Sopenharmony_ci # Create the timescale for a timeline block 293862306a36Sopenharmony_ci # Arguments: 293962306a36Sopenharmony_ci # m0: start time (mode begin) 294062306a36Sopenharmony_ci # mMax: end time (mode end) 294162306a36Sopenharmony_ci # tTotal: total timeline time 294262306a36Sopenharmony_ci # mode: suspend or resume 294362306a36Sopenharmony_ci # Output: 294462306a36Sopenharmony_ci # The html code needed to display the time scale 294562306a36Sopenharmony_ci def createTimeScale(self, m0, mMax, tTotal, mode): 294662306a36Sopenharmony_ci timescale = '<div class="t" style="right:{0}%">{1}</div>\n' 294762306a36Sopenharmony_ci rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">{0}</div>\n' 294862306a36Sopenharmony_ci output = '<div class="timescale">\n' 294962306a36Sopenharmony_ci # set scale for timeline 295062306a36Sopenharmony_ci mTotal = mMax - m0 295162306a36Sopenharmony_ci tS = 0.1 295262306a36Sopenharmony_ci if(tTotal <= 0): 295362306a36Sopenharmony_ci return output+'</div>\n' 295462306a36Sopenharmony_ci if(tTotal > 4): 295562306a36Sopenharmony_ci tS = 1 295662306a36Sopenharmony_ci divTotal = int(mTotal/tS) + 1 295762306a36Sopenharmony_ci divEdge = (mTotal - tS*(divTotal-1))*100/mTotal 295862306a36Sopenharmony_ci for i in range(divTotal): 295962306a36Sopenharmony_ci htmlline = '' 296062306a36Sopenharmony_ci if(mode == 'suspend'): 296162306a36Sopenharmony_ci pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge) 296262306a36Sopenharmony_ci val = '%0.fms' % (float(i-divTotal+1)*tS*1000) 296362306a36Sopenharmony_ci if(i == divTotal - 1): 296462306a36Sopenharmony_ci val = mode 296562306a36Sopenharmony_ci htmlline = timescale.format(pos, val) 296662306a36Sopenharmony_ci else: 296762306a36Sopenharmony_ci pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal)) 296862306a36Sopenharmony_ci val = '%0.fms' % (float(i)*tS*1000) 296962306a36Sopenharmony_ci htmlline = timescale.format(pos, val) 297062306a36Sopenharmony_ci if(i == 0): 297162306a36Sopenharmony_ci htmlline = rline.format(mode) 297262306a36Sopenharmony_ci output += htmlline 297362306a36Sopenharmony_ci self.html += output+'</div>\n' 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci# Class: TestProps 297662306a36Sopenharmony_ci# Description: 297762306a36Sopenharmony_ci# A list of values describing the properties of these test runs 297862306a36Sopenharmony_ciclass TestProps: 297962306a36Sopenharmony_ci stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ 298062306a36Sopenharmony_ci '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ 298162306a36Sopenharmony_ci ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' 298262306a36Sopenharmony_ci wififmt = '^# wifi *(?P<d>\S*) *(?P<s>\S*) *(?P<t>[0-9\.]+).*' 298362306a36Sopenharmony_ci tstatfmt = '^# turbostat (?P<t>\S*)' 298462306a36Sopenharmony_ci testerrfmt = '^# enter_sleep_error (?P<e>.*)' 298562306a36Sopenharmony_ci sysinfofmt = '^# sysinfo .*' 298662306a36Sopenharmony_ci cmdlinefmt = '^# command \| (?P<cmd>.*)' 298762306a36Sopenharmony_ci kparamsfmt = '^# kparams \| (?P<kp>.*)' 298862306a36Sopenharmony_ci devpropfmt = '# Device Properties: .*' 298962306a36Sopenharmony_ci pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9,_]*): (?P<info>.*)' 299062306a36Sopenharmony_ci tracertypefmt = '# tracer: (?P<t>.*)' 299162306a36Sopenharmony_ci firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' 299262306a36Sopenharmony_ci procexecfmt = 'ps - (?P<ps>.*)$' 299362306a36Sopenharmony_ci procmultifmt = '@(?P<n>[0-9]*)\|(?P<ps>.*)$' 299462306a36Sopenharmony_ci ftrace_line_fmt_fg = \ 299562306a36Sopenharmony_ci '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ 299662306a36Sopenharmony_ci ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ 299762306a36Sopenharmony_ci '[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)' 299862306a36Sopenharmony_ci ftrace_line_fmt_nop = \ 299962306a36Sopenharmony_ci ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\ 300062306a36Sopenharmony_ci '(?P<flags>\S*) *(?P<time>[0-9\.]*): *'+\ 300162306a36Sopenharmony_ci '(?P<msg>.*)' 300262306a36Sopenharmony_ci machinesuspend = 'machine_suspend\[.*' 300362306a36Sopenharmony_ci multiproclist = dict() 300462306a36Sopenharmony_ci multiproctime = 0.0 300562306a36Sopenharmony_ci multiproccnt = 0 300662306a36Sopenharmony_ci def __init__(self): 300762306a36Sopenharmony_ci self.stamp = '' 300862306a36Sopenharmony_ci self.sysinfo = '' 300962306a36Sopenharmony_ci self.cmdline = '' 301062306a36Sopenharmony_ci self.testerror = [] 301162306a36Sopenharmony_ci self.turbostat = [] 301262306a36Sopenharmony_ci self.wifi = [] 301362306a36Sopenharmony_ci self.fwdata = [] 301462306a36Sopenharmony_ci self.ftrace_line_fmt = self.ftrace_line_fmt_nop 301562306a36Sopenharmony_ci self.cgformat = False 301662306a36Sopenharmony_ci self.data = 0 301762306a36Sopenharmony_ci self.ktemp = dict() 301862306a36Sopenharmony_ci def setTracerType(self, tracer): 301962306a36Sopenharmony_ci if(tracer == 'function_graph'): 302062306a36Sopenharmony_ci self.cgformat = True 302162306a36Sopenharmony_ci self.ftrace_line_fmt = self.ftrace_line_fmt_fg 302262306a36Sopenharmony_ci elif(tracer == 'nop'): 302362306a36Sopenharmony_ci self.ftrace_line_fmt = self.ftrace_line_fmt_nop 302462306a36Sopenharmony_ci else: 302562306a36Sopenharmony_ci doError('Invalid tracer format: [%s]' % tracer) 302662306a36Sopenharmony_ci def stampInfo(self, line, sv): 302762306a36Sopenharmony_ci if re.match(self.stampfmt, line): 302862306a36Sopenharmony_ci self.stamp = line 302962306a36Sopenharmony_ci return True 303062306a36Sopenharmony_ci elif re.match(self.sysinfofmt, line): 303162306a36Sopenharmony_ci self.sysinfo = line 303262306a36Sopenharmony_ci return True 303362306a36Sopenharmony_ci elif re.match(self.tstatfmt, line): 303462306a36Sopenharmony_ci self.turbostat.append(line) 303562306a36Sopenharmony_ci return True 303662306a36Sopenharmony_ci elif re.match(self.wififmt, line): 303762306a36Sopenharmony_ci self.wifi.append(line) 303862306a36Sopenharmony_ci return True 303962306a36Sopenharmony_ci elif re.match(self.testerrfmt, line): 304062306a36Sopenharmony_ci self.testerror.append(line) 304162306a36Sopenharmony_ci return True 304262306a36Sopenharmony_ci elif re.match(self.firmwarefmt, line): 304362306a36Sopenharmony_ci self.fwdata.append(line) 304462306a36Sopenharmony_ci return True 304562306a36Sopenharmony_ci elif(re.match(self.devpropfmt, line)): 304662306a36Sopenharmony_ci self.parseDevprops(line, sv) 304762306a36Sopenharmony_ci return True 304862306a36Sopenharmony_ci elif(re.match(self.pinfofmt, line)): 304962306a36Sopenharmony_ci self.parsePlatformInfo(line, sv) 305062306a36Sopenharmony_ci return True 305162306a36Sopenharmony_ci m = re.match(self.cmdlinefmt, line) 305262306a36Sopenharmony_ci if m: 305362306a36Sopenharmony_ci self.cmdline = m.group('cmd') 305462306a36Sopenharmony_ci return True 305562306a36Sopenharmony_ci m = re.match(self.tracertypefmt, line) 305662306a36Sopenharmony_ci if(m): 305762306a36Sopenharmony_ci self.setTracerType(m.group('t')) 305862306a36Sopenharmony_ci return True 305962306a36Sopenharmony_ci return False 306062306a36Sopenharmony_ci def parseStamp(self, data, sv): 306162306a36Sopenharmony_ci # global test data 306262306a36Sopenharmony_ci m = re.match(self.stampfmt, self.stamp) 306362306a36Sopenharmony_ci if not self.stamp or not m: 306462306a36Sopenharmony_ci doError('data does not include the expected stamp') 306562306a36Sopenharmony_ci data.stamp = {'time': '', 'host': '', 'mode': ''} 306662306a36Sopenharmony_ci dt = datetime(int(m.group('y'))+2000, int(m.group('m')), 306762306a36Sopenharmony_ci int(m.group('d')), int(m.group('H')), int(m.group('M')), 306862306a36Sopenharmony_ci int(m.group('S'))) 306962306a36Sopenharmony_ci data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') 307062306a36Sopenharmony_ci data.stamp['host'] = m.group('host') 307162306a36Sopenharmony_ci data.stamp['mode'] = m.group('mode') 307262306a36Sopenharmony_ci data.stamp['kernel'] = m.group('kernel') 307362306a36Sopenharmony_ci if re.match(self.sysinfofmt, self.sysinfo): 307462306a36Sopenharmony_ci for f in self.sysinfo.split('|'): 307562306a36Sopenharmony_ci if '#' in f: 307662306a36Sopenharmony_ci continue 307762306a36Sopenharmony_ci tmp = f.strip().split(':', 1) 307862306a36Sopenharmony_ci key = tmp[0] 307962306a36Sopenharmony_ci val = tmp[1] 308062306a36Sopenharmony_ci data.stamp[key] = val 308162306a36Sopenharmony_ci sv.hostname = data.stamp['host'] 308262306a36Sopenharmony_ci sv.suspendmode = data.stamp['mode'] 308362306a36Sopenharmony_ci if sv.suspendmode == 'freeze': 308462306a36Sopenharmony_ci self.machinesuspend = 'timekeeping_freeze\[.*' 308562306a36Sopenharmony_ci else: 308662306a36Sopenharmony_ci self.machinesuspend = 'machine_suspend\[.*' 308762306a36Sopenharmony_ci if sv.suspendmode == 'command' and sv.ftracefile != '': 308862306a36Sopenharmony_ci modes = ['on', 'freeze', 'standby', 'mem', 'disk'] 308962306a36Sopenharmony_ci fp = sv.openlog(sv.ftracefile, 'r') 309062306a36Sopenharmony_ci for line in fp: 309162306a36Sopenharmony_ci m = re.match('.* machine_suspend\[(?P<mode>.*)\]', line) 309262306a36Sopenharmony_ci if m and m.group('mode') in ['1', '2', '3', '4']: 309362306a36Sopenharmony_ci sv.suspendmode = modes[int(m.group('mode'))] 309462306a36Sopenharmony_ci data.stamp['mode'] = sv.suspendmode 309562306a36Sopenharmony_ci break 309662306a36Sopenharmony_ci fp.close() 309762306a36Sopenharmony_ci sv.cmdline = self.cmdline 309862306a36Sopenharmony_ci if not sv.stamp: 309962306a36Sopenharmony_ci sv.stamp = data.stamp 310062306a36Sopenharmony_ci # firmware data 310162306a36Sopenharmony_ci if sv.suspendmode == 'mem' and len(self.fwdata) > data.testnumber: 310262306a36Sopenharmony_ci m = re.match(self.firmwarefmt, self.fwdata[data.testnumber]) 310362306a36Sopenharmony_ci if m: 310462306a36Sopenharmony_ci data.fwSuspend, data.fwResume = int(m.group('s')), int(m.group('r')) 310562306a36Sopenharmony_ci if(data.fwSuspend > 0 or data.fwResume > 0): 310662306a36Sopenharmony_ci data.fwValid = True 310762306a36Sopenharmony_ci # turbostat data 310862306a36Sopenharmony_ci if len(self.turbostat) > data.testnumber: 310962306a36Sopenharmony_ci m = re.match(self.tstatfmt, self.turbostat[data.testnumber]) 311062306a36Sopenharmony_ci if m: 311162306a36Sopenharmony_ci data.turbostat = m.group('t') 311262306a36Sopenharmony_ci # wifi data 311362306a36Sopenharmony_ci if len(self.wifi) > data.testnumber: 311462306a36Sopenharmony_ci m = re.match(self.wififmt, self.wifi[data.testnumber]) 311562306a36Sopenharmony_ci if m: 311662306a36Sopenharmony_ci data.wifi = {'dev': m.group('d'), 'stat': m.group('s'), 311762306a36Sopenharmony_ci 'time': float(m.group('t'))} 311862306a36Sopenharmony_ci data.stamp['wifi'] = m.group('d') 311962306a36Sopenharmony_ci # sleep mode enter errors 312062306a36Sopenharmony_ci if len(self.testerror) > data.testnumber: 312162306a36Sopenharmony_ci m = re.match(self.testerrfmt, self.testerror[data.testnumber]) 312262306a36Sopenharmony_ci if m: 312362306a36Sopenharmony_ci data.enterfail = m.group('e') 312462306a36Sopenharmony_ci def devprops(self, data): 312562306a36Sopenharmony_ci props = dict() 312662306a36Sopenharmony_ci devlist = data.split(';') 312762306a36Sopenharmony_ci for dev in devlist: 312862306a36Sopenharmony_ci f = dev.split(',') 312962306a36Sopenharmony_ci if len(f) < 3: 313062306a36Sopenharmony_ci continue 313162306a36Sopenharmony_ci dev = f[0] 313262306a36Sopenharmony_ci props[dev] = DevProps() 313362306a36Sopenharmony_ci props[dev].altname = f[1] 313462306a36Sopenharmony_ci if int(f[2]): 313562306a36Sopenharmony_ci props[dev].isasync = True 313662306a36Sopenharmony_ci else: 313762306a36Sopenharmony_ci props[dev].isasync = False 313862306a36Sopenharmony_ci return props 313962306a36Sopenharmony_ci def parseDevprops(self, line, sv): 314062306a36Sopenharmony_ci idx = line.index(': ') + 2 314162306a36Sopenharmony_ci if idx >= len(line): 314262306a36Sopenharmony_ci return 314362306a36Sopenharmony_ci props = self.devprops(line[idx:]) 314462306a36Sopenharmony_ci if sv.suspendmode == 'command' and 'testcommandstring' in props: 314562306a36Sopenharmony_ci sv.testcommand = props['testcommandstring'].altname 314662306a36Sopenharmony_ci sv.devprops = props 314762306a36Sopenharmony_ci def parsePlatformInfo(self, line, sv): 314862306a36Sopenharmony_ci m = re.match(self.pinfofmt, line) 314962306a36Sopenharmony_ci if not m: 315062306a36Sopenharmony_ci return 315162306a36Sopenharmony_ci name, info = m.group('val'), m.group('info') 315262306a36Sopenharmony_ci if name == 'devinfo': 315362306a36Sopenharmony_ci sv.devprops = self.devprops(sv.b64unzip(info)) 315462306a36Sopenharmony_ci return 315562306a36Sopenharmony_ci elif name == 'testcmd': 315662306a36Sopenharmony_ci sv.testcommand = info 315762306a36Sopenharmony_ci return 315862306a36Sopenharmony_ci field = info.split('|') 315962306a36Sopenharmony_ci if len(field) < 2: 316062306a36Sopenharmony_ci return 316162306a36Sopenharmony_ci cmdline = field[0].strip() 316262306a36Sopenharmony_ci output = sv.b64unzip(field[1].strip()) 316362306a36Sopenharmony_ci sv.platinfo.append([name, cmdline, output]) 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci# Class: TestRun 316662306a36Sopenharmony_ci# Description: 316762306a36Sopenharmony_ci# A container for a suspend/resume test run. This is necessary as 316862306a36Sopenharmony_ci# there could be more than one, and they need to be separate. 316962306a36Sopenharmony_ciclass TestRun: 317062306a36Sopenharmony_ci def __init__(self, dataobj): 317162306a36Sopenharmony_ci self.data = dataobj 317262306a36Sopenharmony_ci self.ftemp = dict() 317362306a36Sopenharmony_ci self.ttemp = dict() 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ciclass ProcessMonitor: 317662306a36Sopenharmony_ci maxchars = 512 317762306a36Sopenharmony_ci def __init__(self): 317862306a36Sopenharmony_ci self.proclist = dict() 317962306a36Sopenharmony_ci self.running = False 318062306a36Sopenharmony_ci def procstat(self): 318162306a36Sopenharmony_ci c = ['cat /proc/[1-9]*/stat 2>/dev/null'] 318262306a36Sopenharmony_ci process = Popen(c, shell=True, stdout=PIPE) 318362306a36Sopenharmony_ci running = dict() 318462306a36Sopenharmony_ci for line in process.stdout: 318562306a36Sopenharmony_ci data = ascii(line).split() 318662306a36Sopenharmony_ci pid = data[0] 318762306a36Sopenharmony_ci name = re.sub('[()]', '', data[1]) 318862306a36Sopenharmony_ci user = int(data[13]) 318962306a36Sopenharmony_ci kern = int(data[14]) 319062306a36Sopenharmony_ci kjiff = ujiff = 0 319162306a36Sopenharmony_ci if pid not in self.proclist: 319262306a36Sopenharmony_ci self.proclist[pid] = {'name' : name, 'user' : user, 'kern' : kern} 319362306a36Sopenharmony_ci else: 319462306a36Sopenharmony_ci val = self.proclist[pid] 319562306a36Sopenharmony_ci ujiff = user - val['user'] 319662306a36Sopenharmony_ci kjiff = kern - val['kern'] 319762306a36Sopenharmony_ci val['user'] = user 319862306a36Sopenharmony_ci val['kern'] = kern 319962306a36Sopenharmony_ci if ujiff > 0 or kjiff > 0: 320062306a36Sopenharmony_ci running[pid] = ujiff + kjiff 320162306a36Sopenharmony_ci process.wait() 320262306a36Sopenharmony_ci out = [''] 320362306a36Sopenharmony_ci for pid in running: 320462306a36Sopenharmony_ci jiffies = running[pid] 320562306a36Sopenharmony_ci val = self.proclist[pid] 320662306a36Sopenharmony_ci if len(out[-1]) > self.maxchars: 320762306a36Sopenharmony_ci out.append('') 320862306a36Sopenharmony_ci elif len(out[-1]) > 0: 320962306a36Sopenharmony_ci out[-1] += ',' 321062306a36Sopenharmony_ci out[-1] += '%s-%s %d' % (val['name'], pid, jiffies) 321162306a36Sopenharmony_ci if len(out) > 1: 321262306a36Sopenharmony_ci for line in out: 321362306a36Sopenharmony_ci sysvals.fsetVal('ps - @%d|%s' % (len(out), line), 'trace_marker') 321462306a36Sopenharmony_ci else: 321562306a36Sopenharmony_ci sysvals.fsetVal('ps - %s' % out[0], 'trace_marker') 321662306a36Sopenharmony_ci def processMonitor(self, tid): 321762306a36Sopenharmony_ci while self.running: 321862306a36Sopenharmony_ci self.procstat() 321962306a36Sopenharmony_ci def start(self): 322062306a36Sopenharmony_ci self.thread = Thread(target=self.processMonitor, args=(0,)) 322162306a36Sopenharmony_ci self.running = True 322262306a36Sopenharmony_ci self.thread.start() 322362306a36Sopenharmony_ci def stop(self): 322462306a36Sopenharmony_ci self.running = False 322562306a36Sopenharmony_ci 322662306a36Sopenharmony_ci# ----------------- FUNCTIONS -------------------- 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci# Function: doesTraceLogHaveTraceEvents 322962306a36Sopenharmony_ci# Description: 323062306a36Sopenharmony_ci# Quickly determine if the ftrace log has all of the trace events, 323162306a36Sopenharmony_ci# markers, and/or kprobes required for primary parsing. 323262306a36Sopenharmony_cidef doesTraceLogHaveTraceEvents(): 323362306a36Sopenharmony_ci kpcheck = ['_cal: (', '_ret: ('] 323462306a36Sopenharmony_ci techeck = ['suspend_resume', 'device_pm_callback', 'tracing_mark_write'] 323562306a36Sopenharmony_ci tmcheck = ['SUSPEND START', 'RESUME COMPLETE'] 323662306a36Sopenharmony_ci sysvals.usekprobes = False 323762306a36Sopenharmony_ci fp = sysvals.openlog(sysvals.ftracefile, 'r') 323862306a36Sopenharmony_ci for line in fp: 323962306a36Sopenharmony_ci # check for kprobes 324062306a36Sopenharmony_ci if not sysvals.usekprobes: 324162306a36Sopenharmony_ci for i in kpcheck: 324262306a36Sopenharmony_ci if i in line: 324362306a36Sopenharmony_ci sysvals.usekprobes = True 324462306a36Sopenharmony_ci # check for all necessary trace events 324562306a36Sopenharmony_ci check = techeck[:] 324662306a36Sopenharmony_ci for i in techeck: 324762306a36Sopenharmony_ci if i in line: 324862306a36Sopenharmony_ci check.remove(i) 324962306a36Sopenharmony_ci techeck = check 325062306a36Sopenharmony_ci # check for all necessary trace markers 325162306a36Sopenharmony_ci check = tmcheck[:] 325262306a36Sopenharmony_ci for i in tmcheck: 325362306a36Sopenharmony_ci if i in line: 325462306a36Sopenharmony_ci check.remove(i) 325562306a36Sopenharmony_ci tmcheck = check 325662306a36Sopenharmony_ci fp.close() 325762306a36Sopenharmony_ci sysvals.usetraceevents = True if len(techeck) < 3 else False 325862306a36Sopenharmony_ci sysvals.usetracemarkers = True if len(tmcheck) == 0 else False 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci# Function: appendIncompleteTraceLog 326162306a36Sopenharmony_ci# Description: 326262306a36Sopenharmony_ci# Adds callgraph data which lacks trace event data. This is only 326362306a36Sopenharmony_ci# for timelines generated from 3.15 or older 326462306a36Sopenharmony_ci# Arguments: 326562306a36Sopenharmony_ci# testruns: the array of Data objects obtained from parseKernelLog 326662306a36Sopenharmony_cidef appendIncompleteTraceLog(testruns): 326762306a36Sopenharmony_ci # create TestRun vessels for ftrace parsing 326862306a36Sopenharmony_ci testcnt = len(testruns) 326962306a36Sopenharmony_ci testidx = 0 327062306a36Sopenharmony_ci testrun = [] 327162306a36Sopenharmony_ci for data in testruns: 327262306a36Sopenharmony_ci testrun.append(TestRun(data)) 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci # extract the callgraph and traceevent data 327562306a36Sopenharmony_ci sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 327662306a36Sopenharmony_ci os.path.basename(sysvals.ftracefile)) 327762306a36Sopenharmony_ci tp = TestProps() 327862306a36Sopenharmony_ci tf = sysvals.openlog(sysvals.ftracefile, 'r') 327962306a36Sopenharmony_ci data = 0 328062306a36Sopenharmony_ci for line in tf: 328162306a36Sopenharmony_ci # remove any latent carriage returns 328262306a36Sopenharmony_ci line = line.replace('\r\n', '') 328362306a36Sopenharmony_ci if tp.stampInfo(line, sysvals): 328462306a36Sopenharmony_ci continue 328562306a36Sopenharmony_ci # parse only valid lines, if this is not one move on 328662306a36Sopenharmony_ci m = re.match(tp.ftrace_line_fmt, line) 328762306a36Sopenharmony_ci if(not m): 328862306a36Sopenharmony_ci continue 328962306a36Sopenharmony_ci # gather the basic message data from the line 329062306a36Sopenharmony_ci m_time = m.group('time') 329162306a36Sopenharmony_ci m_pid = m.group('pid') 329262306a36Sopenharmony_ci m_msg = m.group('msg') 329362306a36Sopenharmony_ci if(tp.cgformat): 329462306a36Sopenharmony_ci m_param3 = m.group('dur') 329562306a36Sopenharmony_ci else: 329662306a36Sopenharmony_ci m_param3 = 'traceevent' 329762306a36Sopenharmony_ci if(m_time and m_pid and m_msg): 329862306a36Sopenharmony_ci t = FTraceLine(m_time, m_msg, m_param3) 329962306a36Sopenharmony_ci pid = int(m_pid) 330062306a36Sopenharmony_ci else: 330162306a36Sopenharmony_ci continue 330262306a36Sopenharmony_ci # the line should be a call, return, or event 330362306a36Sopenharmony_ci if(not t.fcall and not t.freturn and not t.fevent): 330462306a36Sopenharmony_ci continue 330562306a36Sopenharmony_ci # look for the suspend start marker 330662306a36Sopenharmony_ci if(t.startMarker()): 330762306a36Sopenharmony_ci data = testrun[testidx].data 330862306a36Sopenharmony_ci tp.parseStamp(data, sysvals) 330962306a36Sopenharmony_ci data.setStart(t.time, t.name) 331062306a36Sopenharmony_ci continue 331162306a36Sopenharmony_ci if(not data): 331262306a36Sopenharmony_ci continue 331362306a36Sopenharmony_ci # find the end of resume 331462306a36Sopenharmony_ci if(t.endMarker()): 331562306a36Sopenharmony_ci data.setEnd(t.time, t.name) 331662306a36Sopenharmony_ci testidx += 1 331762306a36Sopenharmony_ci if(testidx >= testcnt): 331862306a36Sopenharmony_ci break 331962306a36Sopenharmony_ci continue 332062306a36Sopenharmony_ci # trace event processing 332162306a36Sopenharmony_ci if(t.fevent): 332262306a36Sopenharmony_ci continue 332362306a36Sopenharmony_ci # call/return processing 332462306a36Sopenharmony_ci elif sysvals.usecallgraph: 332562306a36Sopenharmony_ci # create a callgraph object for the data 332662306a36Sopenharmony_ci if(pid not in testrun[testidx].ftemp): 332762306a36Sopenharmony_ci testrun[testidx].ftemp[pid] = [] 332862306a36Sopenharmony_ci testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 332962306a36Sopenharmony_ci # when the call is finished, see which device matches it 333062306a36Sopenharmony_ci cg = testrun[testidx].ftemp[pid][-1] 333162306a36Sopenharmony_ci res = cg.addLine(t) 333262306a36Sopenharmony_ci if(res != 0): 333362306a36Sopenharmony_ci testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 333462306a36Sopenharmony_ci if(res == -1): 333562306a36Sopenharmony_ci testrun[testidx].ftemp[pid][-1].addLine(t) 333662306a36Sopenharmony_ci tf.close() 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci for test in testrun: 333962306a36Sopenharmony_ci # add the callgraph data to the device hierarchy 334062306a36Sopenharmony_ci for pid in test.ftemp: 334162306a36Sopenharmony_ci for cg in test.ftemp[pid]: 334262306a36Sopenharmony_ci if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 334362306a36Sopenharmony_ci continue 334462306a36Sopenharmony_ci if(not cg.postProcess()): 334562306a36Sopenharmony_ci id = 'task %s cpu %s' % (pid, m.group('cpu')) 334662306a36Sopenharmony_ci sysvals.vprint('Sanity check failed for '+\ 334762306a36Sopenharmony_ci id+', ignoring this callback') 334862306a36Sopenharmony_ci continue 334962306a36Sopenharmony_ci callstart = cg.start 335062306a36Sopenharmony_ci callend = cg.end 335162306a36Sopenharmony_ci for p in test.data.sortedPhases(): 335262306a36Sopenharmony_ci if(test.data.dmesg[p]['start'] <= callstart and 335362306a36Sopenharmony_ci callstart <= test.data.dmesg[p]['end']): 335462306a36Sopenharmony_ci list = test.data.dmesg[p]['list'] 335562306a36Sopenharmony_ci for devname in list: 335662306a36Sopenharmony_ci dev = list[devname] 335762306a36Sopenharmony_ci if(pid == dev['pid'] and 335862306a36Sopenharmony_ci callstart <= dev['start'] and 335962306a36Sopenharmony_ci callend >= dev['end']): 336062306a36Sopenharmony_ci dev['ftrace'] = cg 336162306a36Sopenharmony_ci break 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_ci# Function: loadTraceLog 336462306a36Sopenharmony_ci# Description: 336562306a36Sopenharmony_ci# load the ftrace file into memory and fix up any ordering issues 336662306a36Sopenharmony_ci# Output: 336762306a36Sopenharmony_ci# TestProps instance and an array of lines in proper order 336862306a36Sopenharmony_cidef loadTraceLog(): 336962306a36Sopenharmony_ci tp, data, lines, trace = TestProps(), dict(), [], [] 337062306a36Sopenharmony_ci tf = sysvals.openlog(sysvals.ftracefile, 'r') 337162306a36Sopenharmony_ci for line in tf: 337262306a36Sopenharmony_ci # remove any latent carriage returns 337362306a36Sopenharmony_ci line = line.replace('\r\n', '') 337462306a36Sopenharmony_ci if tp.stampInfo(line, sysvals): 337562306a36Sopenharmony_ci continue 337662306a36Sopenharmony_ci # ignore all other commented lines 337762306a36Sopenharmony_ci if line[0] == '#': 337862306a36Sopenharmony_ci continue 337962306a36Sopenharmony_ci # ftrace line: parse only valid lines 338062306a36Sopenharmony_ci m = re.match(tp.ftrace_line_fmt, line) 338162306a36Sopenharmony_ci if(not m): 338262306a36Sopenharmony_ci continue 338362306a36Sopenharmony_ci dur = m.group('dur') if tp.cgformat else 'traceevent' 338462306a36Sopenharmony_ci info = (m.group('time'), m.group('proc'), m.group('pid'), 338562306a36Sopenharmony_ci m.group('msg'), dur) 338662306a36Sopenharmony_ci # group the data by timestamp 338762306a36Sopenharmony_ci t = float(info[0]) 338862306a36Sopenharmony_ci if t in data: 338962306a36Sopenharmony_ci data[t].append(info) 339062306a36Sopenharmony_ci else: 339162306a36Sopenharmony_ci data[t] = [info] 339262306a36Sopenharmony_ci # we only care about trace event ordering 339362306a36Sopenharmony_ci if (info[3].startswith('suspend_resume:') or \ 339462306a36Sopenharmony_ci info[3].startswith('tracing_mark_write:')) and t not in trace: 339562306a36Sopenharmony_ci trace.append(t) 339662306a36Sopenharmony_ci tf.close() 339762306a36Sopenharmony_ci for t in sorted(data): 339862306a36Sopenharmony_ci first, last, blk = [], [], data[t] 339962306a36Sopenharmony_ci if len(blk) > 1 and t in trace: 340062306a36Sopenharmony_ci # move certain lines to the start or end of a timestamp block 340162306a36Sopenharmony_ci for i in range(len(blk)): 340262306a36Sopenharmony_ci if 'SUSPEND START' in blk[i][3]: 340362306a36Sopenharmony_ci first.append(i) 340462306a36Sopenharmony_ci elif re.match('.* timekeeping_freeze.*begin', blk[i][3]): 340562306a36Sopenharmony_ci last.append(i) 340662306a36Sopenharmony_ci elif re.match('.* timekeeping_freeze.*end', blk[i][3]): 340762306a36Sopenharmony_ci first.append(i) 340862306a36Sopenharmony_ci elif 'RESUME COMPLETE' in blk[i][3]: 340962306a36Sopenharmony_ci last.append(i) 341062306a36Sopenharmony_ci if len(first) == 1 and len(last) == 0: 341162306a36Sopenharmony_ci blk.insert(0, blk.pop(first[0])) 341262306a36Sopenharmony_ci elif len(last) == 1 and len(first) == 0: 341362306a36Sopenharmony_ci blk.append(blk.pop(last[0])) 341462306a36Sopenharmony_ci for info in blk: 341562306a36Sopenharmony_ci lines.append(info) 341662306a36Sopenharmony_ci return (tp, lines) 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci# Function: parseTraceLog 341962306a36Sopenharmony_ci# Description: 342062306a36Sopenharmony_ci# Analyze an ftrace log output file generated from this app during 342162306a36Sopenharmony_ci# the execution phase. Used when the ftrace log is the primary data source 342262306a36Sopenharmony_ci# and includes the suspend_resume and device_pm_callback trace events 342362306a36Sopenharmony_ci# The ftrace filename is taken from sysvals 342462306a36Sopenharmony_ci# Output: 342562306a36Sopenharmony_ci# An array of Data objects 342662306a36Sopenharmony_cidef parseTraceLog(live=False): 342762306a36Sopenharmony_ci sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 342862306a36Sopenharmony_ci os.path.basename(sysvals.ftracefile)) 342962306a36Sopenharmony_ci if(os.path.exists(sysvals.ftracefile) == False): 343062306a36Sopenharmony_ci doError('%s does not exist' % sysvals.ftracefile) 343162306a36Sopenharmony_ci if not live: 343262306a36Sopenharmony_ci sysvals.setupAllKprobes() 343362306a36Sopenharmony_ci ksuscalls = ['ksys_sync', 'pm_prepare_console'] 343462306a36Sopenharmony_ci krescalls = ['pm_restore_console'] 343562306a36Sopenharmony_ci tracewatch = ['irq_wakeup'] 343662306a36Sopenharmony_ci if sysvals.usekprobes: 343762306a36Sopenharmony_ci tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend', 343862306a36Sopenharmony_ci 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 343962306a36Sopenharmony_ci 'CPU_OFF', 'acpi_suspend'] 344062306a36Sopenharmony_ci 344162306a36Sopenharmony_ci # extract the callgraph and traceevent data 344262306a36Sopenharmony_ci s2idle_enter = hwsus = False 344362306a36Sopenharmony_ci testruns, testdata = [], [] 344462306a36Sopenharmony_ci testrun, data, limbo = 0, 0, True 344562306a36Sopenharmony_ci phase = 'suspend_prepare' 344662306a36Sopenharmony_ci tp, tf = loadTraceLog() 344762306a36Sopenharmony_ci for m_time, m_proc, m_pid, m_msg, m_param3 in tf: 344862306a36Sopenharmony_ci # gather the basic message data from the line 344962306a36Sopenharmony_ci if(m_time and m_pid and m_msg): 345062306a36Sopenharmony_ci t = FTraceLine(m_time, m_msg, m_param3) 345162306a36Sopenharmony_ci pid = int(m_pid) 345262306a36Sopenharmony_ci else: 345362306a36Sopenharmony_ci continue 345462306a36Sopenharmony_ci # the line should be a call, return, or event 345562306a36Sopenharmony_ci if(not t.fcall and not t.freturn and not t.fevent): 345662306a36Sopenharmony_ci continue 345762306a36Sopenharmony_ci # find the start of suspend 345862306a36Sopenharmony_ci if(t.startMarker()): 345962306a36Sopenharmony_ci data, limbo = Data(len(testdata)), False 346062306a36Sopenharmony_ci testdata.append(data) 346162306a36Sopenharmony_ci testrun = TestRun(data) 346262306a36Sopenharmony_ci testruns.append(testrun) 346362306a36Sopenharmony_ci tp.parseStamp(data, sysvals) 346462306a36Sopenharmony_ci data.setStart(t.time, t.name) 346562306a36Sopenharmony_ci data.first_suspend_prepare = True 346662306a36Sopenharmony_ci phase = data.setPhase('suspend_prepare', t.time, True) 346762306a36Sopenharmony_ci continue 346862306a36Sopenharmony_ci if(not data or limbo): 346962306a36Sopenharmony_ci continue 347062306a36Sopenharmony_ci # process cpu exec line 347162306a36Sopenharmony_ci if t.type == 'tracing_mark_write': 347262306a36Sopenharmony_ci if t.name == 'CMD COMPLETE' and data.tKernRes == 0: 347362306a36Sopenharmony_ci data.tKernRes = t.time 347462306a36Sopenharmony_ci m = re.match(tp.procexecfmt, t.name) 347562306a36Sopenharmony_ci if(m): 347662306a36Sopenharmony_ci parts, msg = 1, m.group('ps') 347762306a36Sopenharmony_ci m = re.match(tp.procmultifmt, msg) 347862306a36Sopenharmony_ci if(m): 347962306a36Sopenharmony_ci parts, msg = int(m.group('n')), m.group('ps') 348062306a36Sopenharmony_ci if tp.multiproccnt == 0: 348162306a36Sopenharmony_ci tp.multiproctime = t.time 348262306a36Sopenharmony_ci tp.multiproclist = dict() 348362306a36Sopenharmony_ci proclist = tp.multiproclist 348462306a36Sopenharmony_ci tp.multiproccnt += 1 348562306a36Sopenharmony_ci else: 348662306a36Sopenharmony_ci proclist = dict() 348762306a36Sopenharmony_ci tp.multiproccnt = 0 348862306a36Sopenharmony_ci for ps in msg.split(','): 348962306a36Sopenharmony_ci val = ps.split() 349062306a36Sopenharmony_ci if not val or len(val) != 2: 349162306a36Sopenharmony_ci continue 349262306a36Sopenharmony_ci name = val[0].replace('--', '-') 349362306a36Sopenharmony_ci proclist[name] = int(val[1]) 349462306a36Sopenharmony_ci if parts == 1: 349562306a36Sopenharmony_ci data.pstl[t.time] = proclist 349662306a36Sopenharmony_ci elif parts == tp.multiproccnt: 349762306a36Sopenharmony_ci data.pstl[tp.multiproctime] = proclist 349862306a36Sopenharmony_ci tp.multiproccnt = 0 349962306a36Sopenharmony_ci continue 350062306a36Sopenharmony_ci # find the end of resume 350162306a36Sopenharmony_ci if(t.endMarker()): 350262306a36Sopenharmony_ci if data.tKernRes == 0: 350362306a36Sopenharmony_ci data.tKernRes = t.time 350462306a36Sopenharmony_ci data.handleEndMarker(t.time, t.name) 350562306a36Sopenharmony_ci if(not sysvals.usetracemarkers): 350662306a36Sopenharmony_ci # no trace markers? then quit and be sure to finish recording 350762306a36Sopenharmony_ci # the event we used to trigger resume end 350862306a36Sopenharmony_ci if('thaw_processes' in testrun.ttemp and len(testrun.ttemp['thaw_processes']) > 0): 350962306a36Sopenharmony_ci # if an entry exists, assume this is its end 351062306a36Sopenharmony_ci testrun.ttemp['thaw_processes'][-1]['end'] = t.time 351162306a36Sopenharmony_ci limbo = True 351262306a36Sopenharmony_ci continue 351362306a36Sopenharmony_ci # trace event processing 351462306a36Sopenharmony_ci if(t.fevent): 351562306a36Sopenharmony_ci if(t.type == 'suspend_resume'): 351662306a36Sopenharmony_ci # suspend_resume trace events have two types, begin and end 351762306a36Sopenharmony_ci if(re.match('(?P<name>.*) begin$', t.name)): 351862306a36Sopenharmony_ci isbegin = True 351962306a36Sopenharmony_ci elif(re.match('(?P<name>.*) end$', t.name)): 352062306a36Sopenharmony_ci isbegin = False 352162306a36Sopenharmony_ci else: 352262306a36Sopenharmony_ci continue 352362306a36Sopenharmony_ci if '[' in t.name: 352462306a36Sopenharmony_ci m = re.match('(?P<name>.*)\[.*', t.name) 352562306a36Sopenharmony_ci else: 352662306a36Sopenharmony_ci m = re.match('(?P<name>.*) .*', t.name) 352762306a36Sopenharmony_ci name = m.group('name') 352862306a36Sopenharmony_ci # ignore these events 352962306a36Sopenharmony_ci if(name.split('[')[0] in tracewatch): 353062306a36Sopenharmony_ci continue 353162306a36Sopenharmony_ci # -- phase changes -- 353262306a36Sopenharmony_ci # start of kernel suspend 353362306a36Sopenharmony_ci if(re.match('suspend_enter\[.*', t.name)): 353462306a36Sopenharmony_ci if(isbegin and data.tKernSus == 0): 353562306a36Sopenharmony_ci data.tKernSus = t.time 353662306a36Sopenharmony_ci continue 353762306a36Sopenharmony_ci # suspend_prepare start 353862306a36Sopenharmony_ci elif(re.match('dpm_prepare\[.*', t.name)): 353962306a36Sopenharmony_ci if isbegin and data.first_suspend_prepare: 354062306a36Sopenharmony_ci data.first_suspend_prepare = False 354162306a36Sopenharmony_ci if data.tKernSus == 0: 354262306a36Sopenharmony_ci data.tKernSus = t.time 354362306a36Sopenharmony_ci continue 354462306a36Sopenharmony_ci phase = data.setPhase('suspend_prepare', t.time, isbegin) 354562306a36Sopenharmony_ci continue 354662306a36Sopenharmony_ci # suspend start 354762306a36Sopenharmony_ci elif(re.match('dpm_suspend\[.*', t.name)): 354862306a36Sopenharmony_ci phase = data.setPhase('suspend', t.time, isbegin) 354962306a36Sopenharmony_ci continue 355062306a36Sopenharmony_ci # suspend_late start 355162306a36Sopenharmony_ci elif(re.match('dpm_suspend_late\[.*', t.name)): 355262306a36Sopenharmony_ci phase = data.setPhase('suspend_late', t.time, isbegin) 355362306a36Sopenharmony_ci continue 355462306a36Sopenharmony_ci # suspend_noirq start 355562306a36Sopenharmony_ci elif(re.match('dpm_suspend_noirq\[.*', t.name)): 355662306a36Sopenharmony_ci phase = data.setPhase('suspend_noirq', t.time, isbegin) 355762306a36Sopenharmony_ci continue 355862306a36Sopenharmony_ci # suspend_machine/resume_machine 355962306a36Sopenharmony_ci elif(re.match(tp.machinesuspend, t.name)): 356062306a36Sopenharmony_ci lp = data.lastPhase() 356162306a36Sopenharmony_ci if(isbegin): 356262306a36Sopenharmony_ci hwsus = True 356362306a36Sopenharmony_ci if lp.startswith('resume_machine'): 356462306a36Sopenharmony_ci # trim out s2idle loops, track time trying to freeze 356562306a36Sopenharmony_ci llp = data.lastPhase(2) 356662306a36Sopenharmony_ci if llp.startswith('suspend_machine'): 356762306a36Sopenharmony_ci if 'waking' not in data.dmesg[llp]: 356862306a36Sopenharmony_ci data.dmesg[llp]['waking'] = [0, 0.0] 356962306a36Sopenharmony_ci data.dmesg[llp]['waking'][0] += 1 357062306a36Sopenharmony_ci data.dmesg[llp]['waking'][1] += \ 357162306a36Sopenharmony_ci t.time - data.dmesg[lp]['start'] 357262306a36Sopenharmony_ci data.currphase = '' 357362306a36Sopenharmony_ci del data.dmesg[lp] 357462306a36Sopenharmony_ci continue 357562306a36Sopenharmony_ci phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True) 357662306a36Sopenharmony_ci data.setPhase(phase, t.time, False) 357762306a36Sopenharmony_ci if data.tSuspended == 0: 357862306a36Sopenharmony_ci data.tSuspended = t.time 357962306a36Sopenharmony_ci else: 358062306a36Sopenharmony_ci if lp.startswith('resume_machine'): 358162306a36Sopenharmony_ci data.dmesg[lp]['end'] = t.time 358262306a36Sopenharmony_ci continue 358362306a36Sopenharmony_ci phase = data.setPhase('resume_machine', t.time, True) 358462306a36Sopenharmony_ci if(sysvals.suspendmode in ['mem', 'disk']): 358562306a36Sopenharmony_ci susp = phase.replace('resume', 'suspend') 358662306a36Sopenharmony_ci if susp in data.dmesg: 358762306a36Sopenharmony_ci data.dmesg[susp]['end'] = t.time 358862306a36Sopenharmony_ci data.tSuspended = t.time 358962306a36Sopenharmony_ci data.tResumed = t.time 359062306a36Sopenharmony_ci continue 359162306a36Sopenharmony_ci # resume_noirq start 359262306a36Sopenharmony_ci elif(re.match('dpm_resume_noirq\[.*', t.name)): 359362306a36Sopenharmony_ci phase = data.setPhase('resume_noirq', t.time, isbegin) 359462306a36Sopenharmony_ci continue 359562306a36Sopenharmony_ci # resume_early start 359662306a36Sopenharmony_ci elif(re.match('dpm_resume_early\[.*', t.name)): 359762306a36Sopenharmony_ci phase = data.setPhase('resume_early', t.time, isbegin) 359862306a36Sopenharmony_ci continue 359962306a36Sopenharmony_ci # resume start 360062306a36Sopenharmony_ci elif(re.match('dpm_resume\[.*', t.name)): 360162306a36Sopenharmony_ci phase = data.setPhase('resume', t.time, isbegin) 360262306a36Sopenharmony_ci continue 360362306a36Sopenharmony_ci # resume complete start 360462306a36Sopenharmony_ci elif(re.match('dpm_complete\[.*', t.name)): 360562306a36Sopenharmony_ci phase = data.setPhase('resume_complete', t.time, isbegin) 360662306a36Sopenharmony_ci continue 360762306a36Sopenharmony_ci # skip trace events inside devices calls 360862306a36Sopenharmony_ci if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)): 360962306a36Sopenharmony_ci continue 361062306a36Sopenharmony_ci # global events (outside device calls) are graphed 361162306a36Sopenharmony_ci if(name not in testrun.ttemp): 361262306a36Sopenharmony_ci testrun.ttemp[name] = [] 361362306a36Sopenharmony_ci # special handling for s2idle_enter 361462306a36Sopenharmony_ci if name == 'machine_suspend': 361562306a36Sopenharmony_ci if hwsus: 361662306a36Sopenharmony_ci s2idle_enter = hwsus = False 361762306a36Sopenharmony_ci elif s2idle_enter and not isbegin: 361862306a36Sopenharmony_ci if(len(testrun.ttemp[name]) > 0): 361962306a36Sopenharmony_ci testrun.ttemp[name][-1]['end'] = t.time 362062306a36Sopenharmony_ci testrun.ttemp[name][-1]['loop'] += 1 362162306a36Sopenharmony_ci elif not s2idle_enter and isbegin: 362262306a36Sopenharmony_ci s2idle_enter = True 362362306a36Sopenharmony_ci testrun.ttemp[name].append({'begin': t.time, 362462306a36Sopenharmony_ci 'end': t.time, 'pid': pid, 'loop': 0}) 362562306a36Sopenharmony_ci continue 362662306a36Sopenharmony_ci if(isbegin): 362762306a36Sopenharmony_ci # create a new list entry 362862306a36Sopenharmony_ci testrun.ttemp[name].append(\ 362962306a36Sopenharmony_ci {'begin': t.time, 'end': t.time, 'pid': pid}) 363062306a36Sopenharmony_ci else: 363162306a36Sopenharmony_ci if(len(testrun.ttemp[name]) > 0): 363262306a36Sopenharmony_ci # if an entry exists, assume this is its end 363362306a36Sopenharmony_ci testrun.ttemp[name][-1]['end'] = t.time 363462306a36Sopenharmony_ci # device callback start 363562306a36Sopenharmony_ci elif(t.type == 'device_pm_callback_start'): 363662306a36Sopenharmony_ci if phase not in data.dmesg: 363762306a36Sopenharmony_ci continue 363862306a36Sopenharmony_ci m = re.match('(?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*',\ 363962306a36Sopenharmony_ci t.name); 364062306a36Sopenharmony_ci if(not m): 364162306a36Sopenharmony_ci continue 364262306a36Sopenharmony_ci drv = m.group('drv') 364362306a36Sopenharmony_ci n = m.group('d') 364462306a36Sopenharmony_ci p = m.group('p') 364562306a36Sopenharmony_ci if(n and p): 364662306a36Sopenharmony_ci data.newAction(phase, n, pid, p, t.time, -1, drv) 364762306a36Sopenharmony_ci if pid not in data.devpids: 364862306a36Sopenharmony_ci data.devpids.append(pid) 364962306a36Sopenharmony_ci # device callback finish 365062306a36Sopenharmony_ci elif(t.type == 'device_pm_callback_end'): 365162306a36Sopenharmony_ci if phase not in data.dmesg: 365262306a36Sopenharmony_ci continue 365362306a36Sopenharmony_ci m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name); 365462306a36Sopenharmony_ci if(not m): 365562306a36Sopenharmony_ci continue 365662306a36Sopenharmony_ci n = m.group('d') 365762306a36Sopenharmony_ci dev = data.findDevice(phase, n) 365862306a36Sopenharmony_ci if dev: 365962306a36Sopenharmony_ci dev['length'] = t.time - dev['start'] 366062306a36Sopenharmony_ci dev['end'] = t.time 366162306a36Sopenharmony_ci # kprobe event processing 366262306a36Sopenharmony_ci elif(t.fkprobe): 366362306a36Sopenharmony_ci kprobename = t.type 366462306a36Sopenharmony_ci kprobedata = t.name 366562306a36Sopenharmony_ci key = (kprobename, pid) 366662306a36Sopenharmony_ci # displayname is generated from kprobe data 366762306a36Sopenharmony_ci displayname = '' 366862306a36Sopenharmony_ci if(t.fcall): 366962306a36Sopenharmony_ci displayname = sysvals.kprobeDisplayName(kprobename, kprobedata) 367062306a36Sopenharmony_ci if not displayname: 367162306a36Sopenharmony_ci continue 367262306a36Sopenharmony_ci if(key not in tp.ktemp): 367362306a36Sopenharmony_ci tp.ktemp[key] = [] 367462306a36Sopenharmony_ci tp.ktemp[key].append({ 367562306a36Sopenharmony_ci 'pid': pid, 367662306a36Sopenharmony_ci 'begin': t.time, 367762306a36Sopenharmony_ci 'end': -1, 367862306a36Sopenharmony_ci 'name': displayname, 367962306a36Sopenharmony_ci 'cdata': kprobedata, 368062306a36Sopenharmony_ci 'proc': m_proc, 368162306a36Sopenharmony_ci }) 368262306a36Sopenharmony_ci # start of kernel resume 368362306a36Sopenharmony_ci if(data.tKernSus == 0 and phase == 'suspend_prepare' \ 368462306a36Sopenharmony_ci and kprobename in ksuscalls): 368562306a36Sopenharmony_ci data.tKernSus = t.time 368662306a36Sopenharmony_ci elif(t.freturn): 368762306a36Sopenharmony_ci if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1: 368862306a36Sopenharmony_ci continue 368962306a36Sopenharmony_ci e = next((x for x in reversed(tp.ktemp[key]) if x['end'] < 0), 0) 369062306a36Sopenharmony_ci if not e: 369162306a36Sopenharmony_ci continue 369262306a36Sopenharmony_ci if (t.time - e['begin']) * 1000 < sysvals.mindevlen: 369362306a36Sopenharmony_ci tp.ktemp[key].pop() 369462306a36Sopenharmony_ci continue 369562306a36Sopenharmony_ci e['end'] = t.time 369662306a36Sopenharmony_ci e['rdata'] = kprobedata 369762306a36Sopenharmony_ci # end of kernel resume 369862306a36Sopenharmony_ci if(phase != 'suspend_prepare' and kprobename in krescalls): 369962306a36Sopenharmony_ci if phase in data.dmesg: 370062306a36Sopenharmony_ci data.dmesg[phase]['end'] = t.time 370162306a36Sopenharmony_ci data.tKernRes = t.time 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci # callgraph processing 370462306a36Sopenharmony_ci elif sysvals.usecallgraph: 370562306a36Sopenharmony_ci # create a callgraph object for the data 370662306a36Sopenharmony_ci key = (m_proc, pid) 370762306a36Sopenharmony_ci if(key not in testrun.ftemp): 370862306a36Sopenharmony_ci testrun.ftemp[key] = [] 370962306a36Sopenharmony_ci testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 371062306a36Sopenharmony_ci # when the call is finished, see which device matches it 371162306a36Sopenharmony_ci cg = testrun.ftemp[key][-1] 371262306a36Sopenharmony_ci res = cg.addLine(t) 371362306a36Sopenharmony_ci if(res != 0): 371462306a36Sopenharmony_ci testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 371562306a36Sopenharmony_ci if(res == -1): 371662306a36Sopenharmony_ci testrun.ftemp[key][-1].addLine(t) 371762306a36Sopenharmony_ci if len(testdata) < 1: 371862306a36Sopenharmony_ci sysvals.vprint('WARNING: ftrace start marker is missing') 371962306a36Sopenharmony_ci if data and not data.devicegroups: 372062306a36Sopenharmony_ci sysvals.vprint('WARNING: ftrace end marker is missing') 372162306a36Sopenharmony_ci data.handleEndMarker(t.time, t.name) 372262306a36Sopenharmony_ci 372362306a36Sopenharmony_ci if sysvals.suspendmode == 'command': 372462306a36Sopenharmony_ci for test in testruns: 372562306a36Sopenharmony_ci for p in test.data.sortedPhases(): 372662306a36Sopenharmony_ci if p == 'suspend_prepare': 372762306a36Sopenharmony_ci test.data.dmesg[p]['start'] = test.data.start 372862306a36Sopenharmony_ci test.data.dmesg[p]['end'] = test.data.end 372962306a36Sopenharmony_ci else: 373062306a36Sopenharmony_ci test.data.dmesg[p]['start'] = test.data.end 373162306a36Sopenharmony_ci test.data.dmesg[p]['end'] = test.data.end 373262306a36Sopenharmony_ci test.data.tSuspended = test.data.end 373362306a36Sopenharmony_ci test.data.tResumed = test.data.end 373462306a36Sopenharmony_ci test.data.fwValid = False 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_ci # dev source and procmon events can be unreadable with mixed phase height 373762306a36Sopenharmony_ci if sysvals.usedevsrc or sysvals.useprocmon: 373862306a36Sopenharmony_ci sysvals.mixedphaseheight = False 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci # expand phase boundaries so there are no gaps 374162306a36Sopenharmony_ci for data in testdata: 374262306a36Sopenharmony_ci lp = data.sortedPhases()[0] 374362306a36Sopenharmony_ci for p in data.sortedPhases(): 374462306a36Sopenharmony_ci if(p != lp and not ('machine' in p and 'machine' in lp)): 374562306a36Sopenharmony_ci data.dmesg[lp]['end'] = data.dmesg[p]['start'] 374662306a36Sopenharmony_ci lp = p 374762306a36Sopenharmony_ci 374862306a36Sopenharmony_ci for i in range(len(testruns)): 374962306a36Sopenharmony_ci test = testruns[i] 375062306a36Sopenharmony_ci data = test.data 375162306a36Sopenharmony_ci # find the total time range for this test (begin, end) 375262306a36Sopenharmony_ci tlb, tle = data.start, data.end 375362306a36Sopenharmony_ci if i < len(testruns) - 1: 375462306a36Sopenharmony_ci tle = testruns[i+1].data.start 375562306a36Sopenharmony_ci # add the process usage data to the timeline 375662306a36Sopenharmony_ci if sysvals.useprocmon: 375762306a36Sopenharmony_ci data.createProcessUsageEvents() 375862306a36Sopenharmony_ci # add the traceevent data to the device hierarchy 375962306a36Sopenharmony_ci if(sysvals.usetraceevents): 376062306a36Sopenharmony_ci # add actual trace funcs 376162306a36Sopenharmony_ci for name in sorted(test.ttemp): 376262306a36Sopenharmony_ci for event in test.ttemp[name]: 376362306a36Sopenharmony_ci if event['end'] - event['begin'] <= 0: 376462306a36Sopenharmony_ci continue 376562306a36Sopenharmony_ci title = name 376662306a36Sopenharmony_ci if name == 'machine_suspend' and 'loop' in event: 376762306a36Sopenharmony_ci title = 's2idle_enter_%dx' % event['loop'] 376862306a36Sopenharmony_ci data.newActionGlobal(title, event['begin'], event['end'], event['pid']) 376962306a36Sopenharmony_ci # add the kprobe based virtual tracefuncs as actual devices 377062306a36Sopenharmony_ci for key in sorted(tp.ktemp): 377162306a36Sopenharmony_ci name, pid = key 377262306a36Sopenharmony_ci if name not in sysvals.tracefuncs: 377362306a36Sopenharmony_ci continue 377462306a36Sopenharmony_ci if pid not in data.devpids: 377562306a36Sopenharmony_ci data.devpids.append(pid) 377662306a36Sopenharmony_ci for e in tp.ktemp[key]: 377762306a36Sopenharmony_ci kb, ke = e['begin'], e['end'] 377862306a36Sopenharmony_ci if ke - kb < 0.000001 or tlb > kb or tle <= kb: 377962306a36Sopenharmony_ci continue 378062306a36Sopenharmony_ci color = sysvals.kprobeColor(name) 378162306a36Sopenharmony_ci data.newActionGlobal(e['name'], kb, ke, pid, color) 378262306a36Sopenharmony_ci # add config base kprobes and dev kprobes 378362306a36Sopenharmony_ci if sysvals.usedevsrc: 378462306a36Sopenharmony_ci for key in sorted(tp.ktemp): 378562306a36Sopenharmony_ci name, pid = key 378662306a36Sopenharmony_ci if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs: 378762306a36Sopenharmony_ci continue 378862306a36Sopenharmony_ci for e in tp.ktemp[key]: 378962306a36Sopenharmony_ci kb, ke = e['begin'], e['end'] 379062306a36Sopenharmony_ci if ke - kb < 0.000001 or tlb > kb or tle <= kb: 379162306a36Sopenharmony_ci continue 379262306a36Sopenharmony_ci data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb, 379362306a36Sopenharmony_ci ke, e['cdata'], e['rdata']) 379462306a36Sopenharmony_ci if sysvals.usecallgraph: 379562306a36Sopenharmony_ci # add the callgraph data to the device hierarchy 379662306a36Sopenharmony_ci sortlist = dict() 379762306a36Sopenharmony_ci for key in sorted(test.ftemp): 379862306a36Sopenharmony_ci proc, pid = key 379962306a36Sopenharmony_ci for cg in test.ftemp[key]: 380062306a36Sopenharmony_ci if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 380162306a36Sopenharmony_ci continue 380262306a36Sopenharmony_ci if(not cg.postProcess()): 380362306a36Sopenharmony_ci id = 'task %s' % (pid) 380462306a36Sopenharmony_ci sysvals.vprint('Sanity check failed for '+\ 380562306a36Sopenharmony_ci id+', ignoring this callback') 380662306a36Sopenharmony_ci continue 380762306a36Sopenharmony_ci # match cg data to devices 380862306a36Sopenharmony_ci devname = '' 380962306a36Sopenharmony_ci if sysvals.suspendmode != 'command': 381062306a36Sopenharmony_ci devname = cg.deviceMatch(pid, data) 381162306a36Sopenharmony_ci if not devname: 381262306a36Sopenharmony_ci sortkey = '%f%f%d' % (cg.start, cg.end, pid) 381362306a36Sopenharmony_ci sortlist[sortkey] = cg 381462306a36Sopenharmony_ci elif len(cg.list) > 1000000 and cg.name != sysvals.ftopfunc: 381562306a36Sopenharmony_ci sysvals.vprint('WARNING: the callgraph for %s is massive (%d lines)' %\ 381662306a36Sopenharmony_ci (devname, len(cg.list))) 381762306a36Sopenharmony_ci # create blocks for orphan cg data 381862306a36Sopenharmony_ci for sortkey in sorted(sortlist): 381962306a36Sopenharmony_ci cg = sortlist[sortkey] 382062306a36Sopenharmony_ci name = cg.name 382162306a36Sopenharmony_ci if sysvals.isCallgraphFunc(name): 382262306a36Sopenharmony_ci sysvals.vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name)) 382362306a36Sopenharmony_ci cg.newActionFromFunction(data) 382462306a36Sopenharmony_ci if sysvals.suspendmode == 'command': 382562306a36Sopenharmony_ci return (testdata, '') 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_ci # fill in any missing phases 382862306a36Sopenharmony_ci error = [] 382962306a36Sopenharmony_ci for data in testdata: 383062306a36Sopenharmony_ci tn = '' if len(testdata) == 1 else ('%d' % (data.testnumber + 1)) 383162306a36Sopenharmony_ci terr = '' 383262306a36Sopenharmony_ci phasedef = data.phasedef 383362306a36Sopenharmony_ci lp = 'suspend_prepare' 383462306a36Sopenharmony_ci for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 383562306a36Sopenharmony_ci if p not in data.dmesg: 383662306a36Sopenharmony_ci if not terr: 383762306a36Sopenharmony_ci ph = p if 'machine' in p else lp 383862306a36Sopenharmony_ci if p == 'suspend_machine': 383962306a36Sopenharmony_ci sm = sysvals.suspendmode 384062306a36Sopenharmony_ci if sm in suspendmodename: 384162306a36Sopenharmony_ci sm = suspendmodename[sm] 384262306a36Sopenharmony_ci terr = 'test%s did not enter %s power mode' % (tn, sm) 384362306a36Sopenharmony_ci else: 384462306a36Sopenharmony_ci terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph) 384562306a36Sopenharmony_ci pprint('TEST%s FAILED: %s' % (tn, terr)) 384662306a36Sopenharmony_ci error.append(terr) 384762306a36Sopenharmony_ci if data.tSuspended == 0: 384862306a36Sopenharmony_ci data.tSuspended = data.dmesg[lp]['end'] 384962306a36Sopenharmony_ci if data.tResumed == 0: 385062306a36Sopenharmony_ci data.tResumed = data.dmesg[lp]['end'] 385162306a36Sopenharmony_ci data.fwValid = False 385262306a36Sopenharmony_ci sysvals.vprint('WARNING: phase "%s" is missing!' % p) 385362306a36Sopenharmony_ci lp = p 385462306a36Sopenharmony_ci if not terr and 'dev' in data.wifi and data.wifi['stat'] == 'timeout': 385562306a36Sopenharmony_ci terr = '%s%s failed in wifi_resume <i>(%s %.0fs timeout)</i>' % \ 385662306a36Sopenharmony_ci (sysvals.suspendmode, tn, data.wifi['dev'], data.wifi['time']) 385762306a36Sopenharmony_ci error.append(terr) 385862306a36Sopenharmony_ci if not terr and data.enterfail: 385962306a36Sopenharmony_ci pprint('test%s FAILED: enter %s failed with %s' % (tn, sysvals.suspendmode, data.enterfail)) 386062306a36Sopenharmony_ci terr = 'test%s failed to enter %s mode' % (tn, sysvals.suspendmode) 386162306a36Sopenharmony_ci error.append(terr) 386262306a36Sopenharmony_ci if data.tSuspended == 0: 386362306a36Sopenharmony_ci data.tSuspended = data.tKernRes 386462306a36Sopenharmony_ci if data.tResumed == 0: 386562306a36Sopenharmony_ci data.tResumed = data.tSuspended 386662306a36Sopenharmony_ci 386762306a36Sopenharmony_ci if(len(sysvals.devicefilter) > 0): 386862306a36Sopenharmony_ci data.deviceFilter(sysvals.devicefilter) 386962306a36Sopenharmony_ci data.fixupInitcallsThatDidntReturn() 387062306a36Sopenharmony_ci if sysvals.usedevsrc: 387162306a36Sopenharmony_ci data.optimizeDevSrc() 387262306a36Sopenharmony_ci 387362306a36Sopenharmony_ci # x2: merge any overlapping devices between test runs 387462306a36Sopenharmony_ci if sysvals.usedevsrc and len(testdata) > 1: 387562306a36Sopenharmony_ci tc = len(testdata) 387662306a36Sopenharmony_ci for i in range(tc - 1): 387762306a36Sopenharmony_ci devlist = testdata[i].overflowDevices() 387862306a36Sopenharmony_ci for j in range(i + 1, tc): 387962306a36Sopenharmony_ci testdata[j].mergeOverlapDevices(devlist) 388062306a36Sopenharmony_ci testdata[0].stitchTouchingThreads(testdata[1:]) 388162306a36Sopenharmony_ci return (testdata, ', '.join(error)) 388262306a36Sopenharmony_ci 388362306a36Sopenharmony_ci# Function: loadKernelLog 388462306a36Sopenharmony_ci# Description: 388562306a36Sopenharmony_ci# load the dmesg file into memory and fix up any ordering issues 388662306a36Sopenharmony_ci# Output: 388762306a36Sopenharmony_ci# An array of empty Data objects with only their dmesgtext attributes set 388862306a36Sopenharmony_cidef loadKernelLog(): 388962306a36Sopenharmony_ci sysvals.vprint('Analyzing the dmesg data (%s)...' % \ 389062306a36Sopenharmony_ci os.path.basename(sysvals.dmesgfile)) 389162306a36Sopenharmony_ci if(os.path.exists(sysvals.dmesgfile) == False): 389262306a36Sopenharmony_ci doError('%s does not exist' % sysvals.dmesgfile) 389362306a36Sopenharmony_ci 389462306a36Sopenharmony_ci # there can be multiple test runs in a single file 389562306a36Sopenharmony_ci tp = TestProps() 389662306a36Sopenharmony_ci tp.stamp = datetime.now().strftime('# suspend-%m%d%y-%H%M%S localhost mem unknown') 389762306a36Sopenharmony_ci testruns = [] 389862306a36Sopenharmony_ci data = 0 389962306a36Sopenharmony_ci lf = sysvals.openlog(sysvals.dmesgfile, 'r') 390062306a36Sopenharmony_ci for line in lf: 390162306a36Sopenharmony_ci line = line.replace('\r\n', '') 390262306a36Sopenharmony_ci idx = line.find('[') 390362306a36Sopenharmony_ci if idx > 1: 390462306a36Sopenharmony_ci line = line[idx:] 390562306a36Sopenharmony_ci if tp.stampInfo(line, sysvals): 390662306a36Sopenharmony_ci continue 390762306a36Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 390862306a36Sopenharmony_ci if(not m): 390962306a36Sopenharmony_ci continue 391062306a36Sopenharmony_ci msg = m.group("msg") 391162306a36Sopenharmony_ci if re.match('PM: Syncing filesystems.*', msg) or \ 391262306a36Sopenharmony_ci re.match('PM: suspend entry.*', msg): 391362306a36Sopenharmony_ci if(data): 391462306a36Sopenharmony_ci testruns.append(data) 391562306a36Sopenharmony_ci data = Data(len(testruns)) 391662306a36Sopenharmony_ci tp.parseStamp(data, sysvals) 391762306a36Sopenharmony_ci if(not data): 391862306a36Sopenharmony_ci continue 391962306a36Sopenharmony_ci m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg) 392062306a36Sopenharmony_ci if(m): 392162306a36Sopenharmony_ci sysvals.stamp['kernel'] = m.group('k') 392262306a36Sopenharmony_ci m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg) 392362306a36Sopenharmony_ci if not m: 392462306a36Sopenharmony_ci m = re.match('PM: Preparing system for sleep \((?P<m>.*)\)', msg) 392562306a36Sopenharmony_ci if m: 392662306a36Sopenharmony_ci sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m') 392762306a36Sopenharmony_ci data.dmesgtext.append(line) 392862306a36Sopenharmony_ci lf.close() 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci if sysvals.suspendmode == 's2idle': 393162306a36Sopenharmony_ci sysvals.suspendmode = 'freeze' 393262306a36Sopenharmony_ci elif sysvals.suspendmode == 'deep': 393362306a36Sopenharmony_ci sysvals.suspendmode = 'mem' 393462306a36Sopenharmony_ci if data: 393562306a36Sopenharmony_ci testruns.append(data) 393662306a36Sopenharmony_ci if len(testruns) < 1: 393762306a36Sopenharmony_ci doError('dmesg log has no suspend/resume data: %s' \ 393862306a36Sopenharmony_ci % sysvals.dmesgfile) 393962306a36Sopenharmony_ci 394062306a36Sopenharmony_ci # fix lines with same timestamp/function with the call and return swapped 394162306a36Sopenharmony_ci for data in testruns: 394262306a36Sopenharmony_ci last = '' 394362306a36Sopenharmony_ci for line in data.dmesgtext: 394462306a36Sopenharmony_ci ct, cf, n, p = data.initcall_debug_call(line) 394562306a36Sopenharmony_ci rt, rf, l = data.initcall_debug_return(last) 394662306a36Sopenharmony_ci if ct and rt and ct == rt and cf == rf: 394762306a36Sopenharmony_ci i = data.dmesgtext.index(last) 394862306a36Sopenharmony_ci j = data.dmesgtext.index(line) 394962306a36Sopenharmony_ci data.dmesgtext[i] = line 395062306a36Sopenharmony_ci data.dmesgtext[j] = last 395162306a36Sopenharmony_ci last = line 395262306a36Sopenharmony_ci return testruns 395362306a36Sopenharmony_ci 395462306a36Sopenharmony_ci# Function: parseKernelLog 395562306a36Sopenharmony_ci# Description: 395662306a36Sopenharmony_ci# Analyse a dmesg log output file generated from this app during 395762306a36Sopenharmony_ci# the execution phase. Create a set of device structures in memory 395862306a36Sopenharmony_ci# for subsequent formatting in the html output file 395962306a36Sopenharmony_ci# This call is only for legacy support on kernels where the ftrace 396062306a36Sopenharmony_ci# data lacks the suspend_resume or device_pm_callbacks trace events. 396162306a36Sopenharmony_ci# Arguments: 396262306a36Sopenharmony_ci# data: an empty Data object (with dmesgtext) obtained from loadKernelLog 396362306a36Sopenharmony_ci# Output: 396462306a36Sopenharmony_ci# The filled Data object 396562306a36Sopenharmony_cidef parseKernelLog(data): 396662306a36Sopenharmony_ci phase = 'suspend_runtime' 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci if(data.fwValid): 396962306a36Sopenharmony_ci sysvals.vprint('Firmware Suspend = %u ns, Firmware Resume = %u ns' % \ 397062306a36Sopenharmony_ci (data.fwSuspend, data.fwResume)) 397162306a36Sopenharmony_ci 397262306a36Sopenharmony_ci # dmesg phase match table 397362306a36Sopenharmony_ci dm = { 397462306a36Sopenharmony_ci 'suspend_prepare': ['PM: Syncing filesystems.*', 'PM: suspend entry.*'], 397562306a36Sopenharmony_ci 'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*', 397662306a36Sopenharmony_ci 'PM: Suspending system .*'], 397762306a36Sopenharmony_ci 'suspend_late': ['PM: suspend of devices complete after.*', 397862306a36Sopenharmony_ci 'PM: freeze of devices complete after.*'], 397962306a36Sopenharmony_ci 'suspend_noirq': ['PM: late suspend of devices complete after.*', 398062306a36Sopenharmony_ci 'PM: late freeze of devices complete after.*'], 398162306a36Sopenharmony_ci 'suspend_machine': ['PM: suspend-to-idle', 398262306a36Sopenharmony_ci 'PM: noirq suspend of devices complete after.*', 398362306a36Sopenharmony_ci 'PM: noirq freeze of devices complete after.*'], 398462306a36Sopenharmony_ci 'resume_machine': ['[PM: ]*Timekeeping suspended for.*', 398562306a36Sopenharmony_ci 'ACPI: Low-level resume complete.*', 398662306a36Sopenharmony_ci 'ACPI: resume from mwait', 398762306a36Sopenharmony_ci 'Suspended for [0-9\.]* seconds'], 398862306a36Sopenharmony_ci 'resume_noirq': ['PM: resume from suspend-to-idle', 398962306a36Sopenharmony_ci 'ACPI: Waking up from system sleep state.*'], 399062306a36Sopenharmony_ci 'resume_early': ['PM: noirq resume of devices complete after.*', 399162306a36Sopenharmony_ci 'PM: noirq restore of devices complete after.*'], 399262306a36Sopenharmony_ci 'resume': ['PM: early resume of devices complete after.*', 399362306a36Sopenharmony_ci 'PM: early restore of devices complete after.*'], 399462306a36Sopenharmony_ci 'resume_complete': ['PM: resume of devices complete after.*', 399562306a36Sopenharmony_ci 'PM: restore of devices complete after.*'], 399662306a36Sopenharmony_ci 'post_resume': ['.*Restarting tasks \.\.\..*'], 399762306a36Sopenharmony_ci } 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ci # action table (expected events that occur and show up in dmesg) 400062306a36Sopenharmony_ci at = { 400162306a36Sopenharmony_ci 'sync_filesystems': { 400262306a36Sopenharmony_ci 'smsg': '.*[Ff]+ilesystems.*', 400362306a36Sopenharmony_ci 'emsg': 'PM: Preparing system for[a-z]* sleep.*' }, 400462306a36Sopenharmony_ci 'freeze_user_processes': { 400562306a36Sopenharmony_ci 'smsg': 'Freezing user space processes.*', 400662306a36Sopenharmony_ci 'emsg': 'Freezing remaining freezable tasks.*' }, 400762306a36Sopenharmony_ci 'freeze_tasks': { 400862306a36Sopenharmony_ci 'smsg': 'Freezing remaining freezable tasks.*', 400962306a36Sopenharmony_ci 'emsg': 'PM: Suspending system.*' }, 401062306a36Sopenharmony_ci 'ACPI prepare': { 401162306a36Sopenharmony_ci 'smsg': 'ACPI: Preparing to enter system sleep state.*', 401262306a36Sopenharmony_ci 'emsg': 'PM: Saving platform NVS memory.*' }, 401362306a36Sopenharmony_ci 'PM vns': { 401462306a36Sopenharmony_ci 'smsg': 'PM: Saving platform NVS memory.*', 401562306a36Sopenharmony_ci 'emsg': 'Disabling non-boot CPUs .*' }, 401662306a36Sopenharmony_ci } 401762306a36Sopenharmony_ci 401862306a36Sopenharmony_ci t0 = -1.0 401962306a36Sopenharmony_ci cpu_start = -1.0 402062306a36Sopenharmony_ci prevktime = -1.0 402162306a36Sopenharmony_ci actions = dict() 402262306a36Sopenharmony_ci for line in data.dmesgtext: 402362306a36Sopenharmony_ci # parse each dmesg line into the time and message 402462306a36Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 402562306a36Sopenharmony_ci if(m): 402662306a36Sopenharmony_ci val = m.group('ktime') 402762306a36Sopenharmony_ci try: 402862306a36Sopenharmony_ci ktime = float(val) 402962306a36Sopenharmony_ci except: 403062306a36Sopenharmony_ci continue 403162306a36Sopenharmony_ci msg = m.group('msg') 403262306a36Sopenharmony_ci # initialize data start to first line time 403362306a36Sopenharmony_ci if t0 < 0: 403462306a36Sopenharmony_ci data.setStart(ktime) 403562306a36Sopenharmony_ci t0 = ktime 403662306a36Sopenharmony_ci else: 403762306a36Sopenharmony_ci continue 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_ci # check for a phase change line 404062306a36Sopenharmony_ci phasechange = False 404162306a36Sopenharmony_ci for p in dm: 404262306a36Sopenharmony_ci for s in dm[p]: 404362306a36Sopenharmony_ci if(re.match(s, msg)): 404462306a36Sopenharmony_ci phasechange, phase = True, p 404562306a36Sopenharmony_ci dm[p] = [s] 404662306a36Sopenharmony_ci break 404762306a36Sopenharmony_ci 404862306a36Sopenharmony_ci # hack for determining resume_machine end for freeze 404962306a36Sopenharmony_ci if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \ 405062306a36Sopenharmony_ci and phase == 'resume_machine' and \ 405162306a36Sopenharmony_ci data.initcall_debug_call(line, True)): 405262306a36Sopenharmony_ci data.setPhase(phase, ktime, False) 405362306a36Sopenharmony_ci phase = 'resume_noirq' 405462306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 405562306a36Sopenharmony_ci 405662306a36Sopenharmony_ci if phasechange: 405762306a36Sopenharmony_ci if phase == 'suspend_prepare': 405862306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 405962306a36Sopenharmony_ci data.setStart(ktime) 406062306a36Sopenharmony_ci data.tKernSus = ktime 406162306a36Sopenharmony_ci elif phase == 'suspend': 406262306a36Sopenharmony_ci lp = data.lastPhase() 406362306a36Sopenharmony_ci if lp: 406462306a36Sopenharmony_ci data.setPhase(lp, ktime, False) 406562306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 406662306a36Sopenharmony_ci elif phase == 'suspend_late': 406762306a36Sopenharmony_ci lp = data.lastPhase() 406862306a36Sopenharmony_ci if lp: 406962306a36Sopenharmony_ci data.setPhase(lp, ktime, False) 407062306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 407162306a36Sopenharmony_ci elif phase == 'suspend_noirq': 407262306a36Sopenharmony_ci lp = data.lastPhase() 407362306a36Sopenharmony_ci if lp: 407462306a36Sopenharmony_ci data.setPhase(lp, ktime, False) 407562306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 407662306a36Sopenharmony_ci elif phase == 'suspend_machine': 407762306a36Sopenharmony_ci lp = data.lastPhase() 407862306a36Sopenharmony_ci if lp: 407962306a36Sopenharmony_ci data.setPhase(lp, ktime, False) 408062306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 408162306a36Sopenharmony_ci elif phase == 'resume_machine': 408262306a36Sopenharmony_ci lp = data.lastPhase() 408362306a36Sopenharmony_ci if(sysvals.suspendmode in ['freeze', 'standby']): 408462306a36Sopenharmony_ci data.tSuspended = prevktime 408562306a36Sopenharmony_ci if lp: 408662306a36Sopenharmony_ci data.setPhase(lp, prevktime, False) 408762306a36Sopenharmony_ci else: 408862306a36Sopenharmony_ci data.tSuspended = ktime 408962306a36Sopenharmony_ci if lp: 409062306a36Sopenharmony_ci data.setPhase(lp, prevktime, False) 409162306a36Sopenharmony_ci data.tResumed = ktime 409262306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 409362306a36Sopenharmony_ci elif phase == 'resume_noirq': 409462306a36Sopenharmony_ci lp = data.lastPhase() 409562306a36Sopenharmony_ci if lp: 409662306a36Sopenharmony_ci data.setPhase(lp, ktime, False) 409762306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 409862306a36Sopenharmony_ci elif phase == 'resume_early': 409962306a36Sopenharmony_ci lp = data.lastPhase() 410062306a36Sopenharmony_ci if lp: 410162306a36Sopenharmony_ci data.setPhase(lp, ktime, False) 410262306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 410362306a36Sopenharmony_ci elif phase == 'resume': 410462306a36Sopenharmony_ci lp = data.lastPhase() 410562306a36Sopenharmony_ci if lp: 410662306a36Sopenharmony_ci data.setPhase(lp, ktime, False) 410762306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 410862306a36Sopenharmony_ci elif phase == 'resume_complete': 410962306a36Sopenharmony_ci lp = data.lastPhase() 411062306a36Sopenharmony_ci if lp: 411162306a36Sopenharmony_ci data.setPhase(lp, ktime, False) 411262306a36Sopenharmony_ci data.setPhase(phase, ktime, True) 411362306a36Sopenharmony_ci elif phase == 'post_resume': 411462306a36Sopenharmony_ci lp = data.lastPhase() 411562306a36Sopenharmony_ci if lp: 411662306a36Sopenharmony_ci data.setPhase(lp, ktime, False) 411762306a36Sopenharmony_ci data.setEnd(ktime) 411862306a36Sopenharmony_ci data.tKernRes = ktime 411962306a36Sopenharmony_ci break 412062306a36Sopenharmony_ci 412162306a36Sopenharmony_ci # -- device callbacks -- 412262306a36Sopenharmony_ci if(phase in data.sortedPhases()): 412362306a36Sopenharmony_ci # device init call 412462306a36Sopenharmony_ci t, f, n, p = data.initcall_debug_call(line) 412562306a36Sopenharmony_ci if t and f and n and p: 412662306a36Sopenharmony_ci data.newAction(phase, f, int(n), p, ktime, -1, '') 412762306a36Sopenharmony_ci else: 412862306a36Sopenharmony_ci # device init return 412962306a36Sopenharmony_ci t, f, l = data.initcall_debug_return(line) 413062306a36Sopenharmony_ci if t and f and l: 413162306a36Sopenharmony_ci list = data.dmesg[phase]['list'] 413262306a36Sopenharmony_ci if(f in list): 413362306a36Sopenharmony_ci dev = list[f] 413462306a36Sopenharmony_ci dev['length'] = int(l) 413562306a36Sopenharmony_ci dev['end'] = ktime 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci # if trace events are not available, these are better than nothing 413862306a36Sopenharmony_ci if(not sysvals.usetraceevents): 413962306a36Sopenharmony_ci # look for known actions 414062306a36Sopenharmony_ci for a in sorted(at): 414162306a36Sopenharmony_ci if(re.match(at[a]['smsg'], msg)): 414262306a36Sopenharmony_ci if(a not in actions): 414362306a36Sopenharmony_ci actions[a] = [{'begin': ktime, 'end': ktime}] 414462306a36Sopenharmony_ci if(re.match(at[a]['emsg'], msg)): 414562306a36Sopenharmony_ci if(a in actions and actions[a][-1]['begin'] == actions[a][-1]['end']): 414662306a36Sopenharmony_ci actions[a][-1]['end'] = ktime 414762306a36Sopenharmony_ci # now look for CPU on/off events 414862306a36Sopenharmony_ci if(re.match('Disabling non-boot CPUs .*', msg)): 414962306a36Sopenharmony_ci # start of first cpu suspend 415062306a36Sopenharmony_ci cpu_start = ktime 415162306a36Sopenharmony_ci elif(re.match('Enabling non-boot CPUs .*', msg)): 415262306a36Sopenharmony_ci # start of first cpu resume 415362306a36Sopenharmony_ci cpu_start = ktime 415462306a36Sopenharmony_ci elif(re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg) \ 415562306a36Sopenharmony_ci or re.match('psci: CPU(?P<cpu>[0-9]*) killed.*', msg)): 415662306a36Sopenharmony_ci # end of a cpu suspend, start of the next 415762306a36Sopenharmony_ci m = re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg) 415862306a36Sopenharmony_ci if(not m): 415962306a36Sopenharmony_ci m = re.match('psci: CPU(?P<cpu>[0-9]*) killed.*', msg) 416062306a36Sopenharmony_ci cpu = 'CPU'+m.group('cpu') 416162306a36Sopenharmony_ci if(cpu not in actions): 416262306a36Sopenharmony_ci actions[cpu] = [] 416362306a36Sopenharmony_ci actions[cpu].append({'begin': cpu_start, 'end': ktime}) 416462306a36Sopenharmony_ci cpu_start = ktime 416562306a36Sopenharmony_ci elif(re.match('CPU(?P<cpu>[0-9]*) is up', msg)): 416662306a36Sopenharmony_ci # end of a cpu resume, start of the next 416762306a36Sopenharmony_ci m = re.match('CPU(?P<cpu>[0-9]*) is up', msg) 416862306a36Sopenharmony_ci cpu = 'CPU'+m.group('cpu') 416962306a36Sopenharmony_ci if(cpu not in actions): 417062306a36Sopenharmony_ci actions[cpu] = [] 417162306a36Sopenharmony_ci actions[cpu].append({'begin': cpu_start, 'end': ktime}) 417262306a36Sopenharmony_ci cpu_start = ktime 417362306a36Sopenharmony_ci prevktime = ktime 417462306a36Sopenharmony_ci data.initDevicegroups() 417562306a36Sopenharmony_ci 417662306a36Sopenharmony_ci # fill in any missing phases 417762306a36Sopenharmony_ci phasedef = data.phasedef 417862306a36Sopenharmony_ci terr, lp = '', 'suspend_prepare' 417962306a36Sopenharmony_ci if lp not in data.dmesg: 418062306a36Sopenharmony_ci doError('dmesg log format has changed, could not find start of suspend') 418162306a36Sopenharmony_ci for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 418262306a36Sopenharmony_ci if p not in data.dmesg: 418362306a36Sopenharmony_ci if not terr: 418462306a36Sopenharmony_ci pprint('TEST FAILED: %s failed in %s phase' % (sysvals.suspendmode, lp)) 418562306a36Sopenharmony_ci terr = '%s failed in %s phase' % (sysvals.suspendmode, lp) 418662306a36Sopenharmony_ci if data.tSuspended == 0: 418762306a36Sopenharmony_ci data.tSuspended = data.dmesg[lp]['end'] 418862306a36Sopenharmony_ci if data.tResumed == 0: 418962306a36Sopenharmony_ci data.tResumed = data.dmesg[lp]['end'] 419062306a36Sopenharmony_ci sysvals.vprint('WARNING: phase "%s" is missing!' % p) 419162306a36Sopenharmony_ci lp = p 419262306a36Sopenharmony_ci lp = data.sortedPhases()[0] 419362306a36Sopenharmony_ci for p in data.sortedPhases(): 419462306a36Sopenharmony_ci if(p != lp and not ('machine' in p and 'machine' in lp)): 419562306a36Sopenharmony_ci data.dmesg[lp]['end'] = data.dmesg[p]['start'] 419662306a36Sopenharmony_ci lp = p 419762306a36Sopenharmony_ci if data.tSuspended == 0: 419862306a36Sopenharmony_ci data.tSuspended = data.tKernRes 419962306a36Sopenharmony_ci if data.tResumed == 0: 420062306a36Sopenharmony_ci data.tResumed = data.tSuspended 420162306a36Sopenharmony_ci 420262306a36Sopenharmony_ci # fill in any actions we've found 420362306a36Sopenharmony_ci for name in sorted(actions): 420462306a36Sopenharmony_ci for event in actions[name]: 420562306a36Sopenharmony_ci data.newActionGlobal(name, event['begin'], event['end']) 420662306a36Sopenharmony_ci 420762306a36Sopenharmony_ci if(len(sysvals.devicefilter) > 0): 420862306a36Sopenharmony_ci data.deviceFilter(sysvals.devicefilter) 420962306a36Sopenharmony_ci data.fixupInitcallsThatDidntReturn() 421062306a36Sopenharmony_ci return True 421162306a36Sopenharmony_ci 421262306a36Sopenharmony_cidef callgraphHTML(sv, hf, num, cg, title, color, devid): 421362306a36Sopenharmony_ci 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' 421462306a36Sopenharmony_ci html_func_start = '<article>\n<input type="checkbox" class="pf" id="f{0}" checked/><label for="f{0}">{1} {2}</label>\n' 421562306a36Sopenharmony_ci html_func_end = '</article>\n' 421662306a36Sopenharmony_ci html_func_leaf = '<article>{0} {1}</article>\n' 421762306a36Sopenharmony_ci 421862306a36Sopenharmony_ci cgid = devid 421962306a36Sopenharmony_ci if cg.id: 422062306a36Sopenharmony_ci cgid += cg.id 422162306a36Sopenharmony_ci cglen = (cg.end - cg.start) * 1000 422262306a36Sopenharmony_ci if cglen < sv.mincglen: 422362306a36Sopenharmony_ci return num 422462306a36Sopenharmony_ci 422562306a36Sopenharmony_ci fmt = '<r>(%.3f ms @ '+sv.timeformat+' to '+sv.timeformat+')</r>' 422662306a36Sopenharmony_ci flen = fmt % (cglen, cg.start, cg.end) 422762306a36Sopenharmony_ci hf.write(html_func_top.format(cgid, color, num, title, flen)) 422862306a36Sopenharmony_ci num += 1 422962306a36Sopenharmony_ci for line in cg.list: 423062306a36Sopenharmony_ci if(line.length < 0.000000001): 423162306a36Sopenharmony_ci flen = '' 423262306a36Sopenharmony_ci else: 423362306a36Sopenharmony_ci fmt = '<n>(%.3f ms @ '+sv.timeformat+')</n>' 423462306a36Sopenharmony_ci flen = fmt % (line.length*1000, line.time) 423562306a36Sopenharmony_ci if line.isLeaf(): 423662306a36Sopenharmony_ci if line.length * 1000 < sv.mincglen: 423762306a36Sopenharmony_ci continue 423862306a36Sopenharmony_ci hf.write(html_func_leaf.format(line.name, flen)) 423962306a36Sopenharmony_ci elif line.freturn: 424062306a36Sopenharmony_ci hf.write(html_func_end) 424162306a36Sopenharmony_ci else: 424262306a36Sopenharmony_ci hf.write(html_func_start.format(num, line.name, flen)) 424362306a36Sopenharmony_ci num += 1 424462306a36Sopenharmony_ci hf.write(html_func_end) 424562306a36Sopenharmony_ci return num 424662306a36Sopenharmony_ci 424762306a36Sopenharmony_cidef addCallgraphs(sv, hf, data): 424862306a36Sopenharmony_ci hf.write('<section id="callgraphs" class="callgraph">\n') 424962306a36Sopenharmony_ci # write out the ftrace data converted to html 425062306a36Sopenharmony_ci num = 0 425162306a36Sopenharmony_ci for p in data.sortedPhases(): 425262306a36Sopenharmony_ci if sv.cgphase and p != sv.cgphase: 425362306a36Sopenharmony_ci continue 425462306a36Sopenharmony_ci list = data.dmesg[p]['list'] 425562306a36Sopenharmony_ci for d in data.sortedDevices(p): 425662306a36Sopenharmony_ci if len(sv.cgfilter) > 0 and d not in sv.cgfilter: 425762306a36Sopenharmony_ci continue 425862306a36Sopenharmony_ci dev = list[d] 425962306a36Sopenharmony_ci color = 'white' 426062306a36Sopenharmony_ci if 'color' in data.dmesg[p]: 426162306a36Sopenharmony_ci color = data.dmesg[p]['color'] 426262306a36Sopenharmony_ci if 'color' in dev: 426362306a36Sopenharmony_ci color = dev['color'] 426462306a36Sopenharmony_ci name = d if '[' not in d else d.split('[')[0] 426562306a36Sopenharmony_ci if(d in sv.devprops): 426662306a36Sopenharmony_ci name = sv.devprops[d].altName(d) 426762306a36Sopenharmony_ci if 'drv' in dev and dev['drv']: 426862306a36Sopenharmony_ci name += ' {%s}' % dev['drv'] 426962306a36Sopenharmony_ci if sv.suspendmode in suspendmodename: 427062306a36Sopenharmony_ci name += ' '+p 427162306a36Sopenharmony_ci if('ftrace' in dev): 427262306a36Sopenharmony_ci cg = dev['ftrace'] 427362306a36Sopenharmony_ci if cg.name == sv.ftopfunc: 427462306a36Sopenharmony_ci name = 'top level suspend/resume call' 427562306a36Sopenharmony_ci num = callgraphHTML(sv, hf, num, cg, 427662306a36Sopenharmony_ci name, color, dev['id']) 427762306a36Sopenharmony_ci if('ftraces' in dev): 427862306a36Sopenharmony_ci for cg in dev['ftraces']: 427962306a36Sopenharmony_ci num = callgraphHTML(sv, hf, num, cg, 428062306a36Sopenharmony_ci name+' → '+cg.name, color, dev['id']) 428162306a36Sopenharmony_ci hf.write('\n\n </section>\n') 428262306a36Sopenharmony_ci 428362306a36Sopenharmony_cidef summaryCSS(title, center=True): 428462306a36Sopenharmony_ci tdcenter = 'text-align:center;' if center else '' 428562306a36Sopenharmony_ci out = '<!DOCTYPE html>\n<html>\n<head>\n\ 428662306a36Sopenharmony_ci <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 428762306a36Sopenharmony_ci <title>'+title+'</title>\n\ 428862306a36Sopenharmony_ci <style type=\'text/css\'>\n\ 428962306a36Sopenharmony_ci .stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\ 429062306a36Sopenharmony_ci table {width:100%;border-collapse: collapse;border:1px solid;}\n\ 429162306a36Sopenharmony_ci th {border: 1px solid black;background:#222;color:white;}\n\ 429262306a36Sopenharmony_ci td {font: 14px "Times New Roman";'+tdcenter+'}\n\ 429362306a36Sopenharmony_ci tr.head td {border: 1px solid black;background:#aaa;}\n\ 429462306a36Sopenharmony_ci tr.alt {background-color:#ddd;}\n\ 429562306a36Sopenharmony_ci tr.notice {color:red;}\n\ 429662306a36Sopenharmony_ci .minval {background-color:#BBFFBB;}\n\ 429762306a36Sopenharmony_ci .medval {background-color:#BBBBFF;}\n\ 429862306a36Sopenharmony_ci .maxval {background-color:#FFBBBB;}\n\ 429962306a36Sopenharmony_ci .head a {color:#000;text-decoration: none;}\n\ 430062306a36Sopenharmony_ci </style>\n</head>\n<body>\n' 430162306a36Sopenharmony_ci return out 430262306a36Sopenharmony_ci 430362306a36Sopenharmony_ci# Function: createHTMLSummarySimple 430462306a36Sopenharmony_ci# Description: 430562306a36Sopenharmony_ci# Create summary html file for a series of tests 430662306a36Sopenharmony_ci# Arguments: 430762306a36Sopenharmony_ci# testruns: array of Data objects from parseTraceLog 430862306a36Sopenharmony_cidef createHTMLSummarySimple(testruns, htmlfile, title): 430962306a36Sopenharmony_ci # write the html header first (html head, css code, up to body start) 431062306a36Sopenharmony_ci html = summaryCSS('Summary - SleepGraph') 431162306a36Sopenharmony_ci 431262306a36Sopenharmony_ci # extract the test data into list 431362306a36Sopenharmony_ci list = dict() 431462306a36Sopenharmony_ci tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 431562306a36Sopenharmony_ci iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 431662306a36Sopenharmony_ci num = 0 431762306a36Sopenharmony_ci useturbo = usewifi = False 431862306a36Sopenharmony_ci lastmode = '' 431962306a36Sopenharmony_ci cnt = dict() 432062306a36Sopenharmony_ci for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])): 432162306a36Sopenharmony_ci mode = data['mode'] 432262306a36Sopenharmony_ci if mode not in list: 432362306a36Sopenharmony_ci list[mode] = {'data': [], 'avg': [0,0], 'min': [0,0], 'max': [0,0], 'med': [0,0]} 432462306a36Sopenharmony_ci if lastmode and lastmode != mode and num > 0: 432562306a36Sopenharmony_ci for i in range(2): 432662306a36Sopenharmony_ci s = sorted(tMed[i]) 432762306a36Sopenharmony_ci list[lastmode]['med'][i] = s[int(len(s)//2)] 432862306a36Sopenharmony_ci iMed[i] = tMed[i][list[lastmode]['med'][i]] 432962306a36Sopenharmony_ci list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 433062306a36Sopenharmony_ci list[lastmode]['min'] = tMin 433162306a36Sopenharmony_ci list[lastmode]['max'] = tMax 433262306a36Sopenharmony_ci list[lastmode]['idx'] = (iMin, iMed, iMax) 433362306a36Sopenharmony_ci tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 433462306a36Sopenharmony_ci iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 433562306a36Sopenharmony_ci num = 0 433662306a36Sopenharmony_ci pkgpc10 = syslpi = wifi = '' 433762306a36Sopenharmony_ci if 'pkgpc10' in data and 'syslpi' in data: 433862306a36Sopenharmony_ci pkgpc10, syslpi, useturbo = data['pkgpc10'], data['syslpi'], True 433962306a36Sopenharmony_ci if 'wifi' in data: 434062306a36Sopenharmony_ci wifi, usewifi = data['wifi'], True 434162306a36Sopenharmony_ci res = data['result'] 434262306a36Sopenharmony_ci tVal = [float(data['suspend']), float(data['resume'])] 434362306a36Sopenharmony_ci list[mode]['data'].append([data['host'], data['kernel'], 434462306a36Sopenharmony_ci data['time'], tVal[0], tVal[1], data['url'], res, 434562306a36Sopenharmony_ci data['issues'], data['sus_worst'], data['sus_worsttime'], 434662306a36Sopenharmony_ci data['res_worst'], data['res_worsttime'], pkgpc10, syslpi, wifi]) 434762306a36Sopenharmony_ci idx = len(list[mode]['data']) - 1 434862306a36Sopenharmony_ci if res.startswith('fail in'): 434962306a36Sopenharmony_ci res = 'fail' 435062306a36Sopenharmony_ci if res not in cnt: 435162306a36Sopenharmony_ci cnt[res] = 1 435262306a36Sopenharmony_ci else: 435362306a36Sopenharmony_ci cnt[res] += 1 435462306a36Sopenharmony_ci if res == 'pass': 435562306a36Sopenharmony_ci for i in range(2): 435662306a36Sopenharmony_ci tMed[i][tVal[i]] = idx 435762306a36Sopenharmony_ci tAvg[i] += tVal[i] 435862306a36Sopenharmony_ci if tMin[i] == 0 or tVal[i] < tMin[i]: 435962306a36Sopenharmony_ci iMin[i] = idx 436062306a36Sopenharmony_ci tMin[i] = tVal[i] 436162306a36Sopenharmony_ci if tMax[i] == 0 or tVal[i] > tMax[i]: 436262306a36Sopenharmony_ci iMax[i] = idx 436362306a36Sopenharmony_ci tMax[i] = tVal[i] 436462306a36Sopenharmony_ci num += 1 436562306a36Sopenharmony_ci lastmode = mode 436662306a36Sopenharmony_ci if lastmode and num > 0: 436762306a36Sopenharmony_ci for i in range(2): 436862306a36Sopenharmony_ci s = sorted(tMed[i]) 436962306a36Sopenharmony_ci list[lastmode]['med'][i] = s[int(len(s)//2)] 437062306a36Sopenharmony_ci iMed[i] = tMed[i][list[lastmode]['med'][i]] 437162306a36Sopenharmony_ci list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 437262306a36Sopenharmony_ci list[lastmode]['min'] = tMin 437362306a36Sopenharmony_ci list[lastmode]['max'] = tMax 437462306a36Sopenharmony_ci list[lastmode]['idx'] = (iMin, iMed, iMax) 437562306a36Sopenharmony_ci 437662306a36Sopenharmony_ci # group test header 437762306a36Sopenharmony_ci desc = [] 437862306a36Sopenharmony_ci for ilk in sorted(cnt, reverse=True): 437962306a36Sopenharmony_ci if cnt[ilk] > 0: 438062306a36Sopenharmony_ci desc.append('%d %s' % (cnt[ilk], ilk)) 438162306a36Sopenharmony_ci html += '<div class="stamp">%s (%d tests: %s)</div>\n' % (title, len(testruns), ', '.join(desc)) 438262306a36Sopenharmony_ci th = '\t<th>{0}</th>\n' 438362306a36Sopenharmony_ci td = '\t<td>{0}</td>\n' 438462306a36Sopenharmony_ci tdh = '\t<td{1}>{0}</td>\n' 438562306a36Sopenharmony_ci tdlink = '\t<td><a href="{0}">html</a></td>\n' 438662306a36Sopenharmony_ci cols = 12 438762306a36Sopenharmony_ci if useturbo: 438862306a36Sopenharmony_ci cols += 2 438962306a36Sopenharmony_ci if usewifi: 439062306a36Sopenharmony_ci cols += 1 439162306a36Sopenharmony_ci colspan = '%d' % cols 439262306a36Sopenharmony_ci 439362306a36Sopenharmony_ci # table header 439462306a36Sopenharmony_ci html += '<table>\n<tr>\n' + th.format('#') +\ 439562306a36Sopenharmony_ci th.format('Mode') + th.format('Host') + th.format('Kernel') +\ 439662306a36Sopenharmony_ci th.format('Test Time') + th.format('Result') + th.format('Issues') +\ 439762306a36Sopenharmony_ci th.format('Suspend') + th.format('Resume') +\ 439862306a36Sopenharmony_ci th.format('Worst Suspend Device') + th.format('SD Time') +\ 439962306a36Sopenharmony_ci th.format('Worst Resume Device') + th.format('RD Time') 440062306a36Sopenharmony_ci if useturbo: 440162306a36Sopenharmony_ci html += th.format('PkgPC10') + th.format('SysLPI') 440262306a36Sopenharmony_ci if usewifi: 440362306a36Sopenharmony_ci html += th.format('Wifi') 440462306a36Sopenharmony_ci html += th.format('Detail')+'</tr>\n' 440562306a36Sopenharmony_ci # export list into html 440662306a36Sopenharmony_ci head = '<tr class="head"><td>{0}</td><td>{1}</td>'+\ 440762306a36Sopenharmony_ci '<td colspan='+colspan+' class="sus">Suspend Avg={2} '+\ 440862306a36Sopenharmony_ci '<span class=minval><a href="#s{10}min">Min={3}</a></span> '+\ 440962306a36Sopenharmony_ci '<span class=medval><a href="#s{10}med">Med={4}</a></span> '+\ 441062306a36Sopenharmony_ci '<span class=maxval><a href="#s{10}max">Max={5}</a></span> '+\ 441162306a36Sopenharmony_ci 'Resume Avg={6} '+\ 441262306a36Sopenharmony_ci '<span class=minval><a href="#r{10}min">Min={7}</a></span> '+\ 441362306a36Sopenharmony_ci '<span class=medval><a href="#r{10}med">Med={8}</a></span> '+\ 441462306a36Sopenharmony_ci '<span class=maxval><a href="#r{10}max">Max={9}</a></span></td>'+\ 441562306a36Sopenharmony_ci '</tr>\n' 441662306a36Sopenharmony_ci headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan='+\ 441762306a36Sopenharmony_ci colspan+'></td></tr>\n' 441862306a36Sopenharmony_ci for mode in sorted(list): 441962306a36Sopenharmony_ci # header line for each suspend mode 442062306a36Sopenharmony_ci num = 0 442162306a36Sopenharmony_ci tAvg, tMin, tMax, tMed = list[mode]['avg'], list[mode]['min'],\ 442262306a36Sopenharmony_ci list[mode]['max'], list[mode]['med'] 442362306a36Sopenharmony_ci count = len(list[mode]['data']) 442462306a36Sopenharmony_ci if 'idx' in list[mode]: 442562306a36Sopenharmony_ci iMin, iMed, iMax = list[mode]['idx'] 442662306a36Sopenharmony_ci html += head.format('%d' % count, mode.upper(), 442762306a36Sopenharmony_ci '%.3f' % tAvg[0], '%.3f' % tMin[0], '%.3f' % tMed[0], '%.3f' % tMax[0], 442862306a36Sopenharmony_ci '%.3f' % tAvg[1], '%.3f' % tMin[1], '%.3f' % tMed[1], '%.3f' % tMax[1], 442962306a36Sopenharmony_ci mode.lower() 443062306a36Sopenharmony_ci ) 443162306a36Sopenharmony_ci else: 443262306a36Sopenharmony_ci iMin = iMed = iMax = [-1, -1, -1] 443362306a36Sopenharmony_ci html += headnone.format('%d' % count, mode.upper()) 443462306a36Sopenharmony_ci for d in list[mode]['data']: 443562306a36Sopenharmony_ci # row classes - alternate row color 443662306a36Sopenharmony_ci rcls = ['alt'] if num % 2 == 1 else [] 443762306a36Sopenharmony_ci if d[6] != 'pass': 443862306a36Sopenharmony_ci rcls.append('notice') 443962306a36Sopenharmony_ci html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 444062306a36Sopenharmony_ci # figure out if the line has sus or res highlighted 444162306a36Sopenharmony_ci idx = list[mode]['data'].index(d) 444262306a36Sopenharmony_ci tHigh = ['', ''] 444362306a36Sopenharmony_ci for i in range(2): 444462306a36Sopenharmony_ci tag = 's%s' % mode if i == 0 else 'r%s' % mode 444562306a36Sopenharmony_ci if idx == iMin[i]: 444662306a36Sopenharmony_ci tHigh[i] = ' id="%smin" class=minval title="Minimum"' % tag 444762306a36Sopenharmony_ci elif idx == iMax[i]: 444862306a36Sopenharmony_ci tHigh[i] = ' id="%smax" class=maxval title="Maximum"' % tag 444962306a36Sopenharmony_ci elif idx == iMed[i]: 445062306a36Sopenharmony_ci tHigh[i] = ' id="%smed" class=medval title="Median"' % tag 445162306a36Sopenharmony_ci html += td.format("%d" % (list[mode]['data'].index(d) + 1)) # row 445262306a36Sopenharmony_ci html += td.format(mode) # mode 445362306a36Sopenharmony_ci html += td.format(d[0]) # host 445462306a36Sopenharmony_ci html += td.format(d[1]) # kernel 445562306a36Sopenharmony_ci html += td.format(d[2]) # time 445662306a36Sopenharmony_ci html += td.format(d[6]) # result 445762306a36Sopenharmony_ci html += td.format(d[7]) # issues 445862306a36Sopenharmony_ci html += tdh.format('%.3f ms' % d[3], tHigh[0]) if d[3] else td.format('') # suspend 445962306a36Sopenharmony_ci html += tdh.format('%.3f ms' % d[4], tHigh[1]) if d[4] else td.format('') # resume 446062306a36Sopenharmony_ci html += td.format(d[8]) # sus_worst 446162306a36Sopenharmony_ci html += td.format('%.3f ms' % d[9]) if d[9] else td.format('') # sus_worst time 446262306a36Sopenharmony_ci html += td.format(d[10]) # res_worst 446362306a36Sopenharmony_ci html += td.format('%.3f ms' % d[11]) if d[11] else td.format('') # res_worst time 446462306a36Sopenharmony_ci if useturbo: 446562306a36Sopenharmony_ci html += td.format(d[12]) # pkg_pc10 446662306a36Sopenharmony_ci html += td.format(d[13]) # syslpi 446762306a36Sopenharmony_ci if usewifi: 446862306a36Sopenharmony_ci html += td.format(d[14]) # wifi 446962306a36Sopenharmony_ci html += tdlink.format(d[5]) if d[5] else td.format('') # url 447062306a36Sopenharmony_ci html += '</tr>\n' 447162306a36Sopenharmony_ci num += 1 447262306a36Sopenharmony_ci 447362306a36Sopenharmony_ci # flush the data to file 447462306a36Sopenharmony_ci hf = open(htmlfile, 'w') 447562306a36Sopenharmony_ci hf.write(html+'</table>\n</body>\n</html>\n') 447662306a36Sopenharmony_ci hf.close() 447762306a36Sopenharmony_ci 447862306a36Sopenharmony_cidef createHTMLDeviceSummary(testruns, htmlfile, title): 447962306a36Sopenharmony_ci html = summaryCSS('Device Summary - SleepGraph', False) 448062306a36Sopenharmony_ci 448162306a36Sopenharmony_ci # create global device list from all tests 448262306a36Sopenharmony_ci devall = dict() 448362306a36Sopenharmony_ci for data in testruns: 448462306a36Sopenharmony_ci host, url, devlist = data['host'], data['url'], data['devlist'] 448562306a36Sopenharmony_ci for type in devlist: 448662306a36Sopenharmony_ci if type not in devall: 448762306a36Sopenharmony_ci devall[type] = dict() 448862306a36Sopenharmony_ci mdevlist, devlist = devall[type], data['devlist'][type] 448962306a36Sopenharmony_ci for name in devlist: 449062306a36Sopenharmony_ci length = devlist[name] 449162306a36Sopenharmony_ci if name not in mdevlist: 449262306a36Sopenharmony_ci mdevlist[name] = {'name': name, 'host': host, 449362306a36Sopenharmony_ci 'worst': length, 'total': length, 'count': 1, 449462306a36Sopenharmony_ci 'url': url} 449562306a36Sopenharmony_ci else: 449662306a36Sopenharmony_ci if length > mdevlist[name]['worst']: 449762306a36Sopenharmony_ci mdevlist[name]['worst'] = length 449862306a36Sopenharmony_ci mdevlist[name]['url'] = url 449962306a36Sopenharmony_ci mdevlist[name]['host'] = host 450062306a36Sopenharmony_ci mdevlist[name]['total'] += length 450162306a36Sopenharmony_ci mdevlist[name]['count'] += 1 450262306a36Sopenharmony_ci 450362306a36Sopenharmony_ci # generate the html 450462306a36Sopenharmony_ci th = '\t<th>{0}</th>\n' 450562306a36Sopenharmony_ci td = '\t<td align=center>{0}</td>\n' 450662306a36Sopenharmony_ci tdr = '\t<td align=right>{0}</td>\n' 450762306a36Sopenharmony_ci tdlink = '\t<td align=center><a href="{0}">html</a></td>\n' 450862306a36Sopenharmony_ci limit = 1 450962306a36Sopenharmony_ci for type in sorted(devall, reverse=True): 451062306a36Sopenharmony_ci num = 0 451162306a36Sopenharmony_ci devlist = devall[type] 451262306a36Sopenharmony_ci # table header 451362306a36Sopenharmony_ci html += '<div class="stamp">%s (%s devices > %d ms)</div><table>\n' % \ 451462306a36Sopenharmony_ci (title, type.upper(), limit) 451562306a36Sopenharmony_ci html += '<tr>\n' + '<th align=right>Device Name</th>' +\ 451662306a36Sopenharmony_ci th.format('Average Time') + th.format('Count') +\ 451762306a36Sopenharmony_ci th.format('Worst Time') + th.format('Host (worst time)') +\ 451862306a36Sopenharmony_ci th.format('Link (worst time)') + '</tr>\n' 451962306a36Sopenharmony_ci for name in sorted(devlist, key=lambda k:(devlist[k]['worst'], \ 452062306a36Sopenharmony_ci devlist[k]['total'], devlist[k]['name']), reverse=True): 452162306a36Sopenharmony_ci data = devall[type][name] 452262306a36Sopenharmony_ci data['average'] = data['total'] / data['count'] 452362306a36Sopenharmony_ci if data['average'] < limit: 452462306a36Sopenharmony_ci continue 452562306a36Sopenharmony_ci # row classes - alternate row color 452662306a36Sopenharmony_ci rcls = ['alt'] if num % 2 == 1 else [] 452762306a36Sopenharmony_ci html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 452862306a36Sopenharmony_ci html += tdr.format(data['name']) # name 452962306a36Sopenharmony_ci html += td.format('%.3f ms' % data['average']) # average 453062306a36Sopenharmony_ci html += td.format(data['count']) # count 453162306a36Sopenharmony_ci html += td.format('%.3f ms' % data['worst']) # worst 453262306a36Sopenharmony_ci html += td.format(data['host']) # host 453362306a36Sopenharmony_ci html += tdlink.format(data['url']) # url 453462306a36Sopenharmony_ci html += '</tr>\n' 453562306a36Sopenharmony_ci num += 1 453662306a36Sopenharmony_ci html += '</table>\n' 453762306a36Sopenharmony_ci 453862306a36Sopenharmony_ci # flush the data to file 453962306a36Sopenharmony_ci hf = open(htmlfile, 'w') 454062306a36Sopenharmony_ci hf.write(html+'</body>\n</html>\n') 454162306a36Sopenharmony_ci hf.close() 454262306a36Sopenharmony_ci return devall 454362306a36Sopenharmony_ci 454462306a36Sopenharmony_cidef createHTMLIssuesSummary(testruns, issues, htmlfile, title, extra=''): 454562306a36Sopenharmony_ci multihost = len([e for e in issues if len(e['urls']) > 1]) > 0 454662306a36Sopenharmony_ci html = summaryCSS('Issues Summary - SleepGraph', False) 454762306a36Sopenharmony_ci total = len(testruns) 454862306a36Sopenharmony_ci 454962306a36Sopenharmony_ci # generate the html 455062306a36Sopenharmony_ci th = '\t<th>{0}</th>\n' 455162306a36Sopenharmony_ci td = '\t<td align={0}>{1}</td>\n' 455262306a36Sopenharmony_ci tdlink = '<a href="{1}">{0}</a>' 455362306a36Sopenharmony_ci subtitle = '%d issues' % len(issues) if len(issues) > 0 else 'no issues' 455462306a36Sopenharmony_ci html += '<div class="stamp">%s (%s)</div><table>\n' % (title, subtitle) 455562306a36Sopenharmony_ci html += '<tr>\n' + th.format('Issue') + th.format('Count') 455662306a36Sopenharmony_ci if multihost: 455762306a36Sopenharmony_ci html += th.format('Hosts') 455862306a36Sopenharmony_ci html += th.format('Tests') + th.format('Fail Rate') +\ 455962306a36Sopenharmony_ci th.format('First Instance') + '</tr>\n' 456062306a36Sopenharmony_ci 456162306a36Sopenharmony_ci num = 0 456262306a36Sopenharmony_ci for e in sorted(issues, key=lambda v:v['count'], reverse=True): 456362306a36Sopenharmony_ci testtotal = 0 456462306a36Sopenharmony_ci links = [] 456562306a36Sopenharmony_ci for host in sorted(e['urls']): 456662306a36Sopenharmony_ci links.append(tdlink.format(host, e['urls'][host][0])) 456762306a36Sopenharmony_ci testtotal += len(e['urls'][host]) 456862306a36Sopenharmony_ci rate = '%d/%d (%.2f%%)' % (testtotal, total, 100*float(testtotal)/float(total)) 456962306a36Sopenharmony_ci # row classes - alternate row color 457062306a36Sopenharmony_ci rcls = ['alt'] if num % 2 == 1 else [] 457162306a36Sopenharmony_ci html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 457262306a36Sopenharmony_ci html += td.format('left', e['line']) # issue 457362306a36Sopenharmony_ci html += td.format('center', e['count']) # count 457462306a36Sopenharmony_ci if multihost: 457562306a36Sopenharmony_ci html += td.format('center', len(e['urls'])) # hosts 457662306a36Sopenharmony_ci html += td.format('center', testtotal) # test count 457762306a36Sopenharmony_ci html += td.format('center', rate) # test rate 457862306a36Sopenharmony_ci html += td.format('center nowrap', '<br>'.join(links)) # links 457962306a36Sopenharmony_ci html += '</tr>\n' 458062306a36Sopenharmony_ci num += 1 458162306a36Sopenharmony_ci 458262306a36Sopenharmony_ci # flush the data to file 458362306a36Sopenharmony_ci hf = open(htmlfile, 'w') 458462306a36Sopenharmony_ci hf.write(html+'</table>\n'+extra+'</body>\n</html>\n') 458562306a36Sopenharmony_ci hf.close() 458662306a36Sopenharmony_ci return issues 458762306a36Sopenharmony_ci 458862306a36Sopenharmony_cidef ordinal(value): 458962306a36Sopenharmony_ci suffix = 'th' 459062306a36Sopenharmony_ci if value < 10 or value > 19: 459162306a36Sopenharmony_ci if value % 10 == 1: 459262306a36Sopenharmony_ci suffix = 'st' 459362306a36Sopenharmony_ci elif value % 10 == 2: 459462306a36Sopenharmony_ci suffix = 'nd' 459562306a36Sopenharmony_ci elif value % 10 == 3: 459662306a36Sopenharmony_ci suffix = 'rd' 459762306a36Sopenharmony_ci return '%d%s' % (value, suffix) 459862306a36Sopenharmony_ci 459962306a36Sopenharmony_ci# Function: createHTML 460062306a36Sopenharmony_ci# Description: 460162306a36Sopenharmony_ci# Create the output html file from the resident test data 460262306a36Sopenharmony_ci# Arguments: 460362306a36Sopenharmony_ci# testruns: array of Data objects from parseKernelLog or parseTraceLog 460462306a36Sopenharmony_ci# Output: 460562306a36Sopenharmony_ci# True if the html file was created, false if it failed 460662306a36Sopenharmony_cidef createHTML(testruns, testfail): 460762306a36Sopenharmony_ci if len(testruns) < 1: 460862306a36Sopenharmony_ci pprint('ERROR: Not enough test data to build a timeline') 460962306a36Sopenharmony_ci return 461062306a36Sopenharmony_ci 461162306a36Sopenharmony_ci kerror = False 461262306a36Sopenharmony_ci for data in testruns: 461362306a36Sopenharmony_ci if data.kerror: 461462306a36Sopenharmony_ci kerror = True 461562306a36Sopenharmony_ci if(sysvals.suspendmode in ['freeze', 'standby']): 461662306a36Sopenharmony_ci data.trimFreezeTime(testruns[-1].tSuspended) 461762306a36Sopenharmony_ci else: 461862306a36Sopenharmony_ci data.getMemTime() 461962306a36Sopenharmony_ci 462062306a36Sopenharmony_ci # html function templates 462162306a36Sopenharmony_ci html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">{2}→</div>\n' 462262306a36Sopenharmony_ci 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' 462362306a36Sopenharmony_ci html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n' 462462306a36Sopenharmony_ci html_timetotal = '<table class="time1">\n<tr>'\ 462562306a36Sopenharmony_ci '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ 462662306a36Sopenharmony_ci '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ 462762306a36Sopenharmony_ci '</tr>\n</table>\n' 462862306a36Sopenharmony_ci html_timetotal2 = '<table class="time1">\n<tr>'\ 462962306a36Sopenharmony_ci '<td class="green" title="{4}">{3} Suspend Time: <b>{0} ms</b></td>'\ 463062306a36Sopenharmony_ci '<td class="gray" title="time spent in low-power mode with clock running">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\ 463162306a36Sopenharmony_ci '<td class="yellow" title="{5}">{3} Resume Time: <b>{2} ms</b></td>'\ 463262306a36Sopenharmony_ci '</tr>\n</table>\n' 463362306a36Sopenharmony_ci html_timetotal3 = '<table class="time1">\n<tr>'\ 463462306a36Sopenharmony_ci '<td class="green">Execution Time: <b>{0} ms</b></td>'\ 463562306a36Sopenharmony_ci '<td class="yellow">Command: <b>{1}</b></td>'\ 463662306a36Sopenharmony_ci '</tr>\n</table>\n' 463762306a36Sopenharmony_ci html_fail = '<table class="testfail"><tr><td>{0}</td></tr></table>\n' 463862306a36Sopenharmony_ci html_kdesc = '<td class="{3}" title="time spent in kernel execution">{0}Kernel {2}: {1} ms</td>' 463962306a36Sopenharmony_ci html_fwdesc = '<td class="{3}" title="time spent in firmware">{0}Firmware {2}: {1} ms</td>' 464062306a36Sopenharmony_ci html_wifdesc = '<td class="yellow" title="time for wifi to reconnect after resume complete ({2})">{0}Wifi Resume: {1}</td>' 464162306a36Sopenharmony_ci 464262306a36Sopenharmony_ci # html format variables 464362306a36Sopenharmony_ci scaleH = 20 464462306a36Sopenharmony_ci if kerror: 464562306a36Sopenharmony_ci scaleH = 40 464662306a36Sopenharmony_ci 464762306a36Sopenharmony_ci # device timeline 464862306a36Sopenharmony_ci devtl = Timeline(30, scaleH) 464962306a36Sopenharmony_ci 465062306a36Sopenharmony_ci # write the test title and general info header 465162306a36Sopenharmony_ci devtl.createHeader(sysvals, testruns[0].stamp) 465262306a36Sopenharmony_ci 465362306a36Sopenharmony_ci # Generate the header for this timeline 465462306a36Sopenharmony_ci for data in testruns: 465562306a36Sopenharmony_ci tTotal = data.end - data.start 465662306a36Sopenharmony_ci if(tTotal == 0): 465762306a36Sopenharmony_ci doError('No timeline data') 465862306a36Sopenharmony_ci if sysvals.suspendmode == 'command': 465962306a36Sopenharmony_ci run_time = '%.0f' % (tTotal * 1000) 466062306a36Sopenharmony_ci if sysvals.testcommand: 466162306a36Sopenharmony_ci testdesc = sysvals.testcommand 466262306a36Sopenharmony_ci else: 466362306a36Sopenharmony_ci testdesc = 'unknown' 466462306a36Sopenharmony_ci if(len(testruns) > 1): 466562306a36Sopenharmony_ci testdesc = ordinal(data.testnumber+1)+' '+testdesc 466662306a36Sopenharmony_ci thtml = html_timetotal3.format(run_time, testdesc) 466762306a36Sopenharmony_ci devtl.html += thtml 466862306a36Sopenharmony_ci continue 466962306a36Sopenharmony_ci # typical full suspend/resume header 467062306a36Sopenharmony_ci stot, rtot = sktime, rktime = data.getTimeValues() 467162306a36Sopenharmony_ci ssrc, rsrc, testdesc, testdesc2 = ['kernel'], ['kernel'], 'Kernel', '' 467262306a36Sopenharmony_ci if data.fwValid: 467362306a36Sopenharmony_ci stot += (data.fwSuspend/1000000.0) 467462306a36Sopenharmony_ci rtot += (data.fwResume/1000000.0) 467562306a36Sopenharmony_ci ssrc.append('firmware') 467662306a36Sopenharmony_ci rsrc.append('firmware') 467762306a36Sopenharmony_ci testdesc = 'Total' 467862306a36Sopenharmony_ci if 'time' in data.wifi and data.wifi['stat'] != 'timeout': 467962306a36Sopenharmony_ci rtot += data.end - data.tKernRes + (data.wifi['time'] * 1000.0) 468062306a36Sopenharmony_ci rsrc.append('wifi') 468162306a36Sopenharmony_ci testdesc = 'Total' 468262306a36Sopenharmony_ci suspend_time, resume_time = '%.3f' % stot, '%.3f' % rtot 468362306a36Sopenharmony_ci stitle = 'time from kernel suspend start to %s mode [%s time]' % \ 468462306a36Sopenharmony_ci (sysvals.suspendmode, ' & '.join(ssrc)) 468562306a36Sopenharmony_ci rtitle = 'time from %s mode to kernel resume complete [%s time]' % \ 468662306a36Sopenharmony_ci (sysvals.suspendmode, ' & '.join(rsrc)) 468762306a36Sopenharmony_ci if(len(testruns) > 1): 468862306a36Sopenharmony_ci testdesc = testdesc2 = ordinal(data.testnumber+1) 468962306a36Sopenharmony_ci testdesc2 += ' ' 469062306a36Sopenharmony_ci if(len(data.tLow) == 0): 469162306a36Sopenharmony_ci thtml = html_timetotal.format(suspend_time, \ 469262306a36Sopenharmony_ci resume_time, testdesc, stitle, rtitle) 469362306a36Sopenharmony_ci else: 469462306a36Sopenharmony_ci low_time = '+'.join(data.tLow) 469562306a36Sopenharmony_ci thtml = html_timetotal2.format(suspend_time, low_time, \ 469662306a36Sopenharmony_ci resume_time, testdesc, stitle, rtitle) 469762306a36Sopenharmony_ci devtl.html += thtml 469862306a36Sopenharmony_ci if not data.fwValid and 'dev' not in data.wifi: 469962306a36Sopenharmony_ci continue 470062306a36Sopenharmony_ci # extra detail when the times come from multiple sources 470162306a36Sopenharmony_ci thtml = '<table class="time2">\n<tr>' 470262306a36Sopenharmony_ci thtml += html_kdesc.format(testdesc2, '%.3f'%sktime, 'Suspend', 'green') 470362306a36Sopenharmony_ci if data.fwValid: 470462306a36Sopenharmony_ci sftime = '%.3f'%(data.fwSuspend / 1000000.0) 470562306a36Sopenharmony_ci rftime = '%.3f'%(data.fwResume / 1000000.0) 470662306a36Sopenharmony_ci thtml += html_fwdesc.format(testdesc2, sftime, 'Suspend', 'green') 470762306a36Sopenharmony_ci thtml += html_fwdesc.format(testdesc2, rftime, 'Resume', 'yellow') 470862306a36Sopenharmony_ci thtml += html_kdesc.format(testdesc2, '%.3f'%rktime, 'Resume', 'yellow') 470962306a36Sopenharmony_ci if 'time' in data.wifi: 471062306a36Sopenharmony_ci if data.wifi['stat'] != 'timeout': 471162306a36Sopenharmony_ci wtime = '%.0f ms'%(data.end - data.tKernRes + (data.wifi['time'] * 1000.0)) 471262306a36Sopenharmony_ci else: 471362306a36Sopenharmony_ci wtime = 'TIMEOUT' 471462306a36Sopenharmony_ci thtml += html_wifdesc.format(testdesc2, wtime, data.wifi['dev']) 471562306a36Sopenharmony_ci thtml += '</tr>\n</table>\n' 471662306a36Sopenharmony_ci devtl.html += thtml 471762306a36Sopenharmony_ci if testfail: 471862306a36Sopenharmony_ci devtl.html += html_fail.format(testfail) 471962306a36Sopenharmony_ci 472062306a36Sopenharmony_ci # time scale for potentially multiple datasets 472162306a36Sopenharmony_ci t0 = testruns[0].start 472262306a36Sopenharmony_ci tMax = testruns[-1].end 472362306a36Sopenharmony_ci tTotal = tMax - t0 472462306a36Sopenharmony_ci 472562306a36Sopenharmony_ci # determine the maximum number of rows we need to draw 472662306a36Sopenharmony_ci fulllist = [] 472762306a36Sopenharmony_ci threadlist = [] 472862306a36Sopenharmony_ci pscnt = 0 472962306a36Sopenharmony_ci devcnt = 0 473062306a36Sopenharmony_ci for data in testruns: 473162306a36Sopenharmony_ci data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen) 473262306a36Sopenharmony_ci for group in data.devicegroups: 473362306a36Sopenharmony_ci devlist = [] 473462306a36Sopenharmony_ci for phase in group: 473562306a36Sopenharmony_ci for devname in sorted(data.tdevlist[phase]): 473662306a36Sopenharmony_ci d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname]) 473762306a36Sopenharmony_ci devlist.append(d) 473862306a36Sopenharmony_ci if d.isa('kth'): 473962306a36Sopenharmony_ci threadlist.append(d) 474062306a36Sopenharmony_ci else: 474162306a36Sopenharmony_ci if d.isa('ps'): 474262306a36Sopenharmony_ci pscnt += 1 474362306a36Sopenharmony_ci else: 474462306a36Sopenharmony_ci devcnt += 1 474562306a36Sopenharmony_ci fulllist.append(d) 474662306a36Sopenharmony_ci if sysvals.mixedphaseheight: 474762306a36Sopenharmony_ci devtl.getPhaseRows(devlist) 474862306a36Sopenharmony_ci if not sysvals.mixedphaseheight: 474962306a36Sopenharmony_ci if len(threadlist) > 0 and len(fulllist) > 0: 475062306a36Sopenharmony_ci if pscnt > 0 and devcnt > 0: 475162306a36Sopenharmony_ci msg = 'user processes & device pm callbacks' 475262306a36Sopenharmony_ci elif pscnt > 0: 475362306a36Sopenharmony_ci msg = 'user processes' 475462306a36Sopenharmony_ci else: 475562306a36Sopenharmony_ci msg = 'device pm callbacks' 475662306a36Sopenharmony_ci d = testruns[0].addHorizontalDivider(msg, testruns[-1].end) 475762306a36Sopenharmony_ci fulllist.insert(0, d) 475862306a36Sopenharmony_ci devtl.getPhaseRows(fulllist) 475962306a36Sopenharmony_ci if len(threadlist) > 0: 476062306a36Sopenharmony_ci d = testruns[0].addHorizontalDivider('asynchronous kernel threads', testruns[-1].end) 476162306a36Sopenharmony_ci threadlist.insert(0, d) 476262306a36Sopenharmony_ci devtl.getPhaseRows(threadlist, devtl.rows) 476362306a36Sopenharmony_ci devtl.calcTotalRows() 476462306a36Sopenharmony_ci 476562306a36Sopenharmony_ci # draw the full timeline 476662306a36Sopenharmony_ci devtl.createZoomBox(sysvals.suspendmode, len(testruns)) 476762306a36Sopenharmony_ci for data in testruns: 476862306a36Sopenharmony_ci # draw each test run and block chronologically 476962306a36Sopenharmony_ci phases = {'suspend':[],'resume':[]} 477062306a36Sopenharmony_ci for phase in data.sortedPhases(): 477162306a36Sopenharmony_ci if data.dmesg[phase]['start'] >= data.tSuspended: 477262306a36Sopenharmony_ci phases['resume'].append(phase) 477362306a36Sopenharmony_ci else: 477462306a36Sopenharmony_ci phases['suspend'].append(phase) 477562306a36Sopenharmony_ci # now draw the actual timeline blocks 477662306a36Sopenharmony_ci for dir in phases: 477762306a36Sopenharmony_ci # draw suspend and resume blocks separately 477862306a36Sopenharmony_ci bname = '%s%d' % (dir[0], data.testnumber) 477962306a36Sopenharmony_ci if dir == 'suspend': 478062306a36Sopenharmony_ci m0 = data.start 478162306a36Sopenharmony_ci mMax = data.tSuspended 478262306a36Sopenharmony_ci left = '%f' % (((m0-t0)*100.0)/tTotal) 478362306a36Sopenharmony_ci else: 478462306a36Sopenharmony_ci m0 = data.tSuspended 478562306a36Sopenharmony_ci mMax = data.end 478662306a36Sopenharmony_ci # in an x2 run, remove any gap between blocks 478762306a36Sopenharmony_ci if len(testruns) > 1 and data.testnumber == 0: 478862306a36Sopenharmony_ci mMax = testruns[1].start 478962306a36Sopenharmony_ci left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal) 479062306a36Sopenharmony_ci mTotal = mMax - m0 479162306a36Sopenharmony_ci # if a timeline block is 0 length, skip altogether 479262306a36Sopenharmony_ci if mTotal == 0: 479362306a36Sopenharmony_ci continue 479462306a36Sopenharmony_ci width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal) 479562306a36Sopenharmony_ci devtl.html += devtl.html_tblock.format(bname, left, width, devtl.scaleH) 479662306a36Sopenharmony_ci for b in phases[dir]: 479762306a36Sopenharmony_ci # draw the phase color background 479862306a36Sopenharmony_ci phase = data.dmesg[b] 479962306a36Sopenharmony_ci length = phase['end']-phase['start'] 480062306a36Sopenharmony_ci left = '%f' % (((phase['start']-m0)*100.0)/mTotal) 480162306a36Sopenharmony_ci width = '%f' % ((length*100.0)/mTotal) 480262306a36Sopenharmony_ci devtl.html += devtl.html_phase.format(left, width, \ 480362306a36Sopenharmony_ci '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ 480462306a36Sopenharmony_ci data.dmesg[b]['color'], '') 480562306a36Sopenharmony_ci for e in data.errorinfo[dir]: 480662306a36Sopenharmony_ci # draw red lines for any kernel errors found 480762306a36Sopenharmony_ci type, t, idx1, idx2 = e 480862306a36Sopenharmony_ci id = '%d_%d' % (idx1, idx2) 480962306a36Sopenharmony_ci right = '%f' % (((mMax-t)*100.0)/mTotal) 481062306a36Sopenharmony_ci devtl.html += html_error.format(right, id, type) 481162306a36Sopenharmony_ci for b in phases[dir]: 481262306a36Sopenharmony_ci # draw the devices for this phase 481362306a36Sopenharmony_ci phaselist = data.dmesg[b]['list'] 481462306a36Sopenharmony_ci for d in sorted(data.tdevlist[b]): 481562306a36Sopenharmony_ci dname = d if ('[' not in d or 'CPU' in d) else d.split('[')[0] 481662306a36Sopenharmony_ci name, dev = dname, phaselist[d] 481762306a36Sopenharmony_ci drv = xtraclass = xtrainfo = xtrastyle = '' 481862306a36Sopenharmony_ci if 'htmlclass' in dev: 481962306a36Sopenharmony_ci xtraclass = dev['htmlclass'] 482062306a36Sopenharmony_ci if 'color' in dev: 482162306a36Sopenharmony_ci xtrastyle = 'background:%s;' % dev['color'] 482262306a36Sopenharmony_ci if(d in sysvals.devprops): 482362306a36Sopenharmony_ci name = sysvals.devprops[d].altName(d) 482462306a36Sopenharmony_ci xtraclass = sysvals.devprops[d].xtraClass() 482562306a36Sopenharmony_ci xtrainfo = sysvals.devprops[d].xtraInfo() 482662306a36Sopenharmony_ci elif xtraclass == ' kth': 482762306a36Sopenharmony_ci xtrainfo = ' kernel_thread' 482862306a36Sopenharmony_ci if('drv' in dev and dev['drv']): 482962306a36Sopenharmony_ci drv = ' {%s}' % dev['drv'] 483062306a36Sopenharmony_ci rowheight = devtl.phaseRowHeight(data.testnumber, b, dev['row']) 483162306a36Sopenharmony_ci rowtop = devtl.phaseRowTop(data.testnumber, b, dev['row']) 483262306a36Sopenharmony_ci top = '%.3f' % (rowtop + devtl.scaleH) 483362306a36Sopenharmony_ci left = '%f' % (((dev['start']-m0)*100)/mTotal) 483462306a36Sopenharmony_ci width = '%f' % (((dev['end']-dev['start'])*100)/mTotal) 483562306a36Sopenharmony_ci length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) 483662306a36Sopenharmony_ci title = name+drv+xtrainfo+length 483762306a36Sopenharmony_ci if sysvals.suspendmode == 'command': 483862306a36Sopenharmony_ci title += sysvals.testcommand 483962306a36Sopenharmony_ci elif xtraclass == ' ps': 484062306a36Sopenharmony_ci if 'suspend' in b: 484162306a36Sopenharmony_ci title += 'pre_suspend_process' 484262306a36Sopenharmony_ci else: 484362306a36Sopenharmony_ci title += 'post_resume_process' 484462306a36Sopenharmony_ci else: 484562306a36Sopenharmony_ci title += b 484662306a36Sopenharmony_ci devtl.html += devtl.html_device.format(dev['id'], \ 484762306a36Sopenharmony_ci title, left, top, '%.3f'%rowheight, width, \ 484862306a36Sopenharmony_ci dname+drv, xtraclass, xtrastyle) 484962306a36Sopenharmony_ci if('cpuexec' in dev): 485062306a36Sopenharmony_ci for t in sorted(dev['cpuexec']): 485162306a36Sopenharmony_ci start, end = t 485262306a36Sopenharmony_ci height = '%.3f' % (rowheight/3) 485362306a36Sopenharmony_ci top = '%.3f' % (rowtop + devtl.scaleH + 2*rowheight/3) 485462306a36Sopenharmony_ci left = '%f' % (((start-m0)*100)/mTotal) 485562306a36Sopenharmony_ci width = '%f' % ((end-start)*100/mTotal) 485662306a36Sopenharmony_ci color = 'rgba(255, 0, 0, %f)' % dev['cpuexec'][t] 485762306a36Sopenharmony_ci devtl.html += \ 485862306a36Sopenharmony_ci html_cpuexec.format(left, top, height, width, color) 485962306a36Sopenharmony_ci if('src' not in dev): 486062306a36Sopenharmony_ci continue 486162306a36Sopenharmony_ci # draw any trace events for this device 486262306a36Sopenharmony_ci for e in dev['src']: 486362306a36Sopenharmony_ci if e.length == 0: 486462306a36Sopenharmony_ci continue 486562306a36Sopenharmony_ci height = '%.3f' % devtl.rowH 486662306a36Sopenharmony_ci top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH)) 486762306a36Sopenharmony_ci left = '%f' % (((e.time-m0)*100)/mTotal) 486862306a36Sopenharmony_ci width = '%f' % (e.length*100/mTotal) 486962306a36Sopenharmony_ci xtrastyle = '' 487062306a36Sopenharmony_ci if e.color: 487162306a36Sopenharmony_ci xtrastyle = 'background:%s;' % e.color 487262306a36Sopenharmony_ci devtl.html += \ 487362306a36Sopenharmony_ci html_traceevent.format(e.title(), \ 487462306a36Sopenharmony_ci left, top, height, width, e.text(), '', xtrastyle) 487562306a36Sopenharmony_ci # draw the time scale, try to make the number of labels readable 487662306a36Sopenharmony_ci devtl.createTimeScale(m0, mMax, tTotal, dir) 487762306a36Sopenharmony_ci devtl.html += '</div>\n' 487862306a36Sopenharmony_ci 487962306a36Sopenharmony_ci # timeline is finished 488062306a36Sopenharmony_ci devtl.html += '</div>\n</div>\n' 488162306a36Sopenharmony_ci 488262306a36Sopenharmony_ci # draw a legend which describes the phases by color 488362306a36Sopenharmony_ci if sysvals.suspendmode != 'command': 488462306a36Sopenharmony_ci phasedef = testruns[-1].phasedef 488562306a36Sopenharmony_ci devtl.html += '<div class="legend">\n' 488662306a36Sopenharmony_ci pdelta = 100.0/len(phasedef.keys()) 488762306a36Sopenharmony_ci pmargin = pdelta / 4.0 488862306a36Sopenharmony_ci for phase in sorted(phasedef, key=lambda k:phasedef[k]['order']): 488962306a36Sopenharmony_ci id, p = '', phasedef[phase] 489062306a36Sopenharmony_ci for word in phase.split('_'): 489162306a36Sopenharmony_ci id += word[0] 489262306a36Sopenharmony_ci order = '%.2f' % ((p['order'] * pdelta) + pmargin) 489362306a36Sopenharmony_ci name = phase.replace('_', ' ') 489462306a36Sopenharmony_ci devtl.html += devtl.html_legend.format(order, p['color'], name, id) 489562306a36Sopenharmony_ci devtl.html += '</div>\n' 489662306a36Sopenharmony_ci 489762306a36Sopenharmony_ci hf = open(sysvals.htmlfile, 'w') 489862306a36Sopenharmony_ci addCSS(hf, sysvals, len(testruns), kerror) 489962306a36Sopenharmony_ci 490062306a36Sopenharmony_ci # write the device timeline 490162306a36Sopenharmony_ci hf.write(devtl.html) 490262306a36Sopenharmony_ci hf.write('<div id="devicedetailtitle"></div>\n') 490362306a36Sopenharmony_ci hf.write('<div id="devicedetail" style="display:none;">\n') 490462306a36Sopenharmony_ci # draw the colored boxes for the device detail section 490562306a36Sopenharmony_ci for data in testruns: 490662306a36Sopenharmony_ci hf.write('<div id="devicedetail%d">\n' % data.testnumber) 490762306a36Sopenharmony_ci pscolor = 'linear-gradient(to top left, #ccc, #eee)' 490862306a36Sopenharmony_ci hf.write(devtl.html_phaselet.format('pre_suspend_process', \ 490962306a36Sopenharmony_ci '0', '0', pscolor)) 491062306a36Sopenharmony_ci for b in data.sortedPhases(): 491162306a36Sopenharmony_ci phase = data.dmesg[b] 491262306a36Sopenharmony_ci length = phase['end']-phase['start'] 491362306a36Sopenharmony_ci left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) 491462306a36Sopenharmony_ci width = '%.3f' % ((length*100.0)/tTotal) 491562306a36Sopenharmony_ci hf.write(devtl.html_phaselet.format(b, left, width, \ 491662306a36Sopenharmony_ci data.dmesg[b]['color'])) 491762306a36Sopenharmony_ci hf.write(devtl.html_phaselet.format('post_resume_process', \ 491862306a36Sopenharmony_ci '0', '0', pscolor)) 491962306a36Sopenharmony_ci if sysvals.suspendmode == 'command': 492062306a36Sopenharmony_ci hf.write(devtl.html_phaselet.format('cmdexec', '0', '0', pscolor)) 492162306a36Sopenharmony_ci hf.write('</div>\n') 492262306a36Sopenharmony_ci hf.write('</div>\n') 492362306a36Sopenharmony_ci 492462306a36Sopenharmony_ci # write the ftrace data (callgraph) 492562306a36Sopenharmony_ci if sysvals.cgtest >= 0 and len(testruns) > sysvals.cgtest: 492662306a36Sopenharmony_ci data = testruns[sysvals.cgtest] 492762306a36Sopenharmony_ci else: 492862306a36Sopenharmony_ci data = testruns[-1] 492962306a36Sopenharmony_ci if sysvals.usecallgraph: 493062306a36Sopenharmony_ci addCallgraphs(sysvals, hf, data) 493162306a36Sopenharmony_ci 493262306a36Sopenharmony_ci # add the test log as a hidden div 493362306a36Sopenharmony_ci if sysvals.testlog and sysvals.logmsg: 493462306a36Sopenharmony_ci hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') 493562306a36Sopenharmony_ci # add the dmesg log as a hidden div 493662306a36Sopenharmony_ci if sysvals.dmesglog and sysvals.dmesgfile: 493762306a36Sopenharmony_ci hf.write('<div id="dmesglog" style="display:none;">\n') 493862306a36Sopenharmony_ci lf = sysvals.openlog(sysvals.dmesgfile, 'r') 493962306a36Sopenharmony_ci for line in lf: 494062306a36Sopenharmony_ci line = line.replace('<', '<').replace('>', '>') 494162306a36Sopenharmony_ci hf.write(line) 494262306a36Sopenharmony_ci lf.close() 494362306a36Sopenharmony_ci hf.write('</div>\n') 494462306a36Sopenharmony_ci # add the ftrace log as a hidden div 494562306a36Sopenharmony_ci if sysvals.ftracelog and sysvals.ftracefile: 494662306a36Sopenharmony_ci hf.write('<div id="ftracelog" style="display:none;">\n') 494762306a36Sopenharmony_ci lf = sysvals.openlog(sysvals.ftracefile, 'r') 494862306a36Sopenharmony_ci for line in lf: 494962306a36Sopenharmony_ci hf.write(line) 495062306a36Sopenharmony_ci lf.close() 495162306a36Sopenharmony_ci hf.write('</div>\n') 495262306a36Sopenharmony_ci 495362306a36Sopenharmony_ci # write the footer and close 495462306a36Sopenharmony_ci addScriptCode(hf, testruns) 495562306a36Sopenharmony_ci hf.write('</body>\n</html>\n') 495662306a36Sopenharmony_ci hf.close() 495762306a36Sopenharmony_ci return True 495862306a36Sopenharmony_ci 495962306a36Sopenharmony_cidef addCSS(hf, sv, testcount=1, kerror=False, extra=''): 496062306a36Sopenharmony_ci kernel = sv.stamp['kernel'] 496162306a36Sopenharmony_ci host = sv.hostname[0].upper()+sv.hostname[1:] 496262306a36Sopenharmony_ci mode = sv.suspendmode 496362306a36Sopenharmony_ci if sv.suspendmode in suspendmodename: 496462306a36Sopenharmony_ci mode = suspendmodename[sv.suspendmode] 496562306a36Sopenharmony_ci title = host+' '+mode+' '+kernel 496662306a36Sopenharmony_ci 496762306a36Sopenharmony_ci # various format changes by flags 496862306a36Sopenharmony_ci cgchk = 'checked' 496962306a36Sopenharmony_ci cgnchk = 'not(:checked)' 497062306a36Sopenharmony_ci if sv.cgexp: 497162306a36Sopenharmony_ci cgchk = 'not(:checked)' 497262306a36Sopenharmony_ci cgnchk = 'checked' 497362306a36Sopenharmony_ci 497462306a36Sopenharmony_ci hoverZ = 'z-index:8;' 497562306a36Sopenharmony_ci if sv.usedevsrc: 497662306a36Sopenharmony_ci hoverZ = '' 497762306a36Sopenharmony_ci 497862306a36Sopenharmony_ci devlistpos = 'absolute' 497962306a36Sopenharmony_ci if testcount > 1: 498062306a36Sopenharmony_ci devlistpos = 'relative' 498162306a36Sopenharmony_ci 498262306a36Sopenharmony_ci scaleTH = 20 498362306a36Sopenharmony_ci if kerror: 498462306a36Sopenharmony_ci scaleTH = 60 498562306a36Sopenharmony_ci 498662306a36Sopenharmony_ci # write the html header first (html head, css code, up to body start) 498762306a36Sopenharmony_ci html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ 498862306a36Sopenharmony_ci <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 498962306a36Sopenharmony_ci <title>'+title+'</title>\n\ 499062306a36Sopenharmony_ci <style type=\'text/css\'>\n\ 499162306a36Sopenharmony_ci body {overflow-y:scroll;}\n\ 499262306a36Sopenharmony_ci .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ 499362306a36Sopenharmony_ci .stamp.sysinfo {font:10px Arial;}\n\ 499462306a36Sopenharmony_ci .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ 499562306a36Sopenharmony_ci .callgraph article * {padding-left:28px;}\n\ 499662306a36Sopenharmony_ci h1 {color:black;font:bold 30px Times;}\n\ 499762306a36Sopenharmony_ci t0 {color:black;font:bold 30px Times;}\n\ 499862306a36Sopenharmony_ci t1 {color:black;font:30px Times;}\n\ 499962306a36Sopenharmony_ci t2 {color:black;font:25px Times;}\n\ 500062306a36Sopenharmony_ci t3 {color:black;font:20px Times;white-space:nowrap;}\n\ 500162306a36Sopenharmony_ci t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ 500262306a36Sopenharmony_ci cS {font:bold 13px Times;}\n\ 500362306a36Sopenharmony_ci table {width:100%;}\n\ 500462306a36Sopenharmony_ci .gray {background:rgba(80,80,80,0.1);}\n\ 500562306a36Sopenharmony_ci .green {background:rgba(204,255,204,0.4);}\n\ 500662306a36Sopenharmony_ci .purple {background:rgba(128,0,128,0.2);}\n\ 500762306a36Sopenharmony_ci .yellow {background:rgba(255,255,204,0.4);}\n\ 500862306a36Sopenharmony_ci .blue {background:rgba(169,208,245,0.4);}\n\ 500962306a36Sopenharmony_ci .time1 {font:22px Arial;border:1px solid;}\n\ 501062306a36Sopenharmony_ci .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ 501162306a36Sopenharmony_ci .testfail {font:bold 22px Arial;color:red;border:1px dashed;}\n\ 501262306a36Sopenharmony_ci td {text-align:center;}\n\ 501362306a36Sopenharmony_ci r {color:#500000;font:15px Tahoma;}\n\ 501462306a36Sopenharmony_ci n {color:#505050;font:15px Tahoma;}\n\ 501562306a36Sopenharmony_ci .tdhl {color:red;}\n\ 501662306a36Sopenharmony_ci .hide {display:none;}\n\ 501762306a36Sopenharmony_ci .pf {display:none;}\n\ 501862306a36Sopenharmony_ci .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\ 501962306a36Sopenharmony_ci .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\ 502062306a36Sopenharmony_ci .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ 502162306a36Sopenharmony_ci .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ 502262306a36Sopenharmony_ci .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ 502362306a36Sopenharmony_ci .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\ 502462306a36Sopenharmony_ci .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ 502562306a36Sopenharmony_ci .thread:hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 502662306a36Sopenharmony_ci .thread.sec,.thread.sec:hover {background:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ 502762306a36Sopenharmony_ci .hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 502862306a36Sopenharmony_ci .hover.sync {background:white;}\n\ 502962306a36Sopenharmony_ci .hover.bg,.hover.kth,.hover.sync,.hover.ps {background:white;}\n\ 503062306a36Sopenharmony_ci .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ 503162306a36Sopenharmony_ci .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\ 503262306a36Sopenharmony_ci .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ 503362306a36Sopenharmony_ci .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ 503462306a36Sopenharmony_ci .phaselet {float:left;overflow:hidden;border:0px;text-align:center;min-height:100px;font-size:24px;}\n\ 503562306a36Sopenharmony_ci .t {position:absolute;line-height:'+('%d'%scaleTH)+'px;pointer-events:none;top:0;height:100%;border-right:1px solid black;z-index:6;}\n\ 503662306a36Sopenharmony_ci .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\ 503762306a36Sopenharmony_ci .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ 503862306a36Sopenharmony_ci .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ 503962306a36Sopenharmony_ci button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ 504062306a36Sopenharmony_ci .btnfmt {position:relative;float:right;height:25px;width:auto;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ 504162306a36Sopenharmony_ci .devlist {position:'+devlistpos+';width:190px;}\n\ 504262306a36Sopenharmony_ci a:link {color:white;text-decoration:none;}\n\ 504362306a36Sopenharmony_ci a:visited {color:white;}\n\ 504462306a36Sopenharmony_ci a:hover {color:white;}\n\ 504562306a36Sopenharmony_ci a:active {color:white;}\n\ 504662306a36Sopenharmony_ci .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ 504762306a36Sopenharmony_ci #devicedetail {min-height:100px;box-shadow:5px 5px 20px black;}\n\ 504862306a36Sopenharmony_ci .tblock {position:absolute;height:100%;background:#ddd;}\n\ 504962306a36Sopenharmony_ci .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ 505062306a36Sopenharmony_ci .bg {z-index:1;}\n\ 505162306a36Sopenharmony_ci'+extra+'\ 505262306a36Sopenharmony_ci </style>\n</head>\n<body>\n' 505362306a36Sopenharmony_ci hf.write(html_header) 505462306a36Sopenharmony_ci 505562306a36Sopenharmony_ci# Function: addScriptCode 505662306a36Sopenharmony_ci# Description: 505762306a36Sopenharmony_ci# Adds the javascript code to the output html 505862306a36Sopenharmony_ci# Arguments: 505962306a36Sopenharmony_ci# hf: the open html file pointer 506062306a36Sopenharmony_ci# testruns: array of Data objects from parseKernelLog or parseTraceLog 506162306a36Sopenharmony_cidef addScriptCode(hf, testruns): 506262306a36Sopenharmony_ci t0 = testruns[0].start * 1000 506362306a36Sopenharmony_ci tMax = testruns[-1].end * 1000 506462306a36Sopenharmony_ci # create an array in javascript memory with the device details 506562306a36Sopenharmony_ci detail = ' var devtable = [];\n' 506662306a36Sopenharmony_ci for data in testruns: 506762306a36Sopenharmony_ci topo = data.deviceTopology() 506862306a36Sopenharmony_ci detail += ' devtable[%d] = "%s";\n' % (data.testnumber, topo) 506962306a36Sopenharmony_ci detail += ' var bounds = [%f,%f];\n' % (t0, tMax) 507062306a36Sopenharmony_ci # add the code which will manipulate the data in the browser 507162306a36Sopenharmony_ci script_code = \ 507262306a36Sopenharmony_ci '<script type="text/javascript">\n'+detail+\ 507362306a36Sopenharmony_ci ' var resolution = -1;\n'\ 507462306a36Sopenharmony_ci ' var dragval = [0, 0];\n'\ 507562306a36Sopenharmony_ci ' function redrawTimescale(t0, tMax, tS) {\n'\ 507662306a36Sopenharmony_ci ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;">\';\n'\ 507762306a36Sopenharmony_ci ' var tTotal = tMax - t0;\n'\ 507862306a36Sopenharmony_ci ' var list = document.getElementsByClassName("tblock");\n'\ 507962306a36Sopenharmony_ci ' for (var i = 0; i < list.length; i++) {\n'\ 508062306a36Sopenharmony_ci ' var timescale = list[i].getElementsByClassName("timescale")[0];\n'\ 508162306a36Sopenharmony_ci ' var m0 = t0 + (tTotal*parseFloat(list[i].style.left)/100);\n'\ 508262306a36Sopenharmony_ci ' var mTotal = tTotal*parseFloat(list[i].style.width)/100;\n'\ 508362306a36Sopenharmony_ci ' var mMax = m0 + mTotal;\n'\ 508462306a36Sopenharmony_ci ' var html = "";\n'\ 508562306a36Sopenharmony_ci ' var divTotal = Math.floor(mTotal/tS) + 1;\n'\ 508662306a36Sopenharmony_ci ' if(divTotal > 1000) continue;\n'\ 508762306a36Sopenharmony_ci ' var divEdge = (mTotal - tS*(divTotal-1))*100/mTotal;\n'\ 508862306a36Sopenharmony_ci ' var pos = 0.0, val = 0.0;\n'\ 508962306a36Sopenharmony_ci ' for (var j = 0; j < divTotal; j++) {\n'\ 509062306a36Sopenharmony_ci ' var htmlline = "";\n'\ 509162306a36Sopenharmony_ci ' var mode = list[i].id[5];\n'\ 509262306a36Sopenharmony_ci ' if(mode == "s") {\n'\ 509362306a36Sopenharmony_ci ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\ 509462306a36Sopenharmony_ci ' val = (j-divTotal+1)*tS;\n'\ 509562306a36Sopenharmony_ci ' if(j == divTotal - 1)\n'\ 509662306a36Sopenharmony_ci ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S→</cS></div>\';\n'\ 509762306a36Sopenharmony_ci ' else\n'\ 509862306a36Sopenharmony_ci ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 509962306a36Sopenharmony_ci ' } else {\n'\ 510062306a36Sopenharmony_ci ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ 510162306a36Sopenharmony_ci ' val = (j)*tS;\n'\ 510262306a36Sopenharmony_ci ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 510362306a36Sopenharmony_ci ' if(j == 0)\n'\ 510462306a36Sopenharmony_ci ' if(mode == "r")\n'\ 510562306a36Sopenharmony_ci ' htmlline = rline+"<cS>←R</cS></div>";\n'\ 510662306a36Sopenharmony_ci ' else\n'\ 510762306a36Sopenharmony_ci ' htmlline = rline+"<cS>0ms</div>";\n'\ 510862306a36Sopenharmony_ci ' }\n'\ 510962306a36Sopenharmony_ci ' html += htmlline;\n'\ 511062306a36Sopenharmony_ci ' }\n'\ 511162306a36Sopenharmony_ci ' timescale.innerHTML = html;\n'\ 511262306a36Sopenharmony_ci ' }\n'\ 511362306a36Sopenharmony_ci ' }\n'\ 511462306a36Sopenharmony_ci ' function zoomTimeline() {\n'\ 511562306a36Sopenharmony_ci ' var dmesg = document.getElementById("dmesg");\n'\ 511662306a36Sopenharmony_ci ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 511762306a36Sopenharmony_ci ' var left = zoombox.scrollLeft;\n'\ 511862306a36Sopenharmony_ci ' var val = parseFloat(dmesg.style.width);\n'\ 511962306a36Sopenharmony_ci ' var newval = 100;\n'\ 512062306a36Sopenharmony_ci ' var sh = window.outerWidth / 2;\n'\ 512162306a36Sopenharmony_ci ' if(this.id == "zoomin") {\n'\ 512262306a36Sopenharmony_ci ' newval = val * 1.2;\n'\ 512362306a36Sopenharmony_ci ' if(newval > 910034) newval = 910034;\n'\ 512462306a36Sopenharmony_ci ' dmesg.style.width = newval+"%";\n'\ 512562306a36Sopenharmony_ci ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 512662306a36Sopenharmony_ci ' } else if (this.id == "zoomout") {\n'\ 512762306a36Sopenharmony_ci ' newval = val / 1.2;\n'\ 512862306a36Sopenharmony_ci ' if(newval < 100) newval = 100;\n'\ 512962306a36Sopenharmony_ci ' dmesg.style.width = newval+"%";\n'\ 513062306a36Sopenharmony_ci ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 513162306a36Sopenharmony_ci ' } else {\n'\ 513262306a36Sopenharmony_ci ' zoombox.scrollLeft = 0;\n'\ 513362306a36Sopenharmony_ci ' dmesg.style.width = "100%";\n'\ 513462306a36Sopenharmony_ci ' }\n'\ 513562306a36Sopenharmony_ci ' var tS = [10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1];\n'\ 513662306a36Sopenharmony_ci ' var t0 = bounds[0];\n'\ 513762306a36Sopenharmony_ci ' var tMax = bounds[1];\n'\ 513862306a36Sopenharmony_ci ' var tTotal = tMax - t0;\n'\ 513962306a36Sopenharmony_ci ' var wTotal = tTotal * 100.0 / newval;\n'\ 514062306a36Sopenharmony_ci ' var idx = 7*window.innerWidth/1100;\n'\ 514162306a36Sopenharmony_ci ' for(var i = 0; (i < tS.length)&&((wTotal / tS[i]) < idx); i++);\n'\ 514262306a36Sopenharmony_ci ' if(i >= tS.length) i = tS.length - 1;\n'\ 514362306a36Sopenharmony_ci ' if(tS[i] == resolution) return;\n'\ 514462306a36Sopenharmony_ci ' resolution = tS[i];\n'\ 514562306a36Sopenharmony_ci ' redrawTimescale(t0, tMax, tS[i]);\n'\ 514662306a36Sopenharmony_ci ' }\n'\ 514762306a36Sopenharmony_ci ' function deviceName(title) {\n'\ 514862306a36Sopenharmony_ci ' var name = title.slice(0, title.indexOf(" ("));\n'\ 514962306a36Sopenharmony_ci ' return name;\n'\ 515062306a36Sopenharmony_ci ' }\n'\ 515162306a36Sopenharmony_ci ' function deviceHover() {\n'\ 515262306a36Sopenharmony_ci ' var name = deviceName(this.title);\n'\ 515362306a36Sopenharmony_ci ' var dmesg = document.getElementById("dmesg");\n'\ 515462306a36Sopenharmony_ci ' var dev = dmesg.getElementsByClassName("thread");\n'\ 515562306a36Sopenharmony_ci ' var cpu = -1;\n'\ 515662306a36Sopenharmony_ci ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 515762306a36Sopenharmony_ci ' cpu = parseInt(name.slice(7));\n'\ 515862306a36Sopenharmony_ci ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 515962306a36Sopenharmony_ci ' cpu = parseInt(name.slice(8));\n'\ 516062306a36Sopenharmony_ci ' for (var i = 0; i < dev.length; i++) {\n'\ 516162306a36Sopenharmony_ci ' dname = deviceName(dev[i].title);\n'\ 516262306a36Sopenharmony_ci ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 516362306a36Sopenharmony_ci ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 516462306a36Sopenharmony_ci ' (name == dname))\n'\ 516562306a36Sopenharmony_ci ' {\n'\ 516662306a36Sopenharmony_ci ' dev[i].className = "hover "+cname;\n'\ 516762306a36Sopenharmony_ci ' } else {\n'\ 516862306a36Sopenharmony_ci ' dev[i].className = cname;\n'\ 516962306a36Sopenharmony_ci ' }\n'\ 517062306a36Sopenharmony_ci ' }\n'\ 517162306a36Sopenharmony_ci ' }\n'\ 517262306a36Sopenharmony_ci ' function deviceUnhover() {\n'\ 517362306a36Sopenharmony_ci ' var dmesg = document.getElementById("dmesg");\n'\ 517462306a36Sopenharmony_ci ' var dev = dmesg.getElementsByClassName("thread");\n'\ 517562306a36Sopenharmony_ci ' for (var i = 0; i < dev.length; i++) {\n'\ 517662306a36Sopenharmony_ci ' dev[i].className = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 517762306a36Sopenharmony_ci ' }\n'\ 517862306a36Sopenharmony_ci ' }\n'\ 517962306a36Sopenharmony_ci ' function deviceTitle(title, total, cpu) {\n'\ 518062306a36Sopenharmony_ci ' var prefix = "Total";\n'\ 518162306a36Sopenharmony_ci ' if(total.length > 3) {\n'\ 518262306a36Sopenharmony_ci ' prefix = "Average";\n'\ 518362306a36Sopenharmony_ci ' total[1] = (total[1]+total[3])/2;\n'\ 518462306a36Sopenharmony_ci ' total[2] = (total[2]+total[4])/2;\n'\ 518562306a36Sopenharmony_ci ' }\n'\ 518662306a36Sopenharmony_ci ' var devtitle = document.getElementById("devicedetailtitle");\n'\ 518762306a36Sopenharmony_ci ' var name = deviceName(title);\n'\ 518862306a36Sopenharmony_ci ' if(cpu >= 0) name = "CPU"+cpu;\n'\ 518962306a36Sopenharmony_ci ' var driver = "";\n'\ 519062306a36Sopenharmony_ci ' var tS = "<t2>(</t2>";\n'\ 519162306a36Sopenharmony_ci ' var tR = "<t2>)</t2>";\n'\ 519262306a36Sopenharmony_ci ' if(total[1] > 0)\n'\ 519362306a36Sopenharmony_ci ' tS = "<t2>("+prefix+" Suspend:</t2><t0> "+total[1].toFixed(3)+" ms</t0> ";\n'\ 519462306a36Sopenharmony_ci ' if(total[2] > 0)\n'\ 519562306a36Sopenharmony_ci ' tR = " <t2>"+prefix+" Resume:</t2><t0> "+total[2].toFixed(3)+" ms<t2>)</t2></t0>";\n'\ 519662306a36Sopenharmony_ci ' var s = title.indexOf("{");\n'\ 519762306a36Sopenharmony_ci ' var e = title.indexOf("}");\n'\ 519862306a36Sopenharmony_ci ' if((s >= 0) && (e >= 0))\n'\ 519962306a36Sopenharmony_ci ' driver = title.slice(s+1, e) + " <t1>@</t1> ";\n'\ 520062306a36Sopenharmony_ci ' if(total[1] > 0 && total[2] > 0)\n'\ 520162306a36Sopenharmony_ci ' devtitle.innerHTML = "<t0>"+driver+name+"</t0> "+tS+tR;\n'\ 520262306a36Sopenharmony_ci ' else\n'\ 520362306a36Sopenharmony_ci ' devtitle.innerHTML = "<t0>"+title+"</t0>";\n'\ 520462306a36Sopenharmony_ci ' return name;\n'\ 520562306a36Sopenharmony_ci ' }\n'\ 520662306a36Sopenharmony_ci ' function deviceDetail() {\n'\ 520762306a36Sopenharmony_ci ' var devinfo = document.getElementById("devicedetail");\n'\ 520862306a36Sopenharmony_ci ' devinfo.style.display = "block";\n'\ 520962306a36Sopenharmony_ci ' var name = deviceName(this.title);\n'\ 521062306a36Sopenharmony_ci ' var cpu = -1;\n'\ 521162306a36Sopenharmony_ci ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 521262306a36Sopenharmony_ci ' cpu = parseInt(name.slice(7));\n'\ 521362306a36Sopenharmony_ci ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 521462306a36Sopenharmony_ci ' cpu = parseInt(name.slice(8));\n'\ 521562306a36Sopenharmony_ci ' var dmesg = document.getElementById("dmesg");\n'\ 521662306a36Sopenharmony_ci ' var dev = dmesg.getElementsByClassName("thread");\n'\ 521762306a36Sopenharmony_ci ' var idlist = [];\n'\ 521862306a36Sopenharmony_ci ' var pdata = [[]];\n'\ 521962306a36Sopenharmony_ci ' if(document.getElementById("devicedetail1"))\n'\ 522062306a36Sopenharmony_ci ' pdata = [[], []];\n'\ 522162306a36Sopenharmony_ci ' var pd = pdata[0];\n'\ 522262306a36Sopenharmony_ci ' var total = [0.0, 0.0, 0.0];\n'\ 522362306a36Sopenharmony_ci ' for (var i = 0; i < dev.length; i++) {\n'\ 522462306a36Sopenharmony_ci ' dname = deviceName(dev[i].title);\n'\ 522562306a36Sopenharmony_ci ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 522662306a36Sopenharmony_ci ' (name == dname))\n'\ 522762306a36Sopenharmony_ci ' {\n'\ 522862306a36Sopenharmony_ci ' idlist[idlist.length] = dev[i].id;\n'\ 522962306a36Sopenharmony_ci ' var tidx = 1;\n'\ 523062306a36Sopenharmony_ci ' if(dev[i].id[0] == "a") {\n'\ 523162306a36Sopenharmony_ci ' pd = pdata[0];\n'\ 523262306a36Sopenharmony_ci ' } else {\n'\ 523362306a36Sopenharmony_ci ' if(pdata.length == 1) pdata[1] = [];\n'\ 523462306a36Sopenharmony_ci ' if(total.length == 3) total[3]=total[4]=0.0;\n'\ 523562306a36Sopenharmony_ci ' pd = pdata[1];\n'\ 523662306a36Sopenharmony_ci ' tidx = 3;\n'\ 523762306a36Sopenharmony_ci ' }\n'\ 523862306a36Sopenharmony_ci ' var info = dev[i].title.split(" ");\n'\ 523962306a36Sopenharmony_ci ' var pname = info[info.length-1];\n'\ 524062306a36Sopenharmony_ci ' pd[pname] = parseFloat(info[info.length-3].slice(1));\n'\ 524162306a36Sopenharmony_ci ' total[0] += pd[pname];\n'\ 524262306a36Sopenharmony_ci ' if(pname.indexOf("suspend") >= 0)\n'\ 524362306a36Sopenharmony_ci ' total[tidx] += pd[pname];\n'\ 524462306a36Sopenharmony_ci ' else\n'\ 524562306a36Sopenharmony_ci ' total[tidx+1] += pd[pname];\n'\ 524662306a36Sopenharmony_ci ' }\n'\ 524762306a36Sopenharmony_ci ' }\n'\ 524862306a36Sopenharmony_ci ' var devname = deviceTitle(this.title, total, cpu);\n'\ 524962306a36Sopenharmony_ci ' var left = 0.0;\n'\ 525062306a36Sopenharmony_ci ' for (var t = 0; t < pdata.length; t++) {\n'\ 525162306a36Sopenharmony_ci ' pd = pdata[t];\n'\ 525262306a36Sopenharmony_ci ' devinfo = document.getElementById("devicedetail"+t);\n'\ 525362306a36Sopenharmony_ci ' var phases = devinfo.getElementsByClassName("phaselet");\n'\ 525462306a36Sopenharmony_ci ' for (var i = 0; i < phases.length; i++) {\n'\ 525562306a36Sopenharmony_ci ' if(phases[i].id in pd) {\n'\ 525662306a36Sopenharmony_ci ' var w = 100.0*pd[phases[i].id]/total[0];\n'\ 525762306a36Sopenharmony_ci ' var fs = 32;\n'\ 525862306a36Sopenharmony_ci ' if(w < 8) fs = 4*w | 0;\n'\ 525962306a36Sopenharmony_ci ' var fs2 = fs*3/4;\n'\ 526062306a36Sopenharmony_ci ' phases[i].style.width = w+"%";\n'\ 526162306a36Sopenharmony_ci ' phases[i].style.left = left+"%";\n'\ 526262306a36Sopenharmony_ci ' phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\ 526362306a36Sopenharmony_ci ' left += w;\n'\ 526462306a36Sopenharmony_ci ' var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\ 526562306a36Sopenharmony_ci ' var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";\n'\ 526662306a36Sopenharmony_ci ' phases[i].innerHTML = time+pname;\n'\ 526762306a36Sopenharmony_ci ' } else {\n'\ 526862306a36Sopenharmony_ci ' phases[i].style.width = "0%";\n'\ 526962306a36Sopenharmony_ci ' phases[i].style.left = left+"%";\n'\ 527062306a36Sopenharmony_ci ' }\n'\ 527162306a36Sopenharmony_ci ' }\n'\ 527262306a36Sopenharmony_ci ' }\n'\ 527362306a36Sopenharmony_ci ' if(typeof devstats !== \'undefined\')\n'\ 527462306a36Sopenharmony_ci ' callDetail(this.id, this.title);\n'\ 527562306a36Sopenharmony_ci ' var cglist = document.getElementById("callgraphs");\n'\ 527662306a36Sopenharmony_ci ' if(!cglist) return;\n'\ 527762306a36Sopenharmony_ci ' var cg = cglist.getElementsByClassName("atop");\n'\ 527862306a36Sopenharmony_ci ' if(cg.length < 10) return;\n'\ 527962306a36Sopenharmony_ci ' for (var i = 0; i < cg.length; i++) {\n'\ 528062306a36Sopenharmony_ci ' cgid = cg[i].id.split("x")[0]\n'\ 528162306a36Sopenharmony_ci ' if(idlist.indexOf(cgid) >= 0) {\n'\ 528262306a36Sopenharmony_ci ' cg[i].style.display = "block";\n'\ 528362306a36Sopenharmony_ci ' } else {\n'\ 528462306a36Sopenharmony_ci ' cg[i].style.display = "none";\n'\ 528562306a36Sopenharmony_ci ' }\n'\ 528662306a36Sopenharmony_ci ' }\n'\ 528762306a36Sopenharmony_ci ' }\n'\ 528862306a36Sopenharmony_ci ' function callDetail(devid, devtitle) {\n'\ 528962306a36Sopenharmony_ci ' if(!(devid in devstats) || devstats[devid].length < 1)\n'\ 529062306a36Sopenharmony_ci ' return;\n'\ 529162306a36Sopenharmony_ci ' var list = devstats[devid];\n'\ 529262306a36Sopenharmony_ci ' var tmp = devtitle.split(" ");\n'\ 529362306a36Sopenharmony_ci ' var name = tmp[0], phase = tmp[tmp.length-1];\n'\ 529462306a36Sopenharmony_ci ' var dd = document.getElementById(phase);\n'\ 529562306a36Sopenharmony_ci ' var total = parseFloat(tmp[1].slice(1));\n'\ 529662306a36Sopenharmony_ci ' var mlist = [];\n'\ 529762306a36Sopenharmony_ci ' var maxlen = 0;\n'\ 529862306a36Sopenharmony_ci ' var info = []\n'\ 529962306a36Sopenharmony_ci ' for(var i in list) {\n'\ 530062306a36Sopenharmony_ci ' if(list[i][0] == "@") {\n'\ 530162306a36Sopenharmony_ci ' info = list[i].split("|");\n'\ 530262306a36Sopenharmony_ci ' continue;\n'\ 530362306a36Sopenharmony_ci ' }\n'\ 530462306a36Sopenharmony_ci ' var tmp = list[i].split("|");\n'\ 530562306a36Sopenharmony_ci ' var t = parseFloat(tmp[0]), f = tmp[1], c = parseInt(tmp[2]);\n'\ 530662306a36Sopenharmony_ci ' var p = (t*100.0/total).toFixed(2);\n'\ 530762306a36Sopenharmony_ci ' mlist[mlist.length] = [f, c, t.toFixed(2), p+"%"];\n'\ 530862306a36Sopenharmony_ci ' if(f.length > maxlen)\n'\ 530962306a36Sopenharmony_ci ' maxlen = f.length;\n'\ 531062306a36Sopenharmony_ci ' }\n'\ 531162306a36Sopenharmony_ci ' var pad = 5;\n'\ 531262306a36Sopenharmony_ci ' if(mlist.length == 0) pad = 30;\n'\ 531362306a36Sopenharmony_ci ' var html = \'<div style="padding-top:\'+pad+\'px"><t3> <b>\'+name+\':</b>\';\n'\ 531462306a36Sopenharmony_ci ' if(info.length > 2)\n'\ 531562306a36Sopenharmony_ci ' html += " start=<b>"+info[1]+"</b>, end=<b>"+info[2]+"</b>";\n'\ 531662306a36Sopenharmony_ci ' if(info.length > 3)\n'\ 531762306a36Sopenharmony_ci ' html += ", length<i>(w/o overhead)</i>=<b>"+info[3]+" ms</b>";\n'\ 531862306a36Sopenharmony_ci ' if(info.length > 4)\n'\ 531962306a36Sopenharmony_ci ' html += ", return=<b>"+info[4]+"</b>";\n'\ 532062306a36Sopenharmony_ci ' html += "</t3></div>";\n'\ 532162306a36Sopenharmony_ci ' if(mlist.length > 0) {\n'\ 532262306a36Sopenharmony_ci ' html += \'<table class=fstat style="padding-top:\'+(maxlen*5)+\'px;"><tr><th>Function</th>\';\n'\ 532362306a36Sopenharmony_ci ' for(var i in mlist)\n'\ 532462306a36Sopenharmony_ci ' html += "<td class=vt>"+mlist[i][0]+"</td>";\n'\ 532562306a36Sopenharmony_ci ' html += "</tr><tr><th>Calls</th>";\n'\ 532662306a36Sopenharmony_ci ' for(var i in mlist)\n'\ 532762306a36Sopenharmony_ci ' html += "<td>"+mlist[i][1]+"</td>";\n'\ 532862306a36Sopenharmony_ci ' html += "</tr><tr><th>Time(ms)</th>";\n'\ 532962306a36Sopenharmony_ci ' for(var i in mlist)\n'\ 533062306a36Sopenharmony_ci ' html += "<td>"+mlist[i][2]+"</td>";\n'\ 533162306a36Sopenharmony_ci ' html += "</tr><tr><th>Percent</th>";\n'\ 533262306a36Sopenharmony_ci ' for(var i in mlist)\n'\ 533362306a36Sopenharmony_ci ' html += "<td>"+mlist[i][3]+"</td>";\n'\ 533462306a36Sopenharmony_ci ' html += "</tr></table>";\n'\ 533562306a36Sopenharmony_ci ' }\n'\ 533662306a36Sopenharmony_ci ' dd.innerHTML = html;\n'\ 533762306a36Sopenharmony_ci ' var height = (maxlen*5)+100;\n'\ 533862306a36Sopenharmony_ci ' dd.style.height = height+"px";\n'\ 533962306a36Sopenharmony_ci ' document.getElementById("devicedetail").style.height = height+"px";\n'\ 534062306a36Sopenharmony_ci ' }\n'\ 534162306a36Sopenharmony_ci ' function callSelect() {\n'\ 534262306a36Sopenharmony_ci ' var cglist = document.getElementById("callgraphs");\n'\ 534362306a36Sopenharmony_ci ' if(!cglist) return;\n'\ 534462306a36Sopenharmony_ci ' var cg = cglist.getElementsByClassName("atop");\n'\ 534562306a36Sopenharmony_ci ' for (var i = 0; i < cg.length; i++) {\n'\ 534662306a36Sopenharmony_ci ' if(this.id == cg[i].id) {\n'\ 534762306a36Sopenharmony_ci ' cg[i].style.display = "block";\n'\ 534862306a36Sopenharmony_ci ' } else {\n'\ 534962306a36Sopenharmony_ci ' cg[i].style.display = "none";\n'\ 535062306a36Sopenharmony_ci ' }\n'\ 535162306a36Sopenharmony_ci ' }\n'\ 535262306a36Sopenharmony_ci ' }\n'\ 535362306a36Sopenharmony_ci ' function devListWindow(e) {\n'\ 535462306a36Sopenharmony_ci ' var win = window.open();\n'\ 535562306a36Sopenharmony_ci ' var html = "<title>"+e.target.innerHTML+"</title>"+\n'\ 535662306a36Sopenharmony_ci ' "<style type=\\"text/css\\">"+\n'\ 535762306a36Sopenharmony_ci ' " ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\ 535862306a36Sopenharmony_ci ' "</style>"\n'\ 535962306a36Sopenharmony_ci ' var dt = devtable[0];\n'\ 536062306a36Sopenharmony_ci ' if(e.target.id != "devlist1")\n'\ 536162306a36Sopenharmony_ci ' dt = devtable[1];\n'\ 536262306a36Sopenharmony_ci ' win.document.write(html+dt);\n'\ 536362306a36Sopenharmony_ci ' }\n'\ 536462306a36Sopenharmony_ci ' function errWindow() {\n'\ 536562306a36Sopenharmony_ci ' var range = this.id.split("_");\n'\ 536662306a36Sopenharmony_ci ' var idx1 = parseInt(range[0]);\n'\ 536762306a36Sopenharmony_ci ' var idx2 = parseInt(range[1]);\n'\ 536862306a36Sopenharmony_ci ' var win = window.open();\n'\ 536962306a36Sopenharmony_ci ' var log = document.getElementById("dmesglog");\n'\ 537062306a36Sopenharmony_ci ' var title = "<title>dmesg log</title>";\n'\ 537162306a36Sopenharmony_ci ' var text = log.innerHTML.split("\\n");\n'\ 537262306a36Sopenharmony_ci ' var html = "";\n'\ 537362306a36Sopenharmony_ci ' for(var i = 0; i < text.length; i++) {\n'\ 537462306a36Sopenharmony_ci ' if(i == idx1) {\n'\ 537562306a36Sopenharmony_ci ' html += "<e id=target>"+text[i]+"</e>\\n";\n'\ 537662306a36Sopenharmony_ci ' } else if(i > idx1 && i <= idx2) {\n'\ 537762306a36Sopenharmony_ci ' html += "<e>"+text[i]+"</e>\\n";\n'\ 537862306a36Sopenharmony_ci ' } else {\n'\ 537962306a36Sopenharmony_ci ' html += text[i]+"\\n";\n'\ 538062306a36Sopenharmony_ci ' }\n'\ 538162306a36Sopenharmony_ci ' }\n'\ 538262306a36Sopenharmony_ci ' win.document.write("<style>e{color:red}</style>"+title+"<pre>"+html+"</pre>");\n'\ 538362306a36Sopenharmony_ci ' win.location.hash = "#target";\n'\ 538462306a36Sopenharmony_ci ' win.document.close();\n'\ 538562306a36Sopenharmony_ci ' }\n'\ 538662306a36Sopenharmony_ci ' function logWindow(e) {\n'\ 538762306a36Sopenharmony_ci ' var name = e.target.id.slice(4);\n'\ 538862306a36Sopenharmony_ci ' var win = window.open();\n'\ 538962306a36Sopenharmony_ci ' var log = document.getElementById(name+"log");\n'\ 539062306a36Sopenharmony_ci ' var title = "<title>"+document.title.split(" ")[0]+" "+name+" log</title>";\n'\ 539162306a36Sopenharmony_ci ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ 539262306a36Sopenharmony_ci ' win.document.close();\n'\ 539362306a36Sopenharmony_ci ' }\n'\ 539462306a36Sopenharmony_ci ' function onMouseDown(e) {\n'\ 539562306a36Sopenharmony_ci ' dragval[0] = e.clientX;\n'\ 539662306a36Sopenharmony_ci ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ 539762306a36Sopenharmony_ci ' document.onmousemove = onMouseMove;\n'\ 539862306a36Sopenharmony_ci ' }\n'\ 539962306a36Sopenharmony_ci ' function onMouseMove(e) {\n'\ 540062306a36Sopenharmony_ci ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 540162306a36Sopenharmony_ci ' zoombox.scrollLeft = dragval[1] + dragval[0] - e.clientX;\n'\ 540262306a36Sopenharmony_ci ' }\n'\ 540362306a36Sopenharmony_ci ' function onMouseUp(e) {\n'\ 540462306a36Sopenharmony_ci ' document.onmousemove = null;\n'\ 540562306a36Sopenharmony_ci ' }\n'\ 540662306a36Sopenharmony_ci ' function onKeyPress(e) {\n'\ 540762306a36Sopenharmony_ci ' var c = e.charCode;\n'\ 540862306a36Sopenharmony_ci ' if(c != 42 && c != 43 && c != 45) return;\n'\ 540962306a36Sopenharmony_ci ' var click = document.createEvent("Events");\n'\ 541062306a36Sopenharmony_ci ' click.initEvent("click", true, false);\n'\ 541162306a36Sopenharmony_ci ' if(c == 43) \n'\ 541262306a36Sopenharmony_ci ' document.getElementById("zoomin").dispatchEvent(click);\n'\ 541362306a36Sopenharmony_ci ' else if(c == 45)\n'\ 541462306a36Sopenharmony_ci ' document.getElementById("zoomout").dispatchEvent(click);\n'\ 541562306a36Sopenharmony_ci ' else if(c == 42)\n'\ 541662306a36Sopenharmony_ci ' document.getElementById("zoomdef").dispatchEvent(click);\n'\ 541762306a36Sopenharmony_ci ' }\n'\ 541862306a36Sopenharmony_ci ' window.addEventListener("resize", function () {zoomTimeline();});\n'\ 541962306a36Sopenharmony_ci ' window.addEventListener("load", function () {\n'\ 542062306a36Sopenharmony_ci ' var dmesg = document.getElementById("dmesg");\n'\ 542162306a36Sopenharmony_ci ' dmesg.style.width = "100%"\n'\ 542262306a36Sopenharmony_ci ' dmesg.onmousedown = onMouseDown;\n'\ 542362306a36Sopenharmony_ci ' document.onmouseup = onMouseUp;\n'\ 542462306a36Sopenharmony_ci ' document.onkeypress = onKeyPress;\n'\ 542562306a36Sopenharmony_ci ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ 542662306a36Sopenharmony_ci ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ 542762306a36Sopenharmony_ci ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ 542862306a36Sopenharmony_ci ' var list = document.getElementsByClassName("err");\n'\ 542962306a36Sopenharmony_ci ' for (var i = 0; i < list.length; i++)\n'\ 543062306a36Sopenharmony_ci ' list[i].onclick = errWindow;\n'\ 543162306a36Sopenharmony_ci ' var list = document.getElementsByClassName("logbtn");\n'\ 543262306a36Sopenharmony_ci ' for (var i = 0; i < list.length; i++)\n'\ 543362306a36Sopenharmony_ci ' list[i].onclick = logWindow;\n'\ 543462306a36Sopenharmony_ci ' list = document.getElementsByClassName("devlist");\n'\ 543562306a36Sopenharmony_ci ' for (var i = 0; i < list.length; i++)\n'\ 543662306a36Sopenharmony_ci ' list[i].onclick = devListWindow;\n'\ 543762306a36Sopenharmony_ci ' var dev = dmesg.getElementsByClassName("thread");\n'\ 543862306a36Sopenharmony_ci ' for (var i = 0; i < dev.length; i++) {\n'\ 543962306a36Sopenharmony_ci ' dev[i].onclick = deviceDetail;\n'\ 544062306a36Sopenharmony_ci ' dev[i].onmouseover = deviceHover;\n'\ 544162306a36Sopenharmony_ci ' dev[i].onmouseout = deviceUnhover;\n'\ 544262306a36Sopenharmony_ci ' }\n'\ 544362306a36Sopenharmony_ci ' var dev = dmesg.getElementsByClassName("srccall");\n'\ 544462306a36Sopenharmony_ci ' for (var i = 0; i < dev.length; i++)\n'\ 544562306a36Sopenharmony_ci ' dev[i].onclick = callSelect;\n'\ 544662306a36Sopenharmony_ci ' zoomTimeline();\n'\ 544762306a36Sopenharmony_ci ' });\n'\ 544862306a36Sopenharmony_ci '</script>\n' 544962306a36Sopenharmony_ci hf.write(script_code); 545062306a36Sopenharmony_ci 545162306a36Sopenharmony_ci# Function: executeSuspend 545262306a36Sopenharmony_ci# Description: 545362306a36Sopenharmony_ci# Execute system suspend through the sysfs interface, then copy the output 545462306a36Sopenharmony_ci# dmesg and ftrace files to the test output directory. 545562306a36Sopenharmony_cidef executeSuspend(quiet=False): 545662306a36Sopenharmony_ci sv, tp, pm = sysvals, sysvals.tpath, ProcessMonitor() 545762306a36Sopenharmony_ci if sv.wifi: 545862306a36Sopenharmony_ci wifi = sv.checkWifi() 545962306a36Sopenharmony_ci sv.dlog('wifi check, connected device is "%s"' % wifi) 546062306a36Sopenharmony_ci testdata = [] 546162306a36Sopenharmony_ci # run these commands to prepare the system for suspend 546262306a36Sopenharmony_ci if sv.display: 546362306a36Sopenharmony_ci if not quiet: 546462306a36Sopenharmony_ci pprint('SET DISPLAY TO %s' % sv.display.upper()) 546562306a36Sopenharmony_ci ret = sv.displayControl(sv.display) 546662306a36Sopenharmony_ci sv.dlog('xset display %s, ret = %d' % (sv.display, ret)) 546762306a36Sopenharmony_ci time.sleep(1) 546862306a36Sopenharmony_ci if sv.sync: 546962306a36Sopenharmony_ci if not quiet: 547062306a36Sopenharmony_ci pprint('SYNCING FILESYSTEMS') 547162306a36Sopenharmony_ci sv.dlog('syncing filesystems') 547262306a36Sopenharmony_ci call('sync', shell=True) 547362306a36Sopenharmony_ci sv.dlog('read dmesg') 547462306a36Sopenharmony_ci sv.initdmesg() 547562306a36Sopenharmony_ci sv.dlog('cmdinfo before') 547662306a36Sopenharmony_ci sv.cmdinfo(True) 547762306a36Sopenharmony_ci sv.start(pm) 547862306a36Sopenharmony_ci # execute however many s/r runs requested 547962306a36Sopenharmony_ci for count in range(1,sv.execcount+1): 548062306a36Sopenharmony_ci # x2delay in between test runs 548162306a36Sopenharmony_ci if(count > 1 and sv.x2delay > 0): 548262306a36Sopenharmony_ci sv.fsetVal('WAIT %d' % sv.x2delay, 'trace_marker') 548362306a36Sopenharmony_ci time.sleep(sv.x2delay/1000.0) 548462306a36Sopenharmony_ci sv.fsetVal('WAIT END', 'trace_marker') 548562306a36Sopenharmony_ci # start message 548662306a36Sopenharmony_ci if sv.testcommand != '': 548762306a36Sopenharmony_ci pprint('COMMAND START') 548862306a36Sopenharmony_ci else: 548962306a36Sopenharmony_ci if(sv.rtcwake): 549062306a36Sopenharmony_ci pprint('SUSPEND START') 549162306a36Sopenharmony_ci else: 549262306a36Sopenharmony_ci pprint('SUSPEND START (press a key to resume)') 549362306a36Sopenharmony_ci # set rtcwake 549462306a36Sopenharmony_ci if(sv.rtcwake): 549562306a36Sopenharmony_ci if not quiet: 549662306a36Sopenharmony_ci pprint('will issue an rtcwake in %d seconds' % sv.rtcwaketime) 549762306a36Sopenharmony_ci sv.dlog('enable RTC wake alarm') 549862306a36Sopenharmony_ci sv.rtcWakeAlarmOn() 549962306a36Sopenharmony_ci # start of suspend trace marker 550062306a36Sopenharmony_ci sv.fsetVal(datetime.now().strftime(sv.tmstart), 'trace_marker') 550162306a36Sopenharmony_ci # predelay delay 550262306a36Sopenharmony_ci if(count == 1 and sv.predelay > 0): 550362306a36Sopenharmony_ci sv.fsetVal('WAIT %d' % sv.predelay, 'trace_marker') 550462306a36Sopenharmony_ci time.sleep(sv.predelay/1000.0) 550562306a36Sopenharmony_ci sv.fsetVal('WAIT END', 'trace_marker') 550662306a36Sopenharmony_ci # initiate suspend or command 550762306a36Sopenharmony_ci sv.dlog('system executing a suspend') 550862306a36Sopenharmony_ci tdata = {'error': ''} 550962306a36Sopenharmony_ci if sv.testcommand != '': 551062306a36Sopenharmony_ci res = call(sv.testcommand+' 2>&1', shell=True); 551162306a36Sopenharmony_ci if res != 0: 551262306a36Sopenharmony_ci tdata['error'] = 'cmd returned %d' % res 551362306a36Sopenharmony_ci else: 551462306a36Sopenharmony_ci s0ixready = sv.s0ixSupport() 551562306a36Sopenharmony_ci mode = sv.suspendmode 551662306a36Sopenharmony_ci if sv.memmode and os.path.exists(sv.mempowerfile): 551762306a36Sopenharmony_ci mode = 'mem' 551862306a36Sopenharmony_ci sv.testVal(sv.mempowerfile, 'radio', sv.memmode) 551962306a36Sopenharmony_ci if sv.diskmode and os.path.exists(sv.diskpowerfile): 552062306a36Sopenharmony_ci mode = 'disk' 552162306a36Sopenharmony_ci sv.testVal(sv.diskpowerfile, 'radio', sv.diskmode) 552262306a36Sopenharmony_ci if sv.acpidebug: 552362306a36Sopenharmony_ci sv.testVal(sv.acpipath, 'acpi', '0xe') 552462306a36Sopenharmony_ci if ((mode == 'freeze') or (sv.memmode == 's2idle')) \ 552562306a36Sopenharmony_ci and sv.haveTurbostat(): 552662306a36Sopenharmony_ci # execution will pause here 552762306a36Sopenharmony_ci turbo = sv.turbostat(s0ixready) 552862306a36Sopenharmony_ci if turbo: 552962306a36Sopenharmony_ci tdata['turbo'] = turbo 553062306a36Sopenharmony_ci else: 553162306a36Sopenharmony_ci pf = open(sv.powerfile, 'w') 553262306a36Sopenharmony_ci pf.write(mode) 553362306a36Sopenharmony_ci # execution will pause here 553462306a36Sopenharmony_ci try: 553562306a36Sopenharmony_ci pf.close() 553662306a36Sopenharmony_ci except Exception as e: 553762306a36Sopenharmony_ci tdata['error'] = str(e) 553862306a36Sopenharmony_ci sv.fsetVal('CMD COMPLETE', 'trace_marker') 553962306a36Sopenharmony_ci sv.dlog('system returned') 554062306a36Sopenharmony_ci # reset everything 554162306a36Sopenharmony_ci sv.testVal('restoreall') 554262306a36Sopenharmony_ci if(sv.rtcwake): 554362306a36Sopenharmony_ci sv.dlog('disable RTC wake alarm') 554462306a36Sopenharmony_ci sv.rtcWakeAlarmOff() 554562306a36Sopenharmony_ci # postdelay delay 554662306a36Sopenharmony_ci if(count == sv.execcount and sv.postdelay > 0): 554762306a36Sopenharmony_ci sv.fsetVal('WAIT %d' % sv.postdelay, 'trace_marker') 554862306a36Sopenharmony_ci time.sleep(sv.postdelay/1000.0) 554962306a36Sopenharmony_ci sv.fsetVal('WAIT END', 'trace_marker') 555062306a36Sopenharmony_ci # return from suspend 555162306a36Sopenharmony_ci pprint('RESUME COMPLETE') 555262306a36Sopenharmony_ci if(count < sv.execcount): 555362306a36Sopenharmony_ci sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker') 555462306a36Sopenharmony_ci elif(not sv.wifitrace): 555562306a36Sopenharmony_ci sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker') 555662306a36Sopenharmony_ci sv.stop(pm) 555762306a36Sopenharmony_ci if sv.wifi and wifi: 555862306a36Sopenharmony_ci tdata['wifi'] = sv.pollWifi(wifi) 555962306a36Sopenharmony_ci sv.dlog('wifi check, %s' % tdata['wifi']) 556062306a36Sopenharmony_ci if(count == sv.execcount and sv.wifitrace): 556162306a36Sopenharmony_ci sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker') 556262306a36Sopenharmony_ci sv.stop(pm) 556362306a36Sopenharmony_ci if sv.netfix: 556462306a36Sopenharmony_ci tdata['netfix'] = sv.netfixon() 556562306a36Sopenharmony_ci sv.dlog('netfix, %s' % tdata['netfix']) 556662306a36Sopenharmony_ci if(sv.suspendmode == 'mem' or sv.suspendmode == 'command'): 556762306a36Sopenharmony_ci sv.dlog('read the ACPI FPDT') 556862306a36Sopenharmony_ci tdata['fw'] = getFPDT(False) 556962306a36Sopenharmony_ci testdata.append(tdata) 557062306a36Sopenharmony_ci sv.dlog('cmdinfo after') 557162306a36Sopenharmony_ci cmdafter = sv.cmdinfo(False) 557262306a36Sopenharmony_ci # grab a copy of the dmesg output 557362306a36Sopenharmony_ci if not quiet: 557462306a36Sopenharmony_ci pprint('CAPTURING DMESG') 557562306a36Sopenharmony_ci sv.getdmesg(testdata) 557662306a36Sopenharmony_ci # grab a copy of the ftrace output 557762306a36Sopenharmony_ci if sv.useftrace: 557862306a36Sopenharmony_ci if not quiet: 557962306a36Sopenharmony_ci pprint('CAPTURING TRACE') 558062306a36Sopenharmony_ci op = sv.writeDatafileHeader(sv.ftracefile, testdata) 558162306a36Sopenharmony_ci fp = open(tp+'trace', 'rb') 558262306a36Sopenharmony_ci op.write(ascii(fp.read())) 558362306a36Sopenharmony_ci op.close() 558462306a36Sopenharmony_ci sv.fsetVal('', 'trace') 558562306a36Sopenharmony_ci sv.platforminfo(cmdafter) 558662306a36Sopenharmony_ci 558762306a36Sopenharmony_cidef readFile(file): 558862306a36Sopenharmony_ci if os.path.islink(file): 558962306a36Sopenharmony_ci return os.readlink(file).split('/')[-1] 559062306a36Sopenharmony_ci else: 559162306a36Sopenharmony_ci return sysvals.getVal(file).strip() 559262306a36Sopenharmony_ci 559362306a36Sopenharmony_ci# Function: ms2nice 559462306a36Sopenharmony_ci# Description: 559562306a36Sopenharmony_ci# Print out a very concise time string in minutes and seconds 559662306a36Sopenharmony_ci# Output: 559762306a36Sopenharmony_ci# The time string, e.g. "1901m16s" 559862306a36Sopenharmony_cidef ms2nice(val): 559962306a36Sopenharmony_ci val = int(val) 560062306a36Sopenharmony_ci h = val // 3600000 560162306a36Sopenharmony_ci m = (val // 60000) % 60 560262306a36Sopenharmony_ci s = (val // 1000) % 60 560362306a36Sopenharmony_ci if h > 0: 560462306a36Sopenharmony_ci return '%d:%02d:%02d' % (h, m, s) 560562306a36Sopenharmony_ci if m > 0: 560662306a36Sopenharmony_ci return '%02d:%02d' % (m, s) 560762306a36Sopenharmony_ci return '%ds' % s 560862306a36Sopenharmony_ci 560962306a36Sopenharmony_cidef yesno(val): 561062306a36Sopenharmony_ci list = {'enabled':'A', 'disabled':'S', 'auto':'E', 'on':'D', 561162306a36Sopenharmony_ci 'active':'A', 'suspended':'S', 'suspending':'S'} 561262306a36Sopenharmony_ci if val not in list: 561362306a36Sopenharmony_ci return ' ' 561462306a36Sopenharmony_ci return list[val] 561562306a36Sopenharmony_ci 561662306a36Sopenharmony_ci# Function: deviceInfo 561762306a36Sopenharmony_ci# Description: 561862306a36Sopenharmony_ci# Detect all the USB hosts and devices currently connected and add 561962306a36Sopenharmony_ci# a list of USB device names to sysvals for better timeline readability 562062306a36Sopenharmony_cidef deviceInfo(output=''): 562162306a36Sopenharmony_ci if not output: 562262306a36Sopenharmony_ci pprint('LEGEND\n'\ 562362306a36Sopenharmony_ci '---------------------------------------------------------------------------------------------\n'\ 562462306a36Sopenharmony_ci ' A = async/sync PM queue (A/S) C = runtime active children\n'\ 562562306a36Sopenharmony_ci ' R = runtime suspend enabled/disabled (E/D) rACTIVE = runtime active (min/sec)\n'\ 562662306a36Sopenharmony_ci ' S = runtime status active/suspended (A/S) rSUSPEND = runtime suspend (min/sec)\n'\ 562762306a36Sopenharmony_ci ' U = runtime usage count\n'\ 562862306a36Sopenharmony_ci '---------------------------------------------------------------------------------------------\n'\ 562962306a36Sopenharmony_ci 'DEVICE NAME A R S U C rACTIVE rSUSPEND\n'\ 563062306a36Sopenharmony_ci '---------------------------------------------------------------------------------------------') 563162306a36Sopenharmony_ci 563262306a36Sopenharmony_ci res = [] 563362306a36Sopenharmony_ci tgtval = 'runtime_status' 563462306a36Sopenharmony_ci lines = dict() 563562306a36Sopenharmony_ci for dirname, dirnames, filenames in os.walk('/sys/devices'): 563662306a36Sopenharmony_ci if(not re.match('.*/power', dirname) or 563762306a36Sopenharmony_ci 'control' not in filenames or 563862306a36Sopenharmony_ci tgtval not in filenames): 563962306a36Sopenharmony_ci continue 564062306a36Sopenharmony_ci name = '' 564162306a36Sopenharmony_ci dirname = dirname[:-6] 564262306a36Sopenharmony_ci device = dirname.split('/')[-1] 564362306a36Sopenharmony_ci power = dict() 564462306a36Sopenharmony_ci power[tgtval] = readFile('%s/power/%s' % (dirname, tgtval)) 564562306a36Sopenharmony_ci # only list devices which support runtime suspend 564662306a36Sopenharmony_ci if power[tgtval] not in ['active', 'suspended', 'suspending']: 564762306a36Sopenharmony_ci continue 564862306a36Sopenharmony_ci for i in ['product', 'driver', 'subsystem']: 564962306a36Sopenharmony_ci file = '%s/%s' % (dirname, i) 565062306a36Sopenharmony_ci if os.path.exists(file): 565162306a36Sopenharmony_ci name = readFile(file) 565262306a36Sopenharmony_ci break 565362306a36Sopenharmony_ci for i in ['async', 'control', 'runtime_status', 'runtime_usage', 565462306a36Sopenharmony_ci 'runtime_active_kids', 'runtime_active_time', 565562306a36Sopenharmony_ci 'runtime_suspended_time']: 565662306a36Sopenharmony_ci if i in filenames: 565762306a36Sopenharmony_ci power[i] = readFile('%s/power/%s' % (dirname, i)) 565862306a36Sopenharmony_ci if output: 565962306a36Sopenharmony_ci if power['control'] == output: 566062306a36Sopenharmony_ci res.append('%s/power/control' % dirname) 566162306a36Sopenharmony_ci continue 566262306a36Sopenharmony_ci lines[dirname] = '%-26s %-26s %1s %1s %1s %1s %1s %10s %10s' % \ 566362306a36Sopenharmony_ci (device[:26], name[:26], 566462306a36Sopenharmony_ci yesno(power['async']), \ 566562306a36Sopenharmony_ci yesno(power['control']), \ 566662306a36Sopenharmony_ci yesno(power['runtime_status']), \ 566762306a36Sopenharmony_ci power['runtime_usage'], \ 566862306a36Sopenharmony_ci power['runtime_active_kids'], \ 566962306a36Sopenharmony_ci ms2nice(power['runtime_active_time']), \ 567062306a36Sopenharmony_ci ms2nice(power['runtime_suspended_time'])) 567162306a36Sopenharmony_ci for i in sorted(lines): 567262306a36Sopenharmony_ci print(lines[i]) 567362306a36Sopenharmony_ci return res 567462306a36Sopenharmony_ci 567562306a36Sopenharmony_ci# Function: getModes 567662306a36Sopenharmony_ci# Description: 567762306a36Sopenharmony_ci# Determine the supported power modes on this system 567862306a36Sopenharmony_ci# Output: 567962306a36Sopenharmony_ci# A string list of the available modes 568062306a36Sopenharmony_cidef getModes(): 568162306a36Sopenharmony_ci modes = [] 568262306a36Sopenharmony_ci if(os.path.exists(sysvals.powerfile)): 568362306a36Sopenharmony_ci fp = open(sysvals.powerfile, 'r') 568462306a36Sopenharmony_ci modes = fp.read().split() 568562306a36Sopenharmony_ci fp.close() 568662306a36Sopenharmony_ci if(os.path.exists(sysvals.mempowerfile)): 568762306a36Sopenharmony_ci deep = False 568862306a36Sopenharmony_ci fp = open(sysvals.mempowerfile, 'r') 568962306a36Sopenharmony_ci for m in fp.read().split(): 569062306a36Sopenharmony_ci memmode = m.strip('[]') 569162306a36Sopenharmony_ci if memmode == 'deep': 569262306a36Sopenharmony_ci deep = True 569362306a36Sopenharmony_ci else: 569462306a36Sopenharmony_ci modes.append('mem-%s' % memmode) 569562306a36Sopenharmony_ci fp.close() 569662306a36Sopenharmony_ci if 'mem' in modes and not deep: 569762306a36Sopenharmony_ci modes.remove('mem') 569862306a36Sopenharmony_ci if('disk' in modes and os.path.exists(sysvals.diskpowerfile)): 569962306a36Sopenharmony_ci fp = open(sysvals.diskpowerfile, 'r') 570062306a36Sopenharmony_ci for m in fp.read().split(): 570162306a36Sopenharmony_ci modes.append('disk-%s' % m.strip('[]')) 570262306a36Sopenharmony_ci fp.close() 570362306a36Sopenharmony_ci return modes 570462306a36Sopenharmony_ci 570562306a36Sopenharmony_ci# Function: dmidecode 570662306a36Sopenharmony_ci# Description: 570762306a36Sopenharmony_ci# Read the bios tables and pull out system info 570862306a36Sopenharmony_ci# Arguments: 570962306a36Sopenharmony_ci# mempath: /dev/mem or custom mem path 571062306a36Sopenharmony_ci# fatal: True to exit on error, False to return empty dict 571162306a36Sopenharmony_ci# Output: 571262306a36Sopenharmony_ci# A dict object with all available key/values 571362306a36Sopenharmony_cidef dmidecode(mempath, fatal=False): 571462306a36Sopenharmony_ci out = dict() 571562306a36Sopenharmony_ci 571662306a36Sopenharmony_ci # the list of values to retrieve, with hardcoded (type, idx) 571762306a36Sopenharmony_ci info = { 571862306a36Sopenharmony_ci 'bios-vendor': (0, 4), 571962306a36Sopenharmony_ci 'bios-version': (0, 5), 572062306a36Sopenharmony_ci 'bios-release-date': (0, 8), 572162306a36Sopenharmony_ci 'system-manufacturer': (1, 4), 572262306a36Sopenharmony_ci 'system-product-name': (1, 5), 572362306a36Sopenharmony_ci 'system-version': (1, 6), 572462306a36Sopenharmony_ci 'system-serial-number': (1, 7), 572562306a36Sopenharmony_ci 'baseboard-manufacturer': (2, 4), 572662306a36Sopenharmony_ci 'baseboard-product-name': (2, 5), 572762306a36Sopenharmony_ci 'baseboard-version': (2, 6), 572862306a36Sopenharmony_ci 'baseboard-serial-number': (2, 7), 572962306a36Sopenharmony_ci 'chassis-manufacturer': (3, 4), 573062306a36Sopenharmony_ci 'chassis-type': (3, 5), 573162306a36Sopenharmony_ci 'chassis-version': (3, 6), 573262306a36Sopenharmony_ci 'chassis-serial-number': (3, 7), 573362306a36Sopenharmony_ci 'processor-manufacturer': (4, 7), 573462306a36Sopenharmony_ci 'processor-version': (4, 16), 573562306a36Sopenharmony_ci } 573662306a36Sopenharmony_ci if(not os.path.exists(mempath)): 573762306a36Sopenharmony_ci if(fatal): 573862306a36Sopenharmony_ci doError('file does not exist: %s' % mempath) 573962306a36Sopenharmony_ci return out 574062306a36Sopenharmony_ci if(not os.access(mempath, os.R_OK)): 574162306a36Sopenharmony_ci if(fatal): 574262306a36Sopenharmony_ci doError('file is not readable: %s' % mempath) 574362306a36Sopenharmony_ci return out 574462306a36Sopenharmony_ci 574562306a36Sopenharmony_ci # by default use legacy scan, but try to use EFI first 574662306a36Sopenharmony_ci memaddr = 0xf0000 574762306a36Sopenharmony_ci memsize = 0x10000 574862306a36Sopenharmony_ci for ep in ['/sys/firmware/efi/systab', '/proc/efi/systab']: 574962306a36Sopenharmony_ci if not os.path.exists(ep) or not os.access(ep, os.R_OK): 575062306a36Sopenharmony_ci continue 575162306a36Sopenharmony_ci fp = open(ep, 'r') 575262306a36Sopenharmony_ci buf = fp.read() 575362306a36Sopenharmony_ci fp.close() 575462306a36Sopenharmony_ci i = buf.find('SMBIOS=') 575562306a36Sopenharmony_ci if i >= 0: 575662306a36Sopenharmony_ci try: 575762306a36Sopenharmony_ci memaddr = int(buf[i+7:], 16) 575862306a36Sopenharmony_ci memsize = 0x20 575962306a36Sopenharmony_ci except: 576062306a36Sopenharmony_ci continue 576162306a36Sopenharmony_ci 576262306a36Sopenharmony_ci # read in the memory for scanning 576362306a36Sopenharmony_ci try: 576462306a36Sopenharmony_ci fp = open(mempath, 'rb') 576562306a36Sopenharmony_ci fp.seek(memaddr) 576662306a36Sopenharmony_ci buf = fp.read(memsize) 576762306a36Sopenharmony_ci except: 576862306a36Sopenharmony_ci if(fatal): 576962306a36Sopenharmony_ci doError('DMI table is unreachable, sorry') 577062306a36Sopenharmony_ci else: 577162306a36Sopenharmony_ci pprint('WARNING: /dev/mem is not readable, ignoring DMI data') 577262306a36Sopenharmony_ci return out 577362306a36Sopenharmony_ci fp.close() 577462306a36Sopenharmony_ci 577562306a36Sopenharmony_ci # search for either an SM table or DMI table 577662306a36Sopenharmony_ci i = base = length = num = 0 577762306a36Sopenharmony_ci while(i < memsize): 577862306a36Sopenharmony_ci if buf[i:i+4] == b'_SM_' and i < memsize - 16: 577962306a36Sopenharmony_ci length = struct.unpack('H', buf[i+22:i+24])[0] 578062306a36Sopenharmony_ci base, num = struct.unpack('IH', buf[i+24:i+30]) 578162306a36Sopenharmony_ci break 578262306a36Sopenharmony_ci elif buf[i:i+5] == b'_DMI_': 578362306a36Sopenharmony_ci length = struct.unpack('H', buf[i+6:i+8])[0] 578462306a36Sopenharmony_ci base, num = struct.unpack('IH', buf[i+8:i+14]) 578562306a36Sopenharmony_ci break 578662306a36Sopenharmony_ci i += 16 578762306a36Sopenharmony_ci if base == 0 and length == 0 and num == 0: 578862306a36Sopenharmony_ci if(fatal): 578962306a36Sopenharmony_ci doError('Neither SMBIOS nor DMI were found') 579062306a36Sopenharmony_ci else: 579162306a36Sopenharmony_ci return out 579262306a36Sopenharmony_ci 579362306a36Sopenharmony_ci # read in the SM or DMI table 579462306a36Sopenharmony_ci try: 579562306a36Sopenharmony_ci fp = open(mempath, 'rb') 579662306a36Sopenharmony_ci fp.seek(base) 579762306a36Sopenharmony_ci buf = fp.read(length) 579862306a36Sopenharmony_ci except: 579962306a36Sopenharmony_ci if(fatal): 580062306a36Sopenharmony_ci doError('DMI table is unreachable, sorry') 580162306a36Sopenharmony_ci else: 580262306a36Sopenharmony_ci pprint('WARNING: /dev/mem is not readable, ignoring DMI data') 580362306a36Sopenharmony_ci return out 580462306a36Sopenharmony_ci fp.close() 580562306a36Sopenharmony_ci 580662306a36Sopenharmony_ci # scan the table for the values we want 580762306a36Sopenharmony_ci count = i = 0 580862306a36Sopenharmony_ci while(count < num and i <= len(buf) - 4): 580962306a36Sopenharmony_ci type, size, handle = struct.unpack('BBH', buf[i:i+4]) 581062306a36Sopenharmony_ci n = i + size 581162306a36Sopenharmony_ci while n < len(buf) - 1: 581262306a36Sopenharmony_ci if 0 == struct.unpack('H', buf[n:n+2])[0]: 581362306a36Sopenharmony_ci break 581462306a36Sopenharmony_ci n += 1 581562306a36Sopenharmony_ci data = buf[i+size:n+2].split(b'\0') 581662306a36Sopenharmony_ci for name in info: 581762306a36Sopenharmony_ci itype, idxadr = info[name] 581862306a36Sopenharmony_ci if itype == type: 581962306a36Sopenharmony_ci idx = struct.unpack('B', buf[i+idxadr:i+idxadr+1])[0] 582062306a36Sopenharmony_ci if idx > 0 and idx < len(data) - 1: 582162306a36Sopenharmony_ci s = data[idx-1].decode('utf-8') 582262306a36Sopenharmony_ci if s.strip() and s.strip().lower() != 'to be filled by o.e.m.': 582362306a36Sopenharmony_ci out[name] = s 582462306a36Sopenharmony_ci i = n + 2 582562306a36Sopenharmony_ci count += 1 582662306a36Sopenharmony_ci return out 582762306a36Sopenharmony_ci 582862306a36Sopenharmony_ci# Function: getFPDT 582962306a36Sopenharmony_ci# Description: 583062306a36Sopenharmony_ci# Read the acpi bios tables and pull out FPDT, the firmware data 583162306a36Sopenharmony_ci# Arguments: 583262306a36Sopenharmony_ci# output: True to output the info to stdout, False otherwise 583362306a36Sopenharmony_cidef getFPDT(output): 583462306a36Sopenharmony_ci rectype = {} 583562306a36Sopenharmony_ci rectype[0] = 'Firmware Basic Boot Performance Record' 583662306a36Sopenharmony_ci rectype[1] = 'S3 Performance Table Record' 583762306a36Sopenharmony_ci prectype = {} 583862306a36Sopenharmony_ci prectype[0] = 'Basic S3 Resume Performance Record' 583962306a36Sopenharmony_ci prectype[1] = 'Basic S3 Suspend Performance Record' 584062306a36Sopenharmony_ci 584162306a36Sopenharmony_ci sysvals.rootCheck(True) 584262306a36Sopenharmony_ci if(not os.path.exists(sysvals.fpdtpath)): 584362306a36Sopenharmony_ci if(output): 584462306a36Sopenharmony_ci doError('file does not exist: %s' % sysvals.fpdtpath) 584562306a36Sopenharmony_ci return False 584662306a36Sopenharmony_ci if(not os.access(sysvals.fpdtpath, os.R_OK)): 584762306a36Sopenharmony_ci if(output): 584862306a36Sopenharmony_ci doError('file is not readable: %s' % sysvals.fpdtpath) 584962306a36Sopenharmony_ci return False 585062306a36Sopenharmony_ci if(not os.path.exists(sysvals.mempath)): 585162306a36Sopenharmony_ci if(output): 585262306a36Sopenharmony_ci doError('file does not exist: %s' % sysvals.mempath) 585362306a36Sopenharmony_ci return False 585462306a36Sopenharmony_ci if(not os.access(sysvals.mempath, os.R_OK)): 585562306a36Sopenharmony_ci if(output): 585662306a36Sopenharmony_ci doError('file is not readable: %s' % sysvals.mempath) 585762306a36Sopenharmony_ci return False 585862306a36Sopenharmony_ci 585962306a36Sopenharmony_ci fp = open(sysvals.fpdtpath, 'rb') 586062306a36Sopenharmony_ci buf = fp.read() 586162306a36Sopenharmony_ci fp.close() 586262306a36Sopenharmony_ci 586362306a36Sopenharmony_ci if(len(buf) < 36): 586462306a36Sopenharmony_ci if(output): 586562306a36Sopenharmony_ci doError('Invalid FPDT table data, should '+\ 586662306a36Sopenharmony_ci 'be at least 36 bytes') 586762306a36Sopenharmony_ci return False 586862306a36Sopenharmony_ci 586962306a36Sopenharmony_ci table = struct.unpack('4sIBB6s8sI4sI', buf[0:36]) 587062306a36Sopenharmony_ci if(output): 587162306a36Sopenharmony_ci pprint('\n'\ 587262306a36Sopenharmony_ci 'Firmware Performance Data Table (%s)\n'\ 587362306a36Sopenharmony_ci ' Signature : %s\n'\ 587462306a36Sopenharmony_ci ' Table Length : %u\n'\ 587562306a36Sopenharmony_ci ' Revision : %u\n'\ 587662306a36Sopenharmony_ci ' Checksum : 0x%x\n'\ 587762306a36Sopenharmony_ci ' OEM ID : %s\n'\ 587862306a36Sopenharmony_ci ' OEM Table ID : %s\n'\ 587962306a36Sopenharmony_ci ' OEM Revision : %u\n'\ 588062306a36Sopenharmony_ci ' Creator ID : %s\n'\ 588162306a36Sopenharmony_ci ' Creator Revision : 0x%x\n'\ 588262306a36Sopenharmony_ci '' % (ascii(table[0]), ascii(table[0]), table[1], table[2], 588362306a36Sopenharmony_ci table[3], ascii(table[4]), ascii(table[5]), table[6], 588462306a36Sopenharmony_ci ascii(table[7]), table[8])) 588562306a36Sopenharmony_ci 588662306a36Sopenharmony_ci if(table[0] != b'FPDT'): 588762306a36Sopenharmony_ci if(output): 588862306a36Sopenharmony_ci doError('Invalid FPDT table') 588962306a36Sopenharmony_ci return False 589062306a36Sopenharmony_ci if(len(buf) <= 36): 589162306a36Sopenharmony_ci return False 589262306a36Sopenharmony_ci i = 0 589362306a36Sopenharmony_ci fwData = [0, 0] 589462306a36Sopenharmony_ci records = buf[36:] 589562306a36Sopenharmony_ci try: 589662306a36Sopenharmony_ci fp = open(sysvals.mempath, 'rb') 589762306a36Sopenharmony_ci except: 589862306a36Sopenharmony_ci pprint('WARNING: /dev/mem is not readable, ignoring the FPDT data') 589962306a36Sopenharmony_ci return False 590062306a36Sopenharmony_ci while(i < len(records)): 590162306a36Sopenharmony_ci header = struct.unpack('HBB', records[i:i+4]) 590262306a36Sopenharmony_ci if(header[0] not in rectype): 590362306a36Sopenharmony_ci i += header[1] 590462306a36Sopenharmony_ci continue 590562306a36Sopenharmony_ci if(header[1] != 16): 590662306a36Sopenharmony_ci i += header[1] 590762306a36Sopenharmony_ci continue 590862306a36Sopenharmony_ci addr = struct.unpack('Q', records[i+8:i+16])[0] 590962306a36Sopenharmony_ci try: 591062306a36Sopenharmony_ci fp.seek(addr) 591162306a36Sopenharmony_ci first = fp.read(8) 591262306a36Sopenharmony_ci except: 591362306a36Sopenharmony_ci if(output): 591462306a36Sopenharmony_ci pprint('Bad address 0x%x in %s' % (addr, sysvals.mempath)) 591562306a36Sopenharmony_ci return [0, 0] 591662306a36Sopenharmony_ci rechead = struct.unpack('4sI', first) 591762306a36Sopenharmony_ci recdata = fp.read(rechead[1]-8) 591862306a36Sopenharmony_ci if(rechead[0] == b'FBPT'): 591962306a36Sopenharmony_ci record = struct.unpack('HBBIQQQQQ', recdata[:48]) 592062306a36Sopenharmony_ci if(output): 592162306a36Sopenharmony_ci pprint('%s (%s)\n'\ 592262306a36Sopenharmony_ci ' Reset END : %u ns\n'\ 592362306a36Sopenharmony_ci ' OS Loader LoadImage Start : %u ns\n'\ 592462306a36Sopenharmony_ci ' OS Loader StartImage Start : %u ns\n'\ 592562306a36Sopenharmony_ci ' ExitBootServices Entry : %u ns\n'\ 592662306a36Sopenharmony_ci ' ExitBootServices Exit : %u ns'\ 592762306a36Sopenharmony_ci '' % (rectype[header[0]], ascii(rechead[0]), record[4], record[5], 592862306a36Sopenharmony_ci record[6], record[7], record[8])) 592962306a36Sopenharmony_ci elif(rechead[0] == b'S3PT'): 593062306a36Sopenharmony_ci if(output): 593162306a36Sopenharmony_ci pprint('%s (%s)' % (rectype[header[0]], ascii(rechead[0]))) 593262306a36Sopenharmony_ci j = 0 593362306a36Sopenharmony_ci while(j < len(recdata)): 593462306a36Sopenharmony_ci prechead = struct.unpack('HBB', recdata[j:j+4]) 593562306a36Sopenharmony_ci if(prechead[0] not in prectype): 593662306a36Sopenharmony_ci continue 593762306a36Sopenharmony_ci if(prechead[0] == 0): 593862306a36Sopenharmony_ci record = struct.unpack('IIQQ', recdata[j:j+prechead[1]]) 593962306a36Sopenharmony_ci fwData[1] = record[2] 594062306a36Sopenharmony_ci if(output): 594162306a36Sopenharmony_ci pprint(' %s\n'\ 594262306a36Sopenharmony_ci ' Resume Count : %u\n'\ 594362306a36Sopenharmony_ci ' FullResume : %u ns\n'\ 594462306a36Sopenharmony_ci ' AverageResume : %u ns'\ 594562306a36Sopenharmony_ci '' % (prectype[prechead[0]], record[1], 594662306a36Sopenharmony_ci record[2], record[3])) 594762306a36Sopenharmony_ci elif(prechead[0] == 1): 594862306a36Sopenharmony_ci record = struct.unpack('QQ', recdata[j+4:j+prechead[1]]) 594962306a36Sopenharmony_ci fwData[0] = record[1] - record[0] 595062306a36Sopenharmony_ci if(output): 595162306a36Sopenharmony_ci pprint(' %s\n'\ 595262306a36Sopenharmony_ci ' SuspendStart : %u ns\n'\ 595362306a36Sopenharmony_ci ' SuspendEnd : %u ns\n'\ 595462306a36Sopenharmony_ci ' SuspendTime : %u ns'\ 595562306a36Sopenharmony_ci '' % (prectype[prechead[0]], record[0], 595662306a36Sopenharmony_ci record[1], fwData[0])) 595762306a36Sopenharmony_ci 595862306a36Sopenharmony_ci j += prechead[1] 595962306a36Sopenharmony_ci if(output): 596062306a36Sopenharmony_ci pprint('') 596162306a36Sopenharmony_ci i += header[1] 596262306a36Sopenharmony_ci fp.close() 596362306a36Sopenharmony_ci return fwData 596462306a36Sopenharmony_ci 596562306a36Sopenharmony_ci# Function: statusCheck 596662306a36Sopenharmony_ci# Description: 596762306a36Sopenharmony_ci# Verify that the requested command and options will work, and 596862306a36Sopenharmony_ci# print the results to the terminal 596962306a36Sopenharmony_ci# Output: 597062306a36Sopenharmony_ci# True if the test will work, False if not 597162306a36Sopenharmony_cidef statusCheck(probecheck=False): 597262306a36Sopenharmony_ci status = '' 597362306a36Sopenharmony_ci 597462306a36Sopenharmony_ci pprint('Checking this system (%s)...' % platform.node()) 597562306a36Sopenharmony_ci 597662306a36Sopenharmony_ci # check we have root access 597762306a36Sopenharmony_ci res = sysvals.colorText('NO (No features of this tool will work!)') 597862306a36Sopenharmony_ci if(sysvals.rootCheck(False)): 597962306a36Sopenharmony_ci res = 'YES' 598062306a36Sopenharmony_ci pprint(' have root access: %s' % res) 598162306a36Sopenharmony_ci if(res != 'YES'): 598262306a36Sopenharmony_ci pprint(' Try running this script with sudo') 598362306a36Sopenharmony_ci return 'missing root access' 598462306a36Sopenharmony_ci 598562306a36Sopenharmony_ci # check sysfs is mounted 598662306a36Sopenharmony_ci res = sysvals.colorText('NO (No features of this tool will work!)') 598762306a36Sopenharmony_ci if(os.path.exists(sysvals.powerfile)): 598862306a36Sopenharmony_ci res = 'YES' 598962306a36Sopenharmony_ci pprint(' is sysfs mounted: %s' % res) 599062306a36Sopenharmony_ci if(res != 'YES'): 599162306a36Sopenharmony_ci return 'sysfs is missing' 599262306a36Sopenharmony_ci 599362306a36Sopenharmony_ci # check target mode is a valid mode 599462306a36Sopenharmony_ci if sysvals.suspendmode != 'command': 599562306a36Sopenharmony_ci res = sysvals.colorText('NO') 599662306a36Sopenharmony_ci modes = getModes() 599762306a36Sopenharmony_ci if(sysvals.suspendmode in modes): 599862306a36Sopenharmony_ci res = 'YES' 599962306a36Sopenharmony_ci else: 600062306a36Sopenharmony_ci status = '%s mode is not supported' % sysvals.suspendmode 600162306a36Sopenharmony_ci pprint(' is "%s" a valid power mode: %s' % (sysvals.suspendmode, res)) 600262306a36Sopenharmony_ci if(res == 'NO'): 600362306a36Sopenharmony_ci pprint(' valid power modes are: %s' % modes) 600462306a36Sopenharmony_ci pprint(' please choose one with -m') 600562306a36Sopenharmony_ci 600662306a36Sopenharmony_ci # check if ftrace is available 600762306a36Sopenharmony_ci if sysvals.useftrace: 600862306a36Sopenharmony_ci res = sysvals.colorText('NO') 600962306a36Sopenharmony_ci sysvals.useftrace = sysvals.verifyFtrace() 601062306a36Sopenharmony_ci efmt = '"{0}" uses ftrace, and it is not properly supported' 601162306a36Sopenharmony_ci if sysvals.useftrace: 601262306a36Sopenharmony_ci res = 'YES' 601362306a36Sopenharmony_ci elif sysvals.usecallgraph: 601462306a36Sopenharmony_ci status = efmt.format('-f') 601562306a36Sopenharmony_ci elif sysvals.usedevsrc: 601662306a36Sopenharmony_ci status = efmt.format('-dev') 601762306a36Sopenharmony_ci elif sysvals.useprocmon: 601862306a36Sopenharmony_ci status = efmt.format('-proc') 601962306a36Sopenharmony_ci pprint(' is ftrace supported: %s' % res) 602062306a36Sopenharmony_ci 602162306a36Sopenharmony_ci # check if kprobes are available 602262306a36Sopenharmony_ci if sysvals.usekprobes: 602362306a36Sopenharmony_ci res = sysvals.colorText('NO') 602462306a36Sopenharmony_ci sysvals.usekprobes = sysvals.verifyKprobes() 602562306a36Sopenharmony_ci if(sysvals.usekprobes): 602662306a36Sopenharmony_ci res = 'YES' 602762306a36Sopenharmony_ci else: 602862306a36Sopenharmony_ci sysvals.usedevsrc = False 602962306a36Sopenharmony_ci pprint(' are kprobes supported: %s' % res) 603062306a36Sopenharmony_ci 603162306a36Sopenharmony_ci # what data source are we using 603262306a36Sopenharmony_ci res = 'DMESG (very limited, ftrace is preferred)' 603362306a36Sopenharmony_ci if sysvals.useftrace: 603462306a36Sopenharmony_ci sysvals.usetraceevents = True 603562306a36Sopenharmony_ci for e in sysvals.traceevents: 603662306a36Sopenharmony_ci if not os.path.exists(sysvals.epath+e): 603762306a36Sopenharmony_ci sysvals.usetraceevents = False 603862306a36Sopenharmony_ci if(sysvals.usetraceevents): 603962306a36Sopenharmony_ci res = 'FTRACE (all trace events found)' 604062306a36Sopenharmony_ci pprint(' timeline data source: %s' % res) 604162306a36Sopenharmony_ci 604262306a36Sopenharmony_ci # check if rtcwake 604362306a36Sopenharmony_ci res = sysvals.colorText('NO') 604462306a36Sopenharmony_ci if(sysvals.rtcpath != ''): 604562306a36Sopenharmony_ci res = 'YES' 604662306a36Sopenharmony_ci elif(sysvals.rtcwake): 604762306a36Sopenharmony_ci status = 'rtcwake is not properly supported' 604862306a36Sopenharmony_ci pprint(' is rtcwake supported: %s' % res) 604962306a36Sopenharmony_ci 605062306a36Sopenharmony_ci # check info commands 605162306a36Sopenharmony_ci pprint(' optional commands this tool may use for info:') 605262306a36Sopenharmony_ci no = sysvals.colorText('MISSING') 605362306a36Sopenharmony_ci yes = sysvals.colorText('FOUND', 32) 605462306a36Sopenharmony_ci for c in ['turbostat', 'mcelog', 'lspci', 'lsusb', 'netfix']: 605562306a36Sopenharmony_ci if c == 'turbostat': 605662306a36Sopenharmony_ci res = yes if sysvals.haveTurbostat() else no 605762306a36Sopenharmony_ci else: 605862306a36Sopenharmony_ci res = yes if sysvals.getExec(c) else no 605962306a36Sopenharmony_ci pprint(' %s: %s' % (c, res)) 606062306a36Sopenharmony_ci 606162306a36Sopenharmony_ci if not probecheck: 606262306a36Sopenharmony_ci return status 606362306a36Sopenharmony_ci 606462306a36Sopenharmony_ci # verify kprobes 606562306a36Sopenharmony_ci if sysvals.usekprobes: 606662306a36Sopenharmony_ci for name in sysvals.tracefuncs: 606762306a36Sopenharmony_ci sysvals.defaultKprobe(name, sysvals.tracefuncs[name]) 606862306a36Sopenharmony_ci if sysvals.usedevsrc: 606962306a36Sopenharmony_ci for name in sysvals.dev_tracefuncs: 607062306a36Sopenharmony_ci sysvals.defaultKprobe(name, sysvals.dev_tracefuncs[name]) 607162306a36Sopenharmony_ci sysvals.addKprobes(True) 607262306a36Sopenharmony_ci 607362306a36Sopenharmony_ci return status 607462306a36Sopenharmony_ci 607562306a36Sopenharmony_ci# Function: doError 607662306a36Sopenharmony_ci# Description: 607762306a36Sopenharmony_ci# generic error function for catastrphic failures 607862306a36Sopenharmony_ci# Arguments: 607962306a36Sopenharmony_ci# msg: the error message to print 608062306a36Sopenharmony_ci# help: True if printHelp should be called after, False otherwise 608162306a36Sopenharmony_cidef doError(msg, help=False): 608262306a36Sopenharmony_ci if(help == True): 608362306a36Sopenharmony_ci printHelp() 608462306a36Sopenharmony_ci pprint('ERROR: %s\n' % msg) 608562306a36Sopenharmony_ci sysvals.outputResult({'error':msg}) 608662306a36Sopenharmony_ci sys.exit(1) 608762306a36Sopenharmony_ci 608862306a36Sopenharmony_ci# Function: getArgInt 608962306a36Sopenharmony_ci# Description: 609062306a36Sopenharmony_ci# pull out an integer argument from the command line with checks 609162306a36Sopenharmony_cidef getArgInt(name, args, min, max, main=True): 609262306a36Sopenharmony_ci if main: 609362306a36Sopenharmony_ci try: 609462306a36Sopenharmony_ci arg = next(args) 609562306a36Sopenharmony_ci except: 609662306a36Sopenharmony_ci doError(name+': no argument supplied', True) 609762306a36Sopenharmony_ci else: 609862306a36Sopenharmony_ci arg = args 609962306a36Sopenharmony_ci try: 610062306a36Sopenharmony_ci val = int(arg) 610162306a36Sopenharmony_ci except: 610262306a36Sopenharmony_ci doError(name+': non-integer value given', True) 610362306a36Sopenharmony_ci if(val < min or val > max): 610462306a36Sopenharmony_ci doError(name+': value should be between %d and %d' % (min, max), True) 610562306a36Sopenharmony_ci return val 610662306a36Sopenharmony_ci 610762306a36Sopenharmony_ci# Function: getArgFloat 610862306a36Sopenharmony_ci# Description: 610962306a36Sopenharmony_ci# pull out a float argument from the command line with checks 611062306a36Sopenharmony_cidef getArgFloat(name, args, min, max, main=True): 611162306a36Sopenharmony_ci if main: 611262306a36Sopenharmony_ci try: 611362306a36Sopenharmony_ci arg = next(args) 611462306a36Sopenharmony_ci except: 611562306a36Sopenharmony_ci doError(name+': no argument supplied', True) 611662306a36Sopenharmony_ci else: 611762306a36Sopenharmony_ci arg = args 611862306a36Sopenharmony_ci try: 611962306a36Sopenharmony_ci val = float(arg) 612062306a36Sopenharmony_ci except: 612162306a36Sopenharmony_ci doError(name+': non-numerical value given', True) 612262306a36Sopenharmony_ci if(val < min or val > max): 612362306a36Sopenharmony_ci doError(name+': value should be between %f and %f' % (min, max), True) 612462306a36Sopenharmony_ci return val 612562306a36Sopenharmony_ci 612662306a36Sopenharmony_cidef processData(live=False, quiet=False): 612762306a36Sopenharmony_ci if not quiet: 612862306a36Sopenharmony_ci pprint('PROCESSING: %s' % sysvals.htmlfile) 612962306a36Sopenharmony_ci sysvals.vprint('usetraceevents=%s, usetracemarkers=%s, usekprobes=%s' % \ 613062306a36Sopenharmony_ci (sysvals.usetraceevents, sysvals.usetracemarkers, sysvals.usekprobes)) 613162306a36Sopenharmony_ci error = '' 613262306a36Sopenharmony_ci if(sysvals.usetraceevents): 613362306a36Sopenharmony_ci testruns, error = parseTraceLog(live) 613462306a36Sopenharmony_ci if sysvals.dmesgfile: 613562306a36Sopenharmony_ci for data in testruns: 613662306a36Sopenharmony_ci data.extractErrorInfo() 613762306a36Sopenharmony_ci else: 613862306a36Sopenharmony_ci testruns = loadKernelLog() 613962306a36Sopenharmony_ci for data in testruns: 614062306a36Sopenharmony_ci parseKernelLog(data) 614162306a36Sopenharmony_ci if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): 614262306a36Sopenharmony_ci appendIncompleteTraceLog(testruns) 614362306a36Sopenharmony_ci if not sysvals.stamp: 614462306a36Sopenharmony_ci pprint('ERROR: data does not include the expected stamp') 614562306a36Sopenharmony_ci return (testruns, {'error': 'timeline generation failed'}) 614662306a36Sopenharmony_ci shown = ['os', 'bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr', 614762306a36Sopenharmony_ci 'memsz', 'mode', 'numcpu', 'plat', 'time', 'wifi'] 614862306a36Sopenharmony_ci sysvals.vprint('System Info:') 614962306a36Sopenharmony_ci for key in sorted(sysvals.stamp): 615062306a36Sopenharmony_ci if key in shown: 615162306a36Sopenharmony_ci sysvals.vprint(' %-8s : %s' % (key.upper(), sysvals.stamp[key])) 615262306a36Sopenharmony_ci sysvals.vprint('Command:\n %s' % sysvals.cmdline) 615362306a36Sopenharmony_ci for data in testruns: 615462306a36Sopenharmony_ci if data.turbostat: 615562306a36Sopenharmony_ci idx, s = 0, 'Turbostat:\n ' 615662306a36Sopenharmony_ci for val in data.turbostat.split('|'): 615762306a36Sopenharmony_ci idx += len(val) + 1 615862306a36Sopenharmony_ci if idx >= 80: 615962306a36Sopenharmony_ci idx = 0 616062306a36Sopenharmony_ci s += '\n ' 616162306a36Sopenharmony_ci s += val + ' ' 616262306a36Sopenharmony_ci sysvals.vprint(s) 616362306a36Sopenharmony_ci data.printDetails() 616462306a36Sopenharmony_ci if len(sysvals.platinfo) > 0: 616562306a36Sopenharmony_ci sysvals.vprint('\nPlatform Info:') 616662306a36Sopenharmony_ci for info in sysvals.platinfo: 616762306a36Sopenharmony_ci sysvals.vprint('[%s - %s]' % (info[0], info[1])) 616862306a36Sopenharmony_ci sysvals.vprint(info[2]) 616962306a36Sopenharmony_ci sysvals.vprint('') 617062306a36Sopenharmony_ci if sysvals.cgdump: 617162306a36Sopenharmony_ci for data in testruns: 617262306a36Sopenharmony_ci data.debugPrint() 617362306a36Sopenharmony_ci sys.exit(0) 617462306a36Sopenharmony_ci if len(testruns) < 1: 617562306a36Sopenharmony_ci pprint('ERROR: Not enough test data to build a timeline') 617662306a36Sopenharmony_ci return (testruns, {'error': 'timeline generation failed'}) 617762306a36Sopenharmony_ci sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile) 617862306a36Sopenharmony_ci createHTML(testruns, error) 617962306a36Sopenharmony_ci if not quiet: 618062306a36Sopenharmony_ci pprint('DONE: %s' % sysvals.htmlfile) 618162306a36Sopenharmony_ci data = testruns[0] 618262306a36Sopenharmony_ci stamp = data.stamp 618362306a36Sopenharmony_ci stamp['suspend'], stamp['resume'] = data.getTimeValues() 618462306a36Sopenharmony_ci if data.fwValid: 618562306a36Sopenharmony_ci stamp['fwsuspend'], stamp['fwresume'] = data.fwSuspend, data.fwResume 618662306a36Sopenharmony_ci if error: 618762306a36Sopenharmony_ci stamp['error'] = error 618862306a36Sopenharmony_ci return (testruns, stamp) 618962306a36Sopenharmony_ci 619062306a36Sopenharmony_ci# Function: rerunTest 619162306a36Sopenharmony_ci# Description: 619262306a36Sopenharmony_ci# generate an output from an existing set of ftrace/dmesg logs 619362306a36Sopenharmony_cidef rerunTest(htmlfile=''): 619462306a36Sopenharmony_ci if sysvals.ftracefile: 619562306a36Sopenharmony_ci doesTraceLogHaveTraceEvents() 619662306a36Sopenharmony_ci if not sysvals.dmesgfile and not sysvals.usetraceevents: 619762306a36Sopenharmony_ci doError('recreating this html output requires a dmesg file') 619862306a36Sopenharmony_ci if htmlfile: 619962306a36Sopenharmony_ci sysvals.htmlfile = htmlfile 620062306a36Sopenharmony_ci else: 620162306a36Sopenharmony_ci sysvals.setOutputFile() 620262306a36Sopenharmony_ci if os.path.exists(sysvals.htmlfile): 620362306a36Sopenharmony_ci if not os.path.isfile(sysvals.htmlfile): 620462306a36Sopenharmony_ci doError('a directory already exists with this name: %s' % sysvals.htmlfile) 620562306a36Sopenharmony_ci elif not os.access(sysvals.htmlfile, os.W_OK): 620662306a36Sopenharmony_ci doError('missing permission to write to %s' % sysvals.htmlfile) 620762306a36Sopenharmony_ci testruns, stamp = processData() 620862306a36Sopenharmony_ci sysvals.resetlog() 620962306a36Sopenharmony_ci return stamp 621062306a36Sopenharmony_ci 621162306a36Sopenharmony_ci# Function: runTest 621262306a36Sopenharmony_ci# Description: 621362306a36Sopenharmony_ci# execute a suspend/resume, gather the logs, and generate the output 621462306a36Sopenharmony_cidef runTest(n=0, quiet=False): 621562306a36Sopenharmony_ci # prepare for the test 621662306a36Sopenharmony_ci sysvals.initTestOutput('suspend') 621762306a36Sopenharmony_ci op = sysvals.writeDatafileHeader(sysvals.dmesgfile, []) 621862306a36Sopenharmony_ci op.write('# EXECUTION TRACE START\n') 621962306a36Sopenharmony_ci op.close() 622062306a36Sopenharmony_ci if n <= 1: 622162306a36Sopenharmony_ci if sysvals.rs != 0: 622262306a36Sopenharmony_ci sysvals.dlog('%sabling runtime suspend' % ('en' if sysvals.rs > 0 else 'dis')) 622362306a36Sopenharmony_ci sysvals.setRuntimeSuspend(True) 622462306a36Sopenharmony_ci if sysvals.display: 622562306a36Sopenharmony_ci ret = sysvals.displayControl('init') 622662306a36Sopenharmony_ci sysvals.dlog('xset display init, ret = %d' % ret) 622762306a36Sopenharmony_ci sysvals.testVal(sysvals.pmdpath, 'basic', '1') 622862306a36Sopenharmony_ci sysvals.testVal(sysvals.s0ixpath, 'basic', 'Y') 622962306a36Sopenharmony_ci sysvals.dlog('initialize ftrace') 623062306a36Sopenharmony_ci sysvals.initFtrace(quiet) 623162306a36Sopenharmony_ci 623262306a36Sopenharmony_ci # execute the test 623362306a36Sopenharmony_ci executeSuspend(quiet) 623462306a36Sopenharmony_ci sysvals.cleanupFtrace() 623562306a36Sopenharmony_ci if sysvals.skiphtml: 623662306a36Sopenharmony_ci sysvals.outputResult({}, n) 623762306a36Sopenharmony_ci sysvals.sudoUserchown(sysvals.testdir) 623862306a36Sopenharmony_ci return 623962306a36Sopenharmony_ci testruns, stamp = processData(True, quiet) 624062306a36Sopenharmony_ci for data in testruns: 624162306a36Sopenharmony_ci del data 624262306a36Sopenharmony_ci sysvals.sudoUserchown(sysvals.testdir) 624362306a36Sopenharmony_ci sysvals.outputResult(stamp, n) 624462306a36Sopenharmony_ci if 'error' in stamp: 624562306a36Sopenharmony_ci return 2 624662306a36Sopenharmony_ci return 0 624762306a36Sopenharmony_ci 624862306a36Sopenharmony_cidef find_in_html(html, start, end, firstonly=True): 624962306a36Sopenharmony_ci cnt, out, list = len(html), [], [] 625062306a36Sopenharmony_ci if firstonly: 625162306a36Sopenharmony_ci m = re.search(start, html) 625262306a36Sopenharmony_ci if m: 625362306a36Sopenharmony_ci list.append(m) 625462306a36Sopenharmony_ci else: 625562306a36Sopenharmony_ci list = re.finditer(start, html) 625662306a36Sopenharmony_ci for match in list: 625762306a36Sopenharmony_ci s = match.end() 625862306a36Sopenharmony_ci e = cnt if (len(out) < 1 or s + 10000 > cnt) else s + 10000 625962306a36Sopenharmony_ci m = re.search(end, html[s:e]) 626062306a36Sopenharmony_ci if not m: 626162306a36Sopenharmony_ci break 626262306a36Sopenharmony_ci e = s + m.start() 626362306a36Sopenharmony_ci str = html[s:e] 626462306a36Sopenharmony_ci if end == 'ms': 626562306a36Sopenharmony_ci num = re.search(r'[-+]?\d*\.\d+|\d+', str) 626662306a36Sopenharmony_ci str = num.group() if num else 'NaN' 626762306a36Sopenharmony_ci if firstonly: 626862306a36Sopenharmony_ci return str 626962306a36Sopenharmony_ci out.append(str) 627062306a36Sopenharmony_ci if firstonly: 627162306a36Sopenharmony_ci return '' 627262306a36Sopenharmony_ci return out 627362306a36Sopenharmony_ci 627462306a36Sopenharmony_cidef data_from_html(file, outpath, issues, fulldetail=False): 627562306a36Sopenharmony_ci html = open(file, 'r').read() 627662306a36Sopenharmony_ci sysvals.htmlfile = os.path.relpath(file, outpath) 627762306a36Sopenharmony_ci # extract general info 627862306a36Sopenharmony_ci suspend = find_in_html(html, 'Kernel Suspend', 'ms') 627962306a36Sopenharmony_ci resume = find_in_html(html, 'Kernel Resume', 'ms') 628062306a36Sopenharmony_ci sysinfo = find_in_html(html, '<div class="stamp sysinfo">', '</div>') 628162306a36Sopenharmony_ci line = find_in_html(html, '<div class="stamp">', '</div>') 628262306a36Sopenharmony_ci stmp = line.split() 628362306a36Sopenharmony_ci if not suspend or not resume or len(stmp) != 8: 628462306a36Sopenharmony_ci return False 628562306a36Sopenharmony_ci try: 628662306a36Sopenharmony_ci dt = datetime.strptime(' '.join(stmp[3:]), '%B %d %Y, %I:%M:%S %p') 628762306a36Sopenharmony_ci except: 628862306a36Sopenharmony_ci return False 628962306a36Sopenharmony_ci sysvals.hostname = stmp[0] 629062306a36Sopenharmony_ci tstr = dt.strftime('%Y/%m/%d %H:%M:%S') 629162306a36Sopenharmony_ci error = find_in_html(html, '<table class="testfail"><tr><td>', '</td>') 629262306a36Sopenharmony_ci if error: 629362306a36Sopenharmony_ci m = re.match('[a-z0-9]* failed in (?P<p>\S*).*', error) 629462306a36Sopenharmony_ci if m: 629562306a36Sopenharmony_ci result = 'fail in %s' % m.group('p') 629662306a36Sopenharmony_ci else: 629762306a36Sopenharmony_ci result = 'fail' 629862306a36Sopenharmony_ci else: 629962306a36Sopenharmony_ci result = 'pass' 630062306a36Sopenharmony_ci # extract error info 630162306a36Sopenharmony_ci tp, ilist = False, [] 630262306a36Sopenharmony_ci extra = dict() 630362306a36Sopenharmony_ci log = find_in_html(html, '<div id="dmesglog" style="display:none;">', 630462306a36Sopenharmony_ci '</div>').strip() 630562306a36Sopenharmony_ci if log: 630662306a36Sopenharmony_ci d = Data(0) 630762306a36Sopenharmony_ci d.end = 999999999 630862306a36Sopenharmony_ci d.dmesgtext = log.split('\n') 630962306a36Sopenharmony_ci tp = d.extractErrorInfo() 631062306a36Sopenharmony_ci for msg in tp.msglist: 631162306a36Sopenharmony_ci sysvals.errorSummary(issues, msg) 631262306a36Sopenharmony_ci if stmp[2] == 'freeze': 631362306a36Sopenharmony_ci extra = d.turbostatInfo() 631462306a36Sopenharmony_ci elist = dict() 631562306a36Sopenharmony_ci for dir in d.errorinfo: 631662306a36Sopenharmony_ci for err in d.errorinfo[dir]: 631762306a36Sopenharmony_ci if err[0] not in elist: 631862306a36Sopenharmony_ci elist[err[0]] = 0 631962306a36Sopenharmony_ci elist[err[0]] += 1 632062306a36Sopenharmony_ci for i in elist: 632162306a36Sopenharmony_ci ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i) 632262306a36Sopenharmony_ci line = find_in_html(log, '# wifi ', '\n') 632362306a36Sopenharmony_ci if line: 632462306a36Sopenharmony_ci extra['wifi'] = line 632562306a36Sopenharmony_ci line = find_in_html(log, '# netfix ', '\n') 632662306a36Sopenharmony_ci if line: 632762306a36Sopenharmony_ci extra['netfix'] = line 632862306a36Sopenharmony_ci low = find_in_html(html, 'freeze time: <b>', ' ms</b>') 632962306a36Sopenharmony_ci for lowstr in ['waking', '+']: 633062306a36Sopenharmony_ci if not low: 633162306a36Sopenharmony_ci break 633262306a36Sopenharmony_ci if lowstr not in low: 633362306a36Sopenharmony_ci continue 633462306a36Sopenharmony_ci if lowstr == '+': 633562306a36Sopenharmony_ci issue = 'S2LOOPx%d' % len(low.split('+')) 633662306a36Sopenharmony_ci else: 633762306a36Sopenharmony_ci m = re.match('.*waking *(?P<n>[0-9]*) *times.*', low) 633862306a36Sopenharmony_ci issue = 'S2WAKEx%s' % m.group('n') if m else 'S2WAKExNaN' 633962306a36Sopenharmony_ci match = [i for i in issues if i['match'] == issue] 634062306a36Sopenharmony_ci if len(match) > 0: 634162306a36Sopenharmony_ci match[0]['count'] += 1 634262306a36Sopenharmony_ci if sysvals.hostname not in match[0]['urls']: 634362306a36Sopenharmony_ci match[0]['urls'][sysvals.hostname] = [sysvals.htmlfile] 634462306a36Sopenharmony_ci elif sysvals.htmlfile not in match[0]['urls'][sysvals.hostname]: 634562306a36Sopenharmony_ci match[0]['urls'][sysvals.hostname].append(sysvals.htmlfile) 634662306a36Sopenharmony_ci else: 634762306a36Sopenharmony_ci issues.append({ 634862306a36Sopenharmony_ci 'match': issue, 'count': 1, 'line': issue, 634962306a36Sopenharmony_ci 'urls': {sysvals.hostname: [sysvals.htmlfile]}, 635062306a36Sopenharmony_ci }) 635162306a36Sopenharmony_ci ilist.append(issue) 635262306a36Sopenharmony_ci # extract device info 635362306a36Sopenharmony_ci devices = dict() 635462306a36Sopenharmony_ci for line in html.split('\n'): 635562306a36Sopenharmony_ci m = re.match(' *<div id=\"[a,0-9]*\" *title=\"(?P<title>.*)\" class=\"thread.*', line) 635662306a36Sopenharmony_ci if not m or 'thread kth' in line or 'thread sec' in line: 635762306a36Sopenharmony_ci continue 635862306a36Sopenharmony_ci m = re.match('(?P<n>.*) \((?P<t>[0-9,\.]*) ms\) (?P<p>.*)', m.group('title')) 635962306a36Sopenharmony_ci if not m: 636062306a36Sopenharmony_ci continue 636162306a36Sopenharmony_ci name, time, phase = m.group('n'), m.group('t'), m.group('p') 636262306a36Sopenharmony_ci if name == 'async_synchronize_full': 636362306a36Sopenharmony_ci continue 636462306a36Sopenharmony_ci if ' async' in name or ' sync' in name: 636562306a36Sopenharmony_ci name = ' '.join(name.split(' ')[:-1]) 636662306a36Sopenharmony_ci if phase.startswith('suspend'): 636762306a36Sopenharmony_ci d = 'suspend' 636862306a36Sopenharmony_ci elif phase.startswith('resume'): 636962306a36Sopenharmony_ci d = 'resume' 637062306a36Sopenharmony_ci else: 637162306a36Sopenharmony_ci continue 637262306a36Sopenharmony_ci if d not in devices: 637362306a36Sopenharmony_ci devices[d] = dict() 637462306a36Sopenharmony_ci if name not in devices[d]: 637562306a36Sopenharmony_ci devices[d][name] = 0.0 637662306a36Sopenharmony_ci devices[d][name] += float(time) 637762306a36Sopenharmony_ci # create worst device info 637862306a36Sopenharmony_ci worst = dict() 637962306a36Sopenharmony_ci for d in ['suspend', 'resume']: 638062306a36Sopenharmony_ci worst[d] = {'name':'', 'time': 0.0} 638162306a36Sopenharmony_ci dev = devices[d] if d in devices else 0 638262306a36Sopenharmony_ci if dev and len(dev.keys()) > 0: 638362306a36Sopenharmony_ci n = sorted(dev, key=lambda k:(dev[k], k), reverse=True)[0] 638462306a36Sopenharmony_ci worst[d]['name'], worst[d]['time'] = n, dev[n] 638562306a36Sopenharmony_ci data = { 638662306a36Sopenharmony_ci 'mode': stmp[2], 638762306a36Sopenharmony_ci 'host': stmp[0], 638862306a36Sopenharmony_ci 'kernel': stmp[1], 638962306a36Sopenharmony_ci 'sysinfo': sysinfo, 639062306a36Sopenharmony_ci 'time': tstr, 639162306a36Sopenharmony_ci 'result': result, 639262306a36Sopenharmony_ci 'issues': ' '.join(ilist), 639362306a36Sopenharmony_ci 'suspend': suspend, 639462306a36Sopenharmony_ci 'resume': resume, 639562306a36Sopenharmony_ci 'devlist': devices, 639662306a36Sopenharmony_ci 'sus_worst': worst['suspend']['name'], 639762306a36Sopenharmony_ci 'sus_worsttime': worst['suspend']['time'], 639862306a36Sopenharmony_ci 'res_worst': worst['resume']['name'], 639962306a36Sopenharmony_ci 'res_worsttime': worst['resume']['time'], 640062306a36Sopenharmony_ci 'url': sysvals.htmlfile, 640162306a36Sopenharmony_ci } 640262306a36Sopenharmony_ci for key in extra: 640362306a36Sopenharmony_ci data[key] = extra[key] 640462306a36Sopenharmony_ci if fulldetail: 640562306a36Sopenharmony_ci data['funclist'] = find_in_html(html, '<div title="', '" class="traceevent"', False) 640662306a36Sopenharmony_ci if tp: 640762306a36Sopenharmony_ci for arg in ['-multi ', '-info ']: 640862306a36Sopenharmony_ci if arg in tp.cmdline: 640962306a36Sopenharmony_ci data['target'] = tp.cmdline[tp.cmdline.find(arg):].split()[1] 641062306a36Sopenharmony_ci break 641162306a36Sopenharmony_ci return data 641262306a36Sopenharmony_ci 641362306a36Sopenharmony_cidef genHtml(subdir, force=False): 641462306a36Sopenharmony_ci for dirname, dirnames, filenames in os.walk(subdir): 641562306a36Sopenharmony_ci sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = '' 641662306a36Sopenharmony_ci for filename in filenames: 641762306a36Sopenharmony_ci file = os.path.join(dirname, filename) 641862306a36Sopenharmony_ci if sysvals.usable(file): 641962306a36Sopenharmony_ci if(re.match('.*_dmesg.txt', filename)): 642062306a36Sopenharmony_ci sysvals.dmesgfile = file 642162306a36Sopenharmony_ci elif(re.match('.*_ftrace.txt', filename)): 642262306a36Sopenharmony_ci sysvals.ftracefile = file 642362306a36Sopenharmony_ci sysvals.setOutputFile() 642462306a36Sopenharmony_ci if (sysvals.dmesgfile or sysvals.ftracefile) and sysvals.htmlfile and \ 642562306a36Sopenharmony_ci (force or not sysvals.usable(sysvals.htmlfile, True)): 642662306a36Sopenharmony_ci pprint('FTRACE: %s' % sysvals.ftracefile) 642762306a36Sopenharmony_ci if sysvals.dmesgfile: 642862306a36Sopenharmony_ci pprint('DMESG : %s' % sysvals.dmesgfile) 642962306a36Sopenharmony_ci rerunTest() 643062306a36Sopenharmony_ci 643162306a36Sopenharmony_ci# Function: runSummary 643262306a36Sopenharmony_ci# Description: 643362306a36Sopenharmony_ci# create a summary of tests in a sub-directory 643462306a36Sopenharmony_cidef runSummary(subdir, local=True, genhtml=False): 643562306a36Sopenharmony_ci inpath = os.path.abspath(subdir) 643662306a36Sopenharmony_ci outpath = os.path.abspath('.') if local else inpath 643762306a36Sopenharmony_ci pprint('Generating a summary of folder:\n %s' % inpath) 643862306a36Sopenharmony_ci if genhtml: 643962306a36Sopenharmony_ci genHtml(subdir) 644062306a36Sopenharmony_ci target, issues, testruns = '', [], [] 644162306a36Sopenharmony_ci desc = {'host':[],'mode':[],'kernel':[]} 644262306a36Sopenharmony_ci for dirname, dirnames, filenames in os.walk(subdir): 644362306a36Sopenharmony_ci for filename in filenames: 644462306a36Sopenharmony_ci if(not re.match('.*.html', filename)): 644562306a36Sopenharmony_ci continue 644662306a36Sopenharmony_ci data = data_from_html(os.path.join(dirname, filename), outpath, issues) 644762306a36Sopenharmony_ci if(not data): 644862306a36Sopenharmony_ci continue 644962306a36Sopenharmony_ci if 'target' in data: 645062306a36Sopenharmony_ci target = data['target'] 645162306a36Sopenharmony_ci testruns.append(data) 645262306a36Sopenharmony_ci for key in desc: 645362306a36Sopenharmony_ci if data[key] not in desc[key]: 645462306a36Sopenharmony_ci desc[key].append(data[key]) 645562306a36Sopenharmony_ci pprint('Summary files:') 645662306a36Sopenharmony_ci if len(desc['host']) == len(desc['mode']) == len(desc['kernel']) == 1: 645762306a36Sopenharmony_ci title = '%s %s %s' % (desc['host'][0], desc['kernel'][0], desc['mode'][0]) 645862306a36Sopenharmony_ci if target: 645962306a36Sopenharmony_ci title += ' %s' % target 646062306a36Sopenharmony_ci else: 646162306a36Sopenharmony_ci title = inpath 646262306a36Sopenharmony_ci createHTMLSummarySimple(testruns, os.path.join(outpath, 'summary.html'), title) 646362306a36Sopenharmony_ci pprint(' summary.html - tabular list of test data found') 646462306a36Sopenharmony_ci createHTMLDeviceSummary(testruns, os.path.join(outpath, 'summary-devices.html'), title) 646562306a36Sopenharmony_ci pprint(' summary-devices.html - kernel device list sorted by total execution time') 646662306a36Sopenharmony_ci createHTMLIssuesSummary(testruns, issues, os.path.join(outpath, 'summary-issues.html'), title) 646762306a36Sopenharmony_ci pprint(' summary-issues.html - kernel issues found sorted by frequency') 646862306a36Sopenharmony_ci 646962306a36Sopenharmony_ci# Function: checkArgBool 647062306a36Sopenharmony_ci# Description: 647162306a36Sopenharmony_ci# check if a boolean string value is true or false 647262306a36Sopenharmony_cidef checkArgBool(name, value): 647362306a36Sopenharmony_ci if value in switchvalues: 647462306a36Sopenharmony_ci if value in switchoff: 647562306a36Sopenharmony_ci return False 647662306a36Sopenharmony_ci return True 647762306a36Sopenharmony_ci doError('invalid boolean --> (%s: %s), use "true/false" or "1/0"' % (name, value), True) 647862306a36Sopenharmony_ci return False 647962306a36Sopenharmony_ci 648062306a36Sopenharmony_ci# Function: configFromFile 648162306a36Sopenharmony_ci# Description: 648262306a36Sopenharmony_ci# Configure the script via the info in a config file 648362306a36Sopenharmony_cidef configFromFile(file): 648462306a36Sopenharmony_ci Config = configparser.ConfigParser() 648562306a36Sopenharmony_ci 648662306a36Sopenharmony_ci Config.read(file) 648762306a36Sopenharmony_ci sections = Config.sections() 648862306a36Sopenharmony_ci overridekprobes = False 648962306a36Sopenharmony_ci overridedevkprobes = False 649062306a36Sopenharmony_ci if 'Settings' in sections: 649162306a36Sopenharmony_ci for opt in Config.options('Settings'): 649262306a36Sopenharmony_ci value = Config.get('Settings', opt).lower() 649362306a36Sopenharmony_ci option = opt.lower() 649462306a36Sopenharmony_ci if(option == 'verbose'): 649562306a36Sopenharmony_ci sysvals.verbose = checkArgBool(option, value) 649662306a36Sopenharmony_ci elif(option == 'addlogs'): 649762306a36Sopenharmony_ci sysvals.dmesglog = sysvals.ftracelog = checkArgBool(option, value) 649862306a36Sopenharmony_ci elif(option == 'dev'): 649962306a36Sopenharmony_ci sysvals.usedevsrc = checkArgBool(option, value) 650062306a36Sopenharmony_ci elif(option == 'proc'): 650162306a36Sopenharmony_ci sysvals.useprocmon = checkArgBool(option, value) 650262306a36Sopenharmony_ci elif(option == 'x2'): 650362306a36Sopenharmony_ci if checkArgBool(option, value): 650462306a36Sopenharmony_ci sysvals.execcount = 2 650562306a36Sopenharmony_ci elif(option == 'callgraph'): 650662306a36Sopenharmony_ci sysvals.usecallgraph = checkArgBool(option, value) 650762306a36Sopenharmony_ci elif(option == 'override-timeline-functions'): 650862306a36Sopenharmony_ci overridekprobes = checkArgBool(option, value) 650962306a36Sopenharmony_ci elif(option == 'override-dev-timeline-functions'): 651062306a36Sopenharmony_ci overridedevkprobes = checkArgBool(option, value) 651162306a36Sopenharmony_ci elif(option == 'skiphtml'): 651262306a36Sopenharmony_ci sysvals.skiphtml = checkArgBool(option, value) 651362306a36Sopenharmony_ci elif(option == 'sync'): 651462306a36Sopenharmony_ci sysvals.sync = checkArgBool(option, value) 651562306a36Sopenharmony_ci elif(option == 'rs' or option == 'runtimesuspend'): 651662306a36Sopenharmony_ci if value in switchvalues: 651762306a36Sopenharmony_ci if value in switchoff: 651862306a36Sopenharmony_ci sysvals.rs = -1 651962306a36Sopenharmony_ci else: 652062306a36Sopenharmony_ci sysvals.rs = 1 652162306a36Sopenharmony_ci else: 652262306a36Sopenharmony_ci doError('invalid value --> (%s: %s), use "enable/disable"' % (option, value), True) 652362306a36Sopenharmony_ci elif(option == 'display'): 652462306a36Sopenharmony_ci disopt = ['on', 'off', 'standby', 'suspend'] 652562306a36Sopenharmony_ci if value not in disopt: 652662306a36Sopenharmony_ci doError('invalid value --> (%s: %s), use %s' % (option, value, disopt), True) 652762306a36Sopenharmony_ci sysvals.display = value 652862306a36Sopenharmony_ci elif(option == 'gzip'): 652962306a36Sopenharmony_ci sysvals.gzip = checkArgBool(option, value) 653062306a36Sopenharmony_ci elif(option == 'cgfilter'): 653162306a36Sopenharmony_ci sysvals.setCallgraphFilter(value) 653262306a36Sopenharmony_ci elif(option == 'cgskip'): 653362306a36Sopenharmony_ci if value in switchoff: 653462306a36Sopenharmony_ci sysvals.cgskip = '' 653562306a36Sopenharmony_ci else: 653662306a36Sopenharmony_ci sysvals.cgskip = sysvals.configFile(val) 653762306a36Sopenharmony_ci if(not sysvals.cgskip): 653862306a36Sopenharmony_ci doError('%s does not exist' % sysvals.cgskip) 653962306a36Sopenharmony_ci elif(option == 'cgtest'): 654062306a36Sopenharmony_ci sysvals.cgtest = getArgInt('cgtest', value, 0, 1, False) 654162306a36Sopenharmony_ci elif(option == 'cgphase'): 654262306a36Sopenharmony_ci d = Data(0) 654362306a36Sopenharmony_ci if value not in d.phasedef: 654462306a36Sopenharmony_ci doError('invalid phase --> (%s: %s), valid phases are %s'\ 654562306a36Sopenharmony_ci % (option, value, d.phasedef.keys()), True) 654662306a36Sopenharmony_ci sysvals.cgphase = value 654762306a36Sopenharmony_ci elif(option == 'fadd'): 654862306a36Sopenharmony_ci file = sysvals.configFile(value) 654962306a36Sopenharmony_ci if(not file): 655062306a36Sopenharmony_ci doError('%s does not exist' % value) 655162306a36Sopenharmony_ci sysvals.addFtraceFilterFunctions(file) 655262306a36Sopenharmony_ci elif(option == 'result'): 655362306a36Sopenharmony_ci sysvals.result = value 655462306a36Sopenharmony_ci elif(option == 'multi'): 655562306a36Sopenharmony_ci nums = value.split() 655662306a36Sopenharmony_ci if len(nums) != 2: 655762306a36Sopenharmony_ci doError('multi requires 2 integers (exec_count and delay)', True) 655862306a36Sopenharmony_ci sysvals.multiinit(nums[0], nums[1]) 655962306a36Sopenharmony_ci elif(option == 'devicefilter'): 656062306a36Sopenharmony_ci sysvals.setDeviceFilter(value) 656162306a36Sopenharmony_ci elif(option == 'expandcg'): 656262306a36Sopenharmony_ci sysvals.cgexp = checkArgBool(option, value) 656362306a36Sopenharmony_ci elif(option == 'srgap'): 656462306a36Sopenharmony_ci if checkArgBool(option, value): 656562306a36Sopenharmony_ci sysvals.srgap = 5 656662306a36Sopenharmony_ci elif(option == 'mode'): 656762306a36Sopenharmony_ci sysvals.suspendmode = value 656862306a36Sopenharmony_ci elif(option == 'command' or option == 'cmd'): 656962306a36Sopenharmony_ci sysvals.testcommand = value 657062306a36Sopenharmony_ci elif(option == 'x2delay'): 657162306a36Sopenharmony_ci sysvals.x2delay = getArgInt('x2delay', value, 0, 60000, False) 657262306a36Sopenharmony_ci elif(option == 'predelay'): 657362306a36Sopenharmony_ci sysvals.predelay = getArgInt('predelay', value, 0, 60000, False) 657462306a36Sopenharmony_ci elif(option == 'postdelay'): 657562306a36Sopenharmony_ci sysvals.postdelay = getArgInt('postdelay', value, 0, 60000, False) 657662306a36Sopenharmony_ci elif(option == 'maxdepth'): 657762306a36Sopenharmony_ci sysvals.max_graph_depth = getArgInt('maxdepth', value, 0, 1000, False) 657862306a36Sopenharmony_ci elif(option == 'rtcwake'): 657962306a36Sopenharmony_ci if value in switchoff: 658062306a36Sopenharmony_ci sysvals.rtcwake = False 658162306a36Sopenharmony_ci else: 658262306a36Sopenharmony_ci sysvals.rtcwake = True 658362306a36Sopenharmony_ci sysvals.rtcwaketime = getArgInt('rtcwake', value, 0, 3600, False) 658462306a36Sopenharmony_ci elif(option == 'timeprec'): 658562306a36Sopenharmony_ci sysvals.setPrecision(getArgInt('timeprec', value, 0, 6, False)) 658662306a36Sopenharmony_ci elif(option == 'mindev'): 658762306a36Sopenharmony_ci sysvals.mindevlen = getArgFloat('mindev', value, 0.0, 10000.0, False) 658862306a36Sopenharmony_ci elif(option == 'callloop-maxgap'): 658962306a36Sopenharmony_ci sysvals.callloopmaxgap = getArgFloat('callloop-maxgap', value, 0.0, 1.0, False) 659062306a36Sopenharmony_ci elif(option == 'callloop-maxlen'): 659162306a36Sopenharmony_ci sysvals.callloopmaxgap = getArgFloat('callloop-maxlen', value, 0.0, 1.0, False) 659262306a36Sopenharmony_ci elif(option == 'mincg'): 659362306a36Sopenharmony_ci sysvals.mincglen = getArgFloat('mincg', value, 0.0, 10000.0, False) 659462306a36Sopenharmony_ci elif(option == 'bufsize'): 659562306a36Sopenharmony_ci sysvals.bufsize = getArgInt('bufsize', value, 1, 1024*1024*8, False) 659662306a36Sopenharmony_ci elif(option == 'output-dir'): 659762306a36Sopenharmony_ci sysvals.outdir = sysvals.setOutputFolder(value) 659862306a36Sopenharmony_ci 659962306a36Sopenharmony_ci if sysvals.suspendmode == 'command' and not sysvals.testcommand: 660062306a36Sopenharmony_ci doError('No command supplied for mode "command"') 660162306a36Sopenharmony_ci 660262306a36Sopenharmony_ci # compatibility errors 660362306a36Sopenharmony_ci if sysvals.usedevsrc and sysvals.usecallgraph: 660462306a36Sopenharmony_ci doError('-dev is not compatible with -f') 660562306a36Sopenharmony_ci if sysvals.usecallgraph and sysvals.useprocmon: 660662306a36Sopenharmony_ci doError('-proc is not compatible with -f') 660762306a36Sopenharmony_ci 660862306a36Sopenharmony_ci if overridekprobes: 660962306a36Sopenharmony_ci sysvals.tracefuncs = dict() 661062306a36Sopenharmony_ci if overridedevkprobes: 661162306a36Sopenharmony_ci sysvals.dev_tracefuncs = dict() 661262306a36Sopenharmony_ci 661362306a36Sopenharmony_ci kprobes = dict() 661462306a36Sopenharmony_ci kprobesec = 'dev_timeline_functions_'+platform.machine() 661562306a36Sopenharmony_ci if kprobesec in sections: 661662306a36Sopenharmony_ci for name in Config.options(kprobesec): 661762306a36Sopenharmony_ci text = Config.get(kprobesec, name) 661862306a36Sopenharmony_ci kprobes[name] = (text, True) 661962306a36Sopenharmony_ci kprobesec = 'timeline_functions_'+platform.machine() 662062306a36Sopenharmony_ci if kprobesec in sections: 662162306a36Sopenharmony_ci for name in Config.options(kprobesec): 662262306a36Sopenharmony_ci if name in kprobes: 662362306a36Sopenharmony_ci doError('Duplicate timeline function found "%s"' % (name)) 662462306a36Sopenharmony_ci text = Config.get(kprobesec, name) 662562306a36Sopenharmony_ci kprobes[name] = (text, False) 662662306a36Sopenharmony_ci 662762306a36Sopenharmony_ci for name in kprobes: 662862306a36Sopenharmony_ci function = name 662962306a36Sopenharmony_ci format = name 663062306a36Sopenharmony_ci color = '' 663162306a36Sopenharmony_ci args = dict() 663262306a36Sopenharmony_ci text, dev = kprobes[name] 663362306a36Sopenharmony_ci data = text.split() 663462306a36Sopenharmony_ci i = 0 663562306a36Sopenharmony_ci for val in data: 663662306a36Sopenharmony_ci # bracketted strings are special formatting, read them separately 663762306a36Sopenharmony_ci if val[0] == '[' and val[-1] == ']': 663862306a36Sopenharmony_ci for prop in val[1:-1].split(','): 663962306a36Sopenharmony_ci p = prop.split('=') 664062306a36Sopenharmony_ci if p[0] == 'color': 664162306a36Sopenharmony_ci try: 664262306a36Sopenharmony_ci color = int(p[1], 16) 664362306a36Sopenharmony_ci color = '#'+p[1] 664462306a36Sopenharmony_ci except: 664562306a36Sopenharmony_ci color = p[1] 664662306a36Sopenharmony_ci continue 664762306a36Sopenharmony_ci # first real arg should be the format string 664862306a36Sopenharmony_ci if i == 0: 664962306a36Sopenharmony_ci format = val 665062306a36Sopenharmony_ci # all other args are actual function args 665162306a36Sopenharmony_ci else: 665262306a36Sopenharmony_ci d = val.split('=') 665362306a36Sopenharmony_ci args[d[0]] = d[1] 665462306a36Sopenharmony_ci i += 1 665562306a36Sopenharmony_ci if not function or not format: 665662306a36Sopenharmony_ci doError('Invalid kprobe: %s' % name) 665762306a36Sopenharmony_ci for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format): 665862306a36Sopenharmony_ci if arg not in args: 665962306a36Sopenharmony_ci doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 666062306a36Sopenharmony_ci if (dev and name in sysvals.dev_tracefuncs) or (not dev and name in sysvals.tracefuncs): 666162306a36Sopenharmony_ci doError('Duplicate timeline function found "%s"' % (name)) 666262306a36Sopenharmony_ci 666362306a36Sopenharmony_ci kp = { 666462306a36Sopenharmony_ci 'name': name, 666562306a36Sopenharmony_ci 'func': function, 666662306a36Sopenharmony_ci 'format': format, 666762306a36Sopenharmony_ci sysvals.archargs: args 666862306a36Sopenharmony_ci } 666962306a36Sopenharmony_ci if color: 667062306a36Sopenharmony_ci kp['color'] = color 667162306a36Sopenharmony_ci if dev: 667262306a36Sopenharmony_ci sysvals.dev_tracefuncs[name] = kp 667362306a36Sopenharmony_ci else: 667462306a36Sopenharmony_ci sysvals.tracefuncs[name] = kp 667562306a36Sopenharmony_ci 667662306a36Sopenharmony_ci# Function: printHelp 667762306a36Sopenharmony_ci# Description: 667862306a36Sopenharmony_ci# print out the help text 667962306a36Sopenharmony_cidef printHelp(): 668062306a36Sopenharmony_ci pprint('\n%s v%s\n'\ 668162306a36Sopenharmony_ci 'Usage: sudo sleepgraph <options> <commands>\n'\ 668262306a36Sopenharmony_ci '\n'\ 668362306a36Sopenharmony_ci 'Description:\n'\ 668462306a36Sopenharmony_ci ' This tool is designed to assist kernel and OS developers in optimizing\n'\ 668562306a36Sopenharmony_ci ' their linux stack\'s suspend/resume time. Using a kernel image built\n'\ 668662306a36Sopenharmony_ci ' with a few extra options enabled, the tool will execute a suspend and\n'\ 668762306a36Sopenharmony_ci ' capture dmesg and ftrace data until resume is complete. This data is\n'\ 668862306a36Sopenharmony_ci ' transformed into a device timeline and an optional callgraph to give\n'\ 668962306a36Sopenharmony_ci ' a detailed view of which devices/subsystems are taking the most\n'\ 669062306a36Sopenharmony_ci ' time in suspend/resume.\n'\ 669162306a36Sopenharmony_ci '\n'\ 669262306a36Sopenharmony_ci ' If no specific command is given, the default behavior is to initiate\n'\ 669362306a36Sopenharmony_ci ' a suspend/resume and capture the dmesg/ftrace output as an html timeline.\n'\ 669462306a36Sopenharmony_ci '\n'\ 669562306a36Sopenharmony_ci ' Generates output files in subdirectory: suspend-yymmdd-HHMMSS\n'\ 669662306a36Sopenharmony_ci ' HTML output: <hostname>_<mode>.html\n'\ 669762306a36Sopenharmony_ci ' raw dmesg output: <hostname>_<mode>_dmesg.txt\n'\ 669862306a36Sopenharmony_ci ' raw ftrace output: <hostname>_<mode>_ftrace.txt\n'\ 669962306a36Sopenharmony_ci '\n'\ 670062306a36Sopenharmony_ci 'Options:\n'\ 670162306a36Sopenharmony_ci ' -h Print this help text\n'\ 670262306a36Sopenharmony_ci ' -v Print the current tool version\n'\ 670362306a36Sopenharmony_ci ' -config fn Pull arguments and config options from file fn\n'\ 670462306a36Sopenharmony_ci ' -verbose Print extra information during execution and analysis\n'\ 670562306a36Sopenharmony_ci ' -m mode Mode to initiate for suspend (default: %s)\n'\ 670662306a36Sopenharmony_ci ' -o name Overrides the output subdirectory name when running a new test\n'\ 670762306a36Sopenharmony_ci ' default: suspend-{date}-{time}\n'\ 670862306a36Sopenharmony_ci ' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)\n'\ 670962306a36Sopenharmony_ci ' -addlogs Add the dmesg and ftrace logs to the html output\n'\ 671062306a36Sopenharmony_ci ' -noturbostat Dont use turbostat in freeze mode (default: disabled)\n'\ 671162306a36Sopenharmony_ci ' -srgap Add a visible gap in the timeline between sus/res (default: disabled)\n'\ 671262306a36Sopenharmony_ci ' -skiphtml Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\ 671362306a36Sopenharmony_ci ' -result fn Export a results table to a text file for parsing.\n'\ 671462306a36Sopenharmony_ci ' -wifi If a wifi connection is available, check that it reconnects after resume.\n'\ 671562306a36Sopenharmony_ci ' -wifitrace Trace kernel execution through wifi reconnect.\n'\ 671662306a36Sopenharmony_ci ' -netfix Use netfix to reset the network in the event it fails to resume.\n'\ 671762306a36Sopenharmony_ci ' [testprep]\n'\ 671862306a36Sopenharmony_ci ' -sync Sync the filesystems before starting the test\n'\ 671962306a36Sopenharmony_ci ' -rs on/off Enable/disable runtime suspend for all devices, restore all after test\n'\ 672062306a36Sopenharmony_ci ' -display m Change the display mode to m for the test (on/off/standby/suspend)\n'\ 672162306a36Sopenharmony_ci ' [advanced]\n'\ 672262306a36Sopenharmony_ci ' -gzip Gzip the trace and dmesg logs to save space\n'\ 672362306a36Sopenharmony_ci ' -cmd {s} Run the timeline over a custom command, e.g. "sync -d"\n'\ 672462306a36Sopenharmony_ci ' -proc Add usermode process info into the timeline (default: disabled)\n'\ 672562306a36Sopenharmony_ci ' -dev Add kernel function calls and threads to the timeline (default: disabled)\n'\ 672662306a36Sopenharmony_ci ' -x2 Run two suspend/resumes back to back (default: disabled)\n'\ 672762306a36Sopenharmony_ci ' -x2delay t Include t ms delay between multiple test runs (default: 0 ms)\n'\ 672862306a36Sopenharmony_ci ' -predelay t Include t ms delay before 1st suspend (default: 0 ms)\n'\ 672962306a36Sopenharmony_ci ' -postdelay t Include t ms delay after last resume (default: 0 ms)\n'\ 673062306a36Sopenharmony_ci ' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 673162306a36Sopenharmony_ci ' -multi n d Execute <n> consecutive tests at <d> seconds intervals. If <n> is followed\n'\ 673262306a36Sopenharmony_ci ' by a "d", "h", or "m" execute for <n> days, hours, or mins instead.\n'\ 673362306a36Sopenharmony_ci ' The outputs will be created in a new subdirectory with a summary page.\n'\ 673462306a36Sopenharmony_ci ' -maxfail n Abort a -multi run after n consecutive fails (default is 0 = never abort)\n'\ 673562306a36Sopenharmony_ci ' [debug]\n'\ 673662306a36Sopenharmony_ci ' -f Use ftrace to create device callgraphs (default: disabled)\n'\ 673762306a36Sopenharmony_ci ' -ftop Use ftrace on the top level call: "%s" (default: disabled)\n'\ 673862306a36Sopenharmony_ci ' -maxdepth N limit the callgraph data to N call levels (default: 0=all)\n'\ 673962306a36Sopenharmony_ci ' -expandcg pre-expand the callgraph data in the html output (default: disabled)\n'\ 674062306a36Sopenharmony_ci ' -fadd file Add functions to be graphed in the timeline from a list in a text file\n'\ 674162306a36Sopenharmony_ci ' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names\n'\ 674262306a36Sopenharmony_ci ' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 674362306a36Sopenharmony_ci ' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)\n'\ 674462306a36Sopenharmony_ci ' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)\n'\ 674562306a36Sopenharmony_ci ' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)\n'\ 674662306a36Sopenharmony_ci ' -cgfilter S Filter the callgraph output in the timeline\n'\ 674762306a36Sopenharmony_ci ' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\ 674862306a36Sopenharmony_ci ' -bufsize N Set trace buffer size to N kilo-bytes (default: all of free memory)\n'\ 674962306a36Sopenharmony_ci ' -devdump Print out all the raw device data for each phase\n'\ 675062306a36Sopenharmony_ci ' -cgdump Print out all the raw callgraph data\n'\ 675162306a36Sopenharmony_ci '\n'\ 675262306a36Sopenharmony_ci 'Other commands:\n'\ 675362306a36Sopenharmony_ci ' -modes List available suspend modes\n'\ 675462306a36Sopenharmony_ci ' -status Test to see if the system is enabled to run this tool\n'\ 675562306a36Sopenharmony_ci ' -fpdt Print out the contents of the ACPI Firmware Performance Data Table\n'\ 675662306a36Sopenharmony_ci ' -wificheck Print out wifi connection info\n'\ 675762306a36Sopenharmony_ci ' -x<mode> Test xset by toggling the given mode (on/off/standby/suspend)\n'\ 675862306a36Sopenharmony_ci ' -sysinfo Print out system info extracted from BIOS\n'\ 675962306a36Sopenharmony_ci ' -devinfo Print out the pm settings of all devices which support runtime suspend\n'\ 676062306a36Sopenharmony_ci ' -cmdinfo Print out all the platform info collected before and after suspend/resume\n'\ 676162306a36Sopenharmony_ci ' -flist Print the list of functions currently being captured in ftrace\n'\ 676262306a36Sopenharmony_ci ' -flistall Print all functions capable of being captured in ftrace\n'\ 676362306a36Sopenharmony_ci ' -summary dir Create a summary of tests in this dir [-genhtml builds missing html]\n'\ 676462306a36Sopenharmony_ci ' [redo]\n'\ 676562306a36Sopenharmony_ci ' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)\n'\ 676662306a36Sopenharmony_ci ' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)\n'\ 676762306a36Sopenharmony_ci '' % (sysvals.title, sysvals.version, sysvals.suspendmode, sysvals.ftopfunc)) 676862306a36Sopenharmony_ci return True 676962306a36Sopenharmony_ci 677062306a36Sopenharmony_ci# ----------------- MAIN -------------------- 677162306a36Sopenharmony_ci# exec start (skipped if script is loaded as library) 677262306a36Sopenharmony_ciif __name__ == '__main__': 677362306a36Sopenharmony_ci genhtml = False 677462306a36Sopenharmony_ci cmd = '' 677562306a36Sopenharmony_ci simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall', 677662306a36Sopenharmony_ci '-devinfo', '-status', '-xon', '-xoff', '-xstandby', '-xsuspend', 677762306a36Sopenharmony_ci '-xinit', '-xreset', '-xstat', '-wificheck', '-cmdinfo'] 677862306a36Sopenharmony_ci if '-f' in sys.argv: 677962306a36Sopenharmony_ci sysvals.cgskip = sysvals.configFile('cgskip.txt') 678062306a36Sopenharmony_ci # loop through the command line arguments 678162306a36Sopenharmony_ci args = iter(sys.argv[1:]) 678262306a36Sopenharmony_ci for arg in args: 678362306a36Sopenharmony_ci if(arg == '-m'): 678462306a36Sopenharmony_ci try: 678562306a36Sopenharmony_ci val = next(args) 678662306a36Sopenharmony_ci except: 678762306a36Sopenharmony_ci doError('No mode supplied', True) 678862306a36Sopenharmony_ci if val == 'command' and not sysvals.testcommand: 678962306a36Sopenharmony_ci doError('No command supplied for mode "command"', True) 679062306a36Sopenharmony_ci sysvals.suspendmode = val 679162306a36Sopenharmony_ci elif(arg in simplecmds): 679262306a36Sopenharmony_ci cmd = arg[1:] 679362306a36Sopenharmony_ci elif(arg == '-h'): 679462306a36Sopenharmony_ci printHelp() 679562306a36Sopenharmony_ci sys.exit(0) 679662306a36Sopenharmony_ci elif(arg == '-v'): 679762306a36Sopenharmony_ci pprint("Version %s" % sysvals.version) 679862306a36Sopenharmony_ci sys.exit(0) 679962306a36Sopenharmony_ci elif(arg == '-debugtiming'): 680062306a36Sopenharmony_ci debugtiming = True 680162306a36Sopenharmony_ci elif(arg == '-x2'): 680262306a36Sopenharmony_ci sysvals.execcount = 2 680362306a36Sopenharmony_ci elif(arg == '-x2delay'): 680462306a36Sopenharmony_ci sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000) 680562306a36Sopenharmony_ci elif(arg == '-predelay'): 680662306a36Sopenharmony_ci sysvals.predelay = getArgInt('-predelay', args, 0, 60000) 680762306a36Sopenharmony_ci elif(arg == '-postdelay'): 680862306a36Sopenharmony_ci sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000) 680962306a36Sopenharmony_ci elif(arg == '-f'): 681062306a36Sopenharmony_ci sysvals.usecallgraph = True 681162306a36Sopenharmony_ci elif(arg == '-ftop'): 681262306a36Sopenharmony_ci sysvals.usecallgraph = True 681362306a36Sopenharmony_ci sysvals.ftop = True 681462306a36Sopenharmony_ci sysvals.usekprobes = False 681562306a36Sopenharmony_ci elif(arg == '-skiphtml'): 681662306a36Sopenharmony_ci sysvals.skiphtml = True 681762306a36Sopenharmony_ci elif(arg == '-cgdump'): 681862306a36Sopenharmony_ci sysvals.cgdump = True 681962306a36Sopenharmony_ci elif(arg == '-devdump'): 682062306a36Sopenharmony_ci sysvals.devdump = True 682162306a36Sopenharmony_ci elif(arg == '-genhtml'): 682262306a36Sopenharmony_ci genhtml = True 682362306a36Sopenharmony_ci elif(arg == '-addlogs'): 682462306a36Sopenharmony_ci sysvals.dmesglog = sysvals.ftracelog = True 682562306a36Sopenharmony_ci elif(arg == '-nologs'): 682662306a36Sopenharmony_ci sysvals.dmesglog = sysvals.ftracelog = False 682762306a36Sopenharmony_ci elif(arg == '-addlogdmesg'): 682862306a36Sopenharmony_ci sysvals.dmesglog = True 682962306a36Sopenharmony_ci elif(arg == '-addlogftrace'): 683062306a36Sopenharmony_ci sysvals.ftracelog = True 683162306a36Sopenharmony_ci elif(arg == '-noturbostat'): 683262306a36Sopenharmony_ci sysvals.tstat = False 683362306a36Sopenharmony_ci elif(arg == '-verbose'): 683462306a36Sopenharmony_ci sysvals.verbose = True 683562306a36Sopenharmony_ci elif(arg == '-proc'): 683662306a36Sopenharmony_ci sysvals.useprocmon = True 683762306a36Sopenharmony_ci elif(arg == '-dev'): 683862306a36Sopenharmony_ci sysvals.usedevsrc = True 683962306a36Sopenharmony_ci elif(arg == '-sync'): 684062306a36Sopenharmony_ci sysvals.sync = True 684162306a36Sopenharmony_ci elif(arg == '-wifi'): 684262306a36Sopenharmony_ci sysvals.wifi = True 684362306a36Sopenharmony_ci elif(arg == '-wifitrace'): 684462306a36Sopenharmony_ci sysvals.wifitrace = True 684562306a36Sopenharmony_ci elif(arg == '-netfix'): 684662306a36Sopenharmony_ci sysvals.netfix = True 684762306a36Sopenharmony_ci elif(arg == '-gzip'): 684862306a36Sopenharmony_ci sysvals.gzip = True 684962306a36Sopenharmony_ci elif(arg == '-info'): 685062306a36Sopenharmony_ci try: 685162306a36Sopenharmony_ci val = next(args) 685262306a36Sopenharmony_ci except: 685362306a36Sopenharmony_ci doError('-info requires one string argument', True) 685462306a36Sopenharmony_ci elif(arg == '-desc'): 685562306a36Sopenharmony_ci try: 685662306a36Sopenharmony_ci val = next(args) 685762306a36Sopenharmony_ci except: 685862306a36Sopenharmony_ci doError('-desc requires one string argument', True) 685962306a36Sopenharmony_ci elif(arg == '-rs'): 686062306a36Sopenharmony_ci try: 686162306a36Sopenharmony_ci val = next(args) 686262306a36Sopenharmony_ci except: 686362306a36Sopenharmony_ci doError('-rs requires "enable" or "disable"', True) 686462306a36Sopenharmony_ci if val.lower() in switchvalues: 686562306a36Sopenharmony_ci if val.lower() in switchoff: 686662306a36Sopenharmony_ci sysvals.rs = -1 686762306a36Sopenharmony_ci else: 686862306a36Sopenharmony_ci sysvals.rs = 1 686962306a36Sopenharmony_ci else: 687062306a36Sopenharmony_ci doError('invalid option: %s, use "enable/disable" or "on/off"' % val, True) 687162306a36Sopenharmony_ci elif(arg == '-display'): 687262306a36Sopenharmony_ci try: 687362306a36Sopenharmony_ci val = next(args) 687462306a36Sopenharmony_ci except: 687562306a36Sopenharmony_ci doError('-display requires an mode value', True) 687662306a36Sopenharmony_ci disopt = ['on', 'off', 'standby', 'suspend'] 687762306a36Sopenharmony_ci if val.lower() not in disopt: 687862306a36Sopenharmony_ci doError('valid display mode values are %s' % disopt, True) 687962306a36Sopenharmony_ci sysvals.display = val.lower() 688062306a36Sopenharmony_ci elif(arg == '-maxdepth'): 688162306a36Sopenharmony_ci sysvals.max_graph_depth = getArgInt('-maxdepth', args, 0, 1000) 688262306a36Sopenharmony_ci elif(arg == '-rtcwake'): 688362306a36Sopenharmony_ci try: 688462306a36Sopenharmony_ci val = next(args) 688562306a36Sopenharmony_ci except: 688662306a36Sopenharmony_ci doError('No rtcwake time supplied', True) 688762306a36Sopenharmony_ci if val.lower() in switchoff: 688862306a36Sopenharmony_ci sysvals.rtcwake = False 688962306a36Sopenharmony_ci else: 689062306a36Sopenharmony_ci sysvals.rtcwake = True 689162306a36Sopenharmony_ci sysvals.rtcwaketime = getArgInt('-rtcwake', val, 0, 3600, False) 689262306a36Sopenharmony_ci elif(arg == '-timeprec'): 689362306a36Sopenharmony_ci sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6)) 689462306a36Sopenharmony_ci elif(arg == '-mindev'): 689562306a36Sopenharmony_ci sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0) 689662306a36Sopenharmony_ci elif(arg == '-mincg'): 689762306a36Sopenharmony_ci sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0) 689862306a36Sopenharmony_ci elif(arg == '-bufsize'): 689962306a36Sopenharmony_ci sysvals.bufsize = getArgInt('-bufsize', args, 1, 1024*1024*8) 690062306a36Sopenharmony_ci elif(arg == '-cgtest'): 690162306a36Sopenharmony_ci sysvals.cgtest = getArgInt('-cgtest', args, 0, 1) 690262306a36Sopenharmony_ci elif(arg == '-cgphase'): 690362306a36Sopenharmony_ci try: 690462306a36Sopenharmony_ci val = next(args) 690562306a36Sopenharmony_ci except: 690662306a36Sopenharmony_ci doError('No phase name supplied', True) 690762306a36Sopenharmony_ci d = Data(0) 690862306a36Sopenharmony_ci if val not in d.phasedef: 690962306a36Sopenharmony_ci doError('invalid phase --> (%s: %s), valid phases are %s'\ 691062306a36Sopenharmony_ci % (arg, val, d.phasedef.keys()), True) 691162306a36Sopenharmony_ci sysvals.cgphase = val 691262306a36Sopenharmony_ci elif(arg == '-cgfilter'): 691362306a36Sopenharmony_ci try: 691462306a36Sopenharmony_ci val = next(args) 691562306a36Sopenharmony_ci except: 691662306a36Sopenharmony_ci doError('No callgraph functions supplied', True) 691762306a36Sopenharmony_ci sysvals.setCallgraphFilter(val) 691862306a36Sopenharmony_ci elif(arg == '-skipkprobe'): 691962306a36Sopenharmony_ci try: 692062306a36Sopenharmony_ci val = next(args) 692162306a36Sopenharmony_ci except: 692262306a36Sopenharmony_ci doError('No kprobe functions supplied', True) 692362306a36Sopenharmony_ci sysvals.skipKprobes(val) 692462306a36Sopenharmony_ci elif(arg == '-cgskip'): 692562306a36Sopenharmony_ci try: 692662306a36Sopenharmony_ci val = next(args) 692762306a36Sopenharmony_ci except: 692862306a36Sopenharmony_ci doError('No file supplied', True) 692962306a36Sopenharmony_ci if val.lower() in switchoff: 693062306a36Sopenharmony_ci sysvals.cgskip = '' 693162306a36Sopenharmony_ci else: 693262306a36Sopenharmony_ci sysvals.cgskip = sysvals.configFile(val) 693362306a36Sopenharmony_ci if(not sysvals.cgskip): 693462306a36Sopenharmony_ci doError('%s does not exist' % sysvals.cgskip) 693562306a36Sopenharmony_ci elif(arg == '-callloop-maxgap'): 693662306a36Sopenharmony_ci sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', args, 0.0, 1.0) 693762306a36Sopenharmony_ci elif(arg == '-callloop-maxlen'): 693862306a36Sopenharmony_ci sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0) 693962306a36Sopenharmony_ci elif(arg == '-cmd'): 694062306a36Sopenharmony_ci try: 694162306a36Sopenharmony_ci val = next(args) 694262306a36Sopenharmony_ci except: 694362306a36Sopenharmony_ci doError('No command string supplied', True) 694462306a36Sopenharmony_ci sysvals.testcommand = val 694562306a36Sopenharmony_ci sysvals.suspendmode = 'command' 694662306a36Sopenharmony_ci elif(arg == '-expandcg'): 694762306a36Sopenharmony_ci sysvals.cgexp = True 694862306a36Sopenharmony_ci elif(arg == '-srgap'): 694962306a36Sopenharmony_ci sysvals.srgap = 5 695062306a36Sopenharmony_ci elif(arg == '-maxfail'): 695162306a36Sopenharmony_ci sysvals.maxfail = getArgInt('-maxfail', args, 0, 1000000) 695262306a36Sopenharmony_ci elif(arg == '-multi'): 695362306a36Sopenharmony_ci try: 695462306a36Sopenharmony_ci c, d = next(args), next(args) 695562306a36Sopenharmony_ci except: 695662306a36Sopenharmony_ci doError('-multi requires two values', True) 695762306a36Sopenharmony_ci sysvals.multiinit(c, d) 695862306a36Sopenharmony_ci elif(arg == '-o'): 695962306a36Sopenharmony_ci try: 696062306a36Sopenharmony_ci val = next(args) 696162306a36Sopenharmony_ci except: 696262306a36Sopenharmony_ci doError('No subdirectory name supplied', True) 696362306a36Sopenharmony_ci sysvals.outdir = sysvals.setOutputFolder(val) 696462306a36Sopenharmony_ci elif(arg == '-config'): 696562306a36Sopenharmony_ci try: 696662306a36Sopenharmony_ci val = next(args) 696762306a36Sopenharmony_ci except: 696862306a36Sopenharmony_ci doError('No text file supplied', True) 696962306a36Sopenharmony_ci file = sysvals.configFile(val) 697062306a36Sopenharmony_ci if(not file): 697162306a36Sopenharmony_ci doError('%s does not exist' % val) 697262306a36Sopenharmony_ci configFromFile(file) 697362306a36Sopenharmony_ci elif(arg == '-fadd'): 697462306a36Sopenharmony_ci try: 697562306a36Sopenharmony_ci val = next(args) 697662306a36Sopenharmony_ci except: 697762306a36Sopenharmony_ci doError('No text file supplied', True) 697862306a36Sopenharmony_ci file = sysvals.configFile(val) 697962306a36Sopenharmony_ci if(not file): 698062306a36Sopenharmony_ci doError('%s does not exist' % val) 698162306a36Sopenharmony_ci sysvals.addFtraceFilterFunctions(file) 698262306a36Sopenharmony_ci elif(arg == '-dmesg'): 698362306a36Sopenharmony_ci try: 698462306a36Sopenharmony_ci val = next(args) 698562306a36Sopenharmony_ci except: 698662306a36Sopenharmony_ci doError('No dmesg file supplied', True) 698762306a36Sopenharmony_ci sysvals.notestrun = True 698862306a36Sopenharmony_ci sysvals.dmesgfile = val 698962306a36Sopenharmony_ci if(os.path.exists(sysvals.dmesgfile) == False): 699062306a36Sopenharmony_ci doError('%s does not exist' % sysvals.dmesgfile) 699162306a36Sopenharmony_ci elif(arg == '-ftrace'): 699262306a36Sopenharmony_ci try: 699362306a36Sopenharmony_ci val = next(args) 699462306a36Sopenharmony_ci except: 699562306a36Sopenharmony_ci doError('No ftrace file supplied', True) 699662306a36Sopenharmony_ci sysvals.notestrun = True 699762306a36Sopenharmony_ci sysvals.ftracefile = val 699862306a36Sopenharmony_ci if(os.path.exists(sysvals.ftracefile) == False): 699962306a36Sopenharmony_ci doError('%s does not exist' % sysvals.ftracefile) 700062306a36Sopenharmony_ci elif(arg == '-summary'): 700162306a36Sopenharmony_ci try: 700262306a36Sopenharmony_ci val = next(args) 700362306a36Sopenharmony_ci except: 700462306a36Sopenharmony_ci doError('No directory supplied', True) 700562306a36Sopenharmony_ci cmd = 'summary' 700662306a36Sopenharmony_ci sysvals.outdir = val 700762306a36Sopenharmony_ci sysvals.notestrun = True 700862306a36Sopenharmony_ci if(os.path.isdir(val) == False): 700962306a36Sopenharmony_ci doError('%s is not accesible' % val) 701062306a36Sopenharmony_ci elif(arg == '-filter'): 701162306a36Sopenharmony_ci try: 701262306a36Sopenharmony_ci val = next(args) 701362306a36Sopenharmony_ci except: 701462306a36Sopenharmony_ci doError('No devnames supplied', True) 701562306a36Sopenharmony_ci sysvals.setDeviceFilter(val) 701662306a36Sopenharmony_ci elif(arg == '-result'): 701762306a36Sopenharmony_ci try: 701862306a36Sopenharmony_ci val = next(args) 701962306a36Sopenharmony_ci except: 702062306a36Sopenharmony_ci doError('No result file supplied', True) 702162306a36Sopenharmony_ci sysvals.result = val 702262306a36Sopenharmony_ci sysvals.signalHandlerInit() 702362306a36Sopenharmony_ci else: 702462306a36Sopenharmony_ci doError('Invalid argument: '+arg, True) 702562306a36Sopenharmony_ci 702662306a36Sopenharmony_ci # compatibility errors 702762306a36Sopenharmony_ci if(sysvals.usecallgraph and sysvals.usedevsrc): 702862306a36Sopenharmony_ci doError('-dev is not compatible with -f') 702962306a36Sopenharmony_ci if(sysvals.usecallgraph and sysvals.useprocmon): 703062306a36Sopenharmony_ci doError('-proc is not compatible with -f') 703162306a36Sopenharmony_ci 703262306a36Sopenharmony_ci if sysvals.usecallgraph and sysvals.cgskip: 703362306a36Sopenharmony_ci sysvals.vprint('Using cgskip file: %s' % sysvals.cgskip) 703462306a36Sopenharmony_ci sysvals.setCallgraphBlacklist(sysvals.cgskip) 703562306a36Sopenharmony_ci 703662306a36Sopenharmony_ci # callgraph size cannot exceed device size 703762306a36Sopenharmony_ci if sysvals.mincglen < sysvals.mindevlen: 703862306a36Sopenharmony_ci sysvals.mincglen = sysvals.mindevlen 703962306a36Sopenharmony_ci 704062306a36Sopenharmony_ci # remove existing buffers before calculating memory 704162306a36Sopenharmony_ci if(sysvals.usecallgraph or sysvals.usedevsrc): 704262306a36Sopenharmony_ci sysvals.fsetVal('16', 'buffer_size_kb') 704362306a36Sopenharmony_ci sysvals.cpuInfo() 704462306a36Sopenharmony_ci 704562306a36Sopenharmony_ci # just run a utility command and exit 704662306a36Sopenharmony_ci if(cmd != ''): 704762306a36Sopenharmony_ci ret = 0 704862306a36Sopenharmony_ci if(cmd == 'status'): 704962306a36Sopenharmony_ci if not statusCheck(True): 705062306a36Sopenharmony_ci ret = 1 705162306a36Sopenharmony_ci elif(cmd == 'fpdt'): 705262306a36Sopenharmony_ci if not getFPDT(True): 705362306a36Sopenharmony_ci ret = 1 705462306a36Sopenharmony_ci elif(cmd == 'sysinfo'): 705562306a36Sopenharmony_ci sysvals.printSystemInfo(True) 705662306a36Sopenharmony_ci elif(cmd == 'devinfo'): 705762306a36Sopenharmony_ci deviceInfo() 705862306a36Sopenharmony_ci elif(cmd == 'modes'): 705962306a36Sopenharmony_ci pprint(getModes()) 706062306a36Sopenharmony_ci elif(cmd == 'flist'): 706162306a36Sopenharmony_ci sysvals.getFtraceFilterFunctions(True) 706262306a36Sopenharmony_ci elif(cmd == 'flistall'): 706362306a36Sopenharmony_ci sysvals.getFtraceFilterFunctions(False) 706462306a36Sopenharmony_ci elif(cmd == 'summary'): 706562306a36Sopenharmony_ci runSummary(sysvals.outdir, True, genhtml) 706662306a36Sopenharmony_ci elif(cmd in ['xon', 'xoff', 'xstandby', 'xsuspend', 'xinit', 'xreset']): 706762306a36Sopenharmony_ci sysvals.verbose = True 706862306a36Sopenharmony_ci ret = sysvals.displayControl(cmd[1:]) 706962306a36Sopenharmony_ci elif(cmd == 'xstat'): 707062306a36Sopenharmony_ci pprint('Display Status: %s' % sysvals.displayControl('stat').upper()) 707162306a36Sopenharmony_ci elif(cmd == 'wificheck'): 707262306a36Sopenharmony_ci dev = sysvals.checkWifi() 707362306a36Sopenharmony_ci if dev: 707462306a36Sopenharmony_ci print('%s is connected' % sysvals.wifiDetails(dev)) 707562306a36Sopenharmony_ci else: 707662306a36Sopenharmony_ci print('No wifi connection found') 707762306a36Sopenharmony_ci elif(cmd == 'cmdinfo'): 707862306a36Sopenharmony_ci for out in sysvals.cmdinfo(False, True): 707962306a36Sopenharmony_ci print('[%s - %s]\n%s\n' % out) 708062306a36Sopenharmony_ci sys.exit(ret) 708162306a36Sopenharmony_ci 708262306a36Sopenharmony_ci # if instructed, re-analyze existing data files 708362306a36Sopenharmony_ci if(sysvals.notestrun): 708462306a36Sopenharmony_ci stamp = rerunTest(sysvals.outdir) 708562306a36Sopenharmony_ci sysvals.outputResult(stamp) 708662306a36Sopenharmony_ci sys.exit(0) 708762306a36Sopenharmony_ci 708862306a36Sopenharmony_ci # verify that we can run a test 708962306a36Sopenharmony_ci error = statusCheck() 709062306a36Sopenharmony_ci if(error): 709162306a36Sopenharmony_ci doError(error) 709262306a36Sopenharmony_ci 709362306a36Sopenharmony_ci # extract mem/disk extra modes and convert 709462306a36Sopenharmony_ci mode = sysvals.suspendmode 709562306a36Sopenharmony_ci if mode.startswith('mem'): 709662306a36Sopenharmony_ci memmode = mode.split('-', 1)[-1] if '-' in mode else 'deep' 709762306a36Sopenharmony_ci if memmode == 'shallow': 709862306a36Sopenharmony_ci mode = 'standby' 709962306a36Sopenharmony_ci elif memmode == 's2idle': 710062306a36Sopenharmony_ci mode = 'freeze' 710162306a36Sopenharmony_ci else: 710262306a36Sopenharmony_ci mode = 'mem' 710362306a36Sopenharmony_ci sysvals.memmode = memmode 710462306a36Sopenharmony_ci sysvals.suspendmode = mode 710562306a36Sopenharmony_ci if mode.startswith('disk-'): 710662306a36Sopenharmony_ci sysvals.diskmode = mode.split('-', 1)[-1] 710762306a36Sopenharmony_ci sysvals.suspendmode = 'disk' 710862306a36Sopenharmony_ci sysvals.systemInfo(dmidecode(sysvals.mempath)) 710962306a36Sopenharmony_ci 711062306a36Sopenharmony_ci failcnt, ret = 0, 0 711162306a36Sopenharmony_ci if sysvals.multitest['run']: 711262306a36Sopenharmony_ci # run multiple tests in a separate subdirectory 711362306a36Sopenharmony_ci if not sysvals.outdir: 711462306a36Sopenharmony_ci if 'time' in sysvals.multitest: 711562306a36Sopenharmony_ci s = '-%dm' % sysvals.multitest['time'] 711662306a36Sopenharmony_ci else: 711762306a36Sopenharmony_ci s = '-x%d' % sysvals.multitest['count'] 711862306a36Sopenharmony_ci sysvals.outdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S'+s) 711962306a36Sopenharmony_ci if not os.path.isdir(sysvals.outdir): 712062306a36Sopenharmony_ci os.makedirs(sysvals.outdir) 712162306a36Sopenharmony_ci sysvals.sudoUserchown(sysvals.outdir) 712262306a36Sopenharmony_ci finish = datetime.now() 712362306a36Sopenharmony_ci if 'time' in sysvals.multitest: 712462306a36Sopenharmony_ci finish += timedelta(minutes=sysvals.multitest['time']) 712562306a36Sopenharmony_ci for i in range(sysvals.multitest['count']): 712662306a36Sopenharmony_ci sysvals.multistat(True, i, finish) 712762306a36Sopenharmony_ci if i != 0 and sysvals.multitest['delay'] > 0: 712862306a36Sopenharmony_ci pprint('Waiting %d seconds...' % (sysvals.multitest['delay'])) 712962306a36Sopenharmony_ci time.sleep(sysvals.multitest['delay']) 713062306a36Sopenharmony_ci fmt = 'suspend-%y%m%d-%H%M%S' 713162306a36Sopenharmony_ci sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt)) 713262306a36Sopenharmony_ci ret = runTest(i+1, not sysvals.verbose) 713362306a36Sopenharmony_ci failcnt = 0 if not ret else failcnt + 1 713462306a36Sopenharmony_ci if sysvals.maxfail > 0 and failcnt >= sysvals.maxfail: 713562306a36Sopenharmony_ci pprint('Maximum fail count of %d reached, aborting multitest' % (sysvals.maxfail)) 713662306a36Sopenharmony_ci break 713762306a36Sopenharmony_ci sysvals.resetlog() 713862306a36Sopenharmony_ci sysvals.multistat(False, i, finish) 713962306a36Sopenharmony_ci if 'time' in sysvals.multitest and datetime.now() >= finish: 714062306a36Sopenharmony_ci break 714162306a36Sopenharmony_ci if not sysvals.skiphtml: 714262306a36Sopenharmony_ci runSummary(sysvals.outdir, False, False) 714362306a36Sopenharmony_ci sysvals.sudoUserchown(sysvals.outdir) 714462306a36Sopenharmony_ci else: 714562306a36Sopenharmony_ci if sysvals.outdir: 714662306a36Sopenharmony_ci sysvals.testdir = sysvals.outdir 714762306a36Sopenharmony_ci # run the test in the current directory 714862306a36Sopenharmony_ci ret = runTest() 714962306a36Sopenharmony_ci 715062306a36Sopenharmony_ci # reset to default values after testing 715162306a36Sopenharmony_ci if sysvals.display: 715262306a36Sopenharmony_ci sysvals.displayControl('reset') 715362306a36Sopenharmony_ci if sysvals.rs != 0: 715462306a36Sopenharmony_ci sysvals.setRuntimeSuspend(False) 715562306a36Sopenharmony_ci sys.exit(ret) 7156