18c2ecf20Sopenharmony_ci#!/usr/bin/env python3 28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-only 38c2ecf20Sopenharmony_ci# 48c2ecf20Sopenharmony_ci# Tool for analyzing suspend/resume timing 58c2ecf20Sopenharmony_ci# Copyright (c) 2013, Intel Corporation. 68c2ecf20Sopenharmony_ci# 78c2ecf20Sopenharmony_ci# This program is free software; you can redistribute it and/or modify it 88c2ecf20Sopenharmony_ci# under the terms and conditions of the GNU General Public License, 98c2ecf20Sopenharmony_ci# version 2, as published by the Free Software Foundation. 108c2ecf20Sopenharmony_ci# 118c2ecf20Sopenharmony_ci# This program is distributed in the hope it will be useful, but WITHOUT 128c2ecf20Sopenharmony_ci# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 138c2ecf20Sopenharmony_ci# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 148c2ecf20Sopenharmony_ci# more details. 158c2ecf20Sopenharmony_ci# 168c2ecf20Sopenharmony_ci# Authors: 178c2ecf20Sopenharmony_ci# Todd Brandt <todd.e.brandt@linux.intel.com> 188c2ecf20Sopenharmony_ci# 198c2ecf20Sopenharmony_ci# Links: 208c2ecf20Sopenharmony_ci# Home Page 218c2ecf20Sopenharmony_ci# https://01.org/pm-graph 228c2ecf20Sopenharmony_ci# Source repo 238c2ecf20Sopenharmony_ci# git@github.com:intel/pm-graph 248c2ecf20Sopenharmony_ci# 258c2ecf20Sopenharmony_ci# Description: 268c2ecf20Sopenharmony_ci# This tool is designed to assist kernel and OS developers in optimizing 278c2ecf20Sopenharmony_ci# their linux stack's suspend/resume time. Using a kernel image built 288c2ecf20Sopenharmony_ci# with a few extra options enabled, the tool will execute a suspend and 298c2ecf20Sopenharmony_ci# will capture dmesg and ftrace data until resume is complete. This data 308c2ecf20Sopenharmony_ci# is transformed into a device timeline and a callgraph to give a quick 318c2ecf20Sopenharmony_ci# and detailed view of which devices and callbacks are taking the most 328c2ecf20Sopenharmony_ci# time in suspend/resume. The output is a single html file which can be 338c2ecf20Sopenharmony_ci# viewed in firefox or chrome. 348c2ecf20Sopenharmony_ci# 358c2ecf20Sopenharmony_ci# The following kernel build options are required: 368c2ecf20Sopenharmony_ci# CONFIG_DEVMEM=y 378c2ecf20Sopenharmony_ci# CONFIG_PM_DEBUG=y 388c2ecf20Sopenharmony_ci# CONFIG_PM_SLEEP_DEBUG=y 398c2ecf20Sopenharmony_ci# CONFIG_FTRACE=y 408c2ecf20Sopenharmony_ci# CONFIG_FUNCTION_TRACER=y 418c2ecf20Sopenharmony_ci# CONFIG_FUNCTION_GRAPH_TRACER=y 428c2ecf20Sopenharmony_ci# CONFIG_KPROBES=y 438c2ecf20Sopenharmony_ci# CONFIG_KPROBES_ON_FTRACE=y 448c2ecf20Sopenharmony_ci# 458c2ecf20Sopenharmony_ci# For kernel versions older than 3.15: 468c2ecf20Sopenharmony_ci# The following additional kernel parameters are required: 478c2ecf20Sopenharmony_ci# (e.g. in file /etc/default/grub) 488c2ecf20Sopenharmony_ci# GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=16M ..." 498c2ecf20Sopenharmony_ci# 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci# ----------------- LIBRARIES -------------------- 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciimport sys 548c2ecf20Sopenharmony_ciimport time 558c2ecf20Sopenharmony_ciimport os 568c2ecf20Sopenharmony_ciimport string 578c2ecf20Sopenharmony_ciimport re 588c2ecf20Sopenharmony_ciimport platform 598c2ecf20Sopenharmony_ciimport signal 608c2ecf20Sopenharmony_ciimport codecs 618c2ecf20Sopenharmony_cifrom datetime import datetime, timedelta 628c2ecf20Sopenharmony_ciimport struct 638c2ecf20Sopenharmony_ciimport configparser 648c2ecf20Sopenharmony_ciimport gzip 658c2ecf20Sopenharmony_cifrom threading import Thread 668c2ecf20Sopenharmony_cifrom subprocess import call, Popen, PIPE 678c2ecf20Sopenharmony_ciimport base64 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cidef pprint(msg): 708c2ecf20Sopenharmony_ci print(msg) 718c2ecf20Sopenharmony_ci sys.stdout.flush() 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cidef ascii(text): 748c2ecf20Sopenharmony_ci return text.decode('ascii', 'ignore') 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci# ----------------- CLASSES -------------------- 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci# Class: SystemValues 798c2ecf20Sopenharmony_ci# Description: 808c2ecf20Sopenharmony_ci# A global, single-instance container used to 818c2ecf20Sopenharmony_ci# store system values and test parameters 828c2ecf20Sopenharmony_ciclass SystemValues: 838c2ecf20Sopenharmony_ci title = 'SleepGraph' 848c2ecf20Sopenharmony_ci version = '5.7' 858c2ecf20Sopenharmony_ci ansi = False 868c2ecf20Sopenharmony_ci rs = 0 878c2ecf20Sopenharmony_ci display = '' 888c2ecf20Sopenharmony_ci gzip = False 898c2ecf20Sopenharmony_ci sync = False 908c2ecf20Sopenharmony_ci wifi = False 918c2ecf20Sopenharmony_ci verbose = False 928c2ecf20Sopenharmony_ci testlog = True 938c2ecf20Sopenharmony_ci dmesglog = True 948c2ecf20Sopenharmony_ci ftracelog = False 958c2ecf20Sopenharmony_ci tstat = True 968c2ecf20Sopenharmony_ci mindevlen = 0.0 978c2ecf20Sopenharmony_ci mincglen = 0.0 988c2ecf20Sopenharmony_ci cgphase = '' 998c2ecf20Sopenharmony_ci cgtest = -1 1008c2ecf20Sopenharmony_ci cgskip = '' 1018c2ecf20Sopenharmony_ci maxfail = 0 1028c2ecf20Sopenharmony_ci multitest = {'run': False, 'count': 1000000, 'delay': 0} 1038c2ecf20Sopenharmony_ci max_graph_depth = 0 1048c2ecf20Sopenharmony_ci callloopmaxgap = 0.0001 1058c2ecf20Sopenharmony_ci callloopmaxlen = 0.005 1068c2ecf20Sopenharmony_ci bufsize = 0 1078c2ecf20Sopenharmony_ci cpucount = 0 1088c2ecf20Sopenharmony_ci memtotal = 204800 1098c2ecf20Sopenharmony_ci memfree = 204800 1108c2ecf20Sopenharmony_ci srgap = 0 1118c2ecf20Sopenharmony_ci cgexp = False 1128c2ecf20Sopenharmony_ci testdir = '' 1138c2ecf20Sopenharmony_ci outdir = '' 1148c2ecf20Sopenharmony_ci tpath = '/sys/kernel/debug/tracing/' 1158c2ecf20Sopenharmony_ci fpdtpath = '/sys/firmware/acpi/tables/FPDT' 1168c2ecf20Sopenharmony_ci epath = '/sys/kernel/debug/tracing/events/power/' 1178c2ecf20Sopenharmony_ci pmdpath = '/sys/power/pm_debug_messages' 1188c2ecf20Sopenharmony_ci traceevents = [ 1198c2ecf20Sopenharmony_ci 'suspend_resume', 1208c2ecf20Sopenharmony_ci 'wakeup_source_activate', 1218c2ecf20Sopenharmony_ci 'wakeup_source_deactivate', 1228c2ecf20Sopenharmony_ci 'device_pm_callback_end', 1238c2ecf20Sopenharmony_ci 'device_pm_callback_start' 1248c2ecf20Sopenharmony_ci ] 1258c2ecf20Sopenharmony_ci logmsg = '' 1268c2ecf20Sopenharmony_ci testcommand = '' 1278c2ecf20Sopenharmony_ci mempath = '/dev/mem' 1288c2ecf20Sopenharmony_ci powerfile = '/sys/power/state' 1298c2ecf20Sopenharmony_ci mempowerfile = '/sys/power/mem_sleep' 1308c2ecf20Sopenharmony_ci diskpowerfile = '/sys/power/disk' 1318c2ecf20Sopenharmony_ci suspendmode = 'mem' 1328c2ecf20Sopenharmony_ci memmode = '' 1338c2ecf20Sopenharmony_ci diskmode = '' 1348c2ecf20Sopenharmony_ci hostname = 'localhost' 1358c2ecf20Sopenharmony_ci prefix = 'test' 1368c2ecf20Sopenharmony_ci teststamp = '' 1378c2ecf20Sopenharmony_ci sysstamp = '' 1388c2ecf20Sopenharmony_ci dmesgstart = 0.0 1398c2ecf20Sopenharmony_ci dmesgfile = '' 1408c2ecf20Sopenharmony_ci ftracefile = '' 1418c2ecf20Sopenharmony_ci htmlfile = 'output.html' 1428c2ecf20Sopenharmony_ci result = '' 1438c2ecf20Sopenharmony_ci rtcwake = True 1448c2ecf20Sopenharmony_ci rtcwaketime = 15 1458c2ecf20Sopenharmony_ci rtcpath = '' 1468c2ecf20Sopenharmony_ci devicefilter = [] 1478c2ecf20Sopenharmony_ci cgfilter = [] 1488c2ecf20Sopenharmony_ci stamp = 0 1498c2ecf20Sopenharmony_ci execcount = 1 1508c2ecf20Sopenharmony_ci x2delay = 0 1518c2ecf20Sopenharmony_ci skiphtml = False 1528c2ecf20Sopenharmony_ci usecallgraph = False 1538c2ecf20Sopenharmony_ci ftopfunc = 'pm_suspend' 1548c2ecf20Sopenharmony_ci ftop = False 1558c2ecf20Sopenharmony_ci usetraceevents = False 1568c2ecf20Sopenharmony_ci usetracemarkers = True 1578c2ecf20Sopenharmony_ci usekprobes = True 1588c2ecf20Sopenharmony_ci usedevsrc = False 1598c2ecf20Sopenharmony_ci useprocmon = False 1608c2ecf20Sopenharmony_ci notestrun = False 1618c2ecf20Sopenharmony_ci cgdump = False 1628c2ecf20Sopenharmony_ci devdump = False 1638c2ecf20Sopenharmony_ci mixedphaseheight = True 1648c2ecf20Sopenharmony_ci devprops = dict() 1658c2ecf20Sopenharmony_ci platinfo = [] 1668c2ecf20Sopenharmony_ci predelay = 0 1678c2ecf20Sopenharmony_ci postdelay = 0 1688c2ecf20Sopenharmony_ci pmdebug = '' 1698c2ecf20Sopenharmony_ci tmstart = 'SUSPEND START %Y%m%d-%H:%M:%S.%f' 1708c2ecf20Sopenharmony_ci tmend = 'RESUME COMPLETE %Y%m%d-%H:%M:%S.%f' 1718c2ecf20Sopenharmony_ci tracefuncs = { 1728c2ecf20Sopenharmony_ci 'sys_sync': {}, 1738c2ecf20Sopenharmony_ci 'ksys_sync': {}, 1748c2ecf20Sopenharmony_ci 'pm_notifier_call_chain_robust': {}, 1758c2ecf20Sopenharmony_ci 'pm_prepare_console': {}, 1768c2ecf20Sopenharmony_ci 'pm_notifier_call_chain': {}, 1778c2ecf20Sopenharmony_ci 'freeze_processes': {}, 1788c2ecf20Sopenharmony_ci 'freeze_kernel_threads': {}, 1798c2ecf20Sopenharmony_ci 'pm_restrict_gfp_mask': {}, 1808c2ecf20Sopenharmony_ci 'acpi_suspend_begin': {}, 1818c2ecf20Sopenharmony_ci 'acpi_hibernation_begin': {}, 1828c2ecf20Sopenharmony_ci 'acpi_hibernation_enter': {}, 1838c2ecf20Sopenharmony_ci 'acpi_hibernation_leave': {}, 1848c2ecf20Sopenharmony_ci 'acpi_pm_freeze': {}, 1858c2ecf20Sopenharmony_ci 'acpi_pm_thaw': {}, 1868c2ecf20Sopenharmony_ci 'acpi_s2idle_end': {}, 1878c2ecf20Sopenharmony_ci 'acpi_s2idle_sync': {}, 1888c2ecf20Sopenharmony_ci 'acpi_s2idle_begin': {}, 1898c2ecf20Sopenharmony_ci 'acpi_s2idle_prepare': {}, 1908c2ecf20Sopenharmony_ci 'acpi_s2idle_prepare_late': {}, 1918c2ecf20Sopenharmony_ci 'acpi_s2idle_wake': {}, 1928c2ecf20Sopenharmony_ci 'acpi_s2idle_wakeup': {}, 1938c2ecf20Sopenharmony_ci 'acpi_s2idle_restore': {}, 1948c2ecf20Sopenharmony_ci 'acpi_s2idle_restore_early': {}, 1958c2ecf20Sopenharmony_ci 'hibernate_preallocate_memory': {}, 1968c2ecf20Sopenharmony_ci 'create_basic_memory_bitmaps': {}, 1978c2ecf20Sopenharmony_ci 'swsusp_write': {}, 1988c2ecf20Sopenharmony_ci 'suspend_console': {}, 1998c2ecf20Sopenharmony_ci 'acpi_pm_prepare': {}, 2008c2ecf20Sopenharmony_ci 'syscore_suspend': {}, 2018c2ecf20Sopenharmony_ci 'arch_enable_nonboot_cpus_end': {}, 2028c2ecf20Sopenharmony_ci 'syscore_resume': {}, 2038c2ecf20Sopenharmony_ci 'acpi_pm_finish': {}, 2048c2ecf20Sopenharmony_ci 'resume_console': {}, 2058c2ecf20Sopenharmony_ci 'acpi_pm_end': {}, 2068c2ecf20Sopenharmony_ci 'pm_restore_gfp_mask': {}, 2078c2ecf20Sopenharmony_ci 'thaw_processes': {}, 2088c2ecf20Sopenharmony_ci 'pm_restore_console': {}, 2098c2ecf20Sopenharmony_ci 'CPU_OFF': { 2108c2ecf20Sopenharmony_ci 'func':'_cpu_down', 2118c2ecf20Sopenharmony_ci 'args_x86_64': {'cpu':'%di:s32'}, 2128c2ecf20Sopenharmony_ci 'format': 'CPU_OFF[{cpu}]' 2138c2ecf20Sopenharmony_ci }, 2148c2ecf20Sopenharmony_ci 'CPU_ON': { 2158c2ecf20Sopenharmony_ci 'func':'_cpu_up', 2168c2ecf20Sopenharmony_ci 'args_x86_64': {'cpu':'%di:s32'}, 2178c2ecf20Sopenharmony_ci 'format': 'CPU_ON[{cpu}]' 2188c2ecf20Sopenharmony_ci }, 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci dev_tracefuncs = { 2218c2ecf20Sopenharmony_ci # general wait/delay/sleep 2228c2ecf20Sopenharmony_ci 'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 }, 2238c2ecf20Sopenharmony_ci 'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 }, 2248c2ecf20Sopenharmony_ci 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 }, 2258c2ecf20Sopenharmony_ci 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 }, 2268c2ecf20Sopenharmony_ci 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 }, 2278c2ecf20Sopenharmony_ci 'acpi_os_stall': {'ub': 1}, 2288c2ecf20Sopenharmony_ci 'rt_mutex_slowlock': {'ub': 1}, 2298c2ecf20Sopenharmony_ci # ACPI 2308c2ecf20Sopenharmony_ci 'acpi_resume_power_resources': {}, 2318c2ecf20Sopenharmony_ci 'acpi_ps_execute_method': { 'args_x86_64': { 2328c2ecf20Sopenharmony_ci 'fullpath':'+0(+40(%di)):string', 2338c2ecf20Sopenharmony_ci }}, 2348c2ecf20Sopenharmony_ci # mei_me 2358c2ecf20Sopenharmony_ci 'mei_reset': {}, 2368c2ecf20Sopenharmony_ci # filesystem 2378c2ecf20Sopenharmony_ci 'ext4_sync_fs': {}, 2388c2ecf20Sopenharmony_ci # 80211 2398c2ecf20Sopenharmony_ci 'ath10k_bmi_read_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 2408c2ecf20Sopenharmony_ci 'ath10k_bmi_write_memory': { 'args_x86_64': {'length':'%cx:s32'} }, 2418c2ecf20Sopenharmony_ci 'ath10k_bmi_fast_download': { 'args_x86_64': {'length':'%cx:s32'} }, 2428c2ecf20Sopenharmony_ci 'iwlagn_mac_start': {}, 2438c2ecf20Sopenharmony_ci 'iwlagn_alloc_bcast_station': {}, 2448c2ecf20Sopenharmony_ci 'iwl_trans_pcie_start_hw': {}, 2458c2ecf20Sopenharmony_ci 'iwl_trans_pcie_start_fw': {}, 2468c2ecf20Sopenharmony_ci 'iwl_run_init_ucode': {}, 2478c2ecf20Sopenharmony_ci 'iwl_load_ucode_wait_alive': {}, 2488c2ecf20Sopenharmony_ci 'iwl_alive_start': {}, 2498c2ecf20Sopenharmony_ci 'iwlagn_mac_stop': {}, 2508c2ecf20Sopenharmony_ci 'iwlagn_mac_suspend': {}, 2518c2ecf20Sopenharmony_ci 'iwlagn_mac_resume': {}, 2528c2ecf20Sopenharmony_ci 'iwlagn_mac_add_interface': {}, 2538c2ecf20Sopenharmony_ci 'iwlagn_mac_remove_interface': {}, 2548c2ecf20Sopenharmony_ci 'iwlagn_mac_change_interface': {}, 2558c2ecf20Sopenharmony_ci 'iwlagn_mac_config': {}, 2568c2ecf20Sopenharmony_ci 'iwlagn_configure_filter': {}, 2578c2ecf20Sopenharmony_ci 'iwlagn_mac_hw_scan': {}, 2588c2ecf20Sopenharmony_ci 'iwlagn_bss_info_changed': {}, 2598c2ecf20Sopenharmony_ci 'iwlagn_mac_channel_switch': {}, 2608c2ecf20Sopenharmony_ci 'iwlagn_mac_flush': {}, 2618c2ecf20Sopenharmony_ci # ATA 2628c2ecf20Sopenharmony_ci 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} }, 2638c2ecf20Sopenharmony_ci # i915 2648c2ecf20Sopenharmony_ci 'i915_gem_resume': {}, 2658c2ecf20Sopenharmony_ci 'i915_restore_state': {}, 2668c2ecf20Sopenharmony_ci 'intel_opregion_setup': {}, 2678c2ecf20Sopenharmony_ci 'g4x_pre_enable_dp': {}, 2688c2ecf20Sopenharmony_ci 'vlv_pre_enable_dp': {}, 2698c2ecf20Sopenharmony_ci 'chv_pre_enable_dp': {}, 2708c2ecf20Sopenharmony_ci 'g4x_enable_dp': {}, 2718c2ecf20Sopenharmony_ci 'vlv_enable_dp': {}, 2728c2ecf20Sopenharmony_ci 'intel_hpd_init': {}, 2738c2ecf20Sopenharmony_ci 'intel_opregion_register': {}, 2748c2ecf20Sopenharmony_ci 'intel_dp_detect': {}, 2758c2ecf20Sopenharmony_ci 'intel_hdmi_detect': {}, 2768c2ecf20Sopenharmony_ci 'intel_opregion_init': {}, 2778c2ecf20Sopenharmony_ci 'intel_fbdev_set_suspend': {}, 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci infocmds = [ 2808c2ecf20Sopenharmony_ci [0, 'kparams', 'cat', '/proc/cmdline'], 2818c2ecf20Sopenharmony_ci [0, 'mcelog', 'mcelog'], 2828c2ecf20Sopenharmony_ci [0, 'pcidevices', 'lspci', '-tv'], 2838c2ecf20Sopenharmony_ci [0, 'usbdevices', 'lsusb', '-t'], 2848c2ecf20Sopenharmony_ci [1, 'interrupts', 'cat', '/proc/interrupts'], 2858c2ecf20Sopenharmony_ci [1, 'wakeups', 'cat', '/sys/kernel/debug/wakeup_sources'], 2868c2ecf20Sopenharmony_ci [2, 'gpecounts', 'sh', '-c', 'grep -v invalid /sys/firmware/acpi/interrupts/*'], 2878c2ecf20Sopenharmony_ci [2, 'suspendstats', 'sh', '-c', 'grep -v invalid /sys/power/suspend_stats/*'], 2888c2ecf20Sopenharmony_ci [2, 'cpuidle', 'sh', '-c', 'grep -v invalid /sys/devices/system/cpu/cpu*/cpuidle/state*/s2idle/*'], 2898c2ecf20Sopenharmony_ci [2, 'battery', 'sh', '-c', 'grep -v invalid /sys/class/power_supply/*/*'], 2908c2ecf20Sopenharmony_ci ] 2918c2ecf20Sopenharmony_ci cgblacklist = [] 2928c2ecf20Sopenharmony_ci kprobes = dict() 2938c2ecf20Sopenharmony_ci timeformat = '%.3f' 2948c2ecf20Sopenharmony_ci cmdline = '%s %s' % \ 2958c2ecf20Sopenharmony_ci (os.path.basename(sys.argv[0]), ' '.join(sys.argv[1:])) 2968c2ecf20Sopenharmony_ci sudouser = '' 2978c2ecf20Sopenharmony_ci def __init__(self): 2988c2ecf20Sopenharmony_ci self.archargs = 'args_'+platform.machine() 2998c2ecf20Sopenharmony_ci self.hostname = platform.node() 3008c2ecf20Sopenharmony_ci if(self.hostname == ''): 3018c2ecf20Sopenharmony_ci self.hostname = 'localhost' 3028c2ecf20Sopenharmony_ci rtc = "rtc0" 3038c2ecf20Sopenharmony_ci if os.path.exists('/dev/rtc'): 3048c2ecf20Sopenharmony_ci rtc = os.readlink('/dev/rtc') 3058c2ecf20Sopenharmony_ci rtc = '/sys/class/rtc/'+rtc 3068c2ecf20Sopenharmony_ci if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \ 3078c2ecf20Sopenharmony_ci os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'): 3088c2ecf20Sopenharmony_ci self.rtcpath = rtc 3098c2ecf20Sopenharmony_ci if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): 3108c2ecf20Sopenharmony_ci self.ansi = True 3118c2ecf20Sopenharmony_ci self.testdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S') 3128c2ecf20Sopenharmony_ci if os.getuid() == 0 and 'SUDO_USER' in os.environ and \ 3138c2ecf20Sopenharmony_ci os.environ['SUDO_USER']: 3148c2ecf20Sopenharmony_ci self.sudouser = os.environ['SUDO_USER'] 3158c2ecf20Sopenharmony_ci def resetlog(self): 3168c2ecf20Sopenharmony_ci self.logmsg = '' 3178c2ecf20Sopenharmony_ci self.platinfo = [] 3188c2ecf20Sopenharmony_ci def vprint(self, msg): 3198c2ecf20Sopenharmony_ci self.logmsg += msg+'\n' 3208c2ecf20Sopenharmony_ci if self.verbose or msg.startswith('WARNING:'): 3218c2ecf20Sopenharmony_ci pprint(msg) 3228c2ecf20Sopenharmony_ci def signalHandler(self, signum, frame): 3238c2ecf20Sopenharmony_ci if not self.result: 3248c2ecf20Sopenharmony_ci return 3258c2ecf20Sopenharmony_ci signame = self.signames[signum] if signum in self.signames else 'UNKNOWN' 3268c2ecf20Sopenharmony_ci msg = 'Signal %s caused a tool exit, line %d' % (signame, frame.f_lineno) 3278c2ecf20Sopenharmony_ci self.outputResult({'error':msg}) 3288c2ecf20Sopenharmony_ci sys.exit(3) 3298c2ecf20Sopenharmony_ci def signalHandlerInit(self): 3308c2ecf20Sopenharmony_ci capture = ['BUS', 'SYS', 'XCPU', 'XFSZ', 'PWR', 'HUP', 'INT', 'QUIT', 3318c2ecf20Sopenharmony_ci 'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM'] 3328c2ecf20Sopenharmony_ci self.signames = dict() 3338c2ecf20Sopenharmony_ci for i in capture: 3348c2ecf20Sopenharmony_ci s = 'SIG'+i 3358c2ecf20Sopenharmony_ci try: 3368c2ecf20Sopenharmony_ci signum = getattr(signal, s) 3378c2ecf20Sopenharmony_ci signal.signal(signum, self.signalHandler) 3388c2ecf20Sopenharmony_ci except: 3398c2ecf20Sopenharmony_ci continue 3408c2ecf20Sopenharmony_ci self.signames[signum] = s 3418c2ecf20Sopenharmony_ci def rootCheck(self, fatal=True): 3428c2ecf20Sopenharmony_ci if(os.access(self.powerfile, os.W_OK)): 3438c2ecf20Sopenharmony_ci return True 3448c2ecf20Sopenharmony_ci if fatal: 3458c2ecf20Sopenharmony_ci msg = 'This command requires sysfs mount and root access' 3468c2ecf20Sopenharmony_ci pprint('ERROR: %s\n' % msg) 3478c2ecf20Sopenharmony_ci self.outputResult({'error':msg}) 3488c2ecf20Sopenharmony_ci sys.exit(1) 3498c2ecf20Sopenharmony_ci return False 3508c2ecf20Sopenharmony_ci def rootUser(self, fatal=False): 3518c2ecf20Sopenharmony_ci if 'USER' in os.environ and os.environ['USER'] == 'root': 3528c2ecf20Sopenharmony_ci return True 3538c2ecf20Sopenharmony_ci if fatal: 3548c2ecf20Sopenharmony_ci msg = 'This command must be run as root' 3558c2ecf20Sopenharmony_ci pprint('ERROR: %s\n' % msg) 3568c2ecf20Sopenharmony_ci self.outputResult({'error':msg}) 3578c2ecf20Sopenharmony_ci sys.exit(1) 3588c2ecf20Sopenharmony_ci return False 3598c2ecf20Sopenharmony_ci def usable(self, file): 3608c2ecf20Sopenharmony_ci return (os.path.exists(file) and os.path.getsize(file) > 0) 3618c2ecf20Sopenharmony_ci def getExec(self, cmd): 3628c2ecf20Sopenharmony_ci try: 3638c2ecf20Sopenharmony_ci fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout 3648c2ecf20Sopenharmony_ci out = ascii(fp.read()).strip() 3658c2ecf20Sopenharmony_ci fp.close() 3668c2ecf20Sopenharmony_ci except: 3678c2ecf20Sopenharmony_ci out = '' 3688c2ecf20Sopenharmony_ci if out: 3698c2ecf20Sopenharmony_ci return out 3708c2ecf20Sopenharmony_ci for path in ['/sbin', '/bin', '/usr/sbin', '/usr/bin', 3718c2ecf20Sopenharmony_ci '/usr/local/sbin', '/usr/local/bin']: 3728c2ecf20Sopenharmony_ci cmdfull = os.path.join(path, cmd) 3738c2ecf20Sopenharmony_ci if os.path.exists(cmdfull): 3748c2ecf20Sopenharmony_ci return cmdfull 3758c2ecf20Sopenharmony_ci return out 3768c2ecf20Sopenharmony_ci def setPrecision(self, num): 3778c2ecf20Sopenharmony_ci if num < 0 or num > 6: 3788c2ecf20Sopenharmony_ci return 3798c2ecf20Sopenharmony_ci self.timeformat = '%.{0}f'.format(num) 3808c2ecf20Sopenharmony_ci def setOutputFolder(self, value): 3818c2ecf20Sopenharmony_ci args = dict() 3828c2ecf20Sopenharmony_ci n = datetime.now() 3838c2ecf20Sopenharmony_ci args['date'] = n.strftime('%y%m%d') 3848c2ecf20Sopenharmony_ci args['time'] = n.strftime('%H%M%S') 3858c2ecf20Sopenharmony_ci args['hostname'] = args['host'] = self.hostname 3868c2ecf20Sopenharmony_ci args['mode'] = self.suspendmode 3878c2ecf20Sopenharmony_ci return value.format(**args) 3888c2ecf20Sopenharmony_ci def setOutputFile(self): 3898c2ecf20Sopenharmony_ci if self.dmesgfile != '': 3908c2ecf20Sopenharmony_ci m = re.match('(?P<name>.*)_dmesg\.txt.*', self.dmesgfile) 3918c2ecf20Sopenharmony_ci if(m): 3928c2ecf20Sopenharmony_ci self.htmlfile = m.group('name')+'.html' 3938c2ecf20Sopenharmony_ci if self.ftracefile != '': 3948c2ecf20Sopenharmony_ci m = re.match('(?P<name>.*)_ftrace\.txt.*', self.ftracefile) 3958c2ecf20Sopenharmony_ci if(m): 3968c2ecf20Sopenharmony_ci self.htmlfile = m.group('name')+'.html' 3978c2ecf20Sopenharmony_ci def systemInfo(self, info): 3988c2ecf20Sopenharmony_ci p = m = '' 3998c2ecf20Sopenharmony_ci if 'baseboard-manufacturer' in info: 4008c2ecf20Sopenharmony_ci m = info['baseboard-manufacturer'] 4018c2ecf20Sopenharmony_ci elif 'system-manufacturer' in info: 4028c2ecf20Sopenharmony_ci m = info['system-manufacturer'] 4038c2ecf20Sopenharmony_ci if 'system-product-name' in info: 4048c2ecf20Sopenharmony_ci p = info['system-product-name'] 4058c2ecf20Sopenharmony_ci elif 'baseboard-product-name' in info: 4068c2ecf20Sopenharmony_ci p = info['baseboard-product-name'] 4078c2ecf20Sopenharmony_ci if m[:5].lower() == 'intel' and 'baseboard-product-name' in info: 4088c2ecf20Sopenharmony_ci p = info['baseboard-product-name'] 4098c2ecf20Sopenharmony_ci c = info['processor-version'] if 'processor-version' in info else '' 4108c2ecf20Sopenharmony_ci b = info['bios-version'] if 'bios-version' in info else '' 4118c2ecf20Sopenharmony_ci r = info['bios-release-date'] if 'bios-release-date' in info else '' 4128c2ecf20Sopenharmony_ci self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | biosdate:%s | numcpu:%d | memsz:%d | memfr:%d' % \ 4138c2ecf20Sopenharmony_ci (m, p, c, b, r, self.cpucount, self.memtotal, self.memfree) 4148c2ecf20Sopenharmony_ci def printSystemInfo(self, fatal=False): 4158c2ecf20Sopenharmony_ci self.rootCheck(True) 4168c2ecf20Sopenharmony_ci out = dmidecode(self.mempath, fatal) 4178c2ecf20Sopenharmony_ci if len(out) < 1: 4188c2ecf20Sopenharmony_ci return 4198c2ecf20Sopenharmony_ci fmt = '%-24s: %s' 4208c2ecf20Sopenharmony_ci for name in sorted(out): 4218c2ecf20Sopenharmony_ci print(fmt % (name, out[name])) 4228c2ecf20Sopenharmony_ci print(fmt % ('cpucount', ('%d' % self.cpucount))) 4238c2ecf20Sopenharmony_ci print(fmt % ('memtotal', ('%d kB' % self.memtotal))) 4248c2ecf20Sopenharmony_ci print(fmt % ('memfree', ('%d kB' % self.memfree))) 4258c2ecf20Sopenharmony_ci def cpuInfo(self): 4268c2ecf20Sopenharmony_ci self.cpucount = 0 4278c2ecf20Sopenharmony_ci fp = open('/proc/cpuinfo', 'r') 4288c2ecf20Sopenharmony_ci for line in fp: 4298c2ecf20Sopenharmony_ci if re.match('^processor[ \t]*:[ \t]*[0-9]*', line): 4308c2ecf20Sopenharmony_ci self.cpucount += 1 4318c2ecf20Sopenharmony_ci fp.close() 4328c2ecf20Sopenharmony_ci fp = open('/proc/meminfo', 'r') 4338c2ecf20Sopenharmony_ci for line in fp: 4348c2ecf20Sopenharmony_ci m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line) 4358c2ecf20Sopenharmony_ci if m: 4368c2ecf20Sopenharmony_ci self.memtotal = int(m.group('sz')) 4378c2ecf20Sopenharmony_ci m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line) 4388c2ecf20Sopenharmony_ci if m: 4398c2ecf20Sopenharmony_ci self.memfree = int(m.group('sz')) 4408c2ecf20Sopenharmony_ci fp.close() 4418c2ecf20Sopenharmony_ci def initTestOutput(self, name): 4428c2ecf20Sopenharmony_ci self.prefix = self.hostname 4438c2ecf20Sopenharmony_ci v = open('/proc/version', 'r').read().strip() 4448c2ecf20Sopenharmony_ci kver = v.split()[2] 4458c2ecf20Sopenharmony_ci fmt = name+'-%m%d%y-%H%M%S' 4468c2ecf20Sopenharmony_ci testtime = datetime.now().strftime(fmt) 4478c2ecf20Sopenharmony_ci self.teststamp = \ 4488c2ecf20Sopenharmony_ci '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver 4498c2ecf20Sopenharmony_ci ext = '' 4508c2ecf20Sopenharmony_ci if self.gzip: 4518c2ecf20Sopenharmony_ci ext = '.gz' 4528c2ecf20Sopenharmony_ci self.dmesgfile = \ 4538c2ecf20Sopenharmony_ci self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt'+ext 4548c2ecf20Sopenharmony_ci self.ftracefile = \ 4558c2ecf20Sopenharmony_ci self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt'+ext 4568c2ecf20Sopenharmony_ci self.htmlfile = \ 4578c2ecf20Sopenharmony_ci self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' 4588c2ecf20Sopenharmony_ci if not os.path.isdir(self.testdir): 4598c2ecf20Sopenharmony_ci os.makedirs(self.testdir) 4608c2ecf20Sopenharmony_ci self.sudoUserchown(self.testdir) 4618c2ecf20Sopenharmony_ci def getValueList(self, value): 4628c2ecf20Sopenharmony_ci out = [] 4638c2ecf20Sopenharmony_ci for i in value.split(','): 4648c2ecf20Sopenharmony_ci if i.strip(): 4658c2ecf20Sopenharmony_ci out.append(i.strip()) 4668c2ecf20Sopenharmony_ci return out 4678c2ecf20Sopenharmony_ci def setDeviceFilter(self, value): 4688c2ecf20Sopenharmony_ci self.devicefilter = self.getValueList(value) 4698c2ecf20Sopenharmony_ci def setCallgraphFilter(self, value): 4708c2ecf20Sopenharmony_ci self.cgfilter = self.getValueList(value) 4718c2ecf20Sopenharmony_ci def skipKprobes(self, value): 4728c2ecf20Sopenharmony_ci for k in self.getValueList(value): 4738c2ecf20Sopenharmony_ci if k in self.tracefuncs: 4748c2ecf20Sopenharmony_ci del self.tracefuncs[k] 4758c2ecf20Sopenharmony_ci if k in self.dev_tracefuncs: 4768c2ecf20Sopenharmony_ci del self.dev_tracefuncs[k] 4778c2ecf20Sopenharmony_ci def setCallgraphBlacklist(self, file): 4788c2ecf20Sopenharmony_ci self.cgblacklist = self.listFromFile(file) 4798c2ecf20Sopenharmony_ci def rtcWakeAlarmOn(self): 4808c2ecf20Sopenharmony_ci call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True) 4818c2ecf20Sopenharmony_ci nowtime = open(self.rtcpath+'/since_epoch', 'r').read().strip() 4828c2ecf20Sopenharmony_ci if nowtime: 4838c2ecf20Sopenharmony_ci nowtime = int(nowtime) 4848c2ecf20Sopenharmony_ci else: 4858c2ecf20Sopenharmony_ci # if hardware time fails, use the software time 4868c2ecf20Sopenharmony_ci nowtime = int(datetime.now().strftime('%s')) 4878c2ecf20Sopenharmony_ci alarm = nowtime + self.rtcwaketime 4888c2ecf20Sopenharmony_ci call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True) 4898c2ecf20Sopenharmony_ci def rtcWakeAlarmOff(self): 4908c2ecf20Sopenharmony_ci call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True) 4918c2ecf20Sopenharmony_ci def initdmesg(self): 4928c2ecf20Sopenharmony_ci # get the latest time stamp from the dmesg log 4938c2ecf20Sopenharmony_ci fp = Popen('dmesg', stdout=PIPE).stdout 4948c2ecf20Sopenharmony_ci ktime = '0' 4958c2ecf20Sopenharmony_ci for line in fp: 4968c2ecf20Sopenharmony_ci line = ascii(line).replace('\r\n', '') 4978c2ecf20Sopenharmony_ci idx = line.find('[') 4988c2ecf20Sopenharmony_ci if idx > 1: 4998c2ecf20Sopenharmony_ci line = line[idx:] 5008c2ecf20Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 5018c2ecf20Sopenharmony_ci if(m): 5028c2ecf20Sopenharmony_ci ktime = m.group('ktime') 5038c2ecf20Sopenharmony_ci fp.close() 5048c2ecf20Sopenharmony_ci self.dmesgstart = float(ktime) 5058c2ecf20Sopenharmony_ci def getdmesg(self, testdata): 5068c2ecf20Sopenharmony_ci op = self.writeDatafileHeader(self.dmesgfile, testdata) 5078c2ecf20Sopenharmony_ci # store all new dmesg lines since initdmesg was called 5088c2ecf20Sopenharmony_ci fp = Popen('dmesg', stdout=PIPE).stdout 5098c2ecf20Sopenharmony_ci for line in fp: 5108c2ecf20Sopenharmony_ci line = ascii(line).replace('\r\n', '') 5118c2ecf20Sopenharmony_ci idx = line.find('[') 5128c2ecf20Sopenharmony_ci if idx > 1: 5138c2ecf20Sopenharmony_ci line = line[idx:] 5148c2ecf20Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 5158c2ecf20Sopenharmony_ci if(not m): 5168c2ecf20Sopenharmony_ci continue 5178c2ecf20Sopenharmony_ci ktime = float(m.group('ktime')) 5188c2ecf20Sopenharmony_ci if ktime > self.dmesgstart: 5198c2ecf20Sopenharmony_ci op.write(line) 5208c2ecf20Sopenharmony_ci fp.close() 5218c2ecf20Sopenharmony_ci op.close() 5228c2ecf20Sopenharmony_ci def listFromFile(self, file): 5238c2ecf20Sopenharmony_ci list = [] 5248c2ecf20Sopenharmony_ci fp = open(file) 5258c2ecf20Sopenharmony_ci for i in fp.read().split('\n'): 5268c2ecf20Sopenharmony_ci i = i.strip() 5278c2ecf20Sopenharmony_ci if i and i[0] != '#': 5288c2ecf20Sopenharmony_ci list.append(i) 5298c2ecf20Sopenharmony_ci fp.close() 5308c2ecf20Sopenharmony_ci return list 5318c2ecf20Sopenharmony_ci def addFtraceFilterFunctions(self, file): 5328c2ecf20Sopenharmony_ci for i in self.listFromFile(file): 5338c2ecf20Sopenharmony_ci if len(i) < 2: 5348c2ecf20Sopenharmony_ci continue 5358c2ecf20Sopenharmony_ci self.tracefuncs[i] = dict() 5368c2ecf20Sopenharmony_ci def getFtraceFilterFunctions(self, current): 5378c2ecf20Sopenharmony_ci self.rootCheck(True) 5388c2ecf20Sopenharmony_ci if not current: 5398c2ecf20Sopenharmony_ci call('cat '+self.tpath+'available_filter_functions', shell=True) 5408c2ecf20Sopenharmony_ci return 5418c2ecf20Sopenharmony_ci master = self.listFromFile(self.tpath+'available_filter_functions') 5428c2ecf20Sopenharmony_ci for i in sorted(self.tracefuncs): 5438c2ecf20Sopenharmony_ci if 'func' in self.tracefuncs[i]: 5448c2ecf20Sopenharmony_ci i = self.tracefuncs[i]['func'] 5458c2ecf20Sopenharmony_ci if i in master: 5468c2ecf20Sopenharmony_ci print(i) 5478c2ecf20Sopenharmony_ci else: 5488c2ecf20Sopenharmony_ci print(self.colorText(i)) 5498c2ecf20Sopenharmony_ci def setFtraceFilterFunctions(self, list): 5508c2ecf20Sopenharmony_ci master = self.listFromFile(self.tpath+'available_filter_functions') 5518c2ecf20Sopenharmony_ci flist = '' 5528c2ecf20Sopenharmony_ci for i in list: 5538c2ecf20Sopenharmony_ci if i not in master: 5548c2ecf20Sopenharmony_ci continue 5558c2ecf20Sopenharmony_ci if ' [' in i: 5568c2ecf20Sopenharmony_ci flist += i.split(' ')[0]+'\n' 5578c2ecf20Sopenharmony_ci else: 5588c2ecf20Sopenharmony_ci flist += i+'\n' 5598c2ecf20Sopenharmony_ci fp = open(self.tpath+'set_graph_function', 'w') 5608c2ecf20Sopenharmony_ci fp.write(flist) 5618c2ecf20Sopenharmony_ci fp.close() 5628c2ecf20Sopenharmony_ci def basicKprobe(self, name): 5638c2ecf20Sopenharmony_ci self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name} 5648c2ecf20Sopenharmony_ci def defaultKprobe(self, name, kdata): 5658c2ecf20Sopenharmony_ci k = kdata 5668c2ecf20Sopenharmony_ci for field in ['name', 'format', 'func']: 5678c2ecf20Sopenharmony_ci if field not in k: 5688c2ecf20Sopenharmony_ci k[field] = name 5698c2ecf20Sopenharmony_ci if self.archargs in k: 5708c2ecf20Sopenharmony_ci k['args'] = k[self.archargs] 5718c2ecf20Sopenharmony_ci else: 5728c2ecf20Sopenharmony_ci k['args'] = dict() 5738c2ecf20Sopenharmony_ci k['format'] = name 5748c2ecf20Sopenharmony_ci self.kprobes[name] = k 5758c2ecf20Sopenharmony_ci def kprobeColor(self, name): 5768c2ecf20Sopenharmony_ci if name not in self.kprobes or 'color' not in self.kprobes[name]: 5778c2ecf20Sopenharmony_ci return '' 5788c2ecf20Sopenharmony_ci return self.kprobes[name]['color'] 5798c2ecf20Sopenharmony_ci def kprobeDisplayName(self, name, dataraw): 5808c2ecf20Sopenharmony_ci if name not in self.kprobes: 5818c2ecf20Sopenharmony_ci self.basicKprobe(name) 5828c2ecf20Sopenharmony_ci data = '' 5838c2ecf20Sopenharmony_ci quote=0 5848c2ecf20Sopenharmony_ci # first remvoe any spaces inside quotes, and the quotes 5858c2ecf20Sopenharmony_ci for c in dataraw: 5868c2ecf20Sopenharmony_ci if c == '"': 5878c2ecf20Sopenharmony_ci quote = (quote + 1) % 2 5888c2ecf20Sopenharmony_ci if quote and c == ' ': 5898c2ecf20Sopenharmony_ci data += '_' 5908c2ecf20Sopenharmony_ci elif c != '"': 5918c2ecf20Sopenharmony_ci data += c 5928c2ecf20Sopenharmony_ci fmt, args = self.kprobes[name]['format'], self.kprobes[name]['args'] 5938c2ecf20Sopenharmony_ci arglist = dict() 5948c2ecf20Sopenharmony_ci # now process the args 5958c2ecf20Sopenharmony_ci for arg in sorted(args): 5968c2ecf20Sopenharmony_ci arglist[arg] = '' 5978c2ecf20Sopenharmony_ci m = re.match('.* '+arg+'=(?P<arg>.*) ', data); 5988c2ecf20Sopenharmony_ci if m: 5998c2ecf20Sopenharmony_ci arglist[arg] = m.group('arg') 6008c2ecf20Sopenharmony_ci else: 6018c2ecf20Sopenharmony_ci m = re.match('.* '+arg+'=(?P<arg>.*)', data); 6028c2ecf20Sopenharmony_ci if m: 6038c2ecf20Sopenharmony_ci arglist[arg] = m.group('arg') 6048c2ecf20Sopenharmony_ci out = fmt.format(**arglist) 6058c2ecf20Sopenharmony_ci out = out.replace(' ', '_').replace('"', '') 6068c2ecf20Sopenharmony_ci return out 6078c2ecf20Sopenharmony_ci def kprobeText(self, kname, kprobe): 6088c2ecf20Sopenharmony_ci name = fmt = func = kname 6098c2ecf20Sopenharmony_ci args = dict() 6108c2ecf20Sopenharmony_ci if 'name' in kprobe: 6118c2ecf20Sopenharmony_ci name = kprobe['name'] 6128c2ecf20Sopenharmony_ci if 'format' in kprobe: 6138c2ecf20Sopenharmony_ci fmt = kprobe['format'] 6148c2ecf20Sopenharmony_ci if 'func' in kprobe: 6158c2ecf20Sopenharmony_ci func = kprobe['func'] 6168c2ecf20Sopenharmony_ci if self.archargs in kprobe: 6178c2ecf20Sopenharmony_ci args = kprobe[self.archargs] 6188c2ecf20Sopenharmony_ci if 'args' in kprobe: 6198c2ecf20Sopenharmony_ci args = kprobe['args'] 6208c2ecf20Sopenharmony_ci if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func): 6218c2ecf20Sopenharmony_ci doError('Kprobe "%s" has format info in the function name "%s"' % (name, func)) 6228c2ecf20Sopenharmony_ci for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt): 6238c2ecf20Sopenharmony_ci if arg not in args: 6248c2ecf20Sopenharmony_ci doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 6258c2ecf20Sopenharmony_ci val = 'p:%s_cal %s' % (name, func) 6268c2ecf20Sopenharmony_ci for i in sorted(args): 6278c2ecf20Sopenharmony_ci val += ' %s=%s' % (i, args[i]) 6288c2ecf20Sopenharmony_ci val += '\nr:%s_ret %s $retval\n' % (name, func) 6298c2ecf20Sopenharmony_ci return val 6308c2ecf20Sopenharmony_ci def addKprobes(self, output=False): 6318c2ecf20Sopenharmony_ci if len(self.kprobes) < 1: 6328c2ecf20Sopenharmony_ci return 6338c2ecf20Sopenharmony_ci if output: 6348c2ecf20Sopenharmony_ci pprint(' kprobe functions in this kernel:') 6358c2ecf20Sopenharmony_ci # first test each kprobe 6368c2ecf20Sopenharmony_ci rejects = [] 6378c2ecf20Sopenharmony_ci # sort kprobes: trace, ub-dev, custom, dev 6388c2ecf20Sopenharmony_ci kpl = [[], [], [], []] 6398c2ecf20Sopenharmony_ci linesout = len(self.kprobes) 6408c2ecf20Sopenharmony_ci for name in sorted(self.kprobes): 6418c2ecf20Sopenharmony_ci res = self.colorText('YES', 32) 6428c2ecf20Sopenharmony_ci if not self.testKprobe(name, self.kprobes[name]): 6438c2ecf20Sopenharmony_ci res = self.colorText('NO') 6448c2ecf20Sopenharmony_ci rejects.append(name) 6458c2ecf20Sopenharmony_ci else: 6468c2ecf20Sopenharmony_ci if name in self.tracefuncs: 6478c2ecf20Sopenharmony_ci kpl[0].append(name) 6488c2ecf20Sopenharmony_ci elif name in self.dev_tracefuncs: 6498c2ecf20Sopenharmony_ci if 'ub' in self.dev_tracefuncs[name]: 6508c2ecf20Sopenharmony_ci kpl[1].append(name) 6518c2ecf20Sopenharmony_ci else: 6528c2ecf20Sopenharmony_ci kpl[3].append(name) 6538c2ecf20Sopenharmony_ci else: 6548c2ecf20Sopenharmony_ci kpl[2].append(name) 6558c2ecf20Sopenharmony_ci if output: 6568c2ecf20Sopenharmony_ci pprint(' %s: %s' % (name, res)) 6578c2ecf20Sopenharmony_ci kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3] 6588c2ecf20Sopenharmony_ci # remove all failed ones from the list 6598c2ecf20Sopenharmony_ci for name in rejects: 6608c2ecf20Sopenharmony_ci self.kprobes.pop(name) 6618c2ecf20Sopenharmony_ci # set the kprobes all at once 6628c2ecf20Sopenharmony_ci self.fsetVal('', 'kprobe_events') 6638c2ecf20Sopenharmony_ci kprobeevents = '' 6648c2ecf20Sopenharmony_ci for kp in kplist: 6658c2ecf20Sopenharmony_ci kprobeevents += self.kprobeText(kp, self.kprobes[kp]) 6668c2ecf20Sopenharmony_ci self.fsetVal(kprobeevents, 'kprobe_events') 6678c2ecf20Sopenharmony_ci if output: 6688c2ecf20Sopenharmony_ci check = self.fgetVal('kprobe_events') 6698c2ecf20Sopenharmony_ci linesack = (len(check.split('\n')) - 1) // 2 6708c2ecf20Sopenharmony_ci pprint(' kprobe functions enabled: %d/%d' % (linesack, linesout)) 6718c2ecf20Sopenharmony_ci self.fsetVal('1', 'events/kprobes/enable') 6728c2ecf20Sopenharmony_ci def testKprobe(self, kname, kprobe): 6738c2ecf20Sopenharmony_ci self.fsetVal('0', 'events/kprobes/enable') 6748c2ecf20Sopenharmony_ci kprobeevents = self.kprobeText(kname, kprobe) 6758c2ecf20Sopenharmony_ci if not kprobeevents: 6768c2ecf20Sopenharmony_ci return False 6778c2ecf20Sopenharmony_ci try: 6788c2ecf20Sopenharmony_ci self.fsetVal(kprobeevents, 'kprobe_events') 6798c2ecf20Sopenharmony_ci check = self.fgetVal('kprobe_events') 6808c2ecf20Sopenharmony_ci except: 6818c2ecf20Sopenharmony_ci return False 6828c2ecf20Sopenharmony_ci linesout = len(kprobeevents.split('\n')) 6838c2ecf20Sopenharmony_ci linesack = len(check.split('\n')) 6848c2ecf20Sopenharmony_ci if linesack < linesout: 6858c2ecf20Sopenharmony_ci return False 6868c2ecf20Sopenharmony_ci return True 6878c2ecf20Sopenharmony_ci def setVal(self, val, file): 6888c2ecf20Sopenharmony_ci if not os.path.exists(file): 6898c2ecf20Sopenharmony_ci return False 6908c2ecf20Sopenharmony_ci try: 6918c2ecf20Sopenharmony_ci fp = open(file, 'wb', 0) 6928c2ecf20Sopenharmony_ci fp.write(val.encode()) 6938c2ecf20Sopenharmony_ci fp.flush() 6948c2ecf20Sopenharmony_ci fp.close() 6958c2ecf20Sopenharmony_ci except: 6968c2ecf20Sopenharmony_ci return False 6978c2ecf20Sopenharmony_ci return True 6988c2ecf20Sopenharmony_ci def fsetVal(self, val, path): 6998c2ecf20Sopenharmony_ci return self.setVal(val, self.tpath+path) 7008c2ecf20Sopenharmony_ci def getVal(self, file): 7018c2ecf20Sopenharmony_ci res = '' 7028c2ecf20Sopenharmony_ci if not os.path.exists(file): 7038c2ecf20Sopenharmony_ci return res 7048c2ecf20Sopenharmony_ci try: 7058c2ecf20Sopenharmony_ci fp = open(file, 'r') 7068c2ecf20Sopenharmony_ci res = fp.read() 7078c2ecf20Sopenharmony_ci fp.close() 7088c2ecf20Sopenharmony_ci except: 7098c2ecf20Sopenharmony_ci pass 7108c2ecf20Sopenharmony_ci return res 7118c2ecf20Sopenharmony_ci def fgetVal(self, path): 7128c2ecf20Sopenharmony_ci return self.getVal(self.tpath+path) 7138c2ecf20Sopenharmony_ci def cleanupFtrace(self): 7148c2ecf20Sopenharmony_ci if(self.usecallgraph or self.usetraceevents or self.usedevsrc): 7158c2ecf20Sopenharmony_ci self.fsetVal('0', 'events/kprobes/enable') 7168c2ecf20Sopenharmony_ci self.fsetVal('', 'kprobe_events') 7178c2ecf20Sopenharmony_ci self.fsetVal('1024', 'buffer_size_kb') 7188c2ecf20Sopenharmony_ci if self.pmdebug: 7198c2ecf20Sopenharmony_ci self.setVal(self.pmdebug, self.pmdpath) 7208c2ecf20Sopenharmony_ci def setupAllKprobes(self): 7218c2ecf20Sopenharmony_ci for name in self.tracefuncs: 7228c2ecf20Sopenharmony_ci self.defaultKprobe(name, self.tracefuncs[name]) 7238c2ecf20Sopenharmony_ci for name in self.dev_tracefuncs: 7248c2ecf20Sopenharmony_ci self.defaultKprobe(name, self.dev_tracefuncs[name]) 7258c2ecf20Sopenharmony_ci def isCallgraphFunc(self, name): 7268c2ecf20Sopenharmony_ci if len(self.tracefuncs) < 1 and self.suspendmode == 'command': 7278c2ecf20Sopenharmony_ci return True 7288c2ecf20Sopenharmony_ci for i in self.tracefuncs: 7298c2ecf20Sopenharmony_ci if 'func' in self.tracefuncs[i]: 7308c2ecf20Sopenharmony_ci f = self.tracefuncs[i]['func'] 7318c2ecf20Sopenharmony_ci else: 7328c2ecf20Sopenharmony_ci f = i 7338c2ecf20Sopenharmony_ci if name == f: 7348c2ecf20Sopenharmony_ci return True 7358c2ecf20Sopenharmony_ci return False 7368c2ecf20Sopenharmony_ci def initFtrace(self, quiet=False): 7378c2ecf20Sopenharmony_ci if not quiet: 7388c2ecf20Sopenharmony_ci sysvals.printSystemInfo(False) 7398c2ecf20Sopenharmony_ci pprint('INITIALIZING FTRACE...') 7408c2ecf20Sopenharmony_ci # turn trace off 7418c2ecf20Sopenharmony_ci self.fsetVal('0', 'tracing_on') 7428c2ecf20Sopenharmony_ci self.cleanupFtrace() 7438c2ecf20Sopenharmony_ci # pm debug messages 7448c2ecf20Sopenharmony_ci pv = self.getVal(self.pmdpath) 7458c2ecf20Sopenharmony_ci if pv != '1': 7468c2ecf20Sopenharmony_ci self.setVal('1', self.pmdpath) 7478c2ecf20Sopenharmony_ci self.pmdebug = pv 7488c2ecf20Sopenharmony_ci # set the trace clock to global 7498c2ecf20Sopenharmony_ci self.fsetVal('global', 'trace_clock') 7508c2ecf20Sopenharmony_ci self.fsetVal('nop', 'current_tracer') 7518c2ecf20Sopenharmony_ci # set trace buffer to an appropriate value 7528c2ecf20Sopenharmony_ci cpus = max(1, self.cpucount) 7538c2ecf20Sopenharmony_ci if self.bufsize > 0: 7548c2ecf20Sopenharmony_ci tgtsize = self.bufsize 7558c2ecf20Sopenharmony_ci elif self.usecallgraph or self.usedevsrc: 7568c2ecf20Sopenharmony_ci bmax = (1*1024*1024) if self.suspendmode in ['disk', 'command'] \ 7578c2ecf20Sopenharmony_ci else (3*1024*1024) 7588c2ecf20Sopenharmony_ci tgtsize = min(self.memfree, bmax) 7598c2ecf20Sopenharmony_ci else: 7608c2ecf20Sopenharmony_ci tgtsize = 65536 7618c2ecf20Sopenharmony_ci while not self.fsetVal('%d' % (tgtsize // cpus), 'buffer_size_kb'): 7628c2ecf20Sopenharmony_ci # if the size failed to set, lower it and keep trying 7638c2ecf20Sopenharmony_ci tgtsize -= 65536 7648c2ecf20Sopenharmony_ci if tgtsize < 65536: 7658c2ecf20Sopenharmony_ci tgtsize = int(self.fgetVal('buffer_size_kb')) * cpus 7668c2ecf20Sopenharmony_ci break 7678c2ecf20Sopenharmony_ci self.vprint('Setting trace buffers to %d kB (%d kB per cpu)' % (tgtsize, tgtsize/cpus)) 7688c2ecf20Sopenharmony_ci # initialize the callgraph trace 7698c2ecf20Sopenharmony_ci if(self.usecallgraph): 7708c2ecf20Sopenharmony_ci # set trace type 7718c2ecf20Sopenharmony_ci self.fsetVal('function_graph', 'current_tracer') 7728c2ecf20Sopenharmony_ci self.fsetVal('', 'set_ftrace_filter') 7738c2ecf20Sopenharmony_ci # set trace format options 7748c2ecf20Sopenharmony_ci self.fsetVal('print-parent', 'trace_options') 7758c2ecf20Sopenharmony_ci self.fsetVal('funcgraph-abstime', 'trace_options') 7768c2ecf20Sopenharmony_ci self.fsetVal('funcgraph-cpu', 'trace_options') 7778c2ecf20Sopenharmony_ci self.fsetVal('funcgraph-duration', 'trace_options') 7788c2ecf20Sopenharmony_ci self.fsetVal('funcgraph-proc', 'trace_options') 7798c2ecf20Sopenharmony_ci self.fsetVal('funcgraph-tail', 'trace_options') 7808c2ecf20Sopenharmony_ci self.fsetVal('nofuncgraph-overhead', 'trace_options') 7818c2ecf20Sopenharmony_ci self.fsetVal('context-info', 'trace_options') 7828c2ecf20Sopenharmony_ci self.fsetVal('graph-time', 'trace_options') 7838c2ecf20Sopenharmony_ci self.fsetVal('%d' % self.max_graph_depth, 'max_graph_depth') 7848c2ecf20Sopenharmony_ci cf = ['dpm_run_callback'] 7858c2ecf20Sopenharmony_ci if(self.usetraceevents): 7868c2ecf20Sopenharmony_ci cf += ['dpm_prepare', 'dpm_complete'] 7878c2ecf20Sopenharmony_ci for fn in self.tracefuncs: 7888c2ecf20Sopenharmony_ci if 'func' in self.tracefuncs[fn]: 7898c2ecf20Sopenharmony_ci cf.append(self.tracefuncs[fn]['func']) 7908c2ecf20Sopenharmony_ci else: 7918c2ecf20Sopenharmony_ci cf.append(fn) 7928c2ecf20Sopenharmony_ci if self.ftop: 7938c2ecf20Sopenharmony_ci self.setFtraceFilterFunctions([self.ftopfunc]) 7948c2ecf20Sopenharmony_ci else: 7958c2ecf20Sopenharmony_ci self.setFtraceFilterFunctions(cf) 7968c2ecf20Sopenharmony_ci # initialize the kprobe trace 7978c2ecf20Sopenharmony_ci elif self.usekprobes: 7988c2ecf20Sopenharmony_ci for name in self.tracefuncs: 7998c2ecf20Sopenharmony_ci self.defaultKprobe(name, self.tracefuncs[name]) 8008c2ecf20Sopenharmony_ci if self.usedevsrc: 8018c2ecf20Sopenharmony_ci for name in self.dev_tracefuncs: 8028c2ecf20Sopenharmony_ci self.defaultKprobe(name, self.dev_tracefuncs[name]) 8038c2ecf20Sopenharmony_ci if not quiet: 8048c2ecf20Sopenharmony_ci pprint('INITIALIZING KPROBES...') 8058c2ecf20Sopenharmony_ci self.addKprobes(self.verbose) 8068c2ecf20Sopenharmony_ci if(self.usetraceevents): 8078c2ecf20Sopenharmony_ci # turn trace events on 8088c2ecf20Sopenharmony_ci events = iter(self.traceevents) 8098c2ecf20Sopenharmony_ci for e in events: 8108c2ecf20Sopenharmony_ci self.fsetVal('1', 'events/power/'+e+'/enable') 8118c2ecf20Sopenharmony_ci # clear the trace buffer 8128c2ecf20Sopenharmony_ci self.fsetVal('', 'trace') 8138c2ecf20Sopenharmony_ci def verifyFtrace(self): 8148c2ecf20Sopenharmony_ci # files needed for any trace data 8158c2ecf20Sopenharmony_ci files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock', 8168c2ecf20Sopenharmony_ci 'trace_marker', 'trace_options', 'tracing_on'] 8178c2ecf20Sopenharmony_ci # files needed for callgraph trace data 8188c2ecf20Sopenharmony_ci tp = self.tpath 8198c2ecf20Sopenharmony_ci if(self.usecallgraph): 8208c2ecf20Sopenharmony_ci files += [ 8218c2ecf20Sopenharmony_ci 'available_filter_functions', 8228c2ecf20Sopenharmony_ci 'set_ftrace_filter', 8238c2ecf20Sopenharmony_ci 'set_graph_function' 8248c2ecf20Sopenharmony_ci ] 8258c2ecf20Sopenharmony_ci for f in files: 8268c2ecf20Sopenharmony_ci if(os.path.exists(tp+f) == False): 8278c2ecf20Sopenharmony_ci return False 8288c2ecf20Sopenharmony_ci return True 8298c2ecf20Sopenharmony_ci def verifyKprobes(self): 8308c2ecf20Sopenharmony_ci # files needed for kprobes to work 8318c2ecf20Sopenharmony_ci files = ['kprobe_events', 'events'] 8328c2ecf20Sopenharmony_ci tp = self.tpath 8338c2ecf20Sopenharmony_ci for f in files: 8348c2ecf20Sopenharmony_ci if(os.path.exists(tp+f) == False): 8358c2ecf20Sopenharmony_ci return False 8368c2ecf20Sopenharmony_ci return True 8378c2ecf20Sopenharmony_ci def colorText(self, str, color=31): 8388c2ecf20Sopenharmony_ci if not self.ansi: 8398c2ecf20Sopenharmony_ci return str 8408c2ecf20Sopenharmony_ci return '\x1B[%d;40m%s\x1B[m' % (color, str) 8418c2ecf20Sopenharmony_ci def writeDatafileHeader(self, filename, testdata): 8428c2ecf20Sopenharmony_ci fp = self.openlog(filename, 'w') 8438c2ecf20Sopenharmony_ci fp.write('%s\n%s\n# command | %s\n' % (self.teststamp, self.sysstamp, self.cmdline)) 8448c2ecf20Sopenharmony_ci for test in testdata: 8458c2ecf20Sopenharmony_ci if 'fw' in test: 8468c2ecf20Sopenharmony_ci fw = test['fw'] 8478c2ecf20Sopenharmony_ci if(fw): 8488c2ecf20Sopenharmony_ci fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) 8498c2ecf20Sopenharmony_ci if 'turbo' in test: 8508c2ecf20Sopenharmony_ci fp.write('# turbostat %s\n' % test['turbo']) 8518c2ecf20Sopenharmony_ci if 'wifi' in test: 8528c2ecf20Sopenharmony_ci fp.write('# wifi %s\n' % test['wifi']) 8538c2ecf20Sopenharmony_ci if test['error'] or len(testdata) > 1: 8548c2ecf20Sopenharmony_ci fp.write('# enter_sleep_error %s\n' % test['error']) 8558c2ecf20Sopenharmony_ci return fp 8568c2ecf20Sopenharmony_ci def sudoUserchown(self, dir): 8578c2ecf20Sopenharmony_ci if os.path.exists(dir) and self.sudouser: 8588c2ecf20Sopenharmony_ci cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' 8598c2ecf20Sopenharmony_ci call(cmd.format(self.sudouser, dir), shell=True) 8608c2ecf20Sopenharmony_ci def outputResult(self, testdata, num=0): 8618c2ecf20Sopenharmony_ci if not self.result: 8628c2ecf20Sopenharmony_ci return 8638c2ecf20Sopenharmony_ci n = '' 8648c2ecf20Sopenharmony_ci if num > 0: 8658c2ecf20Sopenharmony_ci n = '%d' % num 8668c2ecf20Sopenharmony_ci fp = open(self.result, 'a') 8678c2ecf20Sopenharmony_ci if 'error' in testdata: 8688c2ecf20Sopenharmony_ci fp.write('result%s: fail\n' % n) 8698c2ecf20Sopenharmony_ci fp.write('error%s: %s\n' % (n, testdata['error'])) 8708c2ecf20Sopenharmony_ci else: 8718c2ecf20Sopenharmony_ci fp.write('result%s: pass\n' % n) 8728c2ecf20Sopenharmony_ci for v in ['suspend', 'resume', 'boot', 'lastinit']: 8738c2ecf20Sopenharmony_ci if v in testdata: 8748c2ecf20Sopenharmony_ci fp.write('%s%s: %.3f\n' % (v, n, testdata[v])) 8758c2ecf20Sopenharmony_ci for v in ['fwsuspend', 'fwresume']: 8768c2ecf20Sopenharmony_ci if v in testdata: 8778c2ecf20Sopenharmony_ci fp.write('%s%s: %.3f\n' % (v, n, testdata[v] / 1000000.0)) 8788c2ecf20Sopenharmony_ci if 'bugurl' in testdata: 8798c2ecf20Sopenharmony_ci fp.write('url%s: %s\n' % (n, testdata['bugurl'])) 8808c2ecf20Sopenharmony_ci fp.close() 8818c2ecf20Sopenharmony_ci self.sudoUserchown(self.result) 8828c2ecf20Sopenharmony_ci def configFile(self, file): 8838c2ecf20Sopenharmony_ci dir = os.path.dirname(os.path.realpath(__file__)) 8848c2ecf20Sopenharmony_ci if os.path.exists(file): 8858c2ecf20Sopenharmony_ci return file 8868c2ecf20Sopenharmony_ci elif os.path.exists(dir+'/'+file): 8878c2ecf20Sopenharmony_ci return dir+'/'+file 8888c2ecf20Sopenharmony_ci elif os.path.exists(dir+'/config/'+file): 8898c2ecf20Sopenharmony_ci return dir+'/config/'+file 8908c2ecf20Sopenharmony_ci return '' 8918c2ecf20Sopenharmony_ci def openlog(self, filename, mode): 8928c2ecf20Sopenharmony_ci isgz = self.gzip 8938c2ecf20Sopenharmony_ci if mode == 'r': 8948c2ecf20Sopenharmony_ci try: 8958c2ecf20Sopenharmony_ci with gzip.open(filename, mode+'t') as fp: 8968c2ecf20Sopenharmony_ci test = fp.read(64) 8978c2ecf20Sopenharmony_ci isgz = True 8988c2ecf20Sopenharmony_ci except: 8998c2ecf20Sopenharmony_ci isgz = False 9008c2ecf20Sopenharmony_ci if isgz: 9018c2ecf20Sopenharmony_ci return gzip.open(filename, mode+'t') 9028c2ecf20Sopenharmony_ci return open(filename, mode) 9038c2ecf20Sopenharmony_ci def b64unzip(self, data): 9048c2ecf20Sopenharmony_ci try: 9058c2ecf20Sopenharmony_ci out = codecs.decode(base64.b64decode(data), 'zlib').decode() 9068c2ecf20Sopenharmony_ci except: 9078c2ecf20Sopenharmony_ci out = data 9088c2ecf20Sopenharmony_ci return out 9098c2ecf20Sopenharmony_ci def b64zip(self, data): 9108c2ecf20Sopenharmony_ci out = base64.b64encode(codecs.encode(data.encode(), 'zlib')).decode() 9118c2ecf20Sopenharmony_ci return out 9128c2ecf20Sopenharmony_ci def platforminfo(self, cmdafter): 9138c2ecf20Sopenharmony_ci # add platform info on to a completed ftrace file 9148c2ecf20Sopenharmony_ci if not os.path.exists(self.ftracefile): 9158c2ecf20Sopenharmony_ci return False 9168c2ecf20Sopenharmony_ci footer = '#\n' 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci # add test command string line if need be 9198c2ecf20Sopenharmony_ci if self.suspendmode == 'command' and self.testcommand: 9208c2ecf20Sopenharmony_ci footer += '# platform-testcmd: %s\n' % (self.testcommand) 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci # get a list of target devices from the ftrace file 9238c2ecf20Sopenharmony_ci props = dict() 9248c2ecf20Sopenharmony_ci tp = TestProps() 9258c2ecf20Sopenharmony_ci tf = self.openlog(self.ftracefile, 'r') 9268c2ecf20Sopenharmony_ci for line in tf: 9278c2ecf20Sopenharmony_ci if tp.stampInfo(line, self): 9288c2ecf20Sopenharmony_ci continue 9298c2ecf20Sopenharmony_ci # parse only valid lines, if this is not one move on 9308c2ecf20Sopenharmony_ci m = re.match(tp.ftrace_line_fmt, line) 9318c2ecf20Sopenharmony_ci if(not m or 'device_pm_callback_start' not in line): 9328c2ecf20Sopenharmony_ci continue 9338c2ecf20Sopenharmony_ci m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg')); 9348c2ecf20Sopenharmony_ci if(not m): 9358c2ecf20Sopenharmony_ci continue 9368c2ecf20Sopenharmony_ci dev = m.group('d') 9378c2ecf20Sopenharmony_ci if dev not in props: 9388c2ecf20Sopenharmony_ci props[dev] = DevProps() 9398c2ecf20Sopenharmony_ci tf.close() 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci # now get the syspath for each target device 9428c2ecf20Sopenharmony_ci for dirname, dirnames, filenames in os.walk('/sys/devices'): 9438c2ecf20Sopenharmony_ci if(re.match('.*/power', dirname) and 'async' in filenames): 9448c2ecf20Sopenharmony_ci dev = dirname.split('/')[-2] 9458c2ecf20Sopenharmony_ci if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)): 9468c2ecf20Sopenharmony_ci props[dev].syspath = dirname[:-6] 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci # now fill in the properties for our target devices 9498c2ecf20Sopenharmony_ci for dev in sorted(props): 9508c2ecf20Sopenharmony_ci dirname = props[dev].syspath 9518c2ecf20Sopenharmony_ci if not dirname or not os.path.exists(dirname): 9528c2ecf20Sopenharmony_ci continue 9538c2ecf20Sopenharmony_ci with open(dirname+'/power/async') as fp: 9548c2ecf20Sopenharmony_ci text = fp.read() 9558c2ecf20Sopenharmony_ci props[dev].isasync = False 9568c2ecf20Sopenharmony_ci if 'enabled' in text: 9578c2ecf20Sopenharmony_ci props[dev].isasync = True 9588c2ecf20Sopenharmony_ci fields = os.listdir(dirname) 9598c2ecf20Sopenharmony_ci if 'product' in fields: 9608c2ecf20Sopenharmony_ci with open(dirname+'/product', 'rb') as fp: 9618c2ecf20Sopenharmony_ci props[dev].altname = ascii(fp.read()) 9628c2ecf20Sopenharmony_ci elif 'name' in fields: 9638c2ecf20Sopenharmony_ci with open(dirname+'/name', 'rb') as fp: 9648c2ecf20Sopenharmony_ci props[dev].altname = ascii(fp.read()) 9658c2ecf20Sopenharmony_ci elif 'model' in fields: 9668c2ecf20Sopenharmony_ci with open(dirname+'/model', 'rb') as fp: 9678c2ecf20Sopenharmony_ci props[dev].altname = ascii(fp.read()) 9688c2ecf20Sopenharmony_ci elif 'description' in fields: 9698c2ecf20Sopenharmony_ci with open(dirname+'/description', 'rb') as fp: 9708c2ecf20Sopenharmony_ci props[dev].altname = ascii(fp.read()) 9718c2ecf20Sopenharmony_ci elif 'id' in fields: 9728c2ecf20Sopenharmony_ci with open(dirname+'/id', 'rb') as fp: 9738c2ecf20Sopenharmony_ci props[dev].altname = ascii(fp.read()) 9748c2ecf20Sopenharmony_ci elif 'idVendor' in fields and 'idProduct' in fields: 9758c2ecf20Sopenharmony_ci idv, idp = '', '' 9768c2ecf20Sopenharmony_ci with open(dirname+'/idVendor', 'rb') as fp: 9778c2ecf20Sopenharmony_ci idv = ascii(fp.read()).strip() 9788c2ecf20Sopenharmony_ci with open(dirname+'/idProduct', 'rb') as fp: 9798c2ecf20Sopenharmony_ci idp = ascii(fp.read()).strip() 9808c2ecf20Sopenharmony_ci props[dev].altname = '%s:%s' % (idv, idp) 9818c2ecf20Sopenharmony_ci if props[dev].altname: 9828c2ecf20Sopenharmony_ci out = props[dev].altname.strip().replace('\n', ' ')\ 9838c2ecf20Sopenharmony_ci .replace(',', ' ').replace(';', ' ') 9848c2ecf20Sopenharmony_ci props[dev].altname = out 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci # add a devinfo line to the bottom of ftrace 9878c2ecf20Sopenharmony_ci out = '' 9888c2ecf20Sopenharmony_ci for dev in sorted(props): 9898c2ecf20Sopenharmony_ci out += props[dev].out(dev) 9908c2ecf20Sopenharmony_ci footer += '# platform-devinfo: %s\n' % self.b64zip(out) 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci # add a line for each of these commands with their outputs 9938c2ecf20Sopenharmony_ci for name, cmdline, info in cmdafter: 9948c2ecf20Sopenharmony_ci footer += '# platform-%s: %s | %s\n' % (name, cmdline, self.b64zip(info)) 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci with self.openlog(self.ftracefile, 'a') as fp: 9978c2ecf20Sopenharmony_ci fp.write(footer) 9988c2ecf20Sopenharmony_ci return True 9998c2ecf20Sopenharmony_ci def commonPrefix(self, list): 10008c2ecf20Sopenharmony_ci if len(list) < 2: 10018c2ecf20Sopenharmony_ci return '' 10028c2ecf20Sopenharmony_ci prefix = list[0] 10038c2ecf20Sopenharmony_ci for s in list[1:]: 10048c2ecf20Sopenharmony_ci while s[:len(prefix)] != prefix and prefix: 10058c2ecf20Sopenharmony_ci prefix = prefix[:len(prefix)-1] 10068c2ecf20Sopenharmony_ci if not prefix: 10078c2ecf20Sopenharmony_ci break 10088c2ecf20Sopenharmony_ci if '/' in prefix and prefix[-1] != '/': 10098c2ecf20Sopenharmony_ci prefix = prefix[0:prefix.rfind('/')+1] 10108c2ecf20Sopenharmony_ci return prefix 10118c2ecf20Sopenharmony_ci def dictify(self, text, format): 10128c2ecf20Sopenharmony_ci out = dict() 10138c2ecf20Sopenharmony_ci header = True if format == 1 else False 10148c2ecf20Sopenharmony_ci delim = ' ' if format == 1 else ':' 10158c2ecf20Sopenharmony_ci for line in text.split('\n'): 10168c2ecf20Sopenharmony_ci if header: 10178c2ecf20Sopenharmony_ci header, out['@'] = False, line 10188c2ecf20Sopenharmony_ci continue 10198c2ecf20Sopenharmony_ci line = line.strip() 10208c2ecf20Sopenharmony_ci if delim in line: 10218c2ecf20Sopenharmony_ci data = line.split(delim, 1) 10228c2ecf20Sopenharmony_ci num = re.search(r'[\d]+', data[1]) 10238c2ecf20Sopenharmony_ci if format == 2 and num: 10248c2ecf20Sopenharmony_ci out[data[0].strip()] = num.group() 10258c2ecf20Sopenharmony_ci else: 10268c2ecf20Sopenharmony_ci out[data[0].strip()] = data[1] 10278c2ecf20Sopenharmony_ci return out 10288c2ecf20Sopenharmony_ci def cmdinfo(self, begin, debug=False): 10298c2ecf20Sopenharmony_ci out = [] 10308c2ecf20Sopenharmony_ci if begin: 10318c2ecf20Sopenharmony_ci self.cmd1 = dict() 10328c2ecf20Sopenharmony_ci for cargs in self.infocmds: 10338c2ecf20Sopenharmony_ci delta, name = cargs[0], cargs[1] 10348c2ecf20Sopenharmony_ci cmdline, cmdpath = ' '.join(cargs[2:]), self.getExec(cargs[2]) 10358c2ecf20Sopenharmony_ci if not cmdpath or (begin and not delta): 10368c2ecf20Sopenharmony_ci continue 10378c2ecf20Sopenharmony_ci try: 10388c2ecf20Sopenharmony_ci fp = Popen([cmdpath]+cargs[3:], stdout=PIPE, stderr=PIPE).stdout 10398c2ecf20Sopenharmony_ci info = ascii(fp.read()).strip() 10408c2ecf20Sopenharmony_ci fp.close() 10418c2ecf20Sopenharmony_ci except: 10428c2ecf20Sopenharmony_ci continue 10438c2ecf20Sopenharmony_ci if not debug and begin: 10448c2ecf20Sopenharmony_ci self.cmd1[name] = self.dictify(info, delta) 10458c2ecf20Sopenharmony_ci elif not debug and delta and name in self.cmd1: 10468c2ecf20Sopenharmony_ci before, after = self.cmd1[name], self.dictify(info, delta) 10478c2ecf20Sopenharmony_ci dinfo = ('\t%s\n' % before['@']) if '@' in before else '' 10488c2ecf20Sopenharmony_ci prefix = self.commonPrefix(list(before.keys())) 10498c2ecf20Sopenharmony_ci for key in sorted(before): 10508c2ecf20Sopenharmony_ci if key in after and before[key] != after[key]: 10518c2ecf20Sopenharmony_ci title = key.replace(prefix, '') 10528c2ecf20Sopenharmony_ci if delta == 2: 10538c2ecf20Sopenharmony_ci dinfo += '\t%s : %s -> %s\n' % \ 10548c2ecf20Sopenharmony_ci (title, before[key].strip(), after[key].strip()) 10558c2ecf20Sopenharmony_ci else: 10568c2ecf20Sopenharmony_ci dinfo += '%10s (start) : %s\n%10s (after) : %s\n' % \ 10578c2ecf20Sopenharmony_ci (title, before[key], title, after[key]) 10588c2ecf20Sopenharmony_ci dinfo = '\tnothing changed' if not dinfo else dinfo.rstrip() 10598c2ecf20Sopenharmony_ci out.append((name, cmdline, dinfo)) 10608c2ecf20Sopenharmony_ci else: 10618c2ecf20Sopenharmony_ci out.append((name, cmdline, '\tnothing' if not info else info)) 10628c2ecf20Sopenharmony_ci return out 10638c2ecf20Sopenharmony_ci def haveTurbostat(self): 10648c2ecf20Sopenharmony_ci if not self.tstat: 10658c2ecf20Sopenharmony_ci return False 10668c2ecf20Sopenharmony_ci cmd = self.getExec('turbostat') 10678c2ecf20Sopenharmony_ci if not cmd: 10688c2ecf20Sopenharmony_ci return False 10698c2ecf20Sopenharmony_ci fp = Popen([cmd, '-v'], stdout=PIPE, stderr=PIPE).stderr 10708c2ecf20Sopenharmony_ci out = ascii(fp.read()).strip() 10718c2ecf20Sopenharmony_ci fp.close() 10728c2ecf20Sopenharmony_ci if re.match('turbostat version .*', out): 10738c2ecf20Sopenharmony_ci self.vprint(out) 10748c2ecf20Sopenharmony_ci return True 10758c2ecf20Sopenharmony_ci return False 10768c2ecf20Sopenharmony_ci def turbostat(self): 10778c2ecf20Sopenharmony_ci cmd = self.getExec('turbostat') 10788c2ecf20Sopenharmony_ci rawout = keyline = valline = '' 10798c2ecf20Sopenharmony_ci fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile) 10808c2ecf20Sopenharmony_ci fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE).stderr 10818c2ecf20Sopenharmony_ci for line in fp: 10828c2ecf20Sopenharmony_ci line = ascii(line) 10838c2ecf20Sopenharmony_ci rawout += line 10848c2ecf20Sopenharmony_ci if keyline and valline: 10858c2ecf20Sopenharmony_ci continue 10868c2ecf20Sopenharmony_ci if re.match('(?i)Avg_MHz.*', line): 10878c2ecf20Sopenharmony_ci keyline = line.strip().split() 10888c2ecf20Sopenharmony_ci elif keyline: 10898c2ecf20Sopenharmony_ci valline = line.strip().split() 10908c2ecf20Sopenharmony_ci fp.close() 10918c2ecf20Sopenharmony_ci if not keyline or not valline or len(keyline) != len(valline): 10928c2ecf20Sopenharmony_ci errmsg = 'unrecognized turbostat output:\n'+rawout.strip() 10938c2ecf20Sopenharmony_ci self.vprint(errmsg) 10948c2ecf20Sopenharmony_ci if not self.verbose: 10958c2ecf20Sopenharmony_ci pprint(errmsg) 10968c2ecf20Sopenharmony_ci return '' 10978c2ecf20Sopenharmony_ci if self.verbose: 10988c2ecf20Sopenharmony_ci pprint(rawout.strip()) 10998c2ecf20Sopenharmony_ci out = [] 11008c2ecf20Sopenharmony_ci for key in keyline: 11018c2ecf20Sopenharmony_ci idx = keyline.index(key) 11028c2ecf20Sopenharmony_ci val = valline[idx] 11038c2ecf20Sopenharmony_ci out.append('%s=%s' % (key, val)) 11048c2ecf20Sopenharmony_ci return '|'.join(out) 11058c2ecf20Sopenharmony_ci def wifiDetails(self, dev): 11068c2ecf20Sopenharmony_ci try: 11078c2ecf20Sopenharmony_ci info = open('/sys/class/net/%s/device/uevent' % dev, 'r').read().strip() 11088c2ecf20Sopenharmony_ci except: 11098c2ecf20Sopenharmony_ci return dev 11108c2ecf20Sopenharmony_ci vals = [dev] 11118c2ecf20Sopenharmony_ci for prop in info.split('\n'): 11128c2ecf20Sopenharmony_ci if prop.startswith('DRIVER=') or prop.startswith('PCI_ID='): 11138c2ecf20Sopenharmony_ci vals.append(prop.split('=')[-1]) 11148c2ecf20Sopenharmony_ci return ':'.join(vals) 11158c2ecf20Sopenharmony_ci def checkWifi(self, dev=''): 11168c2ecf20Sopenharmony_ci try: 11178c2ecf20Sopenharmony_ci w = open('/proc/net/wireless', 'r').read().strip() 11188c2ecf20Sopenharmony_ci except: 11198c2ecf20Sopenharmony_ci return '' 11208c2ecf20Sopenharmony_ci for line in reversed(w.split('\n')): 11218c2ecf20Sopenharmony_ci m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', w.split('\n')[-1]) 11228c2ecf20Sopenharmony_ci if not m or (dev and dev != m.group('dev')): 11238c2ecf20Sopenharmony_ci continue 11248c2ecf20Sopenharmony_ci return m.group('dev') 11258c2ecf20Sopenharmony_ci return '' 11268c2ecf20Sopenharmony_ci def pollWifi(self, dev, timeout=60): 11278c2ecf20Sopenharmony_ci start = time.time() 11288c2ecf20Sopenharmony_ci while (time.time() - start) < timeout: 11298c2ecf20Sopenharmony_ci w = self.checkWifi(dev) 11308c2ecf20Sopenharmony_ci if w: 11318c2ecf20Sopenharmony_ci return '%s reconnected %.2f' % \ 11328c2ecf20Sopenharmony_ci (self.wifiDetails(dev), max(0, time.time() - start)) 11338c2ecf20Sopenharmony_ci time.sleep(0.01) 11348c2ecf20Sopenharmony_ci return '%s timeout %d' % (self.wifiDetails(dev), timeout) 11358c2ecf20Sopenharmony_ci def errorSummary(self, errinfo, msg): 11368c2ecf20Sopenharmony_ci found = False 11378c2ecf20Sopenharmony_ci for entry in errinfo: 11388c2ecf20Sopenharmony_ci if re.match(entry['match'], msg): 11398c2ecf20Sopenharmony_ci entry['count'] += 1 11408c2ecf20Sopenharmony_ci if self.hostname not in entry['urls']: 11418c2ecf20Sopenharmony_ci entry['urls'][self.hostname] = [self.htmlfile] 11428c2ecf20Sopenharmony_ci elif self.htmlfile not in entry['urls'][self.hostname]: 11438c2ecf20Sopenharmony_ci entry['urls'][self.hostname].append(self.htmlfile) 11448c2ecf20Sopenharmony_ci found = True 11458c2ecf20Sopenharmony_ci break 11468c2ecf20Sopenharmony_ci if found: 11478c2ecf20Sopenharmony_ci return 11488c2ecf20Sopenharmony_ci arr = msg.split() 11498c2ecf20Sopenharmony_ci for j in range(len(arr)): 11508c2ecf20Sopenharmony_ci if re.match('^[0-9,\-\.]*$', arr[j]): 11518c2ecf20Sopenharmony_ci arr[j] = '[0-9,\-\.]*' 11528c2ecf20Sopenharmony_ci else: 11538c2ecf20Sopenharmony_ci arr[j] = arr[j]\ 11548c2ecf20Sopenharmony_ci .replace('\\', '\\\\').replace(']', '\]').replace('[', '\[')\ 11558c2ecf20Sopenharmony_ci .replace('.', '\.').replace('+', '\+').replace('*', '\*')\ 11568c2ecf20Sopenharmony_ci .replace('(', '\(').replace(')', '\)').replace('}', '\}')\ 11578c2ecf20Sopenharmony_ci .replace('{', '\{') 11588c2ecf20Sopenharmony_ci mstr = ' *'.join(arr) 11598c2ecf20Sopenharmony_ci entry = { 11608c2ecf20Sopenharmony_ci 'line': msg, 11618c2ecf20Sopenharmony_ci 'match': mstr, 11628c2ecf20Sopenharmony_ci 'count': 1, 11638c2ecf20Sopenharmony_ci 'urls': {self.hostname: [self.htmlfile]} 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci errinfo.append(entry) 11668c2ecf20Sopenharmony_ci def multistat(self, start, idx, finish): 11678c2ecf20Sopenharmony_ci if 'time' in self.multitest: 11688c2ecf20Sopenharmony_ci id = '%d Duration=%dmin' % (idx+1, self.multitest['time']) 11698c2ecf20Sopenharmony_ci else: 11708c2ecf20Sopenharmony_ci id = '%d/%d' % (idx+1, self.multitest['count']) 11718c2ecf20Sopenharmony_ci t = time.time() 11728c2ecf20Sopenharmony_ci if 'start' not in self.multitest: 11738c2ecf20Sopenharmony_ci self.multitest['start'] = self.multitest['last'] = t 11748c2ecf20Sopenharmony_ci self.multitest['total'] = 0.0 11758c2ecf20Sopenharmony_ci pprint('TEST (%s) START' % id) 11768c2ecf20Sopenharmony_ci return 11778c2ecf20Sopenharmony_ci dt = t - self.multitest['last'] 11788c2ecf20Sopenharmony_ci if not start: 11798c2ecf20Sopenharmony_ci if idx == 0 and self.multitest['delay'] > 0: 11808c2ecf20Sopenharmony_ci self.multitest['total'] += self.multitest['delay'] 11818c2ecf20Sopenharmony_ci pprint('TEST (%s) COMPLETE -- Duration %.1fs' % (id, dt)) 11828c2ecf20Sopenharmony_ci return 11838c2ecf20Sopenharmony_ci self.multitest['total'] += dt 11848c2ecf20Sopenharmony_ci self.multitest['last'] = t 11858c2ecf20Sopenharmony_ci avg = self.multitest['total'] / idx 11868c2ecf20Sopenharmony_ci if 'time' in self.multitest: 11878c2ecf20Sopenharmony_ci left = finish - datetime.now() 11888c2ecf20Sopenharmony_ci left -= timedelta(microseconds=left.microseconds) 11898c2ecf20Sopenharmony_ci else: 11908c2ecf20Sopenharmony_ci left = timedelta(seconds=((self.multitest['count'] - idx) * int(avg))) 11918c2ecf20Sopenharmony_ci pprint('TEST (%s) START - Avg Duration %.1fs, Time left %s' % \ 11928c2ecf20Sopenharmony_ci (id, avg, str(left))) 11938c2ecf20Sopenharmony_ci def multiinit(self, c, d): 11948c2ecf20Sopenharmony_ci sz, unit = 'count', 'm' 11958c2ecf20Sopenharmony_ci if c.endswith('d') or c.endswith('h') or c.endswith('m'): 11968c2ecf20Sopenharmony_ci sz, unit, c = 'time', c[-1], c[:-1] 11978c2ecf20Sopenharmony_ci self.multitest['run'] = True 11988c2ecf20Sopenharmony_ci self.multitest[sz] = getArgInt('multi: n d (exec count)', c, 1, 1000000, False) 11998c2ecf20Sopenharmony_ci self.multitest['delay'] = getArgInt('multi: n d (delay between tests)', d, 0, 3600, False) 12008c2ecf20Sopenharmony_ci if unit == 'd': 12018c2ecf20Sopenharmony_ci self.multitest[sz] *= 1440 12028c2ecf20Sopenharmony_ci elif unit == 'h': 12038c2ecf20Sopenharmony_ci self.multitest[sz] *= 60 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_cisysvals = SystemValues() 12068c2ecf20Sopenharmony_ciswitchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0'] 12078c2ecf20Sopenharmony_ciswitchoff = ['disable', 'off', 'false', '0'] 12088c2ecf20Sopenharmony_cisuspendmodename = { 12098c2ecf20Sopenharmony_ci 'freeze': 'Freeze (S0)', 12108c2ecf20Sopenharmony_ci 'standby': 'Standby (S1)', 12118c2ecf20Sopenharmony_ci 'mem': 'Suspend (S3)', 12128c2ecf20Sopenharmony_ci 'disk': 'Hibernate (S4)' 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci# Class: DevProps 12168c2ecf20Sopenharmony_ci# Description: 12178c2ecf20Sopenharmony_ci# Simple class which holds property values collected 12188c2ecf20Sopenharmony_ci# for all the devices used in the timeline. 12198c2ecf20Sopenharmony_ciclass DevProps: 12208c2ecf20Sopenharmony_ci def __init__(self): 12218c2ecf20Sopenharmony_ci self.syspath = '' 12228c2ecf20Sopenharmony_ci self.altname = '' 12238c2ecf20Sopenharmony_ci self.isasync = True 12248c2ecf20Sopenharmony_ci self.xtraclass = '' 12258c2ecf20Sopenharmony_ci self.xtrainfo = '' 12268c2ecf20Sopenharmony_ci def out(self, dev): 12278c2ecf20Sopenharmony_ci return '%s,%s,%d;' % (dev, self.altname, self.isasync) 12288c2ecf20Sopenharmony_ci def debug(self, dev): 12298c2ecf20Sopenharmony_ci pprint('%s:\n\taltname = %s\n\t async = %s' % (dev, self.altname, self.isasync)) 12308c2ecf20Sopenharmony_ci def altName(self, dev): 12318c2ecf20Sopenharmony_ci if not self.altname or self.altname == dev: 12328c2ecf20Sopenharmony_ci return dev 12338c2ecf20Sopenharmony_ci return '%s [%s]' % (self.altname, dev) 12348c2ecf20Sopenharmony_ci def xtraClass(self): 12358c2ecf20Sopenharmony_ci if self.xtraclass: 12368c2ecf20Sopenharmony_ci return ' '+self.xtraclass 12378c2ecf20Sopenharmony_ci if not self.isasync: 12388c2ecf20Sopenharmony_ci return ' sync' 12398c2ecf20Sopenharmony_ci return '' 12408c2ecf20Sopenharmony_ci def xtraInfo(self): 12418c2ecf20Sopenharmony_ci if self.xtraclass: 12428c2ecf20Sopenharmony_ci return ' '+self.xtraclass 12438c2ecf20Sopenharmony_ci if self.isasync: 12448c2ecf20Sopenharmony_ci return ' (async)' 12458c2ecf20Sopenharmony_ci return ' (sync)' 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci# Class: DeviceNode 12488c2ecf20Sopenharmony_ci# Description: 12498c2ecf20Sopenharmony_ci# A container used to create a device hierachy, with a single root node 12508c2ecf20Sopenharmony_ci# and a tree of child nodes. Used by Data.deviceTopology() 12518c2ecf20Sopenharmony_ciclass DeviceNode: 12528c2ecf20Sopenharmony_ci def __init__(self, nodename, nodedepth): 12538c2ecf20Sopenharmony_ci self.name = nodename 12548c2ecf20Sopenharmony_ci self.children = [] 12558c2ecf20Sopenharmony_ci self.depth = nodedepth 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci# Class: Data 12588c2ecf20Sopenharmony_ci# Description: 12598c2ecf20Sopenharmony_ci# The primary container for suspend/resume test data. There is one for 12608c2ecf20Sopenharmony_ci# each test run. The data is organized into a cronological hierarchy: 12618c2ecf20Sopenharmony_ci# Data.dmesg { 12628c2ecf20Sopenharmony_ci# phases { 12638c2ecf20Sopenharmony_ci# 10 sequential, non-overlapping phases of S/R 12648c2ecf20Sopenharmony_ci# contents: times for phase start/end, order/color data for html 12658c2ecf20Sopenharmony_ci# devlist { 12668c2ecf20Sopenharmony_ci# device callback or action list for this phase 12678c2ecf20Sopenharmony_ci# device { 12688c2ecf20Sopenharmony_ci# a single device callback or generic action 12698c2ecf20Sopenharmony_ci# contents: start/stop times, pid/cpu/driver info 12708c2ecf20Sopenharmony_ci# parents/children, html id for timeline/callgraph 12718c2ecf20Sopenharmony_ci# optionally includes an ftrace callgraph 12728c2ecf20Sopenharmony_ci# optionally includes dev/ps data 12738c2ecf20Sopenharmony_ci# } 12748c2ecf20Sopenharmony_ci# } 12758c2ecf20Sopenharmony_ci# } 12768c2ecf20Sopenharmony_ci# } 12778c2ecf20Sopenharmony_ci# 12788c2ecf20Sopenharmony_ciclass Data: 12798c2ecf20Sopenharmony_ci phasedef = { 12808c2ecf20Sopenharmony_ci 'suspend_prepare': {'order': 0, 'color': '#CCFFCC'}, 12818c2ecf20Sopenharmony_ci 'suspend': {'order': 1, 'color': '#88FF88'}, 12828c2ecf20Sopenharmony_ci 'suspend_late': {'order': 2, 'color': '#00AA00'}, 12838c2ecf20Sopenharmony_ci 'suspend_noirq': {'order': 3, 'color': '#008888'}, 12848c2ecf20Sopenharmony_ci 'suspend_machine': {'order': 4, 'color': '#0000FF'}, 12858c2ecf20Sopenharmony_ci 'resume_machine': {'order': 5, 'color': '#FF0000'}, 12868c2ecf20Sopenharmony_ci 'resume_noirq': {'order': 6, 'color': '#FF9900'}, 12878c2ecf20Sopenharmony_ci 'resume_early': {'order': 7, 'color': '#FFCC00'}, 12888c2ecf20Sopenharmony_ci 'resume': {'order': 8, 'color': '#FFFF88'}, 12898c2ecf20Sopenharmony_ci 'resume_complete': {'order': 9, 'color': '#FFFFCC'}, 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci errlist = { 12928c2ecf20Sopenharmony_ci 'HWERROR' : r'.*\[ *Hardware Error *\].*', 12938c2ecf20Sopenharmony_ci 'FWBUG' : r'.*\[ *Firmware Bug *\].*', 12948c2ecf20Sopenharmony_ci 'BUG' : r'(?i).*\bBUG\b.*', 12958c2ecf20Sopenharmony_ci 'ERROR' : r'(?i).*\bERROR\b.*', 12968c2ecf20Sopenharmony_ci 'WARNING' : r'(?i).*\bWARNING\b.*', 12978c2ecf20Sopenharmony_ci 'FAULT' : r'(?i).*\bFAULT\b.*', 12988c2ecf20Sopenharmony_ci 'FAIL' : r'(?i).*\bFAILED\b.*', 12998c2ecf20Sopenharmony_ci 'INVALID' : r'(?i).*\bINVALID\b.*', 13008c2ecf20Sopenharmony_ci 'CRASH' : r'(?i).*\bCRASHED\b.*', 13018c2ecf20Sopenharmony_ci 'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*', 13028c2ecf20Sopenharmony_ci 'IRQ' : r'.*\bgenirq: .*', 13038c2ecf20Sopenharmony_ci 'TASKFAIL': r'.*Freezing of tasks *.*', 13048c2ecf20Sopenharmony_ci 'ACPI' : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*', 13058c2ecf20Sopenharmony_ci 'DISKFULL': r'.*\bNo space left on device.*', 13068c2ecf20Sopenharmony_ci 'USBERR' : r'.*usb .*device .*, error [0-9-]*', 13078c2ecf20Sopenharmony_ci 'ATAERR' : r' *ata[0-9\.]*: .*failed.*', 13088c2ecf20Sopenharmony_ci 'MEIERR' : r' *mei.*: .*failed.*', 13098c2ecf20Sopenharmony_ci 'TPMERR' : r'(?i) *tpm *tpm[0-9]*: .*error.*', 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci def __init__(self, num): 13128c2ecf20Sopenharmony_ci idchar = 'abcdefghij' 13138c2ecf20Sopenharmony_ci self.start = 0.0 # test start 13148c2ecf20Sopenharmony_ci self.end = 0.0 # test end 13158c2ecf20Sopenharmony_ci self.hwstart = 0 # rtc test start 13168c2ecf20Sopenharmony_ci self.hwend = 0 # rtc test end 13178c2ecf20Sopenharmony_ci self.tSuspended = 0.0 # low-level suspend start 13188c2ecf20Sopenharmony_ci self.tResumed = 0.0 # low-level resume start 13198c2ecf20Sopenharmony_ci self.tKernSus = 0.0 # kernel level suspend start 13208c2ecf20Sopenharmony_ci self.tKernRes = 0.0 # kernel level resume end 13218c2ecf20Sopenharmony_ci self.fwValid = False # is firmware data available 13228c2ecf20Sopenharmony_ci self.fwSuspend = 0 # time spent in firmware suspend 13238c2ecf20Sopenharmony_ci self.fwResume = 0 # time spent in firmware resume 13248c2ecf20Sopenharmony_ci self.html_device_id = 0 13258c2ecf20Sopenharmony_ci self.stamp = 0 13268c2ecf20Sopenharmony_ci self.outfile = '' 13278c2ecf20Sopenharmony_ci self.kerror = False 13288c2ecf20Sopenharmony_ci self.wifi = dict() 13298c2ecf20Sopenharmony_ci self.turbostat = 0 13308c2ecf20Sopenharmony_ci self.enterfail = '' 13318c2ecf20Sopenharmony_ci self.currphase = '' 13328c2ecf20Sopenharmony_ci self.pstl = dict() # process timeline 13338c2ecf20Sopenharmony_ci self.testnumber = num 13348c2ecf20Sopenharmony_ci self.idstr = idchar[num] 13358c2ecf20Sopenharmony_ci self.dmesgtext = [] # dmesg text file in memory 13368c2ecf20Sopenharmony_ci self.dmesg = dict() # root data structure 13378c2ecf20Sopenharmony_ci self.errorinfo = {'suspend':[],'resume':[]} 13388c2ecf20Sopenharmony_ci self.tLow = [] # time spent in low-level suspends (standby/freeze) 13398c2ecf20Sopenharmony_ci self.devpids = [] 13408c2ecf20Sopenharmony_ci self.devicegroups = 0 13418c2ecf20Sopenharmony_ci def sortedPhases(self): 13428c2ecf20Sopenharmony_ci return sorted(self.dmesg, key=lambda k:self.dmesg[k]['order']) 13438c2ecf20Sopenharmony_ci def initDevicegroups(self): 13448c2ecf20Sopenharmony_ci # called when phases are all finished being added 13458c2ecf20Sopenharmony_ci for phase in sorted(self.dmesg.keys()): 13468c2ecf20Sopenharmony_ci if '*' in phase: 13478c2ecf20Sopenharmony_ci p = phase.split('*') 13488c2ecf20Sopenharmony_ci pnew = '%s%d' % (p[0], len(p)) 13498c2ecf20Sopenharmony_ci self.dmesg[pnew] = self.dmesg.pop(phase) 13508c2ecf20Sopenharmony_ci self.devicegroups = [] 13518c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 13528c2ecf20Sopenharmony_ci self.devicegroups.append([phase]) 13538c2ecf20Sopenharmony_ci def nextPhase(self, phase, offset): 13548c2ecf20Sopenharmony_ci order = self.dmesg[phase]['order'] + offset 13558c2ecf20Sopenharmony_ci for p in self.dmesg: 13568c2ecf20Sopenharmony_ci if self.dmesg[p]['order'] == order: 13578c2ecf20Sopenharmony_ci return p 13588c2ecf20Sopenharmony_ci return '' 13598c2ecf20Sopenharmony_ci def lastPhase(self, depth=1): 13608c2ecf20Sopenharmony_ci plist = self.sortedPhases() 13618c2ecf20Sopenharmony_ci if len(plist) < depth: 13628c2ecf20Sopenharmony_ci return '' 13638c2ecf20Sopenharmony_ci return plist[-1*depth] 13648c2ecf20Sopenharmony_ci def turbostatInfo(self): 13658c2ecf20Sopenharmony_ci tp = TestProps() 13668c2ecf20Sopenharmony_ci out = {'syslpi':'N/A','pkgpc10':'N/A'} 13678c2ecf20Sopenharmony_ci for line in self.dmesgtext: 13688c2ecf20Sopenharmony_ci m = re.match(tp.tstatfmt, line) 13698c2ecf20Sopenharmony_ci if not m: 13708c2ecf20Sopenharmony_ci continue 13718c2ecf20Sopenharmony_ci for i in m.group('t').split('|'): 13728c2ecf20Sopenharmony_ci if 'SYS%LPI' in i: 13738c2ecf20Sopenharmony_ci out['syslpi'] = i.split('=')[-1]+'%' 13748c2ecf20Sopenharmony_ci elif 'pc10' in i: 13758c2ecf20Sopenharmony_ci out['pkgpc10'] = i.split('=')[-1]+'%' 13768c2ecf20Sopenharmony_ci break 13778c2ecf20Sopenharmony_ci return out 13788c2ecf20Sopenharmony_ci def extractErrorInfo(self): 13798c2ecf20Sopenharmony_ci lf = self.dmesgtext 13808c2ecf20Sopenharmony_ci if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 13818c2ecf20Sopenharmony_ci lf = sysvals.openlog(sysvals.dmesgfile, 'r') 13828c2ecf20Sopenharmony_ci i = 0 13838c2ecf20Sopenharmony_ci tp = TestProps() 13848c2ecf20Sopenharmony_ci list = [] 13858c2ecf20Sopenharmony_ci for line in lf: 13868c2ecf20Sopenharmony_ci i += 1 13878c2ecf20Sopenharmony_ci if tp.stampInfo(line, sysvals): 13888c2ecf20Sopenharmony_ci continue 13898c2ecf20Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 13908c2ecf20Sopenharmony_ci if not m: 13918c2ecf20Sopenharmony_ci continue 13928c2ecf20Sopenharmony_ci t = float(m.group('ktime')) 13938c2ecf20Sopenharmony_ci if t < self.start or t > self.end: 13948c2ecf20Sopenharmony_ci continue 13958c2ecf20Sopenharmony_ci dir = 'suspend' if t < self.tSuspended else 'resume' 13968c2ecf20Sopenharmony_ci msg = m.group('msg') 13978c2ecf20Sopenharmony_ci if re.match('capability: warning: .*', msg): 13988c2ecf20Sopenharmony_ci continue 13998c2ecf20Sopenharmony_ci for err in self.errlist: 14008c2ecf20Sopenharmony_ci if re.match(self.errlist[err], msg): 14018c2ecf20Sopenharmony_ci list.append((msg, err, dir, t, i, i)) 14028c2ecf20Sopenharmony_ci self.kerror = True 14038c2ecf20Sopenharmony_ci break 14048c2ecf20Sopenharmony_ci tp.msglist = [] 14058c2ecf20Sopenharmony_ci for msg, type, dir, t, idx1, idx2 in list: 14068c2ecf20Sopenharmony_ci tp.msglist.append(msg) 14078c2ecf20Sopenharmony_ci self.errorinfo[dir].append((type, t, idx1, idx2)) 14088c2ecf20Sopenharmony_ci if self.kerror: 14098c2ecf20Sopenharmony_ci sysvals.dmesglog = True 14108c2ecf20Sopenharmony_ci if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 14118c2ecf20Sopenharmony_ci lf.close() 14128c2ecf20Sopenharmony_ci return tp 14138c2ecf20Sopenharmony_ci def setStart(self, time, msg=''): 14148c2ecf20Sopenharmony_ci self.start = time 14158c2ecf20Sopenharmony_ci if msg: 14168c2ecf20Sopenharmony_ci try: 14178c2ecf20Sopenharmony_ci self.hwstart = datetime.strptime(msg, sysvals.tmstart) 14188c2ecf20Sopenharmony_ci except: 14198c2ecf20Sopenharmony_ci self.hwstart = 0 14208c2ecf20Sopenharmony_ci def setEnd(self, time, msg=''): 14218c2ecf20Sopenharmony_ci self.end = time 14228c2ecf20Sopenharmony_ci if msg: 14238c2ecf20Sopenharmony_ci try: 14248c2ecf20Sopenharmony_ci self.hwend = datetime.strptime(msg, sysvals.tmend) 14258c2ecf20Sopenharmony_ci except: 14268c2ecf20Sopenharmony_ci self.hwend = 0 14278c2ecf20Sopenharmony_ci def isTraceEventOutsideDeviceCalls(self, pid, time): 14288c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 14298c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 14308c2ecf20Sopenharmony_ci for dev in list: 14318c2ecf20Sopenharmony_ci d = list[dev] 14328c2ecf20Sopenharmony_ci if(d['pid'] == pid and time >= d['start'] and 14338c2ecf20Sopenharmony_ci time < d['end']): 14348c2ecf20Sopenharmony_ci return False 14358c2ecf20Sopenharmony_ci return True 14368c2ecf20Sopenharmony_ci def sourcePhase(self, start): 14378c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 14388c2ecf20Sopenharmony_ci if 'machine' in phase: 14398c2ecf20Sopenharmony_ci continue 14408c2ecf20Sopenharmony_ci pend = self.dmesg[phase]['end'] 14418c2ecf20Sopenharmony_ci if start <= pend: 14428c2ecf20Sopenharmony_ci return phase 14438c2ecf20Sopenharmony_ci return 'resume_complete' 14448c2ecf20Sopenharmony_ci def sourceDevice(self, phaselist, start, end, pid, type): 14458c2ecf20Sopenharmony_ci tgtdev = '' 14468c2ecf20Sopenharmony_ci for phase in phaselist: 14478c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 14488c2ecf20Sopenharmony_ci for devname in list: 14498c2ecf20Sopenharmony_ci dev = list[devname] 14508c2ecf20Sopenharmony_ci # pid must match 14518c2ecf20Sopenharmony_ci if dev['pid'] != pid: 14528c2ecf20Sopenharmony_ci continue 14538c2ecf20Sopenharmony_ci devS = dev['start'] 14548c2ecf20Sopenharmony_ci devE = dev['end'] 14558c2ecf20Sopenharmony_ci if type == 'device': 14568c2ecf20Sopenharmony_ci # device target event is entirely inside the source boundary 14578c2ecf20Sopenharmony_ci if(start < devS or start >= devE or end <= devS or end > devE): 14588c2ecf20Sopenharmony_ci continue 14598c2ecf20Sopenharmony_ci elif type == 'thread': 14608c2ecf20Sopenharmony_ci # thread target event will expand the source boundary 14618c2ecf20Sopenharmony_ci if start < devS: 14628c2ecf20Sopenharmony_ci dev['start'] = start 14638c2ecf20Sopenharmony_ci if end > devE: 14648c2ecf20Sopenharmony_ci dev['end'] = end 14658c2ecf20Sopenharmony_ci tgtdev = dev 14668c2ecf20Sopenharmony_ci break 14678c2ecf20Sopenharmony_ci return tgtdev 14688c2ecf20Sopenharmony_ci def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata): 14698c2ecf20Sopenharmony_ci # try to place the call in a device 14708c2ecf20Sopenharmony_ci phases = self.sortedPhases() 14718c2ecf20Sopenharmony_ci tgtdev = self.sourceDevice(phases, start, end, pid, 'device') 14728c2ecf20Sopenharmony_ci # calls with device pids that occur outside device bounds are dropped 14738c2ecf20Sopenharmony_ci # TODO: include these somehow 14748c2ecf20Sopenharmony_ci if not tgtdev and pid in self.devpids: 14758c2ecf20Sopenharmony_ci return False 14768c2ecf20Sopenharmony_ci # try to place the call in a thread 14778c2ecf20Sopenharmony_ci if not tgtdev: 14788c2ecf20Sopenharmony_ci tgtdev = self.sourceDevice(phases, start, end, pid, 'thread') 14798c2ecf20Sopenharmony_ci # create new thread blocks, expand as new calls are found 14808c2ecf20Sopenharmony_ci if not tgtdev: 14818c2ecf20Sopenharmony_ci if proc == '<...>': 14828c2ecf20Sopenharmony_ci threadname = 'kthread-%d' % (pid) 14838c2ecf20Sopenharmony_ci else: 14848c2ecf20Sopenharmony_ci threadname = '%s-%d' % (proc, pid) 14858c2ecf20Sopenharmony_ci tgtphase = self.sourcePhase(start) 14868c2ecf20Sopenharmony_ci self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '') 14878c2ecf20Sopenharmony_ci return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata) 14888c2ecf20Sopenharmony_ci # this should not happen 14898c2ecf20Sopenharmony_ci if not tgtdev: 14908c2ecf20Sopenharmony_ci sysvals.vprint('[%f - %f] %s-%d %s %s %s' % \ 14918c2ecf20Sopenharmony_ci (start, end, proc, pid, kprobename, cdata, rdata)) 14928c2ecf20Sopenharmony_ci return False 14938c2ecf20Sopenharmony_ci # place the call data inside the src element of the tgtdev 14948c2ecf20Sopenharmony_ci if('src' not in tgtdev): 14958c2ecf20Sopenharmony_ci tgtdev['src'] = [] 14968c2ecf20Sopenharmony_ci dtf = sysvals.dev_tracefuncs 14978c2ecf20Sopenharmony_ci ubiquitous = False 14988c2ecf20Sopenharmony_ci if kprobename in dtf and 'ub' in dtf[kprobename]: 14998c2ecf20Sopenharmony_ci ubiquitous = True 15008c2ecf20Sopenharmony_ci title = cdata+' '+rdata 15018c2ecf20Sopenharmony_ci mstr = '\(.*\) *(?P<args>.*) *\((?P<caller>.*)\+.* arg1=(?P<ret>.*)' 15028c2ecf20Sopenharmony_ci m = re.match(mstr, title) 15038c2ecf20Sopenharmony_ci if m: 15048c2ecf20Sopenharmony_ci c = m.group('caller') 15058c2ecf20Sopenharmony_ci a = m.group('args').strip() 15068c2ecf20Sopenharmony_ci r = m.group('ret') 15078c2ecf20Sopenharmony_ci if len(r) > 6: 15088c2ecf20Sopenharmony_ci r = '' 15098c2ecf20Sopenharmony_ci else: 15108c2ecf20Sopenharmony_ci r = 'ret=%s ' % r 15118c2ecf20Sopenharmony_ci if ubiquitous and c in dtf and 'ub' in dtf[c]: 15128c2ecf20Sopenharmony_ci return False 15138c2ecf20Sopenharmony_ci color = sysvals.kprobeColor(kprobename) 15148c2ecf20Sopenharmony_ci e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color) 15158c2ecf20Sopenharmony_ci tgtdev['src'].append(e) 15168c2ecf20Sopenharmony_ci return True 15178c2ecf20Sopenharmony_ci def overflowDevices(self): 15188c2ecf20Sopenharmony_ci # get a list of devices that extend beyond the end of this test run 15198c2ecf20Sopenharmony_ci devlist = [] 15208c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 15218c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 15228c2ecf20Sopenharmony_ci for devname in list: 15238c2ecf20Sopenharmony_ci dev = list[devname] 15248c2ecf20Sopenharmony_ci if dev['end'] > self.end: 15258c2ecf20Sopenharmony_ci devlist.append(dev) 15268c2ecf20Sopenharmony_ci return devlist 15278c2ecf20Sopenharmony_ci def mergeOverlapDevices(self, devlist): 15288c2ecf20Sopenharmony_ci # merge any devices that overlap devlist 15298c2ecf20Sopenharmony_ci for dev in devlist: 15308c2ecf20Sopenharmony_ci devname = dev['name'] 15318c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 15328c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 15338c2ecf20Sopenharmony_ci if devname not in list: 15348c2ecf20Sopenharmony_ci continue 15358c2ecf20Sopenharmony_ci tdev = list[devname] 15368c2ecf20Sopenharmony_ci o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start']) 15378c2ecf20Sopenharmony_ci if o <= 0: 15388c2ecf20Sopenharmony_ci continue 15398c2ecf20Sopenharmony_ci dev['end'] = tdev['end'] 15408c2ecf20Sopenharmony_ci if 'src' not in dev or 'src' not in tdev: 15418c2ecf20Sopenharmony_ci continue 15428c2ecf20Sopenharmony_ci dev['src'] += tdev['src'] 15438c2ecf20Sopenharmony_ci del list[devname] 15448c2ecf20Sopenharmony_ci def usurpTouchingThread(self, name, dev): 15458c2ecf20Sopenharmony_ci # the caller test has priority of this thread, give it to him 15468c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 15478c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 15488c2ecf20Sopenharmony_ci if name in list: 15498c2ecf20Sopenharmony_ci tdev = list[name] 15508c2ecf20Sopenharmony_ci if tdev['start'] - dev['end'] < 0.1: 15518c2ecf20Sopenharmony_ci dev['end'] = tdev['end'] 15528c2ecf20Sopenharmony_ci if 'src' not in dev: 15538c2ecf20Sopenharmony_ci dev['src'] = [] 15548c2ecf20Sopenharmony_ci if 'src' in tdev: 15558c2ecf20Sopenharmony_ci dev['src'] += tdev['src'] 15568c2ecf20Sopenharmony_ci del list[name] 15578c2ecf20Sopenharmony_ci break 15588c2ecf20Sopenharmony_ci def stitchTouchingThreads(self, testlist): 15598c2ecf20Sopenharmony_ci # merge any threads between tests that touch 15608c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 15618c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 15628c2ecf20Sopenharmony_ci for devname in list: 15638c2ecf20Sopenharmony_ci dev = list[devname] 15648c2ecf20Sopenharmony_ci if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']: 15658c2ecf20Sopenharmony_ci continue 15668c2ecf20Sopenharmony_ci for data in testlist: 15678c2ecf20Sopenharmony_ci data.usurpTouchingThread(devname, dev) 15688c2ecf20Sopenharmony_ci def optimizeDevSrc(self): 15698c2ecf20Sopenharmony_ci # merge any src call loops to reduce timeline size 15708c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 15718c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 15728c2ecf20Sopenharmony_ci for dev in list: 15738c2ecf20Sopenharmony_ci if 'src' not in list[dev]: 15748c2ecf20Sopenharmony_ci continue 15758c2ecf20Sopenharmony_ci src = list[dev]['src'] 15768c2ecf20Sopenharmony_ci p = 0 15778c2ecf20Sopenharmony_ci for e in sorted(src, key=lambda event: event.time): 15788c2ecf20Sopenharmony_ci if not p or not e.repeat(p): 15798c2ecf20Sopenharmony_ci p = e 15808c2ecf20Sopenharmony_ci continue 15818c2ecf20Sopenharmony_ci # e is another iteration of p, move it into p 15828c2ecf20Sopenharmony_ci p.end = e.end 15838c2ecf20Sopenharmony_ci p.length = p.end - p.time 15848c2ecf20Sopenharmony_ci p.count += 1 15858c2ecf20Sopenharmony_ci src.remove(e) 15868c2ecf20Sopenharmony_ci def trimTimeVal(self, t, t0, dT, left): 15878c2ecf20Sopenharmony_ci if left: 15888c2ecf20Sopenharmony_ci if(t > t0): 15898c2ecf20Sopenharmony_ci if(t - dT < t0): 15908c2ecf20Sopenharmony_ci return t0 15918c2ecf20Sopenharmony_ci return t - dT 15928c2ecf20Sopenharmony_ci else: 15938c2ecf20Sopenharmony_ci return t 15948c2ecf20Sopenharmony_ci else: 15958c2ecf20Sopenharmony_ci if(t < t0 + dT): 15968c2ecf20Sopenharmony_ci if(t > t0): 15978c2ecf20Sopenharmony_ci return t0 + dT 15988c2ecf20Sopenharmony_ci return t + dT 15998c2ecf20Sopenharmony_ci else: 16008c2ecf20Sopenharmony_ci return t 16018c2ecf20Sopenharmony_ci def trimTime(self, t0, dT, left): 16028c2ecf20Sopenharmony_ci self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left) 16038c2ecf20Sopenharmony_ci self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left) 16048c2ecf20Sopenharmony_ci self.start = self.trimTimeVal(self.start, t0, dT, left) 16058c2ecf20Sopenharmony_ci self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left) 16068c2ecf20Sopenharmony_ci self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left) 16078c2ecf20Sopenharmony_ci self.end = self.trimTimeVal(self.end, t0, dT, left) 16088c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 16098c2ecf20Sopenharmony_ci p = self.dmesg[phase] 16108c2ecf20Sopenharmony_ci p['start'] = self.trimTimeVal(p['start'], t0, dT, left) 16118c2ecf20Sopenharmony_ci p['end'] = self.trimTimeVal(p['end'], t0, dT, left) 16128c2ecf20Sopenharmony_ci list = p['list'] 16138c2ecf20Sopenharmony_ci for name in list: 16148c2ecf20Sopenharmony_ci d = list[name] 16158c2ecf20Sopenharmony_ci d['start'] = self.trimTimeVal(d['start'], t0, dT, left) 16168c2ecf20Sopenharmony_ci d['end'] = self.trimTimeVal(d['end'], t0, dT, left) 16178c2ecf20Sopenharmony_ci d['length'] = d['end'] - d['start'] 16188c2ecf20Sopenharmony_ci if('ftrace' in d): 16198c2ecf20Sopenharmony_ci cg = d['ftrace'] 16208c2ecf20Sopenharmony_ci cg.start = self.trimTimeVal(cg.start, t0, dT, left) 16218c2ecf20Sopenharmony_ci cg.end = self.trimTimeVal(cg.end, t0, dT, left) 16228c2ecf20Sopenharmony_ci for line in cg.list: 16238c2ecf20Sopenharmony_ci line.time = self.trimTimeVal(line.time, t0, dT, left) 16248c2ecf20Sopenharmony_ci if('src' in d): 16258c2ecf20Sopenharmony_ci for e in d['src']: 16268c2ecf20Sopenharmony_ci e.time = self.trimTimeVal(e.time, t0, dT, left) 16278c2ecf20Sopenharmony_ci e.end = self.trimTimeVal(e.end, t0, dT, left) 16288c2ecf20Sopenharmony_ci e.length = e.end - e.time 16298c2ecf20Sopenharmony_ci for dir in ['suspend', 'resume']: 16308c2ecf20Sopenharmony_ci list = [] 16318c2ecf20Sopenharmony_ci for e in self.errorinfo[dir]: 16328c2ecf20Sopenharmony_ci type, tm, idx1, idx2 = e 16338c2ecf20Sopenharmony_ci tm = self.trimTimeVal(tm, t0, dT, left) 16348c2ecf20Sopenharmony_ci list.append((type, tm, idx1, idx2)) 16358c2ecf20Sopenharmony_ci self.errorinfo[dir] = list 16368c2ecf20Sopenharmony_ci def trimFreezeTime(self, tZero): 16378c2ecf20Sopenharmony_ci # trim out any standby or freeze clock time 16388c2ecf20Sopenharmony_ci lp = '' 16398c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 16408c2ecf20Sopenharmony_ci if 'resume_machine' in phase and 'suspend_machine' in lp: 16418c2ecf20Sopenharmony_ci tS, tR = self.dmesg[lp]['end'], self.dmesg[phase]['start'] 16428c2ecf20Sopenharmony_ci tL = tR - tS 16438c2ecf20Sopenharmony_ci if tL > 0: 16448c2ecf20Sopenharmony_ci left = True if tR > tZero else False 16458c2ecf20Sopenharmony_ci self.trimTime(tS, tL, left) 16468c2ecf20Sopenharmony_ci if 'trying' in self.dmesg[lp] and self.dmesg[lp]['trying'] >= 0.001: 16478c2ecf20Sopenharmony_ci tTry = round(self.dmesg[lp]['trying'] * 1000) 16488c2ecf20Sopenharmony_ci text = '%.0f (-%.0f waking)' % (tL * 1000, tTry) 16498c2ecf20Sopenharmony_ci else: 16508c2ecf20Sopenharmony_ci text = '%.0f' % (tL * 1000) 16518c2ecf20Sopenharmony_ci self.tLow.append(text) 16528c2ecf20Sopenharmony_ci lp = phase 16538c2ecf20Sopenharmony_ci def getMemTime(self): 16548c2ecf20Sopenharmony_ci if not self.hwstart or not self.hwend: 16558c2ecf20Sopenharmony_ci return 16568c2ecf20Sopenharmony_ci stime = (self.tSuspended - self.start) * 1000000 16578c2ecf20Sopenharmony_ci rtime = (self.end - self.tResumed) * 1000000 16588c2ecf20Sopenharmony_ci hws = self.hwstart + timedelta(microseconds=stime) 16598c2ecf20Sopenharmony_ci hwr = self.hwend - timedelta(microseconds=rtime) 16608c2ecf20Sopenharmony_ci self.tLow.append('%.0f'%((hwr - hws).total_seconds() * 1000)) 16618c2ecf20Sopenharmony_ci def getTimeValues(self): 16628c2ecf20Sopenharmony_ci sktime = (self.tSuspended - self.tKernSus) * 1000 16638c2ecf20Sopenharmony_ci rktime = (self.tKernRes - self.tResumed) * 1000 16648c2ecf20Sopenharmony_ci return (sktime, rktime) 16658c2ecf20Sopenharmony_ci def setPhase(self, phase, ktime, isbegin, order=-1): 16668c2ecf20Sopenharmony_ci if(isbegin): 16678c2ecf20Sopenharmony_ci # phase start over current phase 16688c2ecf20Sopenharmony_ci if self.currphase: 16698c2ecf20Sopenharmony_ci if 'resume_machine' not in self.currphase: 16708c2ecf20Sopenharmony_ci sysvals.vprint('WARNING: phase %s failed to end' % self.currphase) 16718c2ecf20Sopenharmony_ci self.dmesg[self.currphase]['end'] = ktime 16728c2ecf20Sopenharmony_ci phases = self.dmesg.keys() 16738c2ecf20Sopenharmony_ci color = self.phasedef[phase]['color'] 16748c2ecf20Sopenharmony_ci count = len(phases) if order < 0 else order 16758c2ecf20Sopenharmony_ci # create unique name for every new phase 16768c2ecf20Sopenharmony_ci while phase in phases: 16778c2ecf20Sopenharmony_ci phase += '*' 16788c2ecf20Sopenharmony_ci self.dmesg[phase] = {'list': dict(), 'start': -1.0, 'end': -1.0, 16798c2ecf20Sopenharmony_ci 'row': 0, 'color': color, 'order': count} 16808c2ecf20Sopenharmony_ci self.dmesg[phase]['start'] = ktime 16818c2ecf20Sopenharmony_ci self.currphase = phase 16828c2ecf20Sopenharmony_ci else: 16838c2ecf20Sopenharmony_ci # phase end without a start 16848c2ecf20Sopenharmony_ci if phase not in self.currphase: 16858c2ecf20Sopenharmony_ci if self.currphase: 16868c2ecf20Sopenharmony_ci sysvals.vprint('WARNING: %s ended instead of %s, ftrace corruption?' % (phase, self.currphase)) 16878c2ecf20Sopenharmony_ci else: 16888c2ecf20Sopenharmony_ci sysvals.vprint('WARNING: %s ended without a start, ftrace corruption?' % phase) 16898c2ecf20Sopenharmony_ci return phase 16908c2ecf20Sopenharmony_ci phase = self.currphase 16918c2ecf20Sopenharmony_ci self.dmesg[phase]['end'] = ktime 16928c2ecf20Sopenharmony_ci self.currphase = '' 16938c2ecf20Sopenharmony_ci return phase 16948c2ecf20Sopenharmony_ci def sortedDevices(self, phase): 16958c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 16968c2ecf20Sopenharmony_ci return sorted(list, key=lambda k:list[k]['start']) 16978c2ecf20Sopenharmony_ci def fixupInitcalls(self, phase): 16988c2ecf20Sopenharmony_ci # if any calls never returned, clip them at system resume end 16998c2ecf20Sopenharmony_ci phaselist = self.dmesg[phase]['list'] 17008c2ecf20Sopenharmony_ci for devname in phaselist: 17018c2ecf20Sopenharmony_ci dev = phaselist[devname] 17028c2ecf20Sopenharmony_ci if(dev['end'] < 0): 17038c2ecf20Sopenharmony_ci for p in self.sortedPhases(): 17048c2ecf20Sopenharmony_ci if self.dmesg[p]['end'] > dev['start']: 17058c2ecf20Sopenharmony_ci dev['end'] = self.dmesg[p]['end'] 17068c2ecf20Sopenharmony_ci break 17078c2ecf20Sopenharmony_ci sysvals.vprint('%s (%s): callback didnt return' % (devname, phase)) 17088c2ecf20Sopenharmony_ci def deviceFilter(self, devicefilter): 17098c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 17108c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 17118c2ecf20Sopenharmony_ci rmlist = [] 17128c2ecf20Sopenharmony_ci for name in list: 17138c2ecf20Sopenharmony_ci keep = False 17148c2ecf20Sopenharmony_ci for filter in devicefilter: 17158c2ecf20Sopenharmony_ci if filter in name or \ 17168c2ecf20Sopenharmony_ci ('drv' in list[name] and filter in list[name]['drv']): 17178c2ecf20Sopenharmony_ci keep = True 17188c2ecf20Sopenharmony_ci if not keep: 17198c2ecf20Sopenharmony_ci rmlist.append(name) 17208c2ecf20Sopenharmony_ci for name in rmlist: 17218c2ecf20Sopenharmony_ci del list[name] 17228c2ecf20Sopenharmony_ci def fixupInitcallsThatDidntReturn(self): 17238c2ecf20Sopenharmony_ci # if any calls never returned, clip them at system resume end 17248c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 17258c2ecf20Sopenharmony_ci self.fixupInitcalls(phase) 17268c2ecf20Sopenharmony_ci def phaseOverlap(self, phases): 17278c2ecf20Sopenharmony_ci rmgroups = [] 17288c2ecf20Sopenharmony_ci newgroup = [] 17298c2ecf20Sopenharmony_ci for group in self.devicegroups: 17308c2ecf20Sopenharmony_ci for phase in phases: 17318c2ecf20Sopenharmony_ci if phase not in group: 17328c2ecf20Sopenharmony_ci continue 17338c2ecf20Sopenharmony_ci for p in group: 17348c2ecf20Sopenharmony_ci if p not in newgroup: 17358c2ecf20Sopenharmony_ci newgroup.append(p) 17368c2ecf20Sopenharmony_ci if group not in rmgroups: 17378c2ecf20Sopenharmony_ci rmgroups.append(group) 17388c2ecf20Sopenharmony_ci for group in rmgroups: 17398c2ecf20Sopenharmony_ci self.devicegroups.remove(group) 17408c2ecf20Sopenharmony_ci self.devicegroups.append(newgroup) 17418c2ecf20Sopenharmony_ci def newActionGlobal(self, name, start, end, pid=-1, color=''): 17428c2ecf20Sopenharmony_ci # which phase is this device callback or action in 17438c2ecf20Sopenharmony_ci phases = self.sortedPhases() 17448c2ecf20Sopenharmony_ci targetphase = 'none' 17458c2ecf20Sopenharmony_ci htmlclass = '' 17468c2ecf20Sopenharmony_ci overlap = 0.0 17478c2ecf20Sopenharmony_ci myphases = [] 17488c2ecf20Sopenharmony_ci for phase in phases: 17498c2ecf20Sopenharmony_ci pstart = self.dmesg[phase]['start'] 17508c2ecf20Sopenharmony_ci pend = self.dmesg[phase]['end'] 17518c2ecf20Sopenharmony_ci # see if the action overlaps this phase 17528c2ecf20Sopenharmony_ci o = max(0, min(end, pend) - max(start, pstart)) 17538c2ecf20Sopenharmony_ci if o > 0: 17548c2ecf20Sopenharmony_ci myphases.append(phase) 17558c2ecf20Sopenharmony_ci # set the target phase to the one that overlaps most 17568c2ecf20Sopenharmony_ci if o > overlap: 17578c2ecf20Sopenharmony_ci if overlap > 0 and phase == 'post_resume': 17588c2ecf20Sopenharmony_ci continue 17598c2ecf20Sopenharmony_ci targetphase = phase 17608c2ecf20Sopenharmony_ci overlap = o 17618c2ecf20Sopenharmony_ci # if no target phase was found, pin it to the edge 17628c2ecf20Sopenharmony_ci if targetphase == 'none': 17638c2ecf20Sopenharmony_ci p0start = self.dmesg[phases[0]]['start'] 17648c2ecf20Sopenharmony_ci if start <= p0start: 17658c2ecf20Sopenharmony_ci targetphase = phases[0] 17668c2ecf20Sopenharmony_ci else: 17678c2ecf20Sopenharmony_ci targetphase = phases[-1] 17688c2ecf20Sopenharmony_ci if pid == -2: 17698c2ecf20Sopenharmony_ci htmlclass = ' bg' 17708c2ecf20Sopenharmony_ci elif pid == -3: 17718c2ecf20Sopenharmony_ci htmlclass = ' ps' 17728c2ecf20Sopenharmony_ci if len(myphases) > 1: 17738c2ecf20Sopenharmony_ci htmlclass = ' bg' 17748c2ecf20Sopenharmony_ci self.phaseOverlap(myphases) 17758c2ecf20Sopenharmony_ci if targetphase in phases: 17768c2ecf20Sopenharmony_ci newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color) 17778c2ecf20Sopenharmony_ci return (targetphase, newname) 17788c2ecf20Sopenharmony_ci return False 17798c2ecf20Sopenharmony_ci def newAction(self, phase, name, pid, parent, start, end, drv, htmlclass='', color=''): 17808c2ecf20Sopenharmony_ci # new device callback for a specific phase 17818c2ecf20Sopenharmony_ci self.html_device_id += 1 17828c2ecf20Sopenharmony_ci devid = '%s%d' % (self.idstr, self.html_device_id) 17838c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 17848c2ecf20Sopenharmony_ci length = -1.0 17858c2ecf20Sopenharmony_ci if(start >= 0 and end >= 0): 17868c2ecf20Sopenharmony_ci length = end - start 17878c2ecf20Sopenharmony_ci if pid == -2 or name not in sysvals.tracefuncs.keys(): 17888c2ecf20Sopenharmony_ci i = 2 17898c2ecf20Sopenharmony_ci origname = name 17908c2ecf20Sopenharmony_ci while(name in list): 17918c2ecf20Sopenharmony_ci name = '%s[%d]' % (origname, i) 17928c2ecf20Sopenharmony_ci i += 1 17938c2ecf20Sopenharmony_ci list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid, 17948c2ecf20Sopenharmony_ci 'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv } 17958c2ecf20Sopenharmony_ci if htmlclass: 17968c2ecf20Sopenharmony_ci list[name]['htmlclass'] = htmlclass 17978c2ecf20Sopenharmony_ci if color: 17988c2ecf20Sopenharmony_ci list[name]['color'] = color 17998c2ecf20Sopenharmony_ci return name 18008c2ecf20Sopenharmony_ci def findDevice(self, phase, name): 18018c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 18028c2ecf20Sopenharmony_ci mydev = '' 18038c2ecf20Sopenharmony_ci for devname in sorted(list): 18048c2ecf20Sopenharmony_ci if name == devname or re.match('^%s\[(?P<num>[0-9]*)\]$' % name, devname): 18058c2ecf20Sopenharmony_ci mydev = devname 18068c2ecf20Sopenharmony_ci if mydev: 18078c2ecf20Sopenharmony_ci return list[mydev] 18088c2ecf20Sopenharmony_ci return False 18098c2ecf20Sopenharmony_ci def deviceChildren(self, devname, phase): 18108c2ecf20Sopenharmony_ci devlist = [] 18118c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 18128c2ecf20Sopenharmony_ci for child in list: 18138c2ecf20Sopenharmony_ci if(list[child]['par'] == devname): 18148c2ecf20Sopenharmony_ci devlist.append(child) 18158c2ecf20Sopenharmony_ci return devlist 18168c2ecf20Sopenharmony_ci def maxDeviceNameSize(self, phase): 18178c2ecf20Sopenharmony_ci size = 0 18188c2ecf20Sopenharmony_ci for name in self.dmesg[phase]['list']: 18198c2ecf20Sopenharmony_ci if len(name) > size: 18208c2ecf20Sopenharmony_ci size = len(name) 18218c2ecf20Sopenharmony_ci return size 18228c2ecf20Sopenharmony_ci def printDetails(self): 18238c2ecf20Sopenharmony_ci sysvals.vprint('Timeline Details:') 18248c2ecf20Sopenharmony_ci sysvals.vprint(' test start: %f' % self.start) 18258c2ecf20Sopenharmony_ci sysvals.vprint('kernel suspend start: %f' % self.tKernSus) 18268c2ecf20Sopenharmony_ci tS = tR = False 18278c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 18288c2ecf20Sopenharmony_ci devlist = self.dmesg[phase]['list'] 18298c2ecf20Sopenharmony_ci dc, ps, pe = len(devlist), self.dmesg[phase]['start'], self.dmesg[phase]['end'] 18308c2ecf20Sopenharmony_ci if not tS and ps >= self.tSuspended: 18318c2ecf20Sopenharmony_ci sysvals.vprint(' machine suspended: %f' % self.tSuspended) 18328c2ecf20Sopenharmony_ci tS = True 18338c2ecf20Sopenharmony_ci if not tR and ps >= self.tResumed: 18348c2ecf20Sopenharmony_ci sysvals.vprint(' machine resumed: %f' % self.tResumed) 18358c2ecf20Sopenharmony_ci tR = True 18368c2ecf20Sopenharmony_ci sysvals.vprint('%20s: %f - %f (%d devices)' % (phase, ps, pe, dc)) 18378c2ecf20Sopenharmony_ci if sysvals.devdump: 18388c2ecf20Sopenharmony_ci sysvals.vprint(''.join('-' for i in range(80))) 18398c2ecf20Sopenharmony_ci maxname = '%d' % self.maxDeviceNameSize(phase) 18408c2ecf20Sopenharmony_ci fmt = '%3d) %'+maxname+'s - %f - %f' 18418c2ecf20Sopenharmony_ci c = 1 18428c2ecf20Sopenharmony_ci for name in sorted(devlist): 18438c2ecf20Sopenharmony_ci s = devlist[name]['start'] 18448c2ecf20Sopenharmony_ci e = devlist[name]['end'] 18458c2ecf20Sopenharmony_ci sysvals.vprint(fmt % (c, name, s, e)) 18468c2ecf20Sopenharmony_ci c += 1 18478c2ecf20Sopenharmony_ci sysvals.vprint(''.join('-' for i in range(80))) 18488c2ecf20Sopenharmony_ci sysvals.vprint(' kernel resume end: %f' % self.tKernRes) 18498c2ecf20Sopenharmony_ci sysvals.vprint(' test end: %f' % self.end) 18508c2ecf20Sopenharmony_ci def deviceChildrenAllPhases(self, devname): 18518c2ecf20Sopenharmony_ci devlist = [] 18528c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 18538c2ecf20Sopenharmony_ci list = self.deviceChildren(devname, phase) 18548c2ecf20Sopenharmony_ci for dev in sorted(list): 18558c2ecf20Sopenharmony_ci if dev not in devlist: 18568c2ecf20Sopenharmony_ci devlist.append(dev) 18578c2ecf20Sopenharmony_ci return devlist 18588c2ecf20Sopenharmony_ci def masterTopology(self, name, list, depth): 18598c2ecf20Sopenharmony_ci node = DeviceNode(name, depth) 18608c2ecf20Sopenharmony_ci for cname in list: 18618c2ecf20Sopenharmony_ci # avoid recursions 18628c2ecf20Sopenharmony_ci if name == cname: 18638c2ecf20Sopenharmony_ci continue 18648c2ecf20Sopenharmony_ci clist = self.deviceChildrenAllPhases(cname) 18658c2ecf20Sopenharmony_ci cnode = self.masterTopology(cname, clist, depth+1) 18668c2ecf20Sopenharmony_ci node.children.append(cnode) 18678c2ecf20Sopenharmony_ci return node 18688c2ecf20Sopenharmony_ci def printTopology(self, node): 18698c2ecf20Sopenharmony_ci html = '' 18708c2ecf20Sopenharmony_ci if node.name: 18718c2ecf20Sopenharmony_ci info = '' 18728c2ecf20Sopenharmony_ci drv = '' 18738c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 18748c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 18758c2ecf20Sopenharmony_ci if node.name in list: 18768c2ecf20Sopenharmony_ci s = list[node.name]['start'] 18778c2ecf20Sopenharmony_ci e = list[node.name]['end'] 18788c2ecf20Sopenharmony_ci if list[node.name]['drv']: 18798c2ecf20Sopenharmony_ci drv = ' {'+list[node.name]['drv']+'}' 18808c2ecf20Sopenharmony_ci info += ('<li>%s: %.3fms</li>' % (phase, (e-s)*1000)) 18818c2ecf20Sopenharmony_ci html += '<li><b>'+node.name+drv+'</b>' 18828c2ecf20Sopenharmony_ci if info: 18838c2ecf20Sopenharmony_ci html += '<ul>'+info+'</ul>' 18848c2ecf20Sopenharmony_ci html += '</li>' 18858c2ecf20Sopenharmony_ci if len(node.children) > 0: 18868c2ecf20Sopenharmony_ci html += '<ul>' 18878c2ecf20Sopenharmony_ci for cnode in node.children: 18888c2ecf20Sopenharmony_ci html += self.printTopology(cnode) 18898c2ecf20Sopenharmony_ci html += '</ul>' 18908c2ecf20Sopenharmony_ci return html 18918c2ecf20Sopenharmony_ci def rootDeviceList(self): 18928c2ecf20Sopenharmony_ci # list of devices graphed 18938c2ecf20Sopenharmony_ci real = [] 18948c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 18958c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 18968c2ecf20Sopenharmony_ci for dev in sorted(list): 18978c2ecf20Sopenharmony_ci if list[dev]['pid'] >= 0 and dev not in real: 18988c2ecf20Sopenharmony_ci real.append(dev) 18998c2ecf20Sopenharmony_ci # list of top-most root devices 19008c2ecf20Sopenharmony_ci rootlist = [] 19018c2ecf20Sopenharmony_ci for phase in self.sortedPhases(): 19028c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 19038c2ecf20Sopenharmony_ci for dev in sorted(list): 19048c2ecf20Sopenharmony_ci pdev = list[dev]['par'] 19058c2ecf20Sopenharmony_ci pid = list[dev]['pid'] 19068c2ecf20Sopenharmony_ci if(pid < 0 or re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)): 19078c2ecf20Sopenharmony_ci continue 19088c2ecf20Sopenharmony_ci if pdev and pdev not in real and pdev not in rootlist: 19098c2ecf20Sopenharmony_ci rootlist.append(pdev) 19108c2ecf20Sopenharmony_ci return rootlist 19118c2ecf20Sopenharmony_ci def deviceTopology(self): 19128c2ecf20Sopenharmony_ci rootlist = self.rootDeviceList() 19138c2ecf20Sopenharmony_ci master = self.masterTopology('', rootlist, 0) 19148c2ecf20Sopenharmony_ci return self.printTopology(master) 19158c2ecf20Sopenharmony_ci def selectTimelineDevices(self, widfmt, tTotal, mindevlen): 19168c2ecf20Sopenharmony_ci # only select devices that will actually show up in html 19178c2ecf20Sopenharmony_ci self.tdevlist = dict() 19188c2ecf20Sopenharmony_ci for phase in self.dmesg: 19198c2ecf20Sopenharmony_ci devlist = [] 19208c2ecf20Sopenharmony_ci list = self.dmesg[phase]['list'] 19218c2ecf20Sopenharmony_ci for dev in list: 19228c2ecf20Sopenharmony_ci length = (list[dev]['end'] - list[dev]['start']) * 1000 19238c2ecf20Sopenharmony_ci width = widfmt % (((list[dev]['end']-list[dev]['start'])*100)/tTotal) 19248c2ecf20Sopenharmony_ci if width != '0.000000' and length >= mindevlen: 19258c2ecf20Sopenharmony_ci devlist.append(dev) 19268c2ecf20Sopenharmony_ci self.tdevlist[phase] = devlist 19278c2ecf20Sopenharmony_ci def addHorizontalDivider(self, devname, devend): 19288c2ecf20Sopenharmony_ci phase = 'suspend_prepare' 19298c2ecf20Sopenharmony_ci self.newAction(phase, devname, -2, '', \ 19308c2ecf20Sopenharmony_ci self.start, devend, '', ' sec', '') 19318c2ecf20Sopenharmony_ci if phase not in self.tdevlist: 19328c2ecf20Sopenharmony_ci self.tdevlist[phase] = [] 19338c2ecf20Sopenharmony_ci self.tdevlist[phase].append(devname) 19348c2ecf20Sopenharmony_ci d = DevItem(0, phase, self.dmesg[phase]['list'][devname]) 19358c2ecf20Sopenharmony_ci return d 19368c2ecf20Sopenharmony_ci def addProcessUsageEvent(self, name, times): 19378c2ecf20Sopenharmony_ci # get the start and end times for this process 19388c2ecf20Sopenharmony_ci maxC = 0 19398c2ecf20Sopenharmony_ci tlast = 0 19408c2ecf20Sopenharmony_ci start = -1 19418c2ecf20Sopenharmony_ci end = -1 19428c2ecf20Sopenharmony_ci for t in sorted(times): 19438c2ecf20Sopenharmony_ci if tlast == 0: 19448c2ecf20Sopenharmony_ci tlast = t 19458c2ecf20Sopenharmony_ci continue 19468c2ecf20Sopenharmony_ci if name in self.pstl[t]: 19478c2ecf20Sopenharmony_ci if start == -1 or tlast < start: 19488c2ecf20Sopenharmony_ci start = tlast 19498c2ecf20Sopenharmony_ci if end == -1 or t > end: 19508c2ecf20Sopenharmony_ci end = t 19518c2ecf20Sopenharmony_ci tlast = t 19528c2ecf20Sopenharmony_ci if start == -1 or end == -1: 19538c2ecf20Sopenharmony_ci return 0 19548c2ecf20Sopenharmony_ci # add a new action for this process and get the object 19558c2ecf20Sopenharmony_ci out = self.newActionGlobal(name, start, end, -3) 19568c2ecf20Sopenharmony_ci if not out: 19578c2ecf20Sopenharmony_ci return 0 19588c2ecf20Sopenharmony_ci phase, devname = out 19598c2ecf20Sopenharmony_ci dev = self.dmesg[phase]['list'][devname] 19608c2ecf20Sopenharmony_ci # get the cpu exec data 19618c2ecf20Sopenharmony_ci tlast = 0 19628c2ecf20Sopenharmony_ci clast = 0 19638c2ecf20Sopenharmony_ci cpuexec = dict() 19648c2ecf20Sopenharmony_ci for t in sorted(times): 19658c2ecf20Sopenharmony_ci if tlast == 0 or t <= start or t > end: 19668c2ecf20Sopenharmony_ci tlast = t 19678c2ecf20Sopenharmony_ci continue 19688c2ecf20Sopenharmony_ci list = self.pstl[t] 19698c2ecf20Sopenharmony_ci c = 0 19708c2ecf20Sopenharmony_ci if name in list: 19718c2ecf20Sopenharmony_ci c = list[name] 19728c2ecf20Sopenharmony_ci if c > maxC: 19738c2ecf20Sopenharmony_ci maxC = c 19748c2ecf20Sopenharmony_ci if c != clast: 19758c2ecf20Sopenharmony_ci key = (tlast, t) 19768c2ecf20Sopenharmony_ci cpuexec[key] = c 19778c2ecf20Sopenharmony_ci tlast = t 19788c2ecf20Sopenharmony_ci clast = c 19798c2ecf20Sopenharmony_ci dev['cpuexec'] = cpuexec 19808c2ecf20Sopenharmony_ci return maxC 19818c2ecf20Sopenharmony_ci def createProcessUsageEvents(self): 19828c2ecf20Sopenharmony_ci # get an array of process names 19838c2ecf20Sopenharmony_ci proclist = [] 19848c2ecf20Sopenharmony_ci for t in sorted(self.pstl): 19858c2ecf20Sopenharmony_ci pslist = self.pstl[t] 19868c2ecf20Sopenharmony_ci for ps in sorted(pslist): 19878c2ecf20Sopenharmony_ci if ps not in proclist: 19888c2ecf20Sopenharmony_ci proclist.append(ps) 19898c2ecf20Sopenharmony_ci # get a list of data points for suspend and resume 19908c2ecf20Sopenharmony_ci tsus = [] 19918c2ecf20Sopenharmony_ci tres = [] 19928c2ecf20Sopenharmony_ci for t in sorted(self.pstl): 19938c2ecf20Sopenharmony_ci if t < self.tSuspended: 19948c2ecf20Sopenharmony_ci tsus.append(t) 19958c2ecf20Sopenharmony_ci else: 19968c2ecf20Sopenharmony_ci tres.append(t) 19978c2ecf20Sopenharmony_ci # process the events for suspend and resume 19988c2ecf20Sopenharmony_ci if len(proclist) > 0: 19998c2ecf20Sopenharmony_ci sysvals.vprint('Process Execution:') 20008c2ecf20Sopenharmony_ci for ps in proclist: 20018c2ecf20Sopenharmony_ci c = self.addProcessUsageEvent(ps, tsus) 20028c2ecf20Sopenharmony_ci if c > 0: 20038c2ecf20Sopenharmony_ci sysvals.vprint('%25s (sus): %d' % (ps, c)) 20048c2ecf20Sopenharmony_ci c = self.addProcessUsageEvent(ps, tres) 20058c2ecf20Sopenharmony_ci if c > 0: 20068c2ecf20Sopenharmony_ci sysvals.vprint('%25s (res): %d' % (ps, c)) 20078c2ecf20Sopenharmony_ci def handleEndMarker(self, time, msg=''): 20088c2ecf20Sopenharmony_ci dm = self.dmesg 20098c2ecf20Sopenharmony_ci self.setEnd(time, msg) 20108c2ecf20Sopenharmony_ci self.initDevicegroups() 20118c2ecf20Sopenharmony_ci # give suspend_prepare an end if needed 20128c2ecf20Sopenharmony_ci if 'suspend_prepare' in dm and dm['suspend_prepare']['end'] < 0: 20138c2ecf20Sopenharmony_ci dm['suspend_prepare']['end'] = time 20148c2ecf20Sopenharmony_ci # assume resume machine ends at next phase start 20158c2ecf20Sopenharmony_ci if 'resume_machine' in dm and dm['resume_machine']['end'] < 0: 20168c2ecf20Sopenharmony_ci np = self.nextPhase('resume_machine', 1) 20178c2ecf20Sopenharmony_ci if np: 20188c2ecf20Sopenharmony_ci dm['resume_machine']['end'] = dm[np]['start'] 20198c2ecf20Sopenharmony_ci # if kernel resume end not found, assume its the end marker 20208c2ecf20Sopenharmony_ci if self.tKernRes == 0.0: 20218c2ecf20Sopenharmony_ci self.tKernRes = time 20228c2ecf20Sopenharmony_ci # if kernel suspend start not found, assume its the end marker 20238c2ecf20Sopenharmony_ci if self.tKernSus == 0.0: 20248c2ecf20Sopenharmony_ci self.tKernSus = time 20258c2ecf20Sopenharmony_ci # set resume complete to end at end marker 20268c2ecf20Sopenharmony_ci if 'resume_complete' in dm: 20278c2ecf20Sopenharmony_ci dm['resume_complete']['end'] = time 20288c2ecf20Sopenharmony_ci def debugPrint(self): 20298c2ecf20Sopenharmony_ci for p in self.sortedPhases(): 20308c2ecf20Sopenharmony_ci list = self.dmesg[p]['list'] 20318c2ecf20Sopenharmony_ci for devname in sorted(list): 20328c2ecf20Sopenharmony_ci dev = list[devname] 20338c2ecf20Sopenharmony_ci if 'ftrace' in dev: 20348c2ecf20Sopenharmony_ci dev['ftrace'].debugPrint(' [%s]' % devname) 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci# Class: DevFunction 20378c2ecf20Sopenharmony_ci# Description: 20388c2ecf20Sopenharmony_ci# A container for kprobe function data we want in the dev timeline 20398c2ecf20Sopenharmony_ciclass DevFunction: 20408c2ecf20Sopenharmony_ci def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color): 20418c2ecf20Sopenharmony_ci self.row = 0 20428c2ecf20Sopenharmony_ci self.count = 1 20438c2ecf20Sopenharmony_ci self.name = name 20448c2ecf20Sopenharmony_ci self.args = args 20458c2ecf20Sopenharmony_ci self.caller = caller 20468c2ecf20Sopenharmony_ci self.ret = ret 20478c2ecf20Sopenharmony_ci self.time = start 20488c2ecf20Sopenharmony_ci self.length = end - start 20498c2ecf20Sopenharmony_ci self.end = end 20508c2ecf20Sopenharmony_ci self.ubiquitous = u 20518c2ecf20Sopenharmony_ci self.proc = proc 20528c2ecf20Sopenharmony_ci self.pid = pid 20538c2ecf20Sopenharmony_ci self.color = color 20548c2ecf20Sopenharmony_ci def title(self): 20558c2ecf20Sopenharmony_ci cnt = '' 20568c2ecf20Sopenharmony_ci if self.count > 1: 20578c2ecf20Sopenharmony_ci cnt = '(x%d)' % self.count 20588c2ecf20Sopenharmony_ci l = '%0.3fms' % (self.length * 1000) 20598c2ecf20Sopenharmony_ci if self.ubiquitous: 20608c2ecf20Sopenharmony_ci title = '%s(%s)%s <- %s, %s(%s)' % \ 20618c2ecf20Sopenharmony_ci (self.name, self.args, cnt, self.caller, self.ret, l) 20628c2ecf20Sopenharmony_ci else: 20638c2ecf20Sopenharmony_ci title = '%s(%s) %s%s(%s)' % (self.name, self.args, self.ret, cnt, l) 20648c2ecf20Sopenharmony_ci return title.replace('"', '') 20658c2ecf20Sopenharmony_ci def text(self): 20668c2ecf20Sopenharmony_ci if self.count > 1: 20678c2ecf20Sopenharmony_ci text = '%s(x%d)' % (self.name, self.count) 20688c2ecf20Sopenharmony_ci else: 20698c2ecf20Sopenharmony_ci text = self.name 20708c2ecf20Sopenharmony_ci return text 20718c2ecf20Sopenharmony_ci def repeat(self, tgt): 20728c2ecf20Sopenharmony_ci # is the tgt call just a repeat of this call (e.g. are we in a loop) 20738c2ecf20Sopenharmony_ci dt = self.time - tgt.end 20748c2ecf20Sopenharmony_ci # only combine calls if -all- attributes are identical 20758c2ecf20Sopenharmony_ci if tgt.caller == self.caller and \ 20768c2ecf20Sopenharmony_ci tgt.name == self.name and tgt.args == self.args and \ 20778c2ecf20Sopenharmony_ci tgt.proc == self.proc and tgt.pid == self.pid and \ 20788c2ecf20Sopenharmony_ci tgt.ret == self.ret and dt >= 0 and \ 20798c2ecf20Sopenharmony_ci dt <= sysvals.callloopmaxgap and \ 20808c2ecf20Sopenharmony_ci self.length < sysvals.callloopmaxlen: 20818c2ecf20Sopenharmony_ci return True 20828c2ecf20Sopenharmony_ci return False 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci# Class: FTraceLine 20858c2ecf20Sopenharmony_ci# Description: 20868c2ecf20Sopenharmony_ci# A container for a single line of ftrace data. There are six basic types: 20878c2ecf20Sopenharmony_ci# callgraph line: 20888c2ecf20Sopenharmony_ci# call: " dpm_run_callback() {" 20898c2ecf20Sopenharmony_ci# return: " }" 20908c2ecf20Sopenharmony_ci# leaf: " dpm_run_callback();" 20918c2ecf20Sopenharmony_ci# trace event: 20928c2ecf20Sopenharmony_ci# tracing_mark_write: SUSPEND START or RESUME COMPLETE 20938c2ecf20Sopenharmony_ci# suspend_resume: phase or custom exec block data 20948c2ecf20Sopenharmony_ci# device_pm_callback: device callback info 20958c2ecf20Sopenharmony_ciclass FTraceLine: 20968c2ecf20Sopenharmony_ci def __init__(self, t, m='', d=''): 20978c2ecf20Sopenharmony_ci self.length = 0.0 20988c2ecf20Sopenharmony_ci self.fcall = False 20998c2ecf20Sopenharmony_ci self.freturn = False 21008c2ecf20Sopenharmony_ci self.fevent = False 21018c2ecf20Sopenharmony_ci self.fkprobe = False 21028c2ecf20Sopenharmony_ci self.depth = 0 21038c2ecf20Sopenharmony_ci self.name = '' 21048c2ecf20Sopenharmony_ci self.type = '' 21058c2ecf20Sopenharmony_ci self.time = float(t) 21068c2ecf20Sopenharmony_ci if not m and not d: 21078c2ecf20Sopenharmony_ci return 21088c2ecf20Sopenharmony_ci # is this a trace event 21098c2ecf20Sopenharmony_ci if(d == 'traceevent' or re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m)): 21108c2ecf20Sopenharmony_ci if(d == 'traceevent'): 21118c2ecf20Sopenharmony_ci # nop format trace event 21128c2ecf20Sopenharmony_ci msg = m 21138c2ecf20Sopenharmony_ci else: 21148c2ecf20Sopenharmony_ci # function_graph format trace event 21158c2ecf20Sopenharmony_ci em = re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m) 21168c2ecf20Sopenharmony_ci msg = em.group('msg') 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci emm = re.match('^(?P<call>.*?): (?P<msg>.*)', msg) 21198c2ecf20Sopenharmony_ci if(emm): 21208c2ecf20Sopenharmony_ci self.name = emm.group('msg') 21218c2ecf20Sopenharmony_ci self.type = emm.group('call') 21228c2ecf20Sopenharmony_ci else: 21238c2ecf20Sopenharmony_ci self.name = msg 21248c2ecf20Sopenharmony_ci km = re.match('^(?P<n>.*)_cal$', self.type) 21258c2ecf20Sopenharmony_ci if km: 21268c2ecf20Sopenharmony_ci self.fcall = True 21278c2ecf20Sopenharmony_ci self.fkprobe = True 21288c2ecf20Sopenharmony_ci self.type = km.group('n') 21298c2ecf20Sopenharmony_ci return 21308c2ecf20Sopenharmony_ci km = re.match('^(?P<n>.*)_ret$', self.type) 21318c2ecf20Sopenharmony_ci if km: 21328c2ecf20Sopenharmony_ci self.freturn = True 21338c2ecf20Sopenharmony_ci self.fkprobe = True 21348c2ecf20Sopenharmony_ci self.type = km.group('n') 21358c2ecf20Sopenharmony_ci return 21368c2ecf20Sopenharmony_ci self.fevent = True 21378c2ecf20Sopenharmony_ci return 21388c2ecf20Sopenharmony_ci # convert the duration to seconds 21398c2ecf20Sopenharmony_ci if(d): 21408c2ecf20Sopenharmony_ci self.length = float(d)/1000000 21418c2ecf20Sopenharmony_ci # the indentation determines the depth 21428c2ecf20Sopenharmony_ci match = re.match('^(?P<d> *)(?P<o>.*)$', m) 21438c2ecf20Sopenharmony_ci if(not match): 21448c2ecf20Sopenharmony_ci return 21458c2ecf20Sopenharmony_ci self.depth = self.getDepth(match.group('d')) 21468c2ecf20Sopenharmony_ci m = match.group('o') 21478c2ecf20Sopenharmony_ci # function return 21488c2ecf20Sopenharmony_ci if(m[0] == '}'): 21498c2ecf20Sopenharmony_ci self.freturn = True 21508c2ecf20Sopenharmony_ci if(len(m) > 1): 21518c2ecf20Sopenharmony_ci # includes comment with function name 21528c2ecf20Sopenharmony_ci match = re.match('^} *\/\* *(?P<n>.*) *\*\/$', m) 21538c2ecf20Sopenharmony_ci if(match): 21548c2ecf20Sopenharmony_ci self.name = match.group('n').strip() 21558c2ecf20Sopenharmony_ci # function call 21568c2ecf20Sopenharmony_ci else: 21578c2ecf20Sopenharmony_ci self.fcall = True 21588c2ecf20Sopenharmony_ci # function call with children 21598c2ecf20Sopenharmony_ci if(m[-1] == '{'): 21608c2ecf20Sopenharmony_ci match = re.match('^(?P<n>.*) *\(.*', m) 21618c2ecf20Sopenharmony_ci if(match): 21628c2ecf20Sopenharmony_ci self.name = match.group('n').strip() 21638c2ecf20Sopenharmony_ci # function call with no children (leaf) 21648c2ecf20Sopenharmony_ci elif(m[-1] == ';'): 21658c2ecf20Sopenharmony_ci self.freturn = True 21668c2ecf20Sopenharmony_ci match = re.match('^(?P<n>.*) *\(.*', m) 21678c2ecf20Sopenharmony_ci if(match): 21688c2ecf20Sopenharmony_ci self.name = match.group('n').strip() 21698c2ecf20Sopenharmony_ci # something else (possibly a trace marker) 21708c2ecf20Sopenharmony_ci else: 21718c2ecf20Sopenharmony_ci self.name = m 21728c2ecf20Sopenharmony_ci def isCall(self): 21738c2ecf20Sopenharmony_ci return self.fcall and not self.freturn 21748c2ecf20Sopenharmony_ci def isReturn(self): 21758c2ecf20Sopenharmony_ci return self.freturn and not self.fcall 21768c2ecf20Sopenharmony_ci def isLeaf(self): 21778c2ecf20Sopenharmony_ci return self.fcall and self.freturn 21788c2ecf20Sopenharmony_ci def getDepth(self, str): 21798c2ecf20Sopenharmony_ci return len(str)/2 21808c2ecf20Sopenharmony_ci def debugPrint(self, info=''): 21818c2ecf20Sopenharmony_ci if self.isLeaf(): 21828c2ecf20Sopenharmony_ci pprint(' -- %12.6f (depth=%02d): %s(); (%.3f us) %s' % (self.time, \ 21838c2ecf20Sopenharmony_ci self.depth, self.name, self.length*1000000, info)) 21848c2ecf20Sopenharmony_ci elif self.freturn: 21858c2ecf20Sopenharmony_ci pprint(' -- %12.6f (depth=%02d): %s} (%.3f us) %s' % (self.time, \ 21868c2ecf20Sopenharmony_ci self.depth, self.name, self.length*1000000, info)) 21878c2ecf20Sopenharmony_ci else: 21888c2ecf20Sopenharmony_ci pprint(' -- %12.6f (depth=%02d): %s() { (%.3f us) %s' % (self.time, \ 21898c2ecf20Sopenharmony_ci self.depth, self.name, self.length*1000000, info)) 21908c2ecf20Sopenharmony_ci def startMarker(self): 21918c2ecf20Sopenharmony_ci # Is this the starting line of a suspend? 21928c2ecf20Sopenharmony_ci if not self.fevent: 21938c2ecf20Sopenharmony_ci return False 21948c2ecf20Sopenharmony_ci if sysvals.usetracemarkers: 21958c2ecf20Sopenharmony_ci if(self.name.startswith('SUSPEND START')): 21968c2ecf20Sopenharmony_ci return True 21978c2ecf20Sopenharmony_ci return False 21988c2ecf20Sopenharmony_ci else: 21998c2ecf20Sopenharmony_ci if(self.type == 'suspend_resume' and 22008c2ecf20Sopenharmony_ci re.match('suspend_enter\[.*\] begin', self.name)): 22018c2ecf20Sopenharmony_ci return True 22028c2ecf20Sopenharmony_ci return False 22038c2ecf20Sopenharmony_ci def endMarker(self): 22048c2ecf20Sopenharmony_ci # Is this the ending line of a resume? 22058c2ecf20Sopenharmony_ci if not self.fevent: 22068c2ecf20Sopenharmony_ci return False 22078c2ecf20Sopenharmony_ci if sysvals.usetracemarkers: 22088c2ecf20Sopenharmony_ci if(self.name.startswith('RESUME COMPLETE')): 22098c2ecf20Sopenharmony_ci return True 22108c2ecf20Sopenharmony_ci return False 22118c2ecf20Sopenharmony_ci else: 22128c2ecf20Sopenharmony_ci if(self.type == 'suspend_resume' and 22138c2ecf20Sopenharmony_ci re.match('thaw_processes\[.*\] end', self.name)): 22148c2ecf20Sopenharmony_ci return True 22158c2ecf20Sopenharmony_ci return False 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci# Class: FTraceCallGraph 22188c2ecf20Sopenharmony_ci# Description: 22198c2ecf20Sopenharmony_ci# A container for the ftrace callgraph of a single recursive function. 22208c2ecf20Sopenharmony_ci# This can be a dpm_run_callback, dpm_prepare, or dpm_complete callgraph 22218c2ecf20Sopenharmony_ci# Each instance is tied to a single device in a single phase, and is 22228c2ecf20Sopenharmony_ci# comprised of an ordered list of FTraceLine objects 22238c2ecf20Sopenharmony_ciclass FTraceCallGraph: 22248c2ecf20Sopenharmony_ci vfname = 'missing_function_name' 22258c2ecf20Sopenharmony_ci def __init__(self, pid, sv): 22268c2ecf20Sopenharmony_ci self.id = '' 22278c2ecf20Sopenharmony_ci self.invalid = False 22288c2ecf20Sopenharmony_ci self.name = '' 22298c2ecf20Sopenharmony_ci self.partial = False 22308c2ecf20Sopenharmony_ci self.ignore = False 22318c2ecf20Sopenharmony_ci self.start = -1.0 22328c2ecf20Sopenharmony_ci self.end = -1.0 22338c2ecf20Sopenharmony_ci self.list = [] 22348c2ecf20Sopenharmony_ci self.depth = 0 22358c2ecf20Sopenharmony_ci self.pid = pid 22368c2ecf20Sopenharmony_ci self.sv = sv 22378c2ecf20Sopenharmony_ci def addLine(self, line): 22388c2ecf20Sopenharmony_ci # if this is already invalid, just leave 22398c2ecf20Sopenharmony_ci if(self.invalid): 22408c2ecf20Sopenharmony_ci if(line.depth == 0 and line.freturn): 22418c2ecf20Sopenharmony_ci return 1 22428c2ecf20Sopenharmony_ci return 0 22438c2ecf20Sopenharmony_ci # invalidate on bad depth 22448c2ecf20Sopenharmony_ci if(self.depth < 0): 22458c2ecf20Sopenharmony_ci self.invalidate(line) 22468c2ecf20Sopenharmony_ci return 0 22478c2ecf20Sopenharmony_ci # ignore data til we return to the current depth 22488c2ecf20Sopenharmony_ci if self.ignore: 22498c2ecf20Sopenharmony_ci if line.depth > self.depth: 22508c2ecf20Sopenharmony_ci return 0 22518c2ecf20Sopenharmony_ci else: 22528c2ecf20Sopenharmony_ci self.list[-1].freturn = True 22538c2ecf20Sopenharmony_ci self.list[-1].length = line.time - self.list[-1].time 22548c2ecf20Sopenharmony_ci self.ignore = False 22558c2ecf20Sopenharmony_ci # if this is a return at self.depth, no more work is needed 22568c2ecf20Sopenharmony_ci if line.depth == self.depth and line.isReturn(): 22578c2ecf20Sopenharmony_ci if line.depth == 0: 22588c2ecf20Sopenharmony_ci self.end = line.time 22598c2ecf20Sopenharmony_ci return 1 22608c2ecf20Sopenharmony_ci return 0 22618c2ecf20Sopenharmony_ci # compare current depth with this lines pre-call depth 22628c2ecf20Sopenharmony_ci prelinedep = line.depth 22638c2ecf20Sopenharmony_ci if line.isReturn(): 22648c2ecf20Sopenharmony_ci prelinedep += 1 22658c2ecf20Sopenharmony_ci last = 0 22668c2ecf20Sopenharmony_ci lasttime = line.time 22678c2ecf20Sopenharmony_ci if len(self.list) > 0: 22688c2ecf20Sopenharmony_ci last = self.list[-1] 22698c2ecf20Sopenharmony_ci lasttime = last.time 22708c2ecf20Sopenharmony_ci if last.isLeaf(): 22718c2ecf20Sopenharmony_ci lasttime += last.length 22728c2ecf20Sopenharmony_ci # handle low misalignments by inserting returns 22738c2ecf20Sopenharmony_ci mismatch = prelinedep - self.depth 22748c2ecf20Sopenharmony_ci warning = self.sv.verbose and abs(mismatch) > 1 22758c2ecf20Sopenharmony_ci info = [] 22768c2ecf20Sopenharmony_ci if mismatch < 0: 22778c2ecf20Sopenharmony_ci idx = 0 22788c2ecf20Sopenharmony_ci # add return calls to get the depth down 22798c2ecf20Sopenharmony_ci while prelinedep < self.depth: 22808c2ecf20Sopenharmony_ci self.depth -= 1 22818c2ecf20Sopenharmony_ci if idx == 0 and last and last.isCall(): 22828c2ecf20Sopenharmony_ci # special case, turn last call into a leaf 22838c2ecf20Sopenharmony_ci last.depth = self.depth 22848c2ecf20Sopenharmony_ci last.freturn = True 22858c2ecf20Sopenharmony_ci last.length = line.time - last.time 22868c2ecf20Sopenharmony_ci if warning: 22878c2ecf20Sopenharmony_ci info.append(('[make leaf]', last)) 22888c2ecf20Sopenharmony_ci else: 22898c2ecf20Sopenharmony_ci vline = FTraceLine(lasttime) 22908c2ecf20Sopenharmony_ci vline.depth = self.depth 22918c2ecf20Sopenharmony_ci vline.name = self.vfname 22928c2ecf20Sopenharmony_ci vline.freturn = True 22938c2ecf20Sopenharmony_ci self.list.append(vline) 22948c2ecf20Sopenharmony_ci if warning: 22958c2ecf20Sopenharmony_ci if idx == 0: 22968c2ecf20Sopenharmony_ci info.append(('', last)) 22978c2ecf20Sopenharmony_ci info.append(('[add return]', vline)) 22988c2ecf20Sopenharmony_ci idx += 1 22998c2ecf20Sopenharmony_ci if warning: 23008c2ecf20Sopenharmony_ci info.append(('', line)) 23018c2ecf20Sopenharmony_ci # handle high misalignments by inserting calls 23028c2ecf20Sopenharmony_ci elif mismatch > 0: 23038c2ecf20Sopenharmony_ci idx = 0 23048c2ecf20Sopenharmony_ci if warning: 23058c2ecf20Sopenharmony_ci info.append(('', last)) 23068c2ecf20Sopenharmony_ci # add calls to get the depth up 23078c2ecf20Sopenharmony_ci while prelinedep > self.depth: 23088c2ecf20Sopenharmony_ci if idx == 0 and line.isReturn(): 23098c2ecf20Sopenharmony_ci # special case, turn this return into a leaf 23108c2ecf20Sopenharmony_ci line.fcall = True 23118c2ecf20Sopenharmony_ci prelinedep -= 1 23128c2ecf20Sopenharmony_ci if warning: 23138c2ecf20Sopenharmony_ci info.append(('[make leaf]', line)) 23148c2ecf20Sopenharmony_ci else: 23158c2ecf20Sopenharmony_ci vline = FTraceLine(lasttime) 23168c2ecf20Sopenharmony_ci vline.depth = self.depth 23178c2ecf20Sopenharmony_ci vline.name = self.vfname 23188c2ecf20Sopenharmony_ci vline.fcall = True 23198c2ecf20Sopenharmony_ci self.list.append(vline) 23208c2ecf20Sopenharmony_ci self.depth += 1 23218c2ecf20Sopenharmony_ci if not last: 23228c2ecf20Sopenharmony_ci self.start = vline.time 23238c2ecf20Sopenharmony_ci if warning: 23248c2ecf20Sopenharmony_ci info.append(('[add call]', vline)) 23258c2ecf20Sopenharmony_ci idx += 1 23268c2ecf20Sopenharmony_ci if warning and ('[make leaf]', line) not in info: 23278c2ecf20Sopenharmony_ci info.append(('', line)) 23288c2ecf20Sopenharmony_ci if warning: 23298c2ecf20Sopenharmony_ci pprint('WARNING: ftrace data missing, corrections made:') 23308c2ecf20Sopenharmony_ci for i in info: 23318c2ecf20Sopenharmony_ci t, obj = i 23328c2ecf20Sopenharmony_ci if obj: 23338c2ecf20Sopenharmony_ci obj.debugPrint(t) 23348c2ecf20Sopenharmony_ci # process the call and set the new depth 23358c2ecf20Sopenharmony_ci skipadd = False 23368c2ecf20Sopenharmony_ci md = self.sv.max_graph_depth 23378c2ecf20Sopenharmony_ci if line.isCall(): 23388c2ecf20Sopenharmony_ci # ignore blacklisted/overdepth funcs 23398c2ecf20Sopenharmony_ci if (md and self.depth >= md - 1) or (line.name in self.sv.cgblacklist): 23408c2ecf20Sopenharmony_ci self.ignore = True 23418c2ecf20Sopenharmony_ci else: 23428c2ecf20Sopenharmony_ci self.depth += 1 23438c2ecf20Sopenharmony_ci elif line.isReturn(): 23448c2ecf20Sopenharmony_ci self.depth -= 1 23458c2ecf20Sopenharmony_ci # remove blacklisted/overdepth/empty funcs that slipped through 23468c2ecf20Sopenharmony_ci if (last and last.isCall() and last.depth == line.depth) or \ 23478c2ecf20Sopenharmony_ci (md and last and last.depth >= md) or \ 23488c2ecf20Sopenharmony_ci (line.name in self.sv.cgblacklist): 23498c2ecf20Sopenharmony_ci while len(self.list) > 0 and self.list[-1].depth > line.depth: 23508c2ecf20Sopenharmony_ci self.list.pop(-1) 23518c2ecf20Sopenharmony_ci if len(self.list) == 0: 23528c2ecf20Sopenharmony_ci self.invalid = True 23538c2ecf20Sopenharmony_ci return 1 23548c2ecf20Sopenharmony_ci self.list[-1].freturn = True 23558c2ecf20Sopenharmony_ci self.list[-1].length = line.time - self.list[-1].time 23568c2ecf20Sopenharmony_ci self.list[-1].name = line.name 23578c2ecf20Sopenharmony_ci skipadd = True 23588c2ecf20Sopenharmony_ci if len(self.list) < 1: 23598c2ecf20Sopenharmony_ci self.start = line.time 23608c2ecf20Sopenharmony_ci # check for a mismatch that returned all the way to callgraph end 23618c2ecf20Sopenharmony_ci res = 1 23628c2ecf20Sopenharmony_ci if mismatch < 0 and self.list[-1].depth == 0 and self.list[-1].freturn: 23638c2ecf20Sopenharmony_ci line = self.list[-1] 23648c2ecf20Sopenharmony_ci skipadd = True 23658c2ecf20Sopenharmony_ci res = -1 23668c2ecf20Sopenharmony_ci if not skipadd: 23678c2ecf20Sopenharmony_ci self.list.append(line) 23688c2ecf20Sopenharmony_ci if(line.depth == 0 and line.freturn): 23698c2ecf20Sopenharmony_ci if(self.start < 0): 23708c2ecf20Sopenharmony_ci self.start = line.time 23718c2ecf20Sopenharmony_ci self.end = line.time 23728c2ecf20Sopenharmony_ci if line.fcall: 23738c2ecf20Sopenharmony_ci self.end += line.length 23748c2ecf20Sopenharmony_ci if self.list[0].name == self.vfname: 23758c2ecf20Sopenharmony_ci self.invalid = True 23768c2ecf20Sopenharmony_ci if res == -1: 23778c2ecf20Sopenharmony_ci self.partial = True 23788c2ecf20Sopenharmony_ci return res 23798c2ecf20Sopenharmony_ci return 0 23808c2ecf20Sopenharmony_ci def invalidate(self, line): 23818c2ecf20Sopenharmony_ci if(len(self.list) > 0): 23828c2ecf20Sopenharmony_ci first = self.list[0] 23838c2ecf20Sopenharmony_ci self.list = [] 23848c2ecf20Sopenharmony_ci self.list.append(first) 23858c2ecf20Sopenharmony_ci self.invalid = True 23868c2ecf20Sopenharmony_ci id = 'task %s' % (self.pid) 23878c2ecf20Sopenharmony_ci window = '(%f - %f)' % (self.start, line.time) 23888c2ecf20Sopenharmony_ci if(self.depth < 0): 23898c2ecf20Sopenharmony_ci pprint('Data misalignment for '+id+\ 23908c2ecf20Sopenharmony_ci ' (buffer overflow), ignoring this callback') 23918c2ecf20Sopenharmony_ci else: 23928c2ecf20Sopenharmony_ci pprint('Too much data for '+id+\ 23938c2ecf20Sopenharmony_ci ' '+window+', ignoring this callback') 23948c2ecf20Sopenharmony_ci def slice(self, dev): 23958c2ecf20Sopenharmony_ci minicg = FTraceCallGraph(dev['pid'], self.sv) 23968c2ecf20Sopenharmony_ci minicg.name = self.name 23978c2ecf20Sopenharmony_ci mydepth = -1 23988c2ecf20Sopenharmony_ci good = False 23998c2ecf20Sopenharmony_ci for l in self.list: 24008c2ecf20Sopenharmony_ci if(l.time < dev['start'] or l.time > dev['end']): 24018c2ecf20Sopenharmony_ci continue 24028c2ecf20Sopenharmony_ci if mydepth < 0: 24038c2ecf20Sopenharmony_ci if l.name == 'mutex_lock' and l.freturn: 24048c2ecf20Sopenharmony_ci mydepth = l.depth 24058c2ecf20Sopenharmony_ci continue 24068c2ecf20Sopenharmony_ci elif l.depth == mydepth and l.name == 'mutex_unlock' and l.fcall: 24078c2ecf20Sopenharmony_ci good = True 24088c2ecf20Sopenharmony_ci break 24098c2ecf20Sopenharmony_ci l.depth -= mydepth 24108c2ecf20Sopenharmony_ci minicg.addLine(l) 24118c2ecf20Sopenharmony_ci if not good or len(minicg.list) < 1: 24128c2ecf20Sopenharmony_ci return 0 24138c2ecf20Sopenharmony_ci return minicg 24148c2ecf20Sopenharmony_ci def repair(self, enddepth): 24158c2ecf20Sopenharmony_ci # bring the depth back to 0 with additional returns 24168c2ecf20Sopenharmony_ci fixed = False 24178c2ecf20Sopenharmony_ci last = self.list[-1] 24188c2ecf20Sopenharmony_ci for i in reversed(range(enddepth)): 24198c2ecf20Sopenharmony_ci t = FTraceLine(last.time) 24208c2ecf20Sopenharmony_ci t.depth = i 24218c2ecf20Sopenharmony_ci t.freturn = True 24228c2ecf20Sopenharmony_ci fixed = self.addLine(t) 24238c2ecf20Sopenharmony_ci if fixed != 0: 24248c2ecf20Sopenharmony_ci self.end = last.time 24258c2ecf20Sopenharmony_ci return True 24268c2ecf20Sopenharmony_ci return False 24278c2ecf20Sopenharmony_ci def postProcess(self): 24288c2ecf20Sopenharmony_ci if len(self.list) > 0: 24298c2ecf20Sopenharmony_ci self.name = self.list[0].name 24308c2ecf20Sopenharmony_ci stack = dict() 24318c2ecf20Sopenharmony_ci cnt = 0 24328c2ecf20Sopenharmony_ci last = 0 24338c2ecf20Sopenharmony_ci for l in self.list: 24348c2ecf20Sopenharmony_ci # ftrace bug: reported duration is not reliable 24358c2ecf20Sopenharmony_ci # check each leaf and clip it at max possible length 24368c2ecf20Sopenharmony_ci if last and last.isLeaf(): 24378c2ecf20Sopenharmony_ci if last.length > l.time - last.time: 24388c2ecf20Sopenharmony_ci last.length = l.time - last.time 24398c2ecf20Sopenharmony_ci if l.isCall(): 24408c2ecf20Sopenharmony_ci stack[l.depth] = l 24418c2ecf20Sopenharmony_ci cnt += 1 24428c2ecf20Sopenharmony_ci elif l.isReturn(): 24438c2ecf20Sopenharmony_ci if(l.depth not in stack): 24448c2ecf20Sopenharmony_ci if self.sv.verbose: 24458c2ecf20Sopenharmony_ci pprint('Post Process Error: Depth missing') 24468c2ecf20Sopenharmony_ci l.debugPrint() 24478c2ecf20Sopenharmony_ci return False 24488c2ecf20Sopenharmony_ci # calculate call length from call/return lines 24498c2ecf20Sopenharmony_ci cl = stack[l.depth] 24508c2ecf20Sopenharmony_ci cl.length = l.time - cl.time 24518c2ecf20Sopenharmony_ci if cl.name == self.vfname: 24528c2ecf20Sopenharmony_ci cl.name = l.name 24538c2ecf20Sopenharmony_ci stack.pop(l.depth) 24548c2ecf20Sopenharmony_ci l.length = 0 24558c2ecf20Sopenharmony_ci cnt -= 1 24568c2ecf20Sopenharmony_ci last = l 24578c2ecf20Sopenharmony_ci if(cnt == 0): 24588c2ecf20Sopenharmony_ci # trace caught the whole call tree 24598c2ecf20Sopenharmony_ci return True 24608c2ecf20Sopenharmony_ci elif(cnt < 0): 24618c2ecf20Sopenharmony_ci if self.sv.verbose: 24628c2ecf20Sopenharmony_ci pprint('Post Process Error: Depth is less than 0') 24638c2ecf20Sopenharmony_ci return False 24648c2ecf20Sopenharmony_ci # trace ended before call tree finished 24658c2ecf20Sopenharmony_ci return self.repair(cnt) 24668c2ecf20Sopenharmony_ci def deviceMatch(self, pid, data): 24678c2ecf20Sopenharmony_ci found = '' 24688c2ecf20Sopenharmony_ci # add the callgraph data to the device hierarchy 24698c2ecf20Sopenharmony_ci borderphase = { 24708c2ecf20Sopenharmony_ci 'dpm_prepare': 'suspend_prepare', 24718c2ecf20Sopenharmony_ci 'dpm_complete': 'resume_complete' 24728c2ecf20Sopenharmony_ci } 24738c2ecf20Sopenharmony_ci if(self.name in borderphase): 24748c2ecf20Sopenharmony_ci p = borderphase[self.name] 24758c2ecf20Sopenharmony_ci list = data.dmesg[p]['list'] 24768c2ecf20Sopenharmony_ci for devname in list: 24778c2ecf20Sopenharmony_ci dev = list[devname] 24788c2ecf20Sopenharmony_ci if(pid == dev['pid'] and 24798c2ecf20Sopenharmony_ci self.start <= dev['start'] and 24808c2ecf20Sopenharmony_ci self.end >= dev['end']): 24818c2ecf20Sopenharmony_ci cg = self.slice(dev) 24828c2ecf20Sopenharmony_ci if cg: 24838c2ecf20Sopenharmony_ci dev['ftrace'] = cg 24848c2ecf20Sopenharmony_ci found = devname 24858c2ecf20Sopenharmony_ci return found 24868c2ecf20Sopenharmony_ci for p in data.sortedPhases(): 24878c2ecf20Sopenharmony_ci if(data.dmesg[p]['start'] <= self.start and 24888c2ecf20Sopenharmony_ci self.start <= data.dmesg[p]['end']): 24898c2ecf20Sopenharmony_ci list = data.dmesg[p]['list'] 24908c2ecf20Sopenharmony_ci for devname in sorted(list, key=lambda k:list[k]['start']): 24918c2ecf20Sopenharmony_ci dev = list[devname] 24928c2ecf20Sopenharmony_ci if(pid == dev['pid'] and 24938c2ecf20Sopenharmony_ci self.start <= dev['start'] and 24948c2ecf20Sopenharmony_ci self.end >= dev['end']): 24958c2ecf20Sopenharmony_ci dev['ftrace'] = self 24968c2ecf20Sopenharmony_ci found = devname 24978c2ecf20Sopenharmony_ci break 24988c2ecf20Sopenharmony_ci break 24998c2ecf20Sopenharmony_ci return found 25008c2ecf20Sopenharmony_ci def newActionFromFunction(self, data): 25018c2ecf20Sopenharmony_ci name = self.name 25028c2ecf20Sopenharmony_ci if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']: 25038c2ecf20Sopenharmony_ci return 25048c2ecf20Sopenharmony_ci fs = self.start 25058c2ecf20Sopenharmony_ci fe = self.end 25068c2ecf20Sopenharmony_ci if fs < data.start or fe > data.end: 25078c2ecf20Sopenharmony_ci return 25088c2ecf20Sopenharmony_ci phase = '' 25098c2ecf20Sopenharmony_ci for p in data.sortedPhases(): 25108c2ecf20Sopenharmony_ci if(data.dmesg[p]['start'] <= self.start and 25118c2ecf20Sopenharmony_ci self.start < data.dmesg[p]['end']): 25128c2ecf20Sopenharmony_ci phase = p 25138c2ecf20Sopenharmony_ci break 25148c2ecf20Sopenharmony_ci if not phase: 25158c2ecf20Sopenharmony_ci return 25168c2ecf20Sopenharmony_ci out = data.newActionGlobal(name, fs, fe, -2) 25178c2ecf20Sopenharmony_ci if out: 25188c2ecf20Sopenharmony_ci phase, myname = out 25198c2ecf20Sopenharmony_ci data.dmesg[phase]['list'][myname]['ftrace'] = self 25208c2ecf20Sopenharmony_ci def debugPrint(self, info=''): 25218c2ecf20Sopenharmony_ci pprint('%s pid=%d [%f - %f] %.3f us' % \ 25228c2ecf20Sopenharmony_ci (self.name, self.pid, self.start, self.end, 25238c2ecf20Sopenharmony_ci (self.end - self.start)*1000000)) 25248c2ecf20Sopenharmony_ci for l in self.list: 25258c2ecf20Sopenharmony_ci if l.isLeaf(): 25268c2ecf20Sopenharmony_ci pprint('%f (%02d): %s(); (%.3f us)%s' % (l.time, \ 25278c2ecf20Sopenharmony_ci l.depth, l.name, l.length*1000000, info)) 25288c2ecf20Sopenharmony_ci elif l.freturn: 25298c2ecf20Sopenharmony_ci pprint('%f (%02d): %s} (%.3f us)%s' % (l.time, \ 25308c2ecf20Sopenharmony_ci l.depth, l.name, l.length*1000000, info)) 25318c2ecf20Sopenharmony_ci else: 25328c2ecf20Sopenharmony_ci pprint('%f (%02d): %s() { (%.3f us)%s' % (l.time, \ 25338c2ecf20Sopenharmony_ci l.depth, l.name, l.length*1000000, info)) 25348c2ecf20Sopenharmony_ci pprint(' ') 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ciclass DevItem: 25378c2ecf20Sopenharmony_ci def __init__(self, test, phase, dev): 25388c2ecf20Sopenharmony_ci self.test = test 25398c2ecf20Sopenharmony_ci self.phase = phase 25408c2ecf20Sopenharmony_ci self.dev = dev 25418c2ecf20Sopenharmony_ci def isa(self, cls): 25428c2ecf20Sopenharmony_ci if 'htmlclass' in self.dev and cls in self.dev['htmlclass']: 25438c2ecf20Sopenharmony_ci return True 25448c2ecf20Sopenharmony_ci return False 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci# Class: Timeline 25478c2ecf20Sopenharmony_ci# Description: 25488c2ecf20Sopenharmony_ci# A container for a device timeline which calculates 25498c2ecf20Sopenharmony_ci# all the html properties to display it correctly 25508c2ecf20Sopenharmony_ciclass Timeline: 25518c2ecf20Sopenharmony_ci html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n' 25528c2ecf20Sopenharmony_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' 25538c2ecf20Sopenharmony_ci html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n' 25548c2ecf20Sopenharmony_ci html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' 25558c2ecf20Sopenharmony_ci html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' 25568c2ecf20Sopenharmony_ci def __init__(self, rowheight, scaleheight): 25578c2ecf20Sopenharmony_ci self.html = '' 25588c2ecf20Sopenharmony_ci self.height = 0 # total timeline height 25598c2ecf20Sopenharmony_ci self.scaleH = scaleheight # timescale (top) row height 25608c2ecf20Sopenharmony_ci self.rowH = rowheight # device row height 25618c2ecf20Sopenharmony_ci self.bodyH = 0 # body height 25628c2ecf20Sopenharmony_ci self.rows = 0 # total timeline rows 25638c2ecf20Sopenharmony_ci self.rowlines = dict() 25648c2ecf20Sopenharmony_ci self.rowheight = dict() 25658c2ecf20Sopenharmony_ci def createHeader(self, sv, stamp): 25668c2ecf20Sopenharmony_ci if(not stamp['time']): 25678c2ecf20Sopenharmony_ci return 25688c2ecf20Sopenharmony_ci self.html += '<div class="version"><a href="https://01.org/pm-graph">%s v%s</a></div>' \ 25698c2ecf20Sopenharmony_ci % (sv.title, sv.version) 25708c2ecf20Sopenharmony_ci if sv.logmsg and sv.testlog: 25718c2ecf20Sopenharmony_ci self.html += '<button id="showtest" class="logbtn btnfmt">log</button>' 25728c2ecf20Sopenharmony_ci if sv.dmesglog: 25738c2ecf20Sopenharmony_ci self.html += '<button id="showdmesg" class="logbtn btnfmt">dmesg</button>' 25748c2ecf20Sopenharmony_ci if sv.ftracelog: 25758c2ecf20Sopenharmony_ci self.html += '<button id="showftrace" class="logbtn btnfmt">ftrace</button>' 25768c2ecf20Sopenharmony_ci headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' 25778c2ecf20Sopenharmony_ci self.html += headline_stamp.format(stamp['host'], stamp['kernel'], 25788c2ecf20Sopenharmony_ci stamp['mode'], stamp['time']) 25798c2ecf20Sopenharmony_ci if 'man' in stamp and 'plat' in stamp and 'cpu' in stamp and \ 25808c2ecf20Sopenharmony_ci stamp['man'] and stamp['plat'] and stamp['cpu']: 25818c2ecf20Sopenharmony_ci headline_sysinfo = '<div class="stamp sysinfo">{0} {1} <i>with</i> {2}</div>\n' 25828c2ecf20Sopenharmony_ci self.html += headline_sysinfo.format(stamp['man'], stamp['plat'], stamp['cpu']) 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci # Function: getDeviceRows 25858c2ecf20Sopenharmony_ci # Description: 25868c2ecf20Sopenharmony_ci # determine how may rows the device funcs will take 25878c2ecf20Sopenharmony_ci # Arguments: 25888c2ecf20Sopenharmony_ci # rawlist: the list of devices/actions for a single phase 25898c2ecf20Sopenharmony_ci # Output: 25908c2ecf20Sopenharmony_ci # The total number of rows needed to display this phase of the timeline 25918c2ecf20Sopenharmony_ci def getDeviceRows(self, rawlist): 25928c2ecf20Sopenharmony_ci # clear all rows and set them to undefined 25938c2ecf20Sopenharmony_ci sortdict = dict() 25948c2ecf20Sopenharmony_ci for item in rawlist: 25958c2ecf20Sopenharmony_ci item.row = -1 25968c2ecf20Sopenharmony_ci sortdict[item] = item.length 25978c2ecf20Sopenharmony_ci sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 25988c2ecf20Sopenharmony_ci remaining = len(sortlist) 25998c2ecf20Sopenharmony_ci rowdata = dict() 26008c2ecf20Sopenharmony_ci row = 1 26018c2ecf20Sopenharmony_ci # try to pack each row with as many ranges as possible 26028c2ecf20Sopenharmony_ci while(remaining > 0): 26038c2ecf20Sopenharmony_ci if(row not in rowdata): 26048c2ecf20Sopenharmony_ci rowdata[row] = [] 26058c2ecf20Sopenharmony_ci for i in sortlist: 26068c2ecf20Sopenharmony_ci if(i.row >= 0): 26078c2ecf20Sopenharmony_ci continue 26088c2ecf20Sopenharmony_ci s = i.time 26098c2ecf20Sopenharmony_ci e = i.time + i.length 26108c2ecf20Sopenharmony_ci valid = True 26118c2ecf20Sopenharmony_ci for ritem in rowdata[row]: 26128c2ecf20Sopenharmony_ci rs = ritem.time 26138c2ecf20Sopenharmony_ci re = ritem.time + ritem.length 26148c2ecf20Sopenharmony_ci if(not (((s <= rs) and (e <= rs)) or 26158c2ecf20Sopenharmony_ci ((s >= re) and (e >= re)))): 26168c2ecf20Sopenharmony_ci valid = False 26178c2ecf20Sopenharmony_ci break 26188c2ecf20Sopenharmony_ci if(valid): 26198c2ecf20Sopenharmony_ci rowdata[row].append(i) 26208c2ecf20Sopenharmony_ci i.row = row 26218c2ecf20Sopenharmony_ci remaining -= 1 26228c2ecf20Sopenharmony_ci row += 1 26238c2ecf20Sopenharmony_ci return row 26248c2ecf20Sopenharmony_ci # Function: getPhaseRows 26258c2ecf20Sopenharmony_ci # Description: 26268c2ecf20Sopenharmony_ci # Organize the timeline entries into the smallest 26278c2ecf20Sopenharmony_ci # number of rows possible, with no entry overlapping 26288c2ecf20Sopenharmony_ci # Arguments: 26298c2ecf20Sopenharmony_ci # devlist: the list of devices/actions in a group of contiguous phases 26308c2ecf20Sopenharmony_ci # Output: 26318c2ecf20Sopenharmony_ci # The total number of rows needed to display this phase of the timeline 26328c2ecf20Sopenharmony_ci def getPhaseRows(self, devlist, row=0, sortby='length'): 26338c2ecf20Sopenharmony_ci # clear all rows and set them to undefined 26348c2ecf20Sopenharmony_ci remaining = len(devlist) 26358c2ecf20Sopenharmony_ci rowdata = dict() 26368c2ecf20Sopenharmony_ci sortdict = dict() 26378c2ecf20Sopenharmony_ci myphases = [] 26388c2ecf20Sopenharmony_ci # initialize all device rows to -1 and calculate devrows 26398c2ecf20Sopenharmony_ci for item in devlist: 26408c2ecf20Sopenharmony_ci dev = item.dev 26418c2ecf20Sopenharmony_ci tp = (item.test, item.phase) 26428c2ecf20Sopenharmony_ci if tp not in myphases: 26438c2ecf20Sopenharmony_ci myphases.append(tp) 26448c2ecf20Sopenharmony_ci dev['row'] = -1 26458c2ecf20Sopenharmony_ci if sortby == 'start': 26468c2ecf20Sopenharmony_ci # sort by start 1st, then length 2nd 26478c2ecf20Sopenharmony_ci sortdict[item] = (-1*float(dev['start']), float(dev['end']) - float(dev['start'])) 26488c2ecf20Sopenharmony_ci else: 26498c2ecf20Sopenharmony_ci # sort by length 1st, then name 2nd 26508c2ecf20Sopenharmony_ci sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) 26518c2ecf20Sopenharmony_ci if 'src' in dev: 26528c2ecf20Sopenharmony_ci dev['devrows'] = self.getDeviceRows(dev['src']) 26538c2ecf20Sopenharmony_ci # sort the devlist by length so that large items graph on top 26548c2ecf20Sopenharmony_ci sortlist = sorted(sortdict, key=sortdict.get, reverse=True) 26558c2ecf20Sopenharmony_ci orderedlist = [] 26568c2ecf20Sopenharmony_ci for item in sortlist: 26578c2ecf20Sopenharmony_ci if item.dev['pid'] == -2: 26588c2ecf20Sopenharmony_ci orderedlist.append(item) 26598c2ecf20Sopenharmony_ci for item in sortlist: 26608c2ecf20Sopenharmony_ci if item not in orderedlist: 26618c2ecf20Sopenharmony_ci orderedlist.append(item) 26628c2ecf20Sopenharmony_ci # try to pack each row with as many devices as possible 26638c2ecf20Sopenharmony_ci while(remaining > 0): 26648c2ecf20Sopenharmony_ci rowheight = 1 26658c2ecf20Sopenharmony_ci if(row not in rowdata): 26668c2ecf20Sopenharmony_ci rowdata[row] = [] 26678c2ecf20Sopenharmony_ci for item in orderedlist: 26688c2ecf20Sopenharmony_ci dev = item.dev 26698c2ecf20Sopenharmony_ci if(dev['row'] < 0): 26708c2ecf20Sopenharmony_ci s = dev['start'] 26718c2ecf20Sopenharmony_ci e = dev['end'] 26728c2ecf20Sopenharmony_ci valid = True 26738c2ecf20Sopenharmony_ci for ritem in rowdata[row]: 26748c2ecf20Sopenharmony_ci rs = ritem.dev['start'] 26758c2ecf20Sopenharmony_ci re = ritem.dev['end'] 26768c2ecf20Sopenharmony_ci if(not (((s <= rs) and (e <= rs)) or 26778c2ecf20Sopenharmony_ci ((s >= re) and (e >= re)))): 26788c2ecf20Sopenharmony_ci valid = False 26798c2ecf20Sopenharmony_ci break 26808c2ecf20Sopenharmony_ci if(valid): 26818c2ecf20Sopenharmony_ci rowdata[row].append(item) 26828c2ecf20Sopenharmony_ci dev['row'] = row 26838c2ecf20Sopenharmony_ci remaining -= 1 26848c2ecf20Sopenharmony_ci if 'devrows' in dev and dev['devrows'] > rowheight: 26858c2ecf20Sopenharmony_ci rowheight = dev['devrows'] 26868c2ecf20Sopenharmony_ci for t, p in myphases: 26878c2ecf20Sopenharmony_ci if t not in self.rowlines or t not in self.rowheight: 26888c2ecf20Sopenharmony_ci self.rowlines[t] = dict() 26898c2ecf20Sopenharmony_ci self.rowheight[t] = dict() 26908c2ecf20Sopenharmony_ci if p not in self.rowlines[t] or p not in self.rowheight[t]: 26918c2ecf20Sopenharmony_ci self.rowlines[t][p] = dict() 26928c2ecf20Sopenharmony_ci self.rowheight[t][p] = dict() 26938c2ecf20Sopenharmony_ci rh = self.rowH 26948c2ecf20Sopenharmony_ci # section headers should use a different row height 26958c2ecf20Sopenharmony_ci if len(rowdata[row]) == 1 and \ 26968c2ecf20Sopenharmony_ci 'htmlclass' in rowdata[row][0].dev and \ 26978c2ecf20Sopenharmony_ci 'sec' in rowdata[row][0].dev['htmlclass']: 26988c2ecf20Sopenharmony_ci rh = 15 26998c2ecf20Sopenharmony_ci self.rowlines[t][p][row] = rowheight 27008c2ecf20Sopenharmony_ci self.rowheight[t][p][row] = rowheight * rh 27018c2ecf20Sopenharmony_ci row += 1 27028c2ecf20Sopenharmony_ci if(row > self.rows): 27038c2ecf20Sopenharmony_ci self.rows = int(row) 27048c2ecf20Sopenharmony_ci return row 27058c2ecf20Sopenharmony_ci def phaseRowHeight(self, test, phase, row): 27068c2ecf20Sopenharmony_ci return self.rowheight[test][phase][row] 27078c2ecf20Sopenharmony_ci def phaseRowTop(self, test, phase, row): 27088c2ecf20Sopenharmony_ci top = 0 27098c2ecf20Sopenharmony_ci for i in sorted(self.rowheight[test][phase]): 27108c2ecf20Sopenharmony_ci if i >= row: 27118c2ecf20Sopenharmony_ci break 27128c2ecf20Sopenharmony_ci top += self.rowheight[test][phase][i] 27138c2ecf20Sopenharmony_ci return top 27148c2ecf20Sopenharmony_ci def calcTotalRows(self): 27158c2ecf20Sopenharmony_ci # Calculate the heights and offsets for the header and rows 27168c2ecf20Sopenharmony_ci maxrows = 0 27178c2ecf20Sopenharmony_ci standardphases = [] 27188c2ecf20Sopenharmony_ci for t in self.rowlines: 27198c2ecf20Sopenharmony_ci for p in self.rowlines[t]: 27208c2ecf20Sopenharmony_ci total = 0 27218c2ecf20Sopenharmony_ci for i in sorted(self.rowlines[t][p]): 27228c2ecf20Sopenharmony_ci total += self.rowlines[t][p][i] 27238c2ecf20Sopenharmony_ci if total > maxrows: 27248c2ecf20Sopenharmony_ci maxrows = total 27258c2ecf20Sopenharmony_ci if total == len(self.rowlines[t][p]): 27268c2ecf20Sopenharmony_ci standardphases.append((t, p)) 27278c2ecf20Sopenharmony_ci self.height = self.scaleH + (maxrows*self.rowH) 27288c2ecf20Sopenharmony_ci self.bodyH = self.height - self.scaleH 27298c2ecf20Sopenharmony_ci # if there is 1 line per row, draw them the standard way 27308c2ecf20Sopenharmony_ci for t, p in standardphases: 27318c2ecf20Sopenharmony_ci for i in sorted(self.rowheight[t][p]): 27328c2ecf20Sopenharmony_ci self.rowheight[t][p][i] = float(self.bodyH)/len(self.rowlines[t][p]) 27338c2ecf20Sopenharmony_ci def createZoomBox(self, mode='command', testcount=1): 27348c2ecf20Sopenharmony_ci # Create bounding box, add buttons 27358c2ecf20Sopenharmony_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' 27368c2ecf20Sopenharmony_ci html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' 27378c2ecf20Sopenharmony_ci html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail{0}</button>' 27388c2ecf20Sopenharmony_ci html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' 27398c2ecf20Sopenharmony_ci if mode != 'command': 27408c2ecf20Sopenharmony_ci if testcount > 1: 27418c2ecf20Sopenharmony_ci self.html += html_devlist2 27428c2ecf20Sopenharmony_ci self.html += html_devlist1.format('1') 27438c2ecf20Sopenharmony_ci else: 27448c2ecf20Sopenharmony_ci self.html += html_devlist1.format('') 27458c2ecf20Sopenharmony_ci self.html += html_zoombox 27468c2ecf20Sopenharmony_ci self.html += html_timeline.format('dmesg', self.height) 27478c2ecf20Sopenharmony_ci # Function: createTimeScale 27488c2ecf20Sopenharmony_ci # Description: 27498c2ecf20Sopenharmony_ci # Create the timescale for a timeline block 27508c2ecf20Sopenharmony_ci # Arguments: 27518c2ecf20Sopenharmony_ci # m0: start time (mode begin) 27528c2ecf20Sopenharmony_ci # mMax: end time (mode end) 27538c2ecf20Sopenharmony_ci # tTotal: total timeline time 27548c2ecf20Sopenharmony_ci # mode: suspend or resume 27558c2ecf20Sopenharmony_ci # Output: 27568c2ecf20Sopenharmony_ci # The html code needed to display the time scale 27578c2ecf20Sopenharmony_ci def createTimeScale(self, m0, mMax, tTotal, mode): 27588c2ecf20Sopenharmony_ci timescale = '<div class="t" style="right:{0}%">{1}</div>\n' 27598c2ecf20Sopenharmony_ci rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">{0}</div>\n' 27608c2ecf20Sopenharmony_ci output = '<div class="timescale">\n' 27618c2ecf20Sopenharmony_ci # set scale for timeline 27628c2ecf20Sopenharmony_ci mTotal = mMax - m0 27638c2ecf20Sopenharmony_ci tS = 0.1 27648c2ecf20Sopenharmony_ci if(tTotal <= 0): 27658c2ecf20Sopenharmony_ci return output+'</div>\n' 27668c2ecf20Sopenharmony_ci if(tTotal > 4): 27678c2ecf20Sopenharmony_ci tS = 1 27688c2ecf20Sopenharmony_ci divTotal = int(mTotal/tS) + 1 27698c2ecf20Sopenharmony_ci divEdge = (mTotal - tS*(divTotal-1))*100/mTotal 27708c2ecf20Sopenharmony_ci for i in range(divTotal): 27718c2ecf20Sopenharmony_ci htmlline = '' 27728c2ecf20Sopenharmony_ci if(mode == 'suspend'): 27738c2ecf20Sopenharmony_ci pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge) 27748c2ecf20Sopenharmony_ci val = '%0.fms' % (float(i-divTotal+1)*tS*1000) 27758c2ecf20Sopenharmony_ci if(i == divTotal - 1): 27768c2ecf20Sopenharmony_ci val = mode 27778c2ecf20Sopenharmony_ci htmlline = timescale.format(pos, val) 27788c2ecf20Sopenharmony_ci else: 27798c2ecf20Sopenharmony_ci pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal)) 27808c2ecf20Sopenharmony_ci val = '%0.fms' % (float(i)*tS*1000) 27818c2ecf20Sopenharmony_ci htmlline = timescale.format(pos, val) 27828c2ecf20Sopenharmony_ci if(i == 0): 27838c2ecf20Sopenharmony_ci htmlline = rline.format(mode) 27848c2ecf20Sopenharmony_ci output += htmlline 27858c2ecf20Sopenharmony_ci self.html += output+'</div>\n' 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci# Class: TestProps 27888c2ecf20Sopenharmony_ci# Description: 27898c2ecf20Sopenharmony_ci# A list of values describing the properties of these test runs 27908c2ecf20Sopenharmony_ciclass TestProps: 27918c2ecf20Sopenharmony_ci stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ 27928c2ecf20Sopenharmony_ci '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ 27938c2ecf20Sopenharmony_ci ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' 27948c2ecf20Sopenharmony_ci wififmt = '^# wifi *(?P<d>\S*) *(?P<s>\S*) *(?P<t>[0-9\.]+).*' 27958c2ecf20Sopenharmony_ci tstatfmt = '^# turbostat (?P<t>\S*)' 27968c2ecf20Sopenharmony_ci testerrfmt = '^# enter_sleep_error (?P<e>.*)' 27978c2ecf20Sopenharmony_ci sysinfofmt = '^# sysinfo .*' 27988c2ecf20Sopenharmony_ci cmdlinefmt = '^# command \| (?P<cmd>.*)' 27998c2ecf20Sopenharmony_ci kparamsfmt = '^# kparams \| (?P<kp>.*)' 28008c2ecf20Sopenharmony_ci devpropfmt = '# Device Properties: .*' 28018c2ecf20Sopenharmony_ci pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)' 28028c2ecf20Sopenharmony_ci tracertypefmt = '# tracer: (?P<t>.*)' 28038c2ecf20Sopenharmony_ci firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' 28048c2ecf20Sopenharmony_ci procexecfmt = 'ps - (?P<ps>.*)$' 28058c2ecf20Sopenharmony_ci ftrace_line_fmt_fg = \ 28068c2ecf20Sopenharmony_ci '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ 28078c2ecf20Sopenharmony_ci ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ 28088c2ecf20Sopenharmony_ci '[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)' 28098c2ecf20Sopenharmony_ci ftrace_line_fmt_nop = \ 28108c2ecf20Sopenharmony_ci ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\ 28118c2ecf20Sopenharmony_ci '(?P<flags>\S*) *(?P<time>[0-9\.]*): *'+\ 28128c2ecf20Sopenharmony_ci '(?P<msg>.*)' 28138c2ecf20Sopenharmony_ci machinesuspend = 'machine_suspend\[.*' 28148c2ecf20Sopenharmony_ci def __init__(self): 28158c2ecf20Sopenharmony_ci self.stamp = '' 28168c2ecf20Sopenharmony_ci self.sysinfo = '' 28178c2ecf20Sopenharmony_ci self.cmdline = '' 28188c2ecf20Sopenharmony_ci self.testerror = [] 28198c2ecf20Sopenharmony_ci self.turbostat = [] 28208c2ecf20Sopenharmony_ci self.wifi = [] 28218c2ecf20Sopenharmony_ci self.fwdata = [] 28228c2ecf20Sopenharmony_ci self.ftrace_line_fmt = self.ftrace_line_fmt_nop 28238c2ecf20Sopenharmony_ci self.cgformat = False 28248c2ecf20Sopenharmony_ci self.data = 0 28258c2ecf20Sopenharmony_ci self.ktemp = dict() 28268c2ecf20Sopenharmony_ci def setTracerType(self, tracer): 28278c2ecf20Sopenharmony_ci if(tracer == 'function_graph'): 28288c2ecf20Sopenharmony_ci self.cgformat = True 28298c2ecf20Sopenharmony_ci self.ftrace_line_fmt = self.ftrace_line_fmt_fg 28308c2ecf20Sopenharmony_ci elif(tracer == 'nop'): 28318c2ecf20Sopenharmony_ci self.ftrace_line_fmt = self.ftrace_line_fmt_nop 28328c2ecf20Sopenharmony_ci else: 28338c2ecf20Sopenharmony_ci doError('Invalid tracer format: [%s]' % tracer) 28348c2ecf20Sopenharmony_ci def stampInfo(self, line, sv): 28358c2ecf20Sopenharmony_ci if re.match(self.stampfmt, line): 28368c2ecf20Sopenharmony_ci self.stamp = line 28378c2ecf20Sopenharmony_ci return True 28388c2ecf20Sopenharmony_ci elif re.match(self.sysinfofmt, line): 28398c2ecf20Sopenharmony_ci self.sysinfo = line 28408c2ecf20Sopenharmony_ci return True 28418c2ecf20Sopenharmony_ci elif re.match(self.tstatfmt, line): 28428c2ecf20Sopenharmony_ci self.turbostat.append(line) 28438c2ecf20Sopenharmony_ci return True 28448c2ecf20Sopenharmony_ci elif re.match(self.wififmt, line): 28458c2ecf20Sopenharmony_ci self.wifi.append(line) 28468c2ecf20Sopenharmony_ci return True 28478c2ecf20Sopenharmony_ci elif re.match(self.testerrfmt, line): 28488c2ecf20Sopenharmony_ci self.testerror.append(line) 28498c2ecf20Sopenharmony_ci return True 28508c2ecf20Sopenharmony_ci elif re.match(self.firmwarefmt, line): 28518c2ecf20Sopenharmony_ci self.fwdata.append(line) 28528c2ecf20Sopenharmony_ci return True 28538c2ecf20Sopenharmony_ci elif(re.match(self.devpropfmt, line)): 28548c2ecf20Sopenharmony_ci self.parseDevprops(line, sv) 28558c2ecf20Sopenharmony_ci return True 28568c2ecf20Sopenharmony_ci elif(re.match(self.pinfofmt, line)): 28578c2ecf20Sopenharmony_ci self.parsePlatformInfo(line, sv) 28588c2ecf20Sopenharmony_ci return True 28598c2ecf20Sopenharmony_ci m = re.match(self.cmdlinefmt, line) 28608c2ecf20Sopenharmony_ci if m: 28618c2ecf20Sopenharmony_ci self.cmdline = m.group('cmd') 28628c2ecf20Sopenharmony_ci return True 28638c2ecf20Sopenharmony_ci m = re.match(self.tracertypefmt, line) 28648c2ecf20Sopenharmony_ci if(m): 28658c2ecf20Sopenharmony_ci self.setTracerType(m.group('t')) 28668c2ecf20Sopenharmony_ci return True 28678c2ecf20Sopenharmony_ci return False 28688c2ecf20Sopenharmony_ci def parseStamp(self, data, sv): 28698c2ecf20Sopenharmony_ci # global test data 28708c2ecf20Sopenharmony_ci m = re.match(self.stampfmt, self.stamp) 28718c2ecf20Sopenharmony_ci if not self.stamp or not m: 28728c2ecf20Sopenharmony_ci doError('data does not include the expected stamp') 28738c2ecf20Sopenharmony_ci data.stamp = {'time': '', 'host': '', 'mode': ''} 28748c2ecf20Sopenharmony_ci dt = datetime(int(m.group('y'))+2000, int(m.group('m')), 28758c2ecf20Sopenharmony_ci int(m.group('d')), int(m.group('H')), int(m.group('M')), 28768c2ecf20Sopenharmony_ci int(m.group('S'))) 28778c2ecf20Sopenharmony_ci data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') 28788c2ecf20Sopenharmony_ci data.stamp['host'] = m.group('host') 28798c2ecf20Sopenharmony_ci data.stamp['mode'] = m.group('mode') 28808c2ecf20Sopenharmony_ci data.stamp['kernel'] = m.group('kernel') 28818c2ecf20Sopenharmony_ci if re.match(self.sysinfofmt, self.sysinfo): 28828c2ecf20Sopenharmony_ci for f in self.sysinfo.split('|'): 28838c2ecf20Sopenharmony_ci if '#' in f: 28848c2ecf20Sopenharmony_ci continue 28858c2ecf20Sopenharmony_ci tmp = f.strip().split(':', 1) 28868c2ecf20Sopenharmony_ci key = tmp[0] 28878c2ecf20Sopenharmony_ci val = tmp[1] 28888c2ecf20Sopenharmony_ci data.stamp[key] = val 28898c2ecf20Sopenharmony_ci sv.hostname = data.stamp['host'] 28908c2ecf20Sopenharmony_ci sv.suspendmode = data.stamp['mode'] 28918c2ecf20Sopenharmony_ci if sv.suspendmode == 'freeze': 28928c2ecf20Sopenharmony_ci self.machinesuspend = 'timekeeping_freeze\[.*' 28938c2ecf20Sopenharmony_ci else: 28948c2ecf20Sopenharmony_ci self.machinesuspend = 'machine_suspend\[.*' 28958c2ecf20Sopenharmony_ci if sv.suspendmode == 'command' and sv.ftracefile != '': 28968c2ecf20Sopenharmony_ci modes = ['on', 'freeze', 'standby', 'mem', 'disk'] 28978c2ecf20Sopenharmony_ci fp = sv.openlog(sv.ftracefile, 'r') 28988c2ecf20Sopenharmony_ci for line in fp: 28998c2ecf20Sopenharmony_ci m = re.match('.* machine_suspend\[(?P<mode>.*)\]', line) 29008c2ecf20Sopenharmony_ci if m and m.group('mode') in ['1', '2', '3', '4']: 29018c2ecf20Sopenharmony_ci sv.suspendmode = modes[int(m.group('mode'))] 29028c2ecf20Sopenharmony_ci data.stamp['mode'] = sv.suspendmode 29038c2ecf20Sopenharmony_ci break 29048c2ecf20Sopenharmony_ci fp.close() 29058c2ecf20Sopenharmony_ci sv.cmdline = self.cmdline 29068c2ecf20Sopenharmony_ci if not sv.stamp: 29078c2ecf20Sopenharmony_ci sv.stamp = data.stamp 29088c2ecf20Sopenharmony_ci # firmware data 29098c2ecf20Sopenharmony_ci if sv.suspendmode == 'mem' and len(self.fwdata) > data.testnumber: 29108c2ecf20Sopenharmony_ci m = re.match(self.firmwarefmt, self.fwdata[data.testnumber]) 29118c2ecf20Sopenharmony_ci if m: 29128c2ecf20Sopenharmony_ci data.fwSuspend, data.fwResume = int(m.group('s')), int(m.group('r')) 29138c2ecf20Sopenharmony_ci if(data.fwSuspend > 0 or data.fwResume > 0): 29148c2ecf20Sopenharmony_ci data.fwValid = True 29158c2ecf20Sopenharmony_ci # turbostat data 29168c2ecf20Sopenharmony_ci if len(self.turbostat) > data.testnumber: 29178c2ecf20Sopenharmony_ci m = re.match(self.tstatfmt, self.turbostat[data.testnumber]) 29188c2ecf20Sopenharmony_ci if m: 29198c2ecf20Sopenharmony_ci data.turbostat = m.group('t') 29208c2ecf20Sopenharmony_ci # wifi data 29218c2ecf20Sopenharmony_ci if len(self.wifi) > data.testnumber: 29228c2ecf20Sopenharmony_ci m = re.match(self.wififmt, self.wifi[data.testnumber]) 29238c2ecf20Sopenharmony_ci if m: 29248c2ecf20Sopenharmony_ci data.wifi = {'dev': m.group('d'), 'stat': m.group('s'), 29258c2ecf20Sopenharmony_ci 'time': float(m.group('t'))} 29268c2ecf20Sopenharmony_ci data.stamp['wifi'] = m.group('d') 29278c2ecf20Sopenharmony_ci # sleep mode enter errors 29288c2ecf20Sopenharmony_ci if len(self.testerror) > data.testnumber: 29298c2ecf20Sopenharmony_ci m = re.match(self.testerrfmt, self.testerror[data.testnumber]) 29308c2ecf20Sopenharmony_ci if m: 29318c2ecf20Sopenharmony_ci data.enterfail = m.group('e') 29328c2ecf20Sopenharmony_ci def devprops(self, data): 29338c2ecf20Sopenharmony_ci props = dict() 29348c2ecf20Sopenharmony_ci devlist = data.split(';') 29358c2ecf20Sopenharmony_ci for dev in devlist: 29368c2ecf20Sopenharmony_ci f = dev.split(',') 29378c2ecf20Sopenharmony_ci if len(f) < 3: 29388c2ecf20Sopenharmony_ci continue 29398c2ecf20Sopenharmony_ci dev = f[0] 29408c2ecf20Sopenharmony_ci props[dev] = DevProps() 29418c2ecf20Sopenharmony_ci props[dev].altname = f[1] 29428c2ecf20Sopenharmony_ci if int(f[2]): 29438c2ecf20Sopenharmony_ci props[dev].isasync = True 29448c2ecf20Sopenharmony_ci else: 29458c2ecf20Sopenharmony_ci props[dev].isasync = False 29468c2ecf20Sopenharmony_ci return props 29478c2ecf20Sopenharmony_ci def parseDevprops(self, line, sv): 29488c2ecf20Sopenharmony_ci idx = line.index(': ') + 2 29498c2ecf20Sopenharmony_ci if idx >= len(line): 29508c2ecf20Sopenharmony_ci return 29518c2ecf20Sopenharmony_ci props = self.devprops(line[idx:]) 29528c2ecf20Sopenharmony_ci if sv.suspendmode == 'command' and 'testcommandstring' in props: 29538c2ecf20Sopenharmony_ci sv.testcommand = props['testcommandstring'].altname 29548c2ecf20Sopenharmony_ci sv.devprops = props 29558c2ecf20Sopenharmony_ci def parsePlatformInfo(self, line, sv): 29568c2ecf20Sopenharmony_ci m = re.match(self.pinfofmt, line) 29578c2ecf20Sopenharmony_ci if not m: 29588c2ecf20Sopenharmony_ci return 29598c2ecf20Sopenharmony_ci name, info = m.group('val'), m.group('info') 29608c2ecf20Sopenharmony_ci if name == 'devinfo': 29618c2ecf20Sopenharmony_ci sv.devprops = self.devprops(sv.b64unzip(info)) 29628c2ecf20Sopenharmony_ci return 29638c2ecf20Sopenharmony_ci elif name == 'testcmd': 29648c2ecf20Sopenharmony_ci sv.testcommand = info 29658c2ecf20Sopenharmony_ci return 29668c2ecf20Sopenharmony_ci field = info.split('|') 29678c2ecf20Sopenharmony_ci if len(field) < 2: 29688c2ecf20Sopenharmony_ci return 29698c2ecf20Sopenharmony_ci cmdline = field[0].strip() 29708c2ecf20Sopenharmony_ci output = sv.b64unzip(field[1].strip()) 29718c2ecf20Sopenharmony_ci sv.platinfo.append([name, cmdline, output]) 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci# Class: TestRun 29748c2ecf20Sopenharmony_ci# Description: 29758c2ecf20Sopenharmony_ci# A container for a suspend/resume test run. This is necessary as 29768c2ecf20Sopenharmony_ci# there could be more than one, and they need to be separate. 29778c2ecf20Sopenharmony_ciclass TestRun: 29788c2ecf20Sopenharmony_ci def __init__(self, dataobj): 29798c2ecf20Sopenharmony_ci self.data = dataobj 29808c2ecf20Sopenharmony_ci self.ftemp = dict() 29818c2ecf20Sopenharmony_ci self.ttemp = dict() 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ciclass ProcessMonitor: 29848c2ecf20Sopenharmony_ci def __init__(self): 29858c2ecf20Sopenharmony_ci self.proclist = dict() 29868c2ecf20Sopenharmony_ci self.running = False 29878c2ecf20Sopenharmony_ci def procstat(self): 29888c2ecf20Sopenharmony_ci c = ['cat /proc/[1-9]*/stat 2>/dev/null'] 29898c2ecf20Sopenharmony_ci process = Popen(c, shell=True, stdout=PIPE) 29908c2ecf20Sopenharmony_ci running = dict() 29918c2ecf20Sopenharmony_ci for line in process.stdout: 29928c2ecf20Sopenharmony_ci data = ascii(line).split() 29938c2ecf20Sopenharmony_ci pid = data[0] 29948c2ecf20Sopenharmony_ci name = re.sub('[()]', '', data[1]) 29958c2ecf20Sopenharmony_ci user = int(data[13]) 29968c2ecf20Sopenharmony_ci kern = int(data[14]) 29978c2ecf20Sopenharmony_ci kjiff = ujiff = 0 29988c2ecf20Sopenharmony_ci if pid not in self.proclist: 29998c2ecf20Sopenharmony_ci self.proclist[pid] = {'name' : name, 'user' : user, 'kern' : kern} 30008c2ecf20Sopenharmony_ci else: 30018c2ecf20Sopenharmony_ci val = self.proclist[pid] 30028c2ecf20Sopenharmony_ci ujiff = user - val['user'] 30038c2ecf20Sopenharmony_ci kjiff = kern - val['kern'] 30048c2ecf20Sopenharmony_ci val['user'] = user 30058c2ecf20Sopenharmony_ci val['kern'] = kern 30068c2ecf20Sopenharmony_ci if ujiff > 0 or kjiff > 0: 30078c2ecf20Sopenharmony_ci running[pid] = ujiff + kjiff 30088c2ecf20Sopenharmony_ci process.wait() 30098c2ecf20Sopenharmony_ci out = '' 30108c2ecf20Sopenharmony_ci for pid in running: 30118c2ecf20Sopenharmony_ci jiffies = running[pid] 30128c2ecf20Sopenharmony_ci val = self.proclist[pid] 30138c2ecf20Sopenharmony_ci if out: 30148c2ecf20Sopenharmony_ci out += ',' 30158c2ecf20Sopenharmony_ci out += '%s-%s %d' % (val['name'], pid, jiffies) 30168c2ecf20Sopenharmony_ci return 'ps - '+out 30178c2ecf20Sopenharmony_ci def processMonitor(self, tid): 30188c2ecf20Sopenharmony_ci while self.running: 30198c2ecf20Sopenharmony_ci out = self.procstat() 30208c2ecf20Sopenharmony_ci if out: 30218c2ecf20Sopenharmony_ci sysvals.fsetVal(out, 'trace_marker') 30228c2ecf20Sopenharmony_ci def start(self): 30238c2ecf20Sopenharmony_ci self.thread = Thread(target=self.processMonitor, args=(0,)) 30248c2ecf20Sopenharmony_ci self.running = True 30258c2ecf20Sopenharmony_ci self.thread.start() 30268c2ecf20Sopenharmony_ci def stop(self): 30278c2ecf20Sopenharmony_ci self.running = False 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci# ----------------- FUNCTIONS -------------------- 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci# Function: doesTraceLogHaveTraceEvents 30328c2ecf20Sopenharmony_ci# Description: 30338c2ecf20Sopenharmony_ci# Quickly determine if the ftrace log has all of the trace events, 30348c2ecf20Sopenharmony_ci# markers, and/or kprobes required for primary parsing. 30358c2ecf20Sopenharmony_cidef doesTraceLogHaveTraceEvents(): 30368c2ecf20Sopenharmony_ci kpcheck = ['_cal: (', '_ret: ('] 30378c2ecf20Sopenharmony_ci techeck = ['suspend_resume', 'device_pm_callback'] 30388c2ecf20Sopenharmony_ci tmcheck = ['SUSPEND START', 'RESUME COMPLETE'] 30398c2ecf20Sopenharmony_ci sysvals.usekprobes = False 30408c2ecf20Sopenharmony_ci fp = sysvals.openlog(sysvals.ftracefile, 'r') 30418c2ecf20Sopenharmony_ci for line in fp: 30428c2ecf20Sopenharmony_ci # check for kprobes 30438c2ecf20Sopenharmony_ci if not sysvals.usekprobes: 30448c2ecf20Sopenharmony_ci for i in kpcheck: 30458c2ecf20Sopenharmony_ci if i in line: 30468c2ecf20Sopenharmony_ci sysvals.usekprobes = True 30478c2ecf20Sopenharmony_ci # check for all necessary trace events 30488c2ecf20Sopenharmony_ci check = techeck[:] 30498c2ecf20Sopenharmony_ci for i in techeck: 30508c2ecf20Sopenharmony_ci if i in line: 30518c2ecf20Sopenharmony_ci check.remove(i) 30528c2ecf20Sopenharmony_ci techeck = check 30538c2ecf20Sopenharmony_ci # check for all necessary trace markers 30548c2ecf20Sopenharmony_ci check = tmcheck[:] 30558c2ecf20Sopenharmony_ci for i in tmcheck: 30568c2ecf20Sopenharmony_ci if i in line: 30578c2ecf20Sopenharmony_ci check.remove(i) 30588c2ecf20Sopenharmony_ci tmcheck = check 30598c2ecf20Sopenharmony_ci fp.close() 30608c2ecf20Sopenharmony_ci sysvals.usetraceevents = True if len(techeck) < 2 else False 30618c2ecf20Sopenharmony_ci sysvals.usetracemarkers = True if len(tmcheck) == 0 else False 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci# Function: appendIncompleteTraceLog 30648c2ecf20Sopenharmony_ci# Description: 30658c2ecf20Sopenharmony_ci# [deprecated for kernel 3.15 or newer] 30668c2ecf20Sopenharmony_ci# Adds callgraph data which lacks trace event data. This is only 30678c2ecf20Sopenharmony_ci# for timelines generated from 3.15 or older 30688c2ecf20Sopenharmony_ci# Arguments: 30698c2ecf20Sopenharmony_ci# testruns: the array of Data objects obtained from parseKernelLog 30708c2ecf20Sopenharmony_cidef appendIncompleteTraceLog(testruns): 30718c2ecf20Sopenharmony_ci # create TestRun vessels for ftrace parsing 30728c2ecf20Sopenharmony_ci testcnt = len(testruns) 30738c2ecf20Sopenharmony_ci testidx = 0 30748c2ecf20Sopenharmony_ci testrun = [] 30758c2ecf20Sopenharmony_ci for data in testruns: 30768c2ecf20Sopenharmony_ci testrun.append(TestRun(data)) 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci # extract the callgraph and traceevent data 30798c2ecf20Sopenharmony_ci sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 30808c2ecf20Sopenharmony_ci os.path.basename(sysvals.ftracefile)) 30818c2ecf20Sopenharmony_ci tp = TestProps() 30828c2ecf20Sopenharmony_ci tf = sysvals.openlog(sysvals.ftracefile, 'r') 30838c2ecf20Sopenharmony_ci data = 0 30848c2ecf20Sopenharmony_ci for line in tf: 30858c2ecf20Sopenharmony_ci # remove any latent carriage returns 30868c2ecf20Sopenharmony_ci line = line.replace('\r\n', '') 30878c2ecf20Sopenharmony_ci if tp.stampInfo(line, sysvals): 30888c2ecf20Sopenharmony_ci continue 30898c2ecf20Sopenharmony_ci # parse only valid lines, if this is not one move on 30908c2ecf20Sopenharmony_ci m = re.match(tp.ftrace_line_fmt, line) 30918c2ecf20Sopenharmony_ci if(not m): 30928c2ecf20Sopenharmony_ci continue 30938c2ecf20Sopenharmony_ci # gather the basic message data from the line 30948c2ecf20Sopenharmony_ci m_time = m.group('time') 30958c2ecf20Sopenharmony_ci m_pid = m.group('pid') 30968c2ecf20Sopenharmony_ci m_msg = m.group('msg') 30978c2ecf20Sopenharmony_ci if(tp.cgformat): 30988c2ecf20Sopenharmony_ci m_param3 = m.group('dur') 30998c2ecf20Sopenharmony_ci else: 31008c2ecf20Sopenharmony_ci m_param3 = 'traceevent' 31018c2ecf20Sopenharmony_ci if(m_time and m_pid and m_msg): 31028c2ecf20Sopenharmony_ci t = FTraceLine(m_time, m_msg, m_param3) 31038c2ecf20Sopenharmony_ci pid = int(m_pid) 31048c2ecf20Sopenharmony_ci else: 31058c2ecf20Sopenharmony_ci continue 31068c2ecf20Sopenharmony_ci # the line should be a call, return, or event 31078c2ecf20Sopenharmony_ci if(not t.fcall and not t.freturn and not t.fevent): 31088c2ecf20Sopenharmony_ci continue 31098c2ecf20Sopenharmony_ci # look for the suspend start marker 31108c2ecf20Sopenharmony_ci if(t.startMarker()): 31118c2ecf20Sopenharmony_ci data = testrun[testidx].data 31128c2ecf20Sopenharmony_ci tp.parseStamp(data, sysvals) 31138c2ecf20Sopenharmony_ci data.setStart(t.time, t.name) 31148c2ecf20Sopenharmony_ci continue 31158c2ecf20Sopenharmony_ci if(not data): 31168c2ecf20Sopenharmony_ci continue 31178c2ecf20Sopenharmony_ci # find the end of resume 31188c2ecf20Sopenharmony_ci if(t.endMarker()): 31198c2ecf20Sopenharmony_ci data.setEnd(t.time, t.name) 31208c2ecf20Sopenharmony_ci testidx += 1 31218c2ecf20Sopenharmony_ci if(testidx >= testcnt): 31228c2ecf20Sopenharmony_ci break 31238c2ecf20Sopenharmony_ci continue 31248c2ecf20Sopenharmony_ci # trace event processing 31258c2ecf20Sopenharmony_ci if(t.fevent): 31268c2ecf20Sopenharmony_ci continue 31278c2ecf20Sopenharmony_ci # call/return processing 31288c2ecf20Sopenharmony_ci elif sysvals.usecallgraph: 31298c2ecf20Sopenharmony_ci # create a callgraph object for the data 31308c2ecf20Sopenharmony_ci if(pid not in testrun[testidx].ftemp): 31318c2ecf20Sopenharmony_ci testrun[testidx].ftemp[pid] = [] 31328c2ecf20Sopenharmony_ci testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 31338c2ecf20Sopenharmony_ci # when the call is finished, see which device matches it 31348c2ecf20Sopenharmony_ci cg = testrun[testidx].ftemp[pid][-1] 31358c2ecf20Sopenharmony_ci res = cg.addLine(t) 31368c2ecf20Sopenharmony_ci if(res != 0): 31378c2ecf20Sopenharmony_ci testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid, sysvals)) 31388c2ecf20Sopenharmony_ci if(res == -1): 31398c2ecf20Sopenharmony_ci testrun[testidx].ftemp[pid][-1].addLine(t) 31408c2ecf20Sopenharmony_ci tf.close() 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci for test in testrun: 31438c2ecf20Sopenharmony_ci # add the callgraph data to the device hierarchy 31448c2ecf20Sopenharmony_ci for pid in test.ftemp: 31458c2ecf20Sopenharmony_ci for cg in test.ftemp[pid]: 31468c2ecf20Sopenharmony_ci if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 31478c2ecf20Sopenharmony_ci continue 31488c2ecf20Sopenharmony_ci if(not cg.postProcess()): 31498c2ecf20Sopenharmony_ci id = 'task %s cpu %s' % (pid, m.group('cpu')) 31508c2ecf20Sopenharmony_ci sysvals.vprint('Sanity check failed for '+\ 31518c2ecf20Sopenharmony_ci id+', ignoring this callback') 31528c2ecf20Sopenharmony_ci continue 31538c2ecf20Sopenharmony_ci callstart = cg.start 31548c2ecf20Sopenharmony_ci callend = cg.end 31558c2ecf20Sopenharmony_ci for p in test.data.sortedPhases(): 31568c2ecf20Sopenharmony_ci if(test.data.dmesg[p]['start'] <= callstart and 31578c2ecf20Sopenharmony_ci callstart <= test.data.dmesg[p]['end']): 31588c2ecf20Sopenharmony_ci list = test.data.dmesg[p]['list'] 31598c2ecf20Sopenharmony_ci for devname in list: 31608c2ecf20Sopenharmony_ci dev = list[devname] 31618c2ecf20Sopenharmony_ci if(pid == dev['pid'] and 31628c2ecf20Sopenharmony_ci callstart <= dev['start'] and 31638c2ecf20Sopenharmony_ci callend >= dev['end']): 31648c2ecf20Sopenharmony_ci dev['ftrace'] = cg 31658c2ecf20Sopenharmony_ci break 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci# Function: parseTraceLog 31688c2ecf20Sopenharmony_ci# Description: 31698c2ecf20Sopenharmony_ci# Analyze an ftrace log output file generated from this app during 31708c2ecf20Sopenharmony_ci# the execution phase. Used when the ftrace log is the primary data source 31718c2ecf20Sopenharmony_ci# and includes the suspend_resume and device_pm_callback trace events 31728c2ecf20Sopenharmony_ci# The ftrace filename is taken from sysvals 31738c2ecf20Sopenharmony_ci# Output: 31748c2ecf20Sopenharmony_ci# An array of Data objects 31758c2ecf20Sopenharmony_cidef parseTraceLog(live=False): 31768c2ecf20Sopenharmony_ci sysvals.vprint('Analyzing the ftrace data (%s)...' % \ 31778c2ecf20Sopenharmony_ci os.path.basename(sysvals.ftracefile)) 31788c2ecf20Sopenharmony_ci if(os.path.exists(sysvals.ftracefile) == False): 31798c2ecf20Sopenharmony_ci doError('%s does not exist' % sysvals.ftracefile) 31808c2ecf20Sopenharmony_ci if not live: 31818c2ecf20Sopenharmony_ci sysvals.setupAllKprobes() 31828c2ecf20Sopenharmony_ci ksuscalls = ['ksys_sync', 'pm_prepare_console'] 31838c2ecf20Sopenharmony_ci krescalls = ['pm_restore_console'] 31848c2ecf20Sopenharmony_ci tracewatch = ['irq_wakeup'] 31858c2ecf20Sopenharmony_ci if sysvals.usekprobes: 31868c2ecf20Sopenharmony_ci tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend', 31878c2ecf20Sopenharmony_ci 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 31888c2ecf20Sopenharmony_ci 'CPU_OFF', 'acpi_suspend'] 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci # extract the callgraph and traceevent data 31918c2ecf20Sopenharmony_ci s2idle_enter = hwsus = False 31928c2ecf20Sopenharmony_ci tp = TestProps() 31938c2ecf20Sopenharmony_ci testruns, testdata = [], [] 31948c2ecf20Sopenharmony_ci testrun, data, limbo = 0, 0, True 31958c2ecf20Sopenharmony_ci tf = sysvals.openlog(sysvals.ftracefile, 'r') 31968c2ecf20Sopenharmony_ci phase = 'suspend_prepare' 31978c2ecf20Sopenharmony_ci for line in tf: 31988c2ecf20Sopenharmony_ci # remove any latent carriage returns 31998c2ecf20Sopenharmony_ci line = line.replace('\r\n', '') 32008c2ecf20Sopenharmony_ci if tp.stampInfo(line, sysvals): 32018c2ecf20Sopenharmony_ci continue 32028c2ecf20Sopenharmony_ci # ignore all other commented lines 32038c2ecf20Sopenharmony_ci if line[0] == '#': 32048c2ecf20Sopenharmony_ci continue 32058c2ecf20Sopenharmony_ci # ftrace line: parse only valid lines 32068c2ecf20Sopenharmony_ci m = re.match(tp.ftrace_line_fmt, line) 32078c2ecf20Sopenharmony_ci if(not m): 32088c2ecf20Sopenharmony_ci continue 32098c2ecf20Sopenharmony_ci # gather the basic message data from the line 32108c2ecf20Sopenharmony_ci m_time = m.group('time') 32118c2ecf20Sopenharmony_ci m_proc = m.group('proc') 32128c2ecf20Sopenharmony_ci m_pid = m.group('pid') 32138c2ecf20Sopenharmony_ci m_msg = m.group('msg') 32148c2ecf20Sopenharmony_ci if(tp.cgformat): 32158c2ecf20Sopenharmony_ci m_param3 = m.group('dur') 32168c2ecf20Sopenharmony_ci else: 32178c2ecf20Sopenharmony_ci m_param3 = 'traceevent' 32188c2ecf20Sopenharmony_ci if(m_time and m_pid and m_msg): 32198c2ecf20Sopenharmony_ci t = FTraceLine(m_time, m_msg, m_param3) 32208c2ecf20Sopenharmony_ci pid = int(m_pid) 32218c2ecf20Sopenharmony_ci else: 32228c2ecf20Sopenharmony_ci continue 32238c2ecf20Sopenharmony_ci # the line should be a call, return, or event 32248c2ecf20Sopenharmony_ci if(not t.fcall and not t.freturn and not t.fevent): 32258c2ecf20Sopenharmony_ci continue 32268c2ecf20Sopenharmony_ci # find the start of suspend 32278c2ecf20Sopenharmony_ci if(t.startMarker()): 32288c2ecf20Sopenharmony_ci data, limbo = Data(len(testdata)), False 32298c2ecf20Sopenharmony_ci testdata.append(data) 32308c2ecf20Sopenharmony_ci testrun = TestRun(data) 32318c2ecf20Sopenharmony_ci testruns.append(testrun) 32328c2ecf20Sopenharmony_ci tp.parseStamp(data, sysvals) 32338c2ecf20Sopenharmony_ci data.setStart(t.time, t.name) 32348c2ecf20Sopenharmony_ci data.first_suspend_prepare = True 32358c2ecf20Sopenharmony_ci phase = data.setPhase('suspend_prepare', t.time, True) 32368c2ecf20Sopenharmony_ci continue 32378c2ecf20Sopenharmony_ci if(not data or limbo): 32388c2ecf20Sopenharmony_ci continue 32398c2ecf20Sopenharmony_ci # process cpu exec line 32408c2ecf20Sopenharmony_ci if t.type == 'tracing_mark_write': 32418c2ecf20Sopenharmony_ci m = re.match(tp.procexecfmt, t.name) 32428c2ecf20Sopenharmony_ci if(m): 32438c2ecf20Sopenharmony_ci proclist = dict() 32448c2ecf20Sopenharmony_ci for ps in m.group('ps').split(','): 32458c2ecf20Sopenharmony_ci val = ps.split() 32468c2ecf20Sopenharmony_ci if not val: 32478c2ecf20Sopenharmony_ci continue 32488c2ecf20Sopenharmony_ci name = val[0].replace('--', '-') 32498c2ecf20Sopenharmony_ci proclist[name] = int(val[1]) 32508c2ecf20Sopenharmony_ci data.pstl[t.time] = proclist 32518c2ecf20Sopenharmony_ci continue 32528c2ecf20Sopenharmony_ci # find the end of resume 32538c2ecf20Sopenharmony_ci if(t.endMarker()): 32548c2ecf20Sopenharmony_ci if data.tKernRes == 0: 32558c2ecf20Sopenharmony_ci data.tKernRes = t.time 32568c2ecf20Sopenharmony_ci data.handleEndMarker(t.time, t.name) 32578c2ecf20Sopenharmony_ci if(not sysvals.usetracemarkers): 32588c2ecf20Sopenharmony_ci # no trace markers? then quit and be sure to finish recording 32598c2ecf20Sopenharmony_ci # the event we used to trigger resume end 32608c2ecf20Sopenharmony_ci if('thaw_processes' in testrun.ttemp and len(testrun.ttemp['thaw_processes']) > 0): 32618c2ecf20Sopenharmony_ci # if an entry exists, assume this is its end 32628c2ecf20Sopenharmony_ci testrun.ttemp['thaw_processes'][-1]['end'] = t.time 32638c2ecf20Sopenharmony_ci limbo = True 32648c2ecf20Sopenharmony_ci continue 32658c2ecf20Sopenharmony_ci # trace event processing 32668c2ecf20Sopenharmony_ci if(t.fevent): 32678c2ecf20Sopenharmony_ci if(t.type == 'suspend_resume'): 32688c2ecf20Sopenharmony_ci # suspend_resume trace events have two types, begin and end 32698c2ecf20Sopenharmony_ci if(re.match('(?P<name>.*) begin$', t.name)): 32708c2ecf20Sopenharmony_ci isbegin = True 32718c2ecf20Sopenharmony_ci elif(re.match('(?P<name>.*) end$', t.name)): 32728c2ecf20Sopenharmony_ci isbegin = False 32738c2ecf20Sopenharmony_ci else: 32748c2ecf20Sopenharmony_ci continue 32758c2ecf20Sopenharmony_ci if '[' in t.name: 32768c2ecf20Sopenharmony_ci m = re.match('(?P<name>.*)\[.*', t.name) 32778c2ecf20Sopenharmony_ci else: 32788c2ecf20Sopenharmony_ci m = re.match('(?P<name>.*) .*', t.name) 32798c2ecf20Sopenharmony_ci name = m.group('name') 32808c2ecf20Sopenharmony_ci # ignore these events 32818c2ecf20Sopenharmony_ci if(name.split('[')[0] in tracewatch): 32828c2ecf20Sopenharmony_ci continue 32838c2ecf20Sopenharmony_ci # -- phase changes -- 32848c2ecf20Sopenharmony_ci # start of kernel suspend 32858c2ecf20Sopenharmony_ci if(re.match('suspend_enter\[.*', t.name)): 32868c2ecf20Sopenharmony_ci if(isbegin and data.tKernSus == 0): 32878c2ecf20Sopenharmony_ci data.tKernSus = t.time 32888c2ecf20Sopenharmony_ci continue 32898c2ecf20Sopenharmony_ci # suspend_prepare start 32908c2ecf20Sopenharmony_ci elif(re.match('dpm_prepare\[.*', t.name)): 32918c2ecf20Sopenharmony_ci if isbegin and data.first_suspend_prepare: 32928c2ecf20Sopenharmony_ci data.first_suspend_prepare = False 32938c2ecf20Sopenharmony_ci if data.tKernSus == 0: 32948c2ecf20Sopenharmony_ci data.tKernSus = t.time 32958c2ecf20Sopenharmony_ci continue 32968c2ecf20Sopenharmony_ci phase = data.setPhase('suspend_prepare', t.time, isbegin) 32978c2ecf20Sopenharmony_ci continue 32988c2ecf20Sopenharmony_ci # suspend start 32998c2ecf20Sopenharmony_ci elif(re.match('dpm_suspend\[.*', t.name)): 33008c2ecf20Sopenharmony_ci phase = data.setPhase('suspend', t.time, isbegin) 33018c2ecf20Sopenharmony_ci continue 33028c2ecf20Sopenharmony_ci # suspend_late start 33038c2ecf20Sopenharmony_ci elif(re.match('dpm_suspend_late\[.*', t.name)): 33048c2ecf20Sopenharmony_ci phase = data.setPhase('suspend_late', t.time, isbegin) 33058c2ecf20Sopenharmony_ci continue 33068c2ecf20Sopenharmony_ci # suspend_noirq start 33078c2ecf20Sopenharmony_ci elif(re.match('dpm_suspend_noirq\[.*', t.name)): 33088c2ecf20Sopenharmony_ci phase = data.setPhase('suspend_noirq', t.time, isbegin) 33098c2ecf20Sopenharmony_ci continue 33108c2ecf20Sopenharmony_ci # suspend_machine/resume_machine 33118c2ecf20Sopenharmony_ci elif(re.match(tp.machinesuspend, t.name)): 33128c2ecf20Sopenharmony_ci lp = data.lastPhase() 33138c2ecf20Sopenharmony_ci if(isbegin): 33148c2ecf20Sopenharmony_ci hwsus = True 33158c2ecf20Sopenharmony_ci if lp.startswith('resume_machine'): 33168c2ecf20Sopenharmony_ci # trim out s2idle loops, track time trying to freeze 33178c2ecf20Sopenharmony_ci llp = data.lastPhase(2) 33188c2ecf20Sopenharmony_ci if llp.startswith('suspend_machine'): 33198c2ecf20Sopenharmony_ci if 'trying' not in data.dmesg[llp]: 33208c2ecf20Sopenharmony_ci data.dmesg[llp]['trying'] = 0 33218c2ecf20Sopenharmony_ci data.dmesg[llp]['trying'] += \ 33228c2ecf20Sopenharmony_ci t.time - data.dmesg[lp]['start'] 33238c2ecf20Sopenharmony_ci data.currphase = '' 33248c2ecf20Sopenharmony_ci del data.dmesg[lp] 33258c2ecf20Sopenharmony_ci continue 33268c2ecf20Sopenharmony_ci phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True) 33278c2ecf20Sopenharmony_ci data.setPhase(phase, t.time, False) 33288c2ecf20Sopenharmony_ci if data.tSuspended == 0: 33298c2ecf20Sopenharmony_ci data.tSuspended = t.time 33308c2ecf20Sopenharmony_ci else: 33318c2ecf20Sopenharmony_ci if lp.startswith('resume_machine'): 33328c2ecf20Sopenharmony_ci data.dmesg[lp]['end'] = t.time 33338c2ecf20Sopenharmony_ci continue 33348c2ecf20Sopenharmony_ci phase = data.setPhase('resume_machine', t.time, True) 33358c2ecf20Sopenharmony_ci if(sysvals.suspendmode in ['mem', 'disk']): 33368c2ecf20Sopenharmony_ci susp = phase.replace('resume', 'suspend') 33378c2ecf20Sopenharmony_ci if susp in data.dmesg: 33388c2ecf20Sopenharmony_ci data.dmesg[susp]['end'] = t.time 33398c2ecf20Sopenharmony_ci data.tSuspended = t.time 33408c2ecf20Sopenharmony_ci data.tResumed = t.time 33418c2ecf20Sopenharmony_ci continue 33428c2ecf20Sopenharmony_ci # resume_noirq start 33438c2ecf20Sopenharmony_ci elif(re.match('dpm_resume_noirq\[.*', t.name)): 33448c2ecf20Sopenharmony_ci phase = data.setPhase('resume_noirq', t.time, isbegin) 33458c2ecf20Sopenharmony_ci continue 33468c2ecf20Sopenharmony_ci # resume_early start 33478c2ecf20Sopenharmony_ci elif(re.match('dpm_resume_early\[.*', t.name)): 33488c2ecf20Sopenharmony_ci phase = data.setPhase('resume_early', t.time, isbegin) 33498c2ecf20Sopenharmony_ci continue 33508c2ecf20Sopenharmony_ci # resume start 33518c2ecf20Sopenharmony_ci elif(re.match('dpm_resume\[.*', t.name)): 33528c2ecf20Sopenharmony_ci phase = data.setPhase('resume', t.time, isbegin) 33538c2ecf20Sopenharmony_ci continue 33548c2ecf20Sopenharmony_ci # resume complete start 33558c2ecf20Sopenharmony_ci elif(re.match('dpm_complete\[.*', t.name)): 33568c2ecf20Sopenharmony_ci phase = data.setPhase('resume_complete', t.time, isbegin) 33578c2ecf20Sopenharmony_ci continue 33588c2ecf20Sopenharmony_ci # skip trace events inside devices calls 33598c2ecf20Sopenharmony_ci if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)): 33608c2ecf20Sopenharmony_ci continue 33618c2ecf20Sopenharmony_ci # global events (outside device calls) are graphed 33628c2ecf20Sopenharmony_ci if(name not in testrun.ttemp): 33638c2ecf20Sopenharmony_ci testrun.ttemp[name] = [] 33648c2ecf20Sopenharmony_ci # special handling for s2idle_enter 33658c2ecf20Sopenharmony_ci if name == 'machine_suspend': 33668c2ecf20Sopenharmony_ci if hwsus: 33678c2ecf20Sopenharmony_ci s2idle_enter = hwsus = False 33688c2ecf20Sopenharmony_ci elif s2idle_enter and not isbegin: 33698c2ecf20Sopenharmony_ci if(len(testrun.ttemp[name]) > 0): 33708c2ecf20Sopenharmony_ci testrun.ttemp[name][-1]['end'] = t.time 33718c2ecf20Sopenharmony_ci testrun.ttemp[name][-1]['loop'] += 1 33728c2ecf20Sopenharmony_ci elif not s2idle_enter and isbegin: 33738c2ecf20Sopenharmony_ci s2idle_enter = True 33748c2ecf20Sopenharmony_ci testrun.ttemp[name].append({'begin': t.time, 33758c2ecf20Sopenharmony_ci 'end': t.time, 'pid': pid, 'loop': 0}) 33768c2ecf20Sopenharmony_ci continue 33778c2ecf20Sopenharmony_ci if(isbegin): 33788c2ecf20Sopenharmony_ci # create a new list entry 33798c2ecf20Sopenharmony_ci testrun.ttemp[name].append(\ 33808c2ecf20Sopenharmony_ci {'begin': t.time, 'end': t.time, 'pid': pid}) 33818c2ecf20Sopenharmony_ci else: 33828c2ecf20Sopenharmony_ci if(len(testrun.ttemp[name]) > 0): 33838c2ecf20Sopenharmony_ci # if an entry exists, assume this is its end 33848c2ecf20Sopenharmony_ci testrun.ttemp[name][-1]['end'] = t.time 33858c2ecf20Sopenharmony_ci # device callback start 33868c2ecf20Sopenharmony_ci elif(t.type == 'device_pm_callback_start'): 33878c2ecf20Sopenharmony_ci if phase not in data.dmesg: 33888c2ecf20Sopenharmony_ci continue 33898c2ecf20Sopenharmony_ci m = re.match('(?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*',\ 33908c2ecf20Sopenharmony_ci t.name); 33918c2ecf20Sopenharmony_ci if(not m): 33928c2ecf20Sopenharmony_ci continue 33938c2ecf20Sopenharmony_ci drv = m.group('drv') 33948c2ecf20Sopenharmony_ci n = m.group('d') 33958c2ecf20Sopenharmony_ci p = m.group('p') 33968c2ecf20Sopenharmony_ci if(n and p): 33978c2ecf20Sopenharmony_ci data.newAction(phase, n, pid, p, t.time, -1, drv) 33988c2ecf20Sopenharmony_ci if pid not in data.devpids: 33998c2ecf20Sopenharmony_ci data.devpids.append(pid) 34008c2ecf20Sopenharmony_ci # device callback finish 34018c2ecf20Sopenharmony_ci elif(t.type == 'device_pm_callback_end'): 34028c2ecf20Sopenharmony_ci if phase not in data.dmesg: 34038c2ecf20Sopenharmony_ci continue 34048c2ecf20Sopenharmony_ci m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name); 34058c2ecf20Sopenharmony_ci if(not m): 34068c2ecf20Sopenharmony_ci continue 34078c2ecf20Sopenharmony_ci n = m.group('d') 34088c2ecf20Sopenharmony_ci dev = data.findDevice(phase, n) 34098c2ecf20Sopenharmony_ci if dev: 34108c2ecf20Sopenharmony_ci dev['length'] = t.time - dev['start'] 34118c2ecf20Sopenharmony_ci dev['end'] = t.time 34128c2ecf20Sopenharmony_ci # kprobe event processing 34138c2ecf20Sopenharmony_ci elif(t.fkprobe): 34148c2ecf20Sopenharmony_ci kprobename = t.type 34158c2ecf20Sopenharmony_ci kprobedata = t.name 34168c2ecf20Sopenharmony_ci key = (kprobename, pid) 34178c2ecf20Sopenharmony_ci # displayname is generated from kprobe data 34188c2ecf20Sopenharmony_ci displayname = '' 34198c2ecf20Sopenharmony_ci if(t.fcall): 34208c2ecf20Sopenharmony_ci displayname = sysvals.kprobeDisplayName(kprobename, kprobedata) 34218c2ecf20Sopenharmony_ci if not displayname: 34228c2ecf20Sopenharmony_ci continue 34238c2ecf20Sopenharmony_ci if(key not in tp.ktemp): 34248c2ecf20Sopenharmony_ci tp.ktemp[key] = [] 34258c2ecf20Sopenharmony_ci tp.ktemp[key].append({ 34268c2ecf20Sopenharmony_ci 'pid': pid, 34278c2ecf20Sopenharmony_ci 'begin': t.time, 34288c2ecf20Sopenharmony_ci 'end': -1, 34298c2ecf20Sopenharmony_ci 'name': displayname, 34308c2ecf20Sopenharmony_ci 'cdata': kprobedata, 34318c2ecf20Sopenharmony_ci 'proc': m_proc, 34328c2ecf20Sopenharmony_ci }) 34338c2ecf20Sopenharmony_ci # start of kernel resume 34348c2ecf20Sopenharmony_ci if(data.tKernSus == 0 and phase == 'suspend_prepare' \ 34358c2ecf20Sopenharmony_ci and kprobename in ksuscalls): 34368c2ecf20Sopenharmony_ci data.tKernSus = t.time 34378c2ecf20Sopenharmony_ci elif(t.freturn): 34388c2ecf20Sopenharmony_ci if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1: 34398c2ecf20Sopenharmony_ci continue 34408c2ecf20Sopenharmony_ci e = next((x for x in reversed(tp.ktemp[key]) if x['end'] < 0), 0) 34418c2ecf20Sopenharmony_ci if not e: 34428c2ecf20Sopenharmony_ci continue 34438c2ecf20Sopenharmony_ci e['end'] = t.time 34448c2ecf20Sopenharmony_ci e['rdata'] = kprobedata 34458c2ecf20Sopenharmony_ci # end of kernel resume 34468c2ecf20Sopenharmony_ci if(phase != 'suspend_prepare' and kprobename in krescalls): 34478c2ecf20Sopenharmony_ci if phase in data.dmesg: 34488c2ecf20Sopenharmony_ci data.dmesg[phase]['end'] = t.time 34498c2ecf20Sopenharmony_ci data.tKernRes = t.time 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci # callgraph processing 34528c2ecf20Sopenharmony_ci elif sysvals.usecallgraph: 34538c2ecf20Sopenharmony_ci # create a callgraph object for the data 34548c2ecf20Sopenharmony_ci key = (m_proc, pid) 34558c2ecf20Sopenharmony_ci if(key not in testrun.ftemp): 34568c2ecf20Sopenharmony_ci testrun.ftemp[key] = [] 34578c2ecf20Sopenharmony_ci testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 34588c2ecf20Sopenharmony_ci # when the call is finished, see which device matches it 34598c2ecf20Sopenharmony_ci cg = testrun.ftemp[key][-1] 34608c2ecf20Sopenharmony_ci res = cg.addLine(t) 34618c2ecf20Sopenharmony_ci if(res != 0): 34628c2ecf20Sopenharmony_ci testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 34638c2ecf20Sopenharmony_ci if(res == -1): 34648c2ecf20Sopenharmony_ci testrun.ftemp[key][-1].addLine(t) 34658c2ecf20Sopenharmony_ci tf.close() 34668c2ecf20Sopenharmony_ci if len(testdata) < 1: 34678c2ecf20Sopenharmony_ci sysvals.vprint('WARNING: ftrace start marker is missing') 34688c2ecf20Sopenharmony_ci if data and not data.devicegroups: 34698c2ecf20Sopenharmony_ci sysvals.vprint('WARNING: ftrace end marker is missing') 34708c2ecf20Sopenharmony_ci data.handleEndMarker(t.time, t.name) 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci if sysvals.suspendmode == 'command': 34738c2ecf20Sopenharmony_ci for test in testruns: 34748c2ecf20Sopenharmony_ci for p in test.data.sortedPhases(): 34758c2ecf20Sopenharmony_ci if p == 'suspend_prepare': 34768c2ecf20Sopenharmony_ci test.data.dmesg[p]['start'] = test.data.start 34778c2ecf20Sopenharmony_ci test.data.dmesg[p]['end'] = test.data.end 34788c2ecf20Sopenharmony_ci else: 34798c2ecf20Sopenharmony_ci test.data.dmesg[p]['start'] = test.data.end 34808c2ecf20Sopenharmony_ci test.data.dmesg[p]['end'] = test.data.end 34818c2ecf20Sopenharmony_ci test.data.tSuspended = test.data.end 34828c2ecf20Sopenharmony_ci test.data.tResumed = test.data.end 34838c2ecf20Sopenharmony_ci test.data.fwValid = False 34848c2ecf20Sopenharmony_ci 34858c2ecf20Sopenharmony_ci # dev source and procmon events can be unreadable with mixed phase height 34868c2ecf20Sopenharmony_ci if sysvals.usedevsrc or sysvals.useprocmon: 34878c2ecf20Sopenharmony_ci sysvals.mixedphaseheight = False 34888c2ecf20Sopenharmony_ci 34898c2ecf20Sopenharmony_ci # expand phase boundaries so there are no gaps 34908c2ecf20Sopenharmony_ci for data in testdata: 34918c2ecf20Sopenharmony_ci lp = data.sortedPhases()[0] 34928c2ecf20Sopenharmony_ci for p in data.sortedPhases(): 34938c2ecf20Sopenharmony_ci if(p != lp and not ('machine' in p and 'machine' in lp)): 34948c2ecf20Sopenharmony_ci data.dmesg[lp]['end'] = data.dmesg[p]['start'] 34958c2ecf20Sopenharmony_ci lp = p 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci for i in range(len(testruns)): 34988c2ecf20Sopenharmony_ci test = testruns[i] 34998c2ecf20Sopenharmony_ci data = test.data 35008c2ecf20Sopenharmony_ci # find the total time range for this test (begin, end) 35018c2ecf20Sopenharmony_ci tlb, tle = data.start, data.end 35028c2ecf20Sopenharmony_ci if i < len(testruns) - 1: 35038c2ecf20Sopenharmony_ci tle = testruns[i+1].data.start 35048c2ecf20Sopenharmony_ci # add the process usage data to the timeline 35058c2ecf20Sopenharmony_ci if sysvals.useprocmon: 35068c2ecf20Sopenharmony_ci data.createProcessUsageEvents() 35078c2ecf20Sopenharmony_ci # add the traceevent data to the device hierarchy 35088c2ecf20Sopenharmony_ci if(sysvals.usetraceevents): 35098c2ecf20Sopenharmony_ci # add actual trace funcs 35108c2ecf20Sopenharmony_ci for name in sorted(test.ttemp): 35118c2ecf20Sopenharmony_ci for event in test.ttemp[name]: 35128c2ecf20Sopenharmony_ci if event['end'] - event['begin'] <= 0: 35138c2ecf20Sopenharmony_ci continue 35148c2ecf20Sopenharmony_ci title = name 35158c2ecf20Sopenharmony_ci if name == 'machine_suspend' and 'loop' in event: 35168c2ecf20Sopenharmony_ci title = 's2idle_enter_%dx' % event['loop'] 35178c2ecf20Sopenharmony_ci data.newActionGlobal(title, event['begin'], event['end'], event['pid']) 35188c2ecf20Sopenharmony_ci # add the kprobe based virtual tracefuncs as actual devices 35198c2ecf20Sopenharmony_ci for key in sorted(tp.ktemp): 35208c2ecf20Sopenharmony_ci name, pid = key 35218c2ecf20Sopenharmony_ci if name not in sysvals.tracefuncs: 35228c2ecf20Sopenharmony_ci continue 35238c2ecf20Sopenharmony_ci if pid not in data.devpids: 35248c2ecf20Sopenharmony_ci data.devpids.append(pid) 35258c2ecf20Sopenharmony_ci for e in tp.ktemp[key]: 35268c2ecf20Sopenharmony_ci kb, ke = e['begin'], e['end'] 35278c2ecf20Sopenharmony_ci if ke - kb < 0.000001 or tlb > kb or tle <= kb: 35288c2ecf20Sopenharmony_ci continue 35298c2ecf20Sopenharmony_ci color = sysvals.kprobeColor(name) 35308c2ecf20Sopenharmony_ci data.newActionGlobal(e['name'], kb, ke, pid, color) 35318c2ecf20Sopenharmony_ci # add config base kprobes and dev kprobes 35328c2ecf20Sopenharmony_ci if sysvals.usedevsrc: 35338c2ecf20Sopenharmony_ci for key in sorted(tp.ktemp): 35348c2ecf20Sopenharmony_ci name, pid = key 35358c2ecf20Sopenharmony_ci if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs: 35368c2ecf20Sopenharmony_ci continue 35378c2ecf20Sopenharmony_ci for e in tp.ktemp[key]: 35388c2ecf20Sopenharmony_ci kb, ke = e['begin'], e['end'] 35398c2ecf20Sopenharmony_ci if ke - kb < 0.000001 or tlb > kb or tle <= kb: 35408c2ecf20Sopenharmony_ci continue 35418c2ecf20Sopenharmony_ci data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb, 35428c2ecf20Sopenharmony_ci ke, e['cdata'], e['rdata']) 35438c2ecf20Sopenharmony_ci if sysvals.usecallgraph: 35448c2ecf20Sopenharmony_ci # add the callgraph data to the device hierarchy 35458c2ecf20Sopenharmony_ci sortlist = dict() 35468c2ecf20Sopenharmony_ci for key in sorted(test.ftemp): 35478c2ecf20Sopenharmony_ci proc, pid = key 35488c2ecf20Sopenharmony_ci for cg in test.ftemp[key]: 35498c2ecf20Sopenharmony_ci if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0): 35508c2ecf20Sopenharmony_ci continue 35518c2ecf20Sopenharmony_ci if(not cg.postProcess()): 35528c2ecf20Sopenharmony_ci id = 'task %s' % (pid) 35538c2ecf20Sopenharmony_ci sysvals.vprint('Sanity check failed for '+\ 35548c2ecf20Sopenharmony_ci id+', ignoring this callback') 35558c2ecf20Sopenharmony_ci continue 35568c2ecf20Sopenharmony_ci # match cg data to devices 35578c2ecf20Sopenharmony_ci devname = '' 35588c2ecf20Sopenharmony_ci if sysvals.suspendmode != 'command': 35598c2ecf20Sopenharmony_ci devname = cg.deviceMatch(pid, data) 35608c2ecf20Sopenharmony_ci if not devname: 35618c2ecf20Sopenharmony_ci sortkey = '%f%f%d' % (cg.start, cg.end, pid) 35628c2ecf20Sopenharmony_ci sortlist[sortkey] = cg 35638c2ecf20Sopenharmony_ci elif len(cg.list) > 1000000 and cg.name != sysvals.ftopfunc: 35648c2ecf20Sopenharmony_ci sysvals.vprint('WARNING: the callgraph for %s is massive (%d lines)' %\ 35658c2ecf20Sopenharmony_ci (devname, len(cg.list))) 35668c2ecf20Sopenharmony_ci # create blocks for orphan cg data 35678c2ecf20Sopenharmony_ci for sortkey in sorted(sortlist): 35688c2ecf20Sopenharmony_ci cg = sortlist[sortkey] 35698c2ecf20Sopenharmony_ci name = cg.name 35708c2ecf20Sopenharmony_ci if sysvals.isCallgraphFunc(name): 35718c2ecf20Sopenharmony_ci sysvals.vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name)) 35728c2ecf20Sopenharmony_ci cg.newActionFromFunction(data) 35738c2ecf20Sopenharmony_ci if sysvals.suspendmode == 'command': 35748c2ecf20Sopenharmony_ci return (testdata, '') 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci # fill in any missing phases 35778c2ecf20Sopenharmony_ci error = [] 35788c2ecf20Sopenharmony_ci for data in testdata: 35798c2ecf20Sopenharmony_ci tn = '' if len(testdata) == 1 else ('%d' % (data.testnumber + 1)) 35808c2ecf20Sopenharmony_ci terr = '' 35818c2ecf20Sopenharmony_ci phasedef = data.phasedef 35828c2ecf20Sopenharmony_ci lp = 'suspend_prepare' 35838c2ecf20Sopenharmony_ci for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 35848c2ecf20Sopenharmony_ci if p not in data.dmesg: 35858c2ecf20Sopenharmony_ci if not terr: 35868c2ecf20Sopenharmony_ci ph = p if 'machine' in p else lp 35878c2ecf20Sopenharmony_ci terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph) 35888c2ecf20Sopenharmony_ci pprint('TEST%s FAILED: %s' % (tn, terr)) 35898c2ecf20Sopenharmony_ci error.append(terr) 35908c2ecf20Sopenharmony_ci if data.tSuspended == 0: 35918c2ecf20Sopenharmony_ci data.tSuspended = data.dmesg[lp]['end'] 35928c2ecf20Sopenharmony_ci if data.tResumed == 0: 35938c2ecf20Sopenharmony_ci data.tResumed = data.dmesg[lp]['end'] 35948c2ecf20Sopenharmony_ci data.fwValid = False 35958c2ecf20Sopenharmony_ci sysvals.vprint('WARNING: phase "%s" is missing!' % p) 35968c2ecf20Sopenharmony_ci lp = p 35978c2ecf20Sopenharmony_ci if not terr and 'dev' in data.wifi and data.wifi['stat'] == 'timeout': 35988c2ecf20Sopenharmony_ci terr = '%s%s failed in wifi_resume <i>(%s %.0fs timeout)</i>' % \ 35998c2ecf20Sopenharmony_ci (sysvals.suspendmode, tn, data.wifi['dev'], data.wifi['time']) 36008c2ecf20Sopenharmony_ci error.append(terr) 36018c2ecf20Sopenharmony_ci if not terr and data.enterfail: 36028c2ecf20Sopenharmony_ci pprint('test%s FAILED: enter %s failed with %s' % (tn, sysvals.suspendmode, data.enterfail)) 36038c2ecf20Sopenharmony_ci terr = 'test%s failed to enter %s mode' % (tn, sysvals.suspendmode) 36048c2ecf20Sopenharmony_ci error.append(terr) 36058c2ecf20Sopenharmony_ci if data.tSuspended == 0: 36068c2ecf20Sopenharmony_ci data.tSuspended = data.tKernRes 36078c2ecf20Sopenharmony_ci if data.tResumed == 0: 36088c2ecf20Sopenharmony_ci data.tResumed = data.tSuspended 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci if(len(sysvals.devicefilter) > 0): 36118c2ecf20Sopenharmony_ci data.deviceFilter(sysvals.devicefilter) 36128c2ecf20Sopenharmony_ci data.fixupInitcallsThatDidntReturn() 36138c2ecf20Sopenharmony_ci if sysvals.usedevsrc: 36148c2ecf20Sopenharmony_ci data.optimizeDevSrc() 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci # x2: merge any overlapping devices between test runs 36178c2ecf20Sopenharmony_ci if sysvals.usedevsrc and len(testdata) > 1: 36188c2ecf20Sopenharmony_ci tc = len(testdata) 36198c2ecf20Sopenharmony_ci for i in range(tc - 1): 36208c2ecf20Sopenharmony_ci devlist = testdata[i].overflowDevices() 36218c2ecf20Sopenharmony_ci for j in range(i + 1, tc): 36228c2ecf20Sopenharmony_ci testdata[j].mergeOverlapDevices(devlist) 36238c2ecf20Sopenharmony_ci testdata[0].stitchTouchingThreads(testdata[1:]) 36248c2ecf20Sopenharmony_ci return (testdata, ', '.join(error)) 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_ci# Function: loadKernelLog 36278c2ecf20Sopenharmony_ci# Description: 36288c2ecf20Sopenharmony_ci# [deprecated for kernel 3.15.0 or newer] 36298c2ecf20Sopenharmony_ci# load the dmesg file into memory and fix up any ordering issues 36308c2ecf20Sopenharmony_ci# The dmesg filename is taken from sysvals 36318c2ecf20Sopenharmony_ci# Output: 36328c2ecf20Sopenharmony_ci# An array of empty Data objects with only their dmesgtext attributes set 36338c2ecf20Sopenharmony_cidef loadKernelLog(): 36348c2ecf20Sopenharmony_ci sysvals.vprint('Analyzing the dmesg data (%s)...' % \ 36358c2ecf20Sopenharmony_ci os.path.basename(sysvals.dmesgfile)) 36368c2ecf20Sopenharmony_ci if(os.path.exists(sysvals.dmesgfile) == False): 36378c2ecf20Sopenharmony_ci doError('%s does not exist' % sysvals.dmesgfile) 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci # there can be multiple test runs in a single file 36408c2ecf20Sopenharmony_ci tp = TestProps() 36418c2ecf20Sopenharmony_ci tp.stamp = datetime.now().strftime('# suspend-%m%d%y-%H%M%S localhost mem unknown') 36428c2ecf20Sopenharmony_ci testruns = [] 36438c2ecf20Sopenharmony_ci data = 0 36448c2ecf20Sopenharmony_ci lf = sysvals.openlog(sysvals.dmesgfile, 'r') 36458c2ecf20Sopenharmony_ci for line in lf: 36468c2ecf20Sopenharmony_ci line = line.replace('\r\n', '') 36478c2ecf20Sopenharmony_ci idx = line.find('[') 36488c2ecf20Sopenharmony_ci if idx > 1: 36498c2ecf20Sopenharmony_ci line = line[idx:] 36508c2ecf20Sopenharmony_ci if tp.stampInfo(line, sysvals): 36518c2ecf20Sopenharmony_ci continue 36528c2ecf20Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 36538c2ecf20Sopenharmony_ci if(not m): 36548c2ecf20Sopenharmony_ci continue 36558c2ecf20Sopenharmony_ci msg = m.group("msg") 36568c2ecf20Sopenharmony_ci if(re.match('PM: Syncing filesystems.*', msg)): 36578c2ecf20Sopenharmony_ci if(data): 36588c2ecf20Sopenharmony_ci testruns.append(data) 36598c2ecf20Sopenharmony_ci data = Data(len(testruns)) 36608c2ecf20Sopenharmony_ci tp.parseStamp(data, sysvals) 36618c2ecf20Sopenharmony_ci if(not data): 36628c2ecf20Sopenharmony_ci continue 36638c2ecf20Sopenharmony_ci m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg) 36648c2ecf20Sopenharmony_ci if(m): 36658c2ecf20Sopenharmony_ci sysvals.stamp['kernel'] = m.group('k') 36668c2ecf20Sopenharmony_ci m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg) 36678c2ecf20Sopenharmony_ci if(m): 36688c2ecf20Sopenharmony_ci sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m') 36698c2ecf20Sopenharmony_ci data.dmesgtext.append(line) 36708c2ecf20Sopenharmony_ci lf.close() 36718c2ecf20Sopenharmony_ci 36728c2ecf20Sopenharmony_ci if data: 36738c2ecf20Sopenharmony_ci testruns.append(data) 36748c2ecf20Sopenharmony_ci if len(testruns) < 1: 36758c2ecf20Sopenharmony_ci doError('dmesg log has no suspend/resume data: %s' \ 36768c2ecf20Sopenharmony_ci % sysvals.dmesgfile) 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci # fix lines with same timestamp/function with the call and return swapped 36798c2ecf20Sopenharmony_ci for data in testruns: 36808c2ecf20Sopenharmony_ci last = '' 36818c2ecf20Sopenharmony_ci for line in data.dmesgtext: 36828c2ecf20Sopenharmony_ci mc = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling '+\ 36838c2ecf20Sopenharmony_ci '(?P<f>.*)\+ @ .*, parent: .*', line) 36848c2ecf20Sopenharmony_ci mr = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\ 36858c2ecf20Sopenharmony_ci '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', last) 36868c2ecf20Sopenharmony_ci if(mc and mr and (mc.group('t') == mr.group('t')) and 36878c2ecf20Sopenharmony_ci (mc.group('f') == mr.group('f'))): 36888c2ecf20Sopenharmony_ci i = data.dmesgtext.index(last) 36898c2ecf20Sopenharmony_ci j = data.dmesgtext.index(line) 36908c2ecf20Sopenharmony_ci data.dmesgtext[i] = line 36918c2ecf20Sopenharmony_ci data.dmesgtext[j] = last 36928c2ecf20Sopenharmony_ci last = line 36938c2ecf20Sopenharmony_ci return testruns 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci# Function: parseKernelLog 36968c2ecf20Sopenharmony_ci# Description: 36978c2ecf20Sopenharmony_ci# [deprecated for kernel 3.15.0 or newer] 36988c2ecf20Sopenharmony_ci# Analyse a dmesg log output file generated from this app during 36998c2ecf20Sopenharmony_ci# the execution phase. Create a set of device structures in memory 37008c2ecf20Sopenharmony_ci# for subsequent formatting in the html output file 37018c2ecf20Sopenharmony_ci# This call is only for legacy support on kernels where the ftrace 37028c2ecf20Sopenharmony_ci# data lacks the suspend_resume or device_pm_callbacks trace events. 37038c2ecf20Sopenharmony_ci# Arguments: 37048c2ecf20Sopenharmony_ci# data: an empty Data object (with dmesgtext) obtained from loadKernelLog 37058c2ecf20Sopenharmony_ci# Output: 37068c2ecf20Sopenharmony_ci# The filled Data object 37078c2ecf20Sopenharmony_cidef parseKernelLog(data): 37088c2ecf20Sopenharmony_ci phase = 'suspend_runtime' 37098c2ecf20Sopenharmony_ci 37108c2ecf20Sopenharmony_ci if(data.fwValid): 37118c2ecf20Sopenharmony_ci sysvals.vprint('Firmware Suspend = %u ns, Firmware Resume = %u ns' % \ 37128c2ecf20Sopenharmony_ci (data.fwSuspend, data.fwResume)) 37138c2ecf20Sopenharmony_ci 37148c2ecf20Sopenharmony_ci # dmesg phase match table 37158c2ecf20Sopenharmony_ci dm = { 37168c2ecf20Sopenharmony_ci 'suspend_prepare': ['PM: Syncing filesystems.*'], 37178c2ecf20Sopenharmony_ci 'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*'], 37188c2ecf20Sopenharmony_ci 'suspend_late': ['PM: suspend of devices complete after.*'], 37198c2ecf20Sopenharmony_ci 'suspend_noirq': ['PM: late suspend of devices complete after.*'], 37208c2ecf20Sopenharmony_ci 'suspend_machine': ['PM: noirq suspend of devices complete after.*'], 37218c2ecf20Sopenharmony_ci 'resume_machine': ['ACPI: Low-level resume complete.*'], 37228c2ecf20Sopenharmony_ci 'resume_noirq': ['ACPI: Waking up from system sleep state.*'], 37238c2ecf20Sopenharmony_ci 'resume_early': ['PM: noirq resume of devices complete after.*'], 37248c2ecf20Sopenharmony_ci 'resume': ['PM: early resume of devices complete after.*'], 37258c2ecf20Sopenharmony_ci 'resume_complete': ['PM: resume of devices complete after.*'], 37268c2ecf20Sopenharmony_ci 'post_resume': ['.*Restarting tasks \.\.\..*'], 37278c2ecf20Sopenharmony_ci } 37288c2ecf20Sopenharmony_ci if(sysvals.suspendmode == 'standby'): 37298c2ecf20Sopenharmony_ci dm['resume_machine'] = ['PM: Restoring platform NVS memory'] 37308c2ecf20Sopenharmony_ci elif(sysvals.suspendmode == 'disk'): 37318c2ecf20Sopenharmony_ci dm['suspend_late'] = ['PM: freeze of devices complete after.*'] 37328c2ecf20Sopenharmony_ci dm['suspend_noirq'] = ['PM: late freeze of devices complete after.*'] 37338c2ecf20Sopenharmony_ci dm['suspend_machine'] = ['PM: noirq freeze of devices complete after.*'] 37348c2ecf20Sopenharmony_ci dm['resume_machine'] = ['PM: Restoring platform NVS memory'] 37358c2ecf20Sopenharmony_ci dm['resume_early'] = ['PM: noirq restore of devices complete after.*'] 37368c2ecf20Sopenharmony_ci dm['resume'] = ['PM: early restore of devices complete after.*'] 37378c2ecf20Sopenharmony_ci dm['resume_complete'] = ['PM: restore of devices complete after.*'] 37388c2ecf20Sopenharmony_ci elif(sysvals.suspendmode == 'freeze'): 37398c2ecf20Sopenharmony_ci dm['resume_machine'] = ['ACPI: resume from mwait'] 37408c2ecf20Sopenharmony_ci 37418c2ecf20Sopenharmony_ci # action table (expected events that occur and show up in dmesg) 37428c2ecf20Sopenharmony_ci at = { 37438c2ecf20Sopenharmony_ci 'sync_filesystems': { 37448c2ecf20Sopenharmony_ci 'smsg': 'PM: Syncing filesystems.*', 37458c2ecf20Sopenharmony_ci 'emsg': 'PM: Preparing system for mem sleep.*' }, 37468c2ecf20Sopenharmony_ci 'freeze_user_processes': { 37478c2ecf20Sopenharmony_ci 'smsg': 'Freezing user space processes .*', 37488c2ecf20Sopenharmony_ci 'emsg': 'Freezing remaining freezable tasks.*' }, 37498c2ecf20Sopenharmony_ci 'freeze_tasks': { 37508c2ecf20Sopenharmony_ci 'smsg': 'Freezing remaining freezable tasks.*', 37518c2ecf20Sopenharmony_ci 'emsg': 'PM: Entering (?P<mode>[a-z,A-Z]*) sleep.*' }, 37528c2ecf20Sopenharmony_ci 'ACPI prepare': { 37538c2ecf20Sopenharmony_ci 'smsg': 'ACPI: Preparing to enter system sleep state.*', 37548c2ecf20Sopenharmony_ci 'emsg': 'PM: Saving platform NVS memory.*' }, 37558c2ecf20Sopenharmony_ci 'PM vns': { 37568c2ecf20Sopenharmony_ci 'smsg': 'PM: Saving platform NVS memory.*', 37578c2ecf20Sopenharmony_ci 'emsg': 'Disabling non-boot CPUs .*' }, 37588c2ecf20Sopenharmony_ci } 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci t0 = -1.0 37618c2ecf20Sopenharmony_ci cpu_start = -1.0 37628c2ecf20Sopenharmony_ci prevktime = -1.0 37638c2ecf20Sopenharmony_ci actions = dict() 37648c2ecf20Sopenharmony_ci for line in data.dmesgtext: 37658c2ecf20Sopenharmony_ci # parse each dmesg line into the time and message 37668c2ecf20Sopenharmony_ci m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 37678c2ecf20Sopenharmony_ci if(m): 37688c2ecf20Sopenharmony_ci val = m.group('ktime') 37698c2ecf20Sopenharmony_ci try: 37708c2ecf20Sopenharmony_ci ktime = float(val) 37718c2ecf20Sopenharmony_ci except: 37728c2ecf20Sopenharmony_ci continue 37738c2ecf20Sopenharmony_ci msg = m.group('msg') 37748c2ecf20Sopenharmony_ci # initialize data start to first line time 37758c2ecf20Sopenharmony_ci if t0 < 0: 37768c2ecf20Sopenharmony_ci data.setStart(ktime) 37778c2ecf20Sopenharmony_ci t0 = ktime 37788c2ecf20Sopenharmony_ci else: 37798c2ecf20Sopenharmony_ci continue 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ci # check for a phase change line 37828c2ecf20Sopenharmony_ci phasechange = False 37838c2ecf20Sopenharmony_ci for p in dm: 37848c2ecf20Sopenharmony_ci for s in dm[p]: 37858c2ecf20Sopenharmony_ci if(re.match(s, msg)): 37868c2ecf20Sopenharmony_ci phasechange, phase = True, p 37878c2ecf20Sopenharmony_ci break 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci # hack for determining resume_machine end for freeze 37908c2ecf20Sopenharmony_ci if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \ 37918c2ecf20Sopenharmony_ci and phase == 'resume_machine' and \ 37928c2ecf20Sopenharmony_ci re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): 37938c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, False) 37948c2ecf20Sopenharmony_ci phase = 'resume_noirq' 37958c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 37968c2ecf20Sopenharmony_ci 37978c2ecf20Sopenharmony_ci if phasechange: 37988c2ecf20Sopenharmony_ci if phase == 'suspend_prepare': 37998c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 38008c2ecf20Sopenharmony_ci data.setStart(ktime) 38018c2ecf20Sopenharmony_ci data.tKernSus = ktime 38028c2ecf20Sopenharmony_ci elif phase == 'suspend': 38038c2ecf20Sopenharmony_ci lp = data.lastPhase() 38048c2ecf20Sopenharmony_ci if lp: 38058c2ecf20Sopenharmony_ci data.setPhase(lp, ktime, False) 38068c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 38078c2ecf20Sopenharmony_ci elif phase == 'suspend_late': 38088c2ecf20Sopenharmony_ci lp = data.lastPhase() 38098c2ecf20Sopenharmony_ci if lp: 38108c2ecf20Sopenharmony_ci data.setPhase(lp, ktime, False) 38118c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 38128c2ecf20Sopenharmony_ci elif phase == 'suspend_noirq': 38138c2ecf20Sopenharmony_ci lp = data.lastPhase() 38148c2ecf20Sopenharmony_ci if lp: 38158c2ecf20Sopenharmony_ci data.setPhase(lp, ktime, False) 38168c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 38178c2ecf20Sopenharmony_ci elif phase == 'suspend_machine': 38188c2ecf20Sopenharmony_ci lp = data.lastPhase() 38198c2ecf20Sopenharmony_ci if lp: 38208c2ecf20Sopenharmony_ci data.setPhase(lp, ktime, False) 38218c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 38228c2ecf20Sopenharmony_ci elif phase == 'resume_machine': 38238c2ecf20Sopenharmony_ci lp = data.lastPhase() 38248c2ecf20Sopenharmony_ci if(sysvals.suspendmode in ['freeze', 'standby']): 38258c2ecf20Sopenharmony_ci data.tSuspended = prevktime 38268c2ecf20Sopenharmony_ci if lp: 38278c2ecf20Sopenharmony_ci data.setPhase(lp, prevktime, False) 38288c2ecf20Sopenharmony_ci else: 38298c2ecf20Sopenharmony_ci data.tSuspended = ktime 38308c2ecf20Sopenharmony_ci if lp: 38318c2ecf20Sopenharmony_ci data.setPhase(lp, prevktime, False) 38328c2ecf20Sopenharmony_ci data.tResumed = ktime 38338c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 38348c2ecf20Sopenharmony_ci elif phase == 'resume_noirq': 38358c2ecf20Sopenharmony_ci lp = data.lastPhase() 38368c2ecf20Sopenharmony_ci if lp: 38378c2ecf20Sopenharmony_ci data.setPhase(lp, ktime, False) 38388c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 38398c2ecf20Sopenharmony_ci elif phase == 'resume_early': 38408c2ecf20Sopenharmony_ci lp = data.lastPhase() 38418c2ecf20Sopenharmony_ci if lp: 38428c2ecf20Sopenharmony_ci data.setPhase(lp, ktime, False) 38438c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 38448c2ecf20Sopenharmony_ci elif phase == 'resume': 38458c2ecf20Sopenharmony_ci lp = data.lastPhase() 38468c2ecf20Sopenharmony_ci if lp: 38478c2ecf20Sopenharmony_ci data.setPhase(lp, ktime, False) 38488c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 38498c2ecf20Sopenharmony_ci elif phase == 'resume_complete': 38508c2ecf20Sopenharmony_ci lp = data.lastPhase() 38518c2ecf20Sopenharmony_ci if lp: 38528c2ecf20Sopenharmony_ci data.setPhase(lp, ktime, False) 38538c2ecf20Sopenharmony_ci data.setPhase(phase, ktime, True) 38548c2ecf20Sopenharmony_ci elif phase == 'post_resume': 38558c2ecf20Sopenharmony_ci lp = data.lastPhase() 38568c2ecf20Sopenharmony_ci if lp: 38578c2ecf20Sopenharmony_ci data.setPhase(lp, ktime, False) 38588c2ecf20Sopenharmony_ci data.setEnd(ktime) 38598c2ecf20Sopenharmony_ci data.tKernRes = ktime 38608c2ecf20Sopenharmony_ci break 38618c2ecf20Sopenharmony_ci 38628c2ecf20Sopenharmony_ci # -- device callbacks -- 38638c2ecf20Sopenharmony_ci if(phase in data.sortedPhases()): 38648c2ecf20Sopenharmony_ci # device init call 38658c2ecf20Sopenharmony_ci if(re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): 38668c2ecf20Sopenharmony_ci sm = re.match('calling (?P<f>.*)\+ @ '+\ 38678c2ecf20Sopenharmony_ci '(?P<n>.*), parent: (?P<p>.*)', msg); 38688c2ecf20Sopenharmony_ci f = sm.group('f') 38698c2ecf20Sopenharmony_ci n = sm.group('n') 38708c2ecf20Sopenharmony_ci p = sm.group('p') 38718c2ecf20Sopenharmony_ci if(f and n and p): 38728c2ecf20Sopenharmony_ci data.newAction(phase, f, int(n), p, ktime, -1, '') 38738c2ecf20Sopenharmony_ci # device init return 38748c2ecf20Sopenharmony_ci elif(re.match('call (?P<f>.*)\+ returned .* after '+\ 38758c2ecf20Sopenharmony_ci '(?P<t>.*) usecs', msg)): 38768c2ecf20Sopenharmony_ci sm = re.match('call (?P<f>.*)\+ returned .* after '+\ 38778c2ecf20Sopenharmony_ci '(?P<t>.*) usecs(?P<a>.*)', msg); 38788c2ecf20Sopenharmony_ci f = sm.group('f') 38798c2ecf20Sopenharmony_ci t = sm.group('t') 38808c2ecf20Sopenharmony_ci list = data.dmesg[phase]['list'] 38818c2ecf20Sopenharmony_ci if(f in list): 38828c2ecf20Sopenharmony_ci dev = list[f] 38838c2ecf20Sopenharmony_ci dev['length'] = int(t) 38848c2ecf20Sopenharmony_ci dev['end'] = ktime 38858c2ecf20Sopenharmony_ci 38868c2ecf20Sopenharmony_ci # if trace events are not available, these are better than nothing 38878c2ecf20Sopenharmony_ci if(not sysvals.usetraceevents): 38888c2ecf20Sopenharmony_ci # look for known actions 38898c2ecf20Sopenharmony_ci for a in sorted(at): 38908c2ecf20Sopenharmony_ci if(re.match(at[a]['smsg'], msg)): 38918c2ecf20Sopenharmony_ci if(a not in actions): 38928c2ecf20Sopenharmony_ci actions[a] = [] 38938c2ecf20Sopenharmony_ci actions[a].append({'begin': ktime, 'end': ktime}) 38948c2ecf20Sopenharmony_ci if(re.match(at[a]['emsg'], msg)): 38958c2ecf20Sopenharmony_ci if(a in actions): 38968c2ecf20Sopenharmony_ci actions[a][-1]['end'] = ktime 38978c2ecf20Sopenharmony_ci # now look for CPU on/off events 38988c2ecf20Sopenharmony_ci if(re.match('Disabling non-boot CPUs .*', msg)): 38998c2ecf20Sopenharmony_ci # start of first cpu suspend 39008c2ecf20Sopenharmony_ci cpu_start = ktime 39018c2ecf20Sopenharmony_ci elif(re.match('Enabling non-boot CPUs .*', msg)): 39028c2ecf20Sopenharmony_ci # start of first cpu resume 39038c2ecf20Sopenharmony_ci cpu_start = ktime 39048c2ecf20Sopenharmony_ci elif(re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg)): 39058c2ecf20Sopenharmony_ci # end of a cpu suspend, start of the next 39068c2ecf20Sopenharmony_ci m = re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg) 39078c2ecf20Sopenharmony_ci cpu = 'CPU'+m.group('cpu') 39088c2ecf20Sopenharmony_ci if(cpu not in actions): 39098c2ecf20Sopenharmony_ci actions[cpu] = [] 39108c2ecf20Sopenharmony_ci actions[cpu].append({'begin': cpu_start, 'end': ktime}) 39118c2ecf20Sopenharmony_ci cpu_start = ktime 39128c2ecf20Sopenharmony_ci elif(re.match('CPU(?P<cpu>[0-9]*) is up', msg)): 39138c2ecf20Sopenharmony_ci # end of a cpu resume, start of the next 39148c2ecf20Sopenharmony_ci m = re.match('CPU(?P<cpu>[0-9]*) is up', msg) 39158c2ecf20Sopenharmony_ci cpu = 'CPU'+m.group('cpu') 39168c2ecf20Sopenharmony_ci if(cpu not in actions): 39178c2ecf20Sopenharmony_ci actions[cpu] = [] 39188c2ecf20Sopenharmony_ci actions[cpu].append({'begin': cpu_start, 'end': ktime}) 39198c2ecf20Sopenharmony_ci cpu_start = ktime 39208c2ecf20Sopenharmony_ci prevktime = ktime 39218c2ecf20Sopenharmony_ci data.initDevicegroups() 39228c2ecf20Sopenharmony_ci 39238c2ecf20Sopenharmony_ci # fill in any missing phases 39248c2ecf20Sopenharmony_ci phasedef = data.phasedef 39258c2ecf20Sopenharmony_ci terr, lp = '', 'suspend_prepare' 39268c2ecf20Sopenharmony_ci for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 39278c2ecf20Sopenharmony_ci if p not in data.dmesg: 39288c2ecf20Sopenharmony_ci if not terr: 39298c2ecf20Sopenharmony_ci pprint('TEST FAILED: %s failed in %s phase' % (sysvals.suspendmode, lp)) 39308c2ecf20Sopenharmony_ci terr = '%s failed in %s phase' % (sysvals.suspendmode, lp) 39318c2ecf20Sopenharmony_ci if data.tSuspended == 0: 39328c2ecf20Sopenharmony_ci data.tSuspended = data.dmesg[lp]['end'] 39338c2ecf20Sopenharmony_ci if data.tResumed == 0: 39348c2ecf20Sopenharmony_ci data.tResumed = data.dmesg[lp]['end'] 39358c2ecf20Sopenharmony_ci sysvals.vprint('WARNING: phase "%s" is missing!' % p) 39368c2ecf20Sopenharmony_ci lp = p 39378c2ecf20Sopenharmony_ci lp = data.sortedPhases()[0] 39388c2ecf20Sopenharmony_ci for p in data.sortedPhases(): 39398c2ecf20Sopenharmony_ci if(p != lp and not ('machine' in p and 'machine' in lp)): 39408c2ecf20Sopenharmony_ci data.dmesg[lp]['end'] = data.dmesg[p]['start'] 39418c2ecf20Sopenharmony_ci lp = p 39428c2ecf20Sopenharmony_ci if data.tSuspended == 0: 39438c2ecf20Sopenharmony_ci data.tSuspended = data.tKernRes 39448c2ecf20Sopenharmony_ci if data.tResumed == 0: 39458c2ecf20Sopenharmony_ci data.tResumed = data.tSuspended 39468c2ecf20Sopenharmony_ci 39478c2ecf20Sopenharmony_ci # fill in any actions we've found 39488c2ecf20Sopenharmony_ci for name in sorted(actions): 39498c2ecf20Sopenharmony_ci for event in actions[name]: 39508c2ecf20Sopenharmony_ci data.newActionGlobal(name, event['begin'], event['end']) 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci if(len(sysvals.devicefilter) > 0): 39538c2ecf20Sopenharmony_ci data.deviceFilter(sysvals.devicefilter) 39548c2ecf20Sopenharmony_ci data.fixupInitcallsThatDidntReturn() 39558c2ecf20Sopenharmony_ci return True 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_cidef callgraphHTML(sv, hf, num, cg, title, color, devid): 39588c2ecf20Sopenharmony_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' 39598c2ecf20Sopenharmony_ci html_func_start = '<article>\n<input type="checkbox" class="pf" id="f{0}" checked/><label for="f{0}">{1} {2}</label>\n' 39608c2ecf20Sopenharmony_ci html_func_end = '</article>\n' 39618c2ecf20Sopenharmony_ci html_func_leaf = '<article>{0} {1}</article>\n' 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci cgid = devid 39648c2ecf20Sopenharmony_ci if cg.id: 39658c2ecf20Sopenharmony_ci cgid += cg.id 39668c2ecf20Sopenharmony_ci cglen = (cg.end - cg.start) * 1000 39678c2ecf20Sopenharmony_ci if cglen < sv.mincglen: 39688c2ecf20Sopenharmony_ci return num 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci fmt = '<r>(%.3f ms @ '+sv.timeformat+' to '+sv.timeformat+')</r>' 39718c2ecf20Sopenharmony_ci flen = fmt % (cglen, cg.start, cg.end) 39728c2ecf20Sopenharmony_ci hf.write(html_func_top.format(cgid, color, num, title, flen)) 39738c2ecf20Sopenharmony_ci num += 1 39748c2ecf20Sopenharmony_ci for line in cg.list: 39758c2ecf20Sopenharmony_ci if(line.length < 0.000000001): 39768c2ecf20Sopenharmony_ci flen = '' 39778c2ecf20Sopenharmony_ci else: 39788c2ecf20Sopenharmony_ci fmt = '<n>(%.3f ms @ '+sv.timeformat+')</n>' 39798c2ecf20Sopenharmony_ci flen = fmt % (line.length*1000, line.time) 39808c2ecf20Sopenharmony_ci if line.isLeaf(): 39818c2ecf20Sopenharmony_ci hf.write(html_func_leaf.format(line.name, flen)) 39828c2ecf20Sopenharmony_ci elif line.freturn: 39838c2ecf20Sopenharmony_ci hf.write(html_func_end) 39848c2ecf20Sopenharmony_ci else: 39858c2ecf20Sopenharmony_ci hf.write(html_func_start.format(num, line.name, flen)) 39868c2ecf20Sopenharmony_ci num += 1 39878c2ecf20Sopenharmony_ci hf.write(html_func_end) 39888c2ecf20Sopenharmony_ci return num 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_cidef addCallgraphs(sv, hf, data): 39918c2ecf20Sopenharmony_ci hf.write('<section id="callgraphs" class="callgraph">\n') 39928c2ecf20Sopenharmony_ci # write out the ftrace data converted to html 39938c2ecf20Sopenharmony_ci num = 0 39948c2ecf20Sopenharmony_ci for p in data.sortedPhases(): 39958c2ecf20Sopenharmony_ci if sv.cgphase and p != sv.cgphase: 39968c2ecf20Sopenharmony_ci continue 39978c2ecf20Sopenharmony_ci list = data.dmesg[p]['list'] 39988c2ecf20Sopenharmony_ci for d in data.sortedDevices(p): 39998c2ecf20Sopenharmony_ci if len(sv.cgfilter) > 0 and d not in sv.cgfilter: 40008c2ecf20Sopenharmony_ci continue 40018c2ecf20Sopenharmony_ci dev = list[d] 40028c2ecf20Sopenharmony_ci color = 'white' 40038c2ecf20Sopenharmony_ci if 'color' in data.dmesg[p]: 40048c2ecf20Sopenharmony_ci color = data.dmesg[p]['color'] 40058c2ecf20Sopenharmony_ci if 'color' in dev: 40068c2ecf20Sopenharmony_ci color = dev['color'] 40078c2ecf20Sopenharmony_ci name = d if '[' not in d else d.split('[')[0] 40088c2ecf20Sopenharmony_ci if(d in sv.devprops): 40098c2ecf20Sopenharmony_ci name = sv.devprops[d].altName(d) 40108c2ecf20Sopenharmony_ci if 'drv' in dev and dev['drv']: 40118c2ecf20Sopenharmony_ci name += ' {%s}' % dev['drv'] 40128c2ecf20Sopenharmony_ci if sv.suspendmode in suspendmodename: 40138c2ecf20Sopenharmony_ci name += ' '+p 40148c2ecf20Sopenharmony_ci if('ftrace' in dev): 40158c2ecf20Sopenharmony_ci cg = dev['ftrace'] 40168c2ecf20Sopenharmony_ci if cg.name == sv.ftopfunc: 40178c2ecf20Sopenharmony_ci name = 'top level suspend/resume call' 40188c2ecf20Sopenharmony_ci num = callgraphHTML(sv, hf, num, cg, 40198c2ecf20Sopenharmony_ci name, color, dev['id']) 40208c2ecf20Sopenharmony_ci if('ftraces' in dev): 40218c2ecf20Sopenharmony_ci for cg in dev['ftraces']: 40228c2ecf20Sopenharmony_ci num = callgraphHTML(sv, hf, num, cg, 40238c2ecf20Sopenharmony_ci name+' → '+cg.name, color, dev['id']) 40248c2ecf20Sopenharmony_ci hf.write('\n\n </section>\n') 40258c2ecf20Sopenharmony_ci 40268c2ecf20Sopenharmony_cidef summaryCSS(title, center=True): 40278c2ecf20Sopenharmony_ci tdcenter = 'text-align:center;' if center else '' 40288c2ecf20Sopenharmony_ci out = '<!DOCTYPE html>\n<html>\n<head>\n\ 40298c2ecf20Sopenharmony_ci <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 40308c2ecf20Sopenharmony_ci <title>'+title+'</title>\n\ 40318c2ecf20Sopenharmony_ci <style type=\'text/css\'>\n\ 40328c2ecf20Sopenharmony_ci .stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\ 40338c2ecf20Sopenharmony_ci table {width:100%;border-collapse: collapse;border:1px solid;}\n\ 40348c2ecf20Sopenharmony_ci th {border: 1px solid black;background:#222;color:white;}\n\ 40358c2ecf20Sopenharmony_ci td {font: 14px "Times New Roman";'+tdcenter+'}\n\ 40368c2ecf20Sopenharmony_ci tr.head td {border: 1px solid black;background:#aaa;}\n\ 40378c2ecf20Sopenharmony_ci tr.alt {background-color:#ddd;}\n\ 40388c2ecf20Sopenharmony_ci tr.notice {color:red;}\n\ 40398c2ecf20Sopenharmony_ci .minval {background-color:#BBFFBB;}\n\ 40408c2ecf20Sopenharmony_ci .medval {background-color:#BBBBFF;}\n\ 40418c2ecf20Sopenharmony_ci .maxval {background-color:#FFBBBB;}\n\ 40428c2ecf20Sopenharmony_ci .head a {color:#000;text-decoration: none;}\n\ 40438c2ecf20Sopenharmony_ci </style>\n</head>\n<body>\n' 40448c2ecf20Sopenharmony_ci return out 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_ci# Function: createHTMLSummarySimple 40478c2ecf20Sopenharmony_ci# Description: 40488c2ecf20Sopenharmony_ci# Create summary html file for a series of tests 40498c2ecf20Sopenharmony_ci# Arguments: 40508c2ecf20Sopenharmony_ci# testruns: array of Data objects from parseTraceLog 40518c2ecf20Sopenharmony_cidef createHTMLSummarySimple(testruns, htmlfile, title): 40528c2ecf20Sopenharmony_ci # write the html header first (html head, css code, up to body start) 40538c2ecf20Sopenharmony_ci html = summaryCSS('Summary - SleepGraph') 40548c2ecf20Sopenharmony_ci 40558c2ecf20Sopenharmony_ci # extract the test data into list 40568c2ecf20Sopenharmony_ci list = dict() 40578c2ecf20Sopenharmony_ci tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 40588c2ecf20Sopenharmony_ci iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 40598c2ecf20Sopenharmony_ci num = 0 40608c2ecf20Sopenharmony_ci useturbo = usewifi = False 40618c2ecf20Sopenharmony_ci lastmode = '' 40628c2ecf20Sopenharmony_ci cnt = dict() 40638c2ecf20Sopenharmony_ci for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])): 40648c2ecf20Sopenharmony_ci mode = data['mode'] 40658c2ecf20Sopenharmony_ci if mode not in list: 40668c2ecf20Sopenharmony_ci list[mode] = {'data': [], 'avg': [0,0], 'min': [0,0], 'max': [0,0], 'med': [0,0]} 40678c2ecf20Sopenharmony_ci if lastmode and lastmode != mode and num > 0: 40688c2ecf20Sopenharmony_ci for i in range(2): 40698c2ecf20Sopenharmony_ci s = sorted(tMed[i]) 40708c2ecf20Sopenharmony_ci list[lastmode]['med'][i] = s[int(len(s)//2)] 40718c2ecf20Sopenharmony_ci iMed[i] = tMed[i][list[lastmode]['med'][i]] 40728c2ecf20Sopenharmony_ci list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 40738c2ecf20Sopenharmony_ci list[lastmode]['min'] = tMin 40748c2ecf20Sopenharmony_ci list[lastmode]['max'] = tMax 40758c2ecf20Sopenharmony_ci list[lastmode]['idx'] = (iMin, iMed, iMax) 40768c2ecf20Sopenharmony_ci tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 40778c2ecf20Sopenharmony_ci iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 40788c2ecf20Sopenharmony_ci num = 0 40798c2ecf20Sopenharmony_ci pkgpc10 = syslpi = wifi = '' 40808c2ecf20Sopenharmony_ci if 'pkgpc10' in data and 'syslpi' in data: 40818c2ecf20Sopenharmony_ci pkgpc10, syslpi, useturbo = data['pkgpc10'], data['syslpi'], True 40828c2ecf20Sopenharmony_ci if 'wifi' in data: 40838c2ecf20Sopenharmony_ci wifi, usewifi = data['wifi'], True 40848c2ecf20Sopenharmony_ci res = data['result'] 40858c2ecf20Sopenharmony_ci tVal = [float(data['suspend']), float(data['resume'])] 40868c2ecf20Sopenharmony_ci list[mode]['data'].append([data['host'], data['kernel'], 40878c2ecf20Sopenharmony_ci data['time'], tVal[0], tVal[1], data['url'], res, 40888c2ecf20Sopenharmony_ci data['issues'], data['sus_worst'], data['sus_worsttime'], 40898c2ecf20Sopenharmony_ci data['res_worst'], data['res_worsttime'], pkgpc10, syslpi, wifi]) 40908c2ecf20Sopenharmony_ci idx = len(list[mode]['data']) - 1 40918c2ecf20Sopenharmony_ci if res.startswith('fail in'): 40928c2ecf20Sopenharmony_ci res = 'fail' 40938c2ecf20Sopenharmony_ci if res not in cnt: 40948c2ecf20Sopenharmony_ci cnt[res] = 1 40958c2ecf20Sopenharmony_ci else: 40968c2ecf20Sopenharmony_ci cnt[res] += 1 40978c2ecf20Sopenharmony_ci if res == 'pass': 40988c2ecf20Sopenharmony_ci for i in range(2): 40998c2ecf20Sopenharmony_ci tMed[i][tVal[i]] = idx 41008c2ecf20Sopenharmony_ci tAvg[i] += tVal[i] 41018c2ecf20Sopenharmony_ci if tMin[i] == 0 or tVal[i] < tMin[i]: 41028c2ecf20Sopenharmony_ci iMin[i] = idx 41038c2ecf20Sopenharmony_ci tMin[i] = tVal[i] 41048c2ecf20Sopenharmony_ci if tMax[i] == 0 or tVal[i] > tMax[i]: 41058c2ecf20Sopenharmony_ci iMax[i] = idx 41068c2ecf20Sopenharmony_ci tMax[i] = tVal[i] 41078c2ecf20Sopenharmony_ci num += 1 41088c2ecf20Sopenharmony_ci lastmode = mode 41098c2ecf20Sopenharmony_ci if lastmode and num > 0: 41108c2ecf20Sopenharmony_ci for i in range(2): 41118c2ecf20Sopenharmony_ci s = sorted(tMed[i]) 41128c2ecf20Sopenharmony_ci list[lastmode]['med'][i] = s[int(len(s)//2)] 41138c2ecf20Sopenharmony_ci iMed[i] = tMed[i][list[lastmode]['med'][i]] 41148c2ecf20Sopenharmony_ci list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 41158c2ecf20Sopenharmony_ci list[lastmode]['min'] = tMin 41168c2ecf20Sopenharmony_ci list[lastmode]['max'] = tMax 41178c2ecf20Sopenharmony_ci list[lastmode]['idx'] = (iMin, iMed, iMax) 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_ci # group test header 41208c2ecf20Sopenharmony_ci desc = [] 41218c2ecf20Sopenharmony_ci for ilk in sorted(cnt, reverse=True): 41228c2ecf20Sopenharmony_ci if cnt[ilk] > 0: 41238c2ecf20Sopenharmony_ci desc.append('%d %s' % (cnt[ilk], ilk)) 41248c2ecf20Sopenharmony_ci html += '<div class="stamp">%s (%d tests: %s)</div>\n' % (title, len(testruns), ', '.join(desc)) 41258c2ecf20Sopenharmony_ci th = '\t<th>{0}</th>\n' 41268c2ecf20Sopenharmony_ci td = '\t<td>{0}</td>\n' 41278c2ecf20Sopenharmony_ci tdh = '\t<td{1}>{0}</td>\n' 41288c2ecf20Sopenharmony_ci tdlink = '\t<td><a href="{0}">html</a></td>\n' 41298c2ecf20Sopenharmony_ci cols = 12 41308c2ecf20Sopenharmony_ci if useturbo: 41318c2ecf20Sopenharmony_ci cols += 2 41328c2ecf20Sopenharmony_ci if usewifi: 41338c2ecf20Sopenharmony_ci cols += 1 41348c2ecf20Sopenharmony_ci colspan = '%d' % cols 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ci # table header 41378c2ecf20Sopenharmony_ci html += '<table>\n<tr>\n' + th.format('#') +\ 41388c2ecf20Sopenharmony_ci th.format('Mode') + th.format('Host') + th.format('Kernel') +\ 41398c2ecf20Sopenharmony_ci th.format('Test Time') + th.format('Result') + th.format('Issues') +\ 41408c2ecf20Sopenharmony_ci th.format('Suspend') + th.format('Resume') +\ 41418c2ecf20Sopenharmony_ci th.format('Worst Suspend Device') + th.format('SD Time') +\ 41428c2ecf20Sopenharmony_ci th.format('Worst Resume Device') + th.format('RD Time') 41438c2ecf20Sopenharmony_ci if useturbo: 41448c2ecf20Sopenharmony_ci html += th.format('PkgPC10') + th.format('SysLPI') 41458c2ecf20Sopenharmony_ci if usewifi: 41468c2ecf20Sopenharmony_ci html += th.format('Wifi') 41478c2ecf20Sopenharmony_ci html += th.format('Detail')+'</tr>\n' 41488c2ecf20Sopenharmony_ci # export list into html 41498c2ecf20Sopenharmony_ci head = '<tr class="head"><td>{0}</td><td>{1}</td>'+\ 41508c2ecf20Sopenharmony_ci '<td colspan='+colspan+' class="sus">Suspend Avg={2} '+\ 41518c2ecf20Sopenharmony_ci '<span class=minval><a href="#s{10}min">Min={3}</a></span> '+\ 41528c2ecf20Sopenharmony_ci '<span class=medval><a href="#s{10}med">Med={4}</a></span> '+\ 41538c2ecf20Sopenharmony_ci '<span class=maxval><a href="#s{10}max">Max={5}</a></span> '+\ 41548c2ecf20Sopenharmony_ci 'Resume Avg={6} '+\ 41558c2ecf20Sopenharmony_ci '<span class=minval><a href="#r{10}min">Min={7}</a></span> '+\ 41568c2ecf20Sopenharmony_ci '<span class=medval><a href="#r{10}med">Med={8}</a></span> '+\ 41578c2ecf20Sopenharmony_ci '<span class=maxval><a href="#r{10}max">Max={9}</a></span></td>'+\ 41588c2ecf20Sopenharmony_ci '</tr>\n' 41598c2ecf20Sopenharmony_ci headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan='+\ 41608c2ecf20Sopenharmony_ci colspan+'></td></tr>\n' 41618c2ecf20Sopenharmony_ci for mode in sorted(list): 41628c2ecf20Sopenharmony_ci # header line for each suspend mode 41638c2ecf20Sopenharmony_ci num = 0 41648c2ecf20Sopenharmony_ci tAvg, tMin, tMax, tMed = list[mode]['avg'], list[mode]['min'],\ 41658c2ecf20Sopenharmony_ci list[mode]['max'], list[mode]['med'] 41668c2ecf20Sopenharmony_ci count = len(list[mode]['data']) 41678c2ecf20Sopenharmony_ci if 'idx' in list[mode]: 41688c2ecf20Sopenharmony_ci iMin, iMed, iMax = list[mode]['idx'] 41698c2ecf20Sopenharmony_ci html += head.format('%d' % count, mode.upper(), 41708c2ecf20Sopenharmony_ci '%.3f' % tAvg[0], '%.3f' % tMin[0], '%.3f' % tMed[0], '%.3f' % tMax[0], 41718c2ecf20Sopenharmony_ci '%.3f' % tAvg[1], '%.3f' % tMin[1], '%.3f' % tMed[1], '%.3f' % tMax[1], 41728c2ecf20Sopenharmony_ci mode.lower() 41738c2ecf20Sopenharmony_ci ) 41748c2ecf20Sopenharmony_ci else: 41758c2ecf20Sopenharmony_ci iMin = iMed = iMax = [-1, -1, -1] 41768c2ecf20Sopenharmony_ci html += headnone.format('%d' % count, mode.upper()) 41778c2ecf20Sopenharmony_ci for d in list[mode]['data']: 41788c2ecf20Sopenharmony_ci # row classes - alternate row color 41798c2ecf20Sopenharmony_ci rcls = ['alt'] if num % 2 == 1 else [] 41808c2ecf20Sopenharmony_ci if d[6] != 'pass': 41818c2ecf20Sopenharmony_ci rcls.append('notice') 41828c2ecf20Sopenharmony_ci html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 41838c2ecf20Sopenharmony_ci # figure out if the line has sus or res highlighted 41848c2ecf20Sopenharmony_ci idx = list[mode]['data'].index(d) 41858c2ecf20Sopenharmony_ci tHigh = ['', ''] 41868c2ecf20Sopenharmony_ci for i in range(2): 41878c2ecf20Sopenharmony_ci tag = 's%s' % mode if i == 0 else 'r%s' % mode 41888c2ecf20Sopenharmony_ci if idx == iMin[i]: 41898c2ecf20Sopenharmony_ci tHigh[i] = ' id="%smin" class=minval title="Minimum"' % tag 41908c2ecf20Sopenharmony_ci elif idx == iMax[i]: 41918c2ecf20Sopenharmony_ci tHigh[i] = ' id="%smax" class=maxval title="Maximum"' % tag 41928c2ecf20Sopenharmony_ci elif idx == iMed[i]: 41938c2ecf20Sopenharmony_ci tHigh[i] = ' id="%smed" class=medval title="Median"' % tag 41948c2ecf20Sopenharmony_ci html += td.format("%d" % (list[mode]['data'].index(d) + 1)) # row 41958c2ecf20Sopenharmony_ci html += td.format(mode) # mode 41968c2ecf20Sopenharmony_ci html += td.format(d[0]) # host 41978c2ecf20Sopenharmony_ci html += td.format(d[1]) # kernel 41988c2ecf20Sopenharmony_ci html += td.format(d[2]) # time 41998c2ecf20Sopenharmony_ci html += td.format(d[6]) # result 42008c2ecf20Sopenharmony_ci html += td.format(d[7]) # issues 42018c2ecf20Sopenharmony_ci html += tdh.format('%.3f ms' % d[3], tHigh[0]) if d[3] else td.format('') # suspend 42028c2ecf20Sopenharmony_ci html += tdh.format('%.3f ms' % d[4], tHigh[1]) if d[4] else td.format('') # resume 42038c2ecf20Sopenharmony_ci html += td.format(d[8]) # sus_worst 42048c2ecf20Sopenharmony_ci html += td.format('%.3f ms' % d[9]) if d[9] else td.format('') # sus_worst time 42058c2ecf20Sopenharmony_ci html += td.format(d[10]) # res_worst 42068c2ecf20Sopenharmony_ci html += td.format('%.3f ms' % d[11]) if d[11] else td.format('') # res_worst time 42078c2ecf20Sopenharmony_ci if useturbo: 42088c2ecf20Sopenharmony_ci html += td.format(d[12]) # pkg_pc10 42098c2ecf20Sopenharmony_ci html += td.format(d[13]) # syslpi 42108c2ecf20Sopenharmony_ci if usewifi: 42118c2ecf20Sopenharmony_ci html += td.format(d[14]) # wifi 42128c2ecf20Sopenharmony_ci html += tdlink.format(d[5]) if d[5] else td.format('') # url 42138c2ecf20Sopenharmony_ci html += '</tr>\n' 42148c2ecf20Sopenharmony_ci num += 1 42158c2ecf20Sopenharmony_ci 42168c2ecf20Sopenharmony_ci # flush the data to file 42178c2ecf20Sopenharmony_ci hf = open(htmlfile, 'w') 42188c2ecf20Sopenharmony_ci hf.write(html+'</table>\n</body>\n</html>\n') 42198c2ecf20Sopenharmony_ci hf.close() 42208c2ecf20Sopenharmony_ci 42218c2ecf20Sopenharmony_cidef createHTMLDeviceSummary(testruns, htmlfile, title): 42228c2ecf20Sopenharmony_ci html = summaryCSS('Device Summary - SleepGraph', False) 42238c2ecf20Sopenharmony_ci 42248c2ecf20Sopenharmony_ci # create global device list from all tests 42258c2ecf20Sopenharmony_ci devall = dict() 42268c2ecf20Sopenharmony_ci for data in testruns: 42278c2ecf20Sopenharmony_ci host, url, devlist = data['host'], data['url'], data['devlist'] 42288c2ecf20Sopenharmony_ci for type in devlist: 42298c2ecf20Sopenharmony_ci if type not in devall: 42308c2ecf20Sopenharmony_ci devall[type] = dict() 42318c2ecf20Sopenharmony_ci mdevlist, devlist = devall[type], data['devlist'][type] 42328c2ecf20Sopenharmony_ci for name in devlist: 42338c2ecf20Sopenharmony_ci length = devlist[name] 42348c2ecf20Sopenharmony_ci if name not in mdevlist: 42358c2ecf20Sopenharmony_ci mdevlist[name] = {'name': name, 'host': host, 42368c2ecf20Sopenharmony_ci 'worst': length, 'total': length, 'count': 1, 42378c2ecf20Sopenharmony_ci 'url': url} 42388c2ecf20Sopenharmony_ci else: 42398c2ecf20Sopenharmony_ci if length > mdevlist[name]['worst']: 42408c2ecf20Sopenharmony_ci mdevlist[name]['worst'] = length 42418c2ecf20Sopenharmony_ci mdevlist[name]['url'] = url 42428c2ecf20Sopenharmony_ci mdevlist[name]['host'] = host 42438c2ecf20Sopenharmony_ci mdevlist[name]['total'] += length 42448c2ecf20Sopenharmony_ci mdevlist[name]['count'] += 1 42458c2ecf20Sopenharmony_ci 42468c2ecf20Sopenharmony_ci # generate the html 42478c2ecf20Sopenharmony_ci th = '\t<th>{0}</th>\n' 42488c2ecf20Sopenharmony_ci td = '\t<td align=center>{0}</td>\n' 42498c2ecf20Sopenharmony_ci tdr = '\t<td align=right>{0}</td>\n' 42508c2ecf20Sopenharmony_ci tdlink = '\t<td align=center><a href="{0}">html</a></td>\n' 42518c2ecf20Sopenharmony_ci limit = 1 42528c2ecf20Sopenharmony_ci for type in sorted(devall, reverse=True): 42538c2ecf20Sopenharmony_ci num = 0 42548c2ecf20Sopenharmony_ci devlist = devall[type] 42558c2ecf20Sopenharmony_ci # table header 42568c2ecf20Sopenharmony_ci html += '<div class="stamp">%s (%s devices > %d ms)</div><table>\n' % \ 42578c2ecf20Sopenharmony_ci (title, type.upper(), limit) 42588c2ecf20Sopenharmony_ci html += '<tr>\n' + '<th align=right>Device Name</th>' +\ 42598c2ecf20Sopenharmony_ci th.format('Average Time') + th.format('Count') +\ 42608c2ecf20Sopenharmony_ci th.format('Worst Time') + th.format('Host (worst time)') +\ 42618c2ecf20Sopenharmony_ci th.format('Link (worst time)') + '</tr>\n' 42628c2ecf20Sopenharmony_ci for name in sorted(devlist, key=lambda k:(devlist[k]['worst'], \ 42638c2ecf20Sopenharmony_ci devlist[k]['total'], devlist[k]['name']), reverse=True): 42648c2ecf20Sopenharmony_ci data = devall[type][name] 42658c2ecf20Sopenharmony_ci data['average'] = data['total'] / data['count'] 42668c2ecf20Sopenharmony_ci if data['average'] < limit: 42678c2ecf20Sopenharmony_ci continue 42688c2ecf20Sopenharmony_ci # row classes - alternate row color 42698c2ecf20Sopenharmony_ci rcls = ['alt'] if num % 2 == 1 else [] 42708c2ecf20Sopenharmony_ci html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 42718c2ecf20Sopenharmony_ci html += tdr.format(data['name']) # name 42728c2ecf20Sopenharmony_ci html += td.format('%.3f ms' % data['average']) # average 42738c2ecf20Sopenharmony_ci html += td.format(data['count']) # count 42748c2ecf20Sopenharmony_ci html += td.format('%.3f ms' % data['worst']) # worst 42758c2ecf20Sopenharmony_ci html += td.format(data['host']) # host 42768c2ecf20Sopenharmony_ci html += tdlink.format(data['url']) # url 42778c2ecf20Sopenharmony_ci html += '</tr>\n' 42788c2ecf20Sopenharmony_ci num += 1 42798c2ecf20Sopenharmony_ci html += '</table>\n' 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_ci # flush the data to file 42828c2ecf20Sopenharmony_ci hf = open(htmlfile, 'w') 42838c2ecf20Sopenharmony_ci hf.write(html+'</body>\n</html>\n') 42848c2ecf20Sopenharmony_ci hf.close() 42858c2ecf20Sopenharmony_ci return devall 42868c2ecf20Sopenharmony_ci 42878c2ecf20Sopenharmony_cidef createHTMLIssuesSummary(testruns, issues, htmlfile, title, extra=''): 42888c2ecf20Sopenharmony_ci multihost = len([e for e in issues if len(e['urls']) > 1]) > 0 42898c2ecf20Sopenharmony_ci html = summaryCSS('Issues Summary - SleepGraph', False) 42908c2ecf20Sopenharmony_ci total = len(testruns) 42918c2ecf20Sopenharmony_ci 42928c2ecf20Sopenharmony_ci # generate the html 42938c2ecf20Sopenharmony_ci th = '\t<th>{0}</th>\n' 42948c2ecf20Sopenharmony_ci td = '\t<td align={0}>{1}</td>\n' 42958c2ecf20Sopenharmony_ci tdlink = '<a href="{1}">{0}</a>' 42968c2ecf20Sopenharmony_ci subtitle = '%d issues' % len(issues) if len(issues) > 0 else 'no issues' 42978c2ecf20Sopenharmony_ci html += '<div class="stamp">%s (%s)</div><table>\n' % (title, subtitle) 42988c2ecf20Sopenharmony_ci html += '<tr>\n' + th.format('Issue') + th.format('Count') 42998c2ecf20Sopenharmony_ci if multihost: 43008c2ecf20Sopenharmony_ci html += th.format('Hosts') 43018c2ecf20Sopenharmony_ci html += th.format('Tests') + th.format('Fail Rate') +\ 43028c2ecf20Sopenharmony_ci th.format('First Instance') + '</tr>\n' 43038c2ecf20Sopenharmony_ci 43048c2ecf20Sopenharmony_ci num = 0 43058c2ecf20Sopenharmony_ci for e in sorted(issues, key=lambda v:v['count'], reverse=True): 43068c2ecf20Sopenharmony_ci testtotal = 0 43078c2ecf20Sopenharmony_ci links = [] 43088c2ecf20Sopenharmony_ci for host in sorted(e['urls']): 43098c2ecf20Sopenharmony_ci links.append(tdlink.format(host, e['urls'][host][0])) 43108c2ecf20Sopenharmony_ci testtotal += len(e['urls'][host]) 43118c2ecf20Sopenharmony_ci rate = '%d/%d (%.2f%%)' % (testtotal, total, 100*float(testtotal)/float(total)) 43128c2ecf20Sopenharmony_ci # row classes - alternate row color 43138c2ecf20Sopenharmony_ci rcls = ['alt'] if num % 2 == 1 else [] 43148c2ecf20Sopenharmony_ci html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 43158c2ecf20Sopenharmony_ci html += td.format('left', e['line']) # issue 43168c2ecf20Sopenharmony_ci html += td.format('center', e['count']) # count 43178c2ecf20Sopenharmony_ci if multihost: 43188c2ecf20Sopenharmony_ci html += td.format('center', len(e['urls'])) # hosts 43198c2ecf20Sopenharmony_ci html += td.format('center', testtotal) # test count 43208c2ecf20Sopenharmony_ci html += td.format('center', rate) # test rate 43218c2ecf20Sopenharmony_ci html += td.format('center nowrap', '<br>'.join(links)) # links 43228c2ecf20Sopenharmony_ci html += '</tr>\n' 43238c2ecf20Sopenharmony_ci num += 1 43248c2ecf20Sopenharmony_ci 43258c2ecf20Sopenharmony_ci # flush the data to file 43268c2ecf20Sopenharmony_ci hf = open(htmlfile, 'w') 43278c2ecf20Sopenharmony_ci hf.write(html+'</table>\n'+extra+'</body>\n</html>\n') 43288c2ecf20Sopenharmony_ci hf.close() 43298c2ecf20Sopenharmony_ci return issues 43308c2ecf20Sopenharmony_ci 43318c2ecf20Sopenharmony_cidef ordinal(value): 43328c2ecf20Sopenharmony_ci suffix = 'th' 43338c2ecf20Sopenharmony_ci if value < 10 or value > 19: 43348c2ecf20Sopenharmony_ci if value % 10 == 1: 43358c2ecf20Sopenharmony_ci suffix = 'st' 43368c2ecf20Sopenharmony_ci elif value % 10 == 2: 43378c2ecf20Sopenharmony_ci suffix = 'nd' 43388c2ecf20Sopenharmony_ci elif value % 10 == 3: 43398c2ecf20Sopenharmony_ci suffix = 'rd' 43408c2ecf20Sopenharmony_ci return '%d%s' % (value, suffix) 43418c2ecf20Sopenharmony_ci 43428c2ecf20Sopenharmony_ci# Function: createHTML 43438c2ecf20Sopenharmony_ci# Description: 43448c2ecf20Sopenharmony_ci# Create the output html file from the resident test data 43458c2ecf20Sopenharmony_ci# Arguments: 43468c2ecf20Sopenharmony_ci# testruns: array of Data objects from parseKernelLog or parseTraceLog 43478c2ecf20Sopenharmony_ci# Output: 43488c2ecf20Sopenharmony_ci# True if the html file was created, false if it failed 43498c2ecf20Sopenharmony_cidef createHTML(testruns, testfail): 43508c2ecf20Sopenharmony_ci if len(testruns) < 1: 43518c2ecf20Sopenharmony_ci pprint('ERROR: Not enough test data to build a timeline') 43528c2ecf20Sopenharmony_ci return 43538c2ecf20Sopenharmony_ci 43548c2ecf20Sopenharmony_ci kerror = False 43558c2ecf20Sopenharmony_ci for data in testruns: 43568c2ecf20Sopenharmony_ci if data.kerror: 43578c2ecf20Sopenharmony_ci kerror = True 43588c2ecf20Sopenharmony_ci if(sysvals.suspendmode in ['freeze', 'standby']): 43598c2ecf20Sopenharmony_ci data.trimFreezeTime(testruns[-1].tSuspended) 43608c2ecf20Sopenharmony_ci else: 43618c2ecf20Sopenharmony_ci data.getMemTime() 43628c2ecf20Sopenharmony_ci 43638c2ecf20Sopenharmony_ci # html function templates 43648c2ecf20Sopenharmony_ci html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">{2}→</div>\n' 43658c2ecf20Sopenharmony_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' 43668c2ecf20Sopenharmony_ci html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n' 43678c2ecf20Sopenharmony_ci html_timetotal = '<table class="time1">\n<tr>'\ 43688c2ecf20Sopenharmony_ci '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ 43698c2ecf20Sopenharmony_ci '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ 43708c2ecf20Sopenharmony_ci '</tr>\n</table>\n' 43718c2ecf20Sopenharmony_ci html_timetotal2 = '<table class="time1">\n<tr>'\ 43728c2ecf20Sopenharmony_ci '<td class="green" title="{4}">{3} Suspend Time: <b>{0} ms</b></td>'\ 43738c2ecf20Sopenharmony_ci '<td class="gray" title="time spent in low-power mode with clock running">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\ 43748c2ecf20Sopenharmony_ci '<td class="yellow" title="{5}">{3} Resume Time: <b>{2} ms</b></td>'\ 43758c2ecf20Sopenharmony_ci '</tr>\n</table>\n' 43768c2ecf20Sopenharmony_ci html_timetotal3 = '<table class="time1">\n<tr>'\ 43778c2ecf20Sopenharmony_ci '<td class="green">Execution Time: <b>{0} ms</b></td>'\ 43788c2ecf20Sopenharmony_ci '<td class="yellow">Command: <b>{1}</b></td>'\ 43798c2ecf20Sopenharmony_ci '</tr>\n</table>\n' 43808c2ecf20Sopenharmony_ci html_fail = '<table class="testfail"><tr><td>{0}</td></tr></table>\n' 43818c2ecf20Sopenharmony_ci html_kdesc = '<td class="{3}" title="time spent in kernel execution">{0}Kernel {2}: {1} ms</td>' 43828c2ecf20Sopenharmony_ci html_fwdesc = '<td class="{3}" title="time spent in firmware">{0}Firmware {2}: {1} ms</td>' 43838c2ecf20Sopenharmony_ci html_wifdesc = '<td class="yellow" title="time for wifi to reconnect after resume complete ({2})">{0}Wifi Resume: {1}</td>' 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ci # html format variables 43868c2ecf20Sopenharmony_ci scaleH = 20 43878c2ecf20Sopenharmony_ci if kerror: 43888c2ecf20Sopenharmony_ci scaleH = 40 43898c2ecf20Sopenharmony_ci 43908c2ecf20Sopenharmony_ci # device timeline 43918c2ecf20Sopenharmony_ci devtl = Timeline(30, scaleH) 43928c2ecf20Sopenharmony_ci 43938c2ecf20Sopenharmony_ci # write the test title and general info header 43948c2ecf20Sopenharmony_ci devtl.createHeader(sysvals, testruns[0].stamp) 43958c2ecf20Sopenharmony_ci 43968c2ecf20Sopenharmony_ci # Generate the header for this timeline 43978c2ecf20Sopenharmony_ci for data in testruns: 43988c2ecf20Sopenharmony_ci tTotal = data.end - data.start 43998c2ecf20Sopenharmony_ci if(tTotal == 0): 44008c2ecf20Sopenharmony_ci doError('No timeline data') 44018c2ecf20Sopenharmony_ci if sysvals.suspendmode == 'command': 44028c2ecf20Sopenharmony_ci run_time = '%.0f' % (tTotal * 1000) 44038c2ecf20Sopenharmony_ci if sysvals.testcommand: 44048c2ecf20Sopenharmony_ci testdesc = sysvals.testcommand 44058c2ecf20Sopenharmony_ci else: 44068c2ecf20Sopenharmony_ci testdesc = 'unknown' 44078c2ecf20Sopenharmony_ci if(len(testruns) > 1): 44088c2ecf20Sopenharmony_ci testdesc = ordinal(data.testnumber+1)+' '+testdesc 44098c2ecf20Sopenharmony_ci thtml = html_timetotal3.format(run_time, testdesc) 44108c2ecf20Sopenharmony_ci devtl.html += thtml 44118c2ecf20Sopenharmony_ci continue 44128c2ecf20Sopenharmony_ci # typical full suspend/resume header 44138c2ecf20Sopenharmony_ci stot, rtot = sktime, rktime = data.getTimeValues() 44148c2ecf20Sopenharmony_ci ssrc, rsrc, testdesc, testdesc2 = ['kernel'], ['kernel'], 'Kernel', '' 44158c2ecf20Sopenharmony_ci if data.fwValid: 44168c2ecf20Sopenharmony_ci stot += (data.fwSuspend/1000000.0) 44178c2ecf20Sopenharmony_ci rtot += (data.fwResume/1000000.0) 44188c2ecf20Sopenharmony_ci ssrc.append('firmware') 44198c2ecf20Sopenharmony_ci rsrc.append('firmware') 44208c2ecf20Sopenharmony_ci testdesc = 'Total' 44218c2ecf20Sopenharmony_ci if 'time' in data.wifi and data.wifi['stat'] != 'timeout': 44228c2ecf20Sopenharmony_ci rtot += data.end - data.tKernRes + (data.wifi['time'] * 1000.0) 44238c2ecf20Sopenharmony_ci rsrc.append('wifi') 44248c2ecf20Sopenharmony_ci testdesc = 'Total' 44258c2ecf20Sopenharmony_ci suspend_time, resume_time = '%.3f' % stot, '%.3f' % rtot 44268c2ecf20Sopenharmony_ci stitle = 'time from kernel suspend start to %s mode [%s time]' % \ 44278c2ecf20Sopenharmony_ci (sysvals.suspendmode, ' & '.join(ssrc)) 44288c2ecf20Sopenharmony_ci rtitle = 'time from %s mode to kernel resume complete [%s time]' % \ 44298c2ecf20Sopenharmony_ci (sysvals.suspendmode, ' & '.join(rsrc)) 44308c2ecf20Sopenharmony_ci if(len(testruns) > 1): 44318c2ecf20Sopenharmony_ci testdesc = testdesc2 = ordinal(data.testnumber+1) 44328c2ecf20Sopenharmony_ci testdesc2 += ' ' 44338c2ecf20Sopenharmony_ci if(len(data.tLow) == 0): 44348c2ecf20Sopenharmony_ci thtml = html_timetotal.format(suspend_time, \ 44358c2ecf20Sopenharmony_ci resume_time, testdesc, stitle, rtitle) 44368c2ecf20Sopenharmony_ci else: 44378c2ecf20Sopenharmony_ci low_time = '+'.join(data.tLow) 44388c2ecf20Sopenharmony_ci thtml = html_timetotal2.format(suspend_time, low_time, \ 44398c2ecf20Sopenharmony_ci resume_time, testdesc, stitle, rtitle) 44408c2ecf20Sopenharmony_ci devtl.html += thtml 44418c2ecf20Sopenharmony_ci if not data.fwValid and 'dev' not in data.wifi: 44428c2ecf20Sopenharmony_ci continue 44438c2ecf20Sopenharmony_ci # extra detail when the times come from multiple sources 44448c2ecf20Sopenharmony_ci thtml = '<table class="time2">\n<tr>' 44458c2ecf20Sopenharmony_ci thtml += html_kdesc.format(testdesc2, '%.3f'%sktime, 'Suspend', 'green') 44468c2ecf20Sopenharmony_ci if data.fwValid: 44478c2ecf20Sopenharmony_ci sftime = '%.3f'%(data.fwSuspend / 1000000.0) 44488c2ecf20Sopenharmony_ci rftime = '%.3f'%(data.fwResume / 1000000.0) 44498c2ecf20Sopenharmony_ci thtml += html_fwdesc.format(testdesc2, sftime, 'Suspend', 'green') 44508c2ecf20Sopenharmony_ci thtml += html_fwdesc.format(testdesc2, rftime, 'Resume', 'yellow') 44518c2ecf20Sopenharmony_ci thtml += html_kdesc.format(testdesc2, '%.3f'%rktime, 'Resume', 'yellow') 44528c2ecf20Sopenharmony_ci if 'time' in data.wifi: 44538c2ecf20Sopenharmony_ci if data.wifi['stat'] != 'timeout': 44548c2ecf20Sopenharmony_ci wtime = '%.0f ms'%(data.end - data.tKernRes + (data.wifi['time'] * 1000.0)) 44558c2ecf20Sopenharmony_ci else: 44568c2ecf20Sopenharmony_ci wtime = 'TIMEOUT' 44578c2ecf20Sopenharmony_ci thtml += html_wifdesc.format(testdesc2, wtime, data.wifi['dev']) 44588c2ecf20Sopenharmony_ci thtml += '</tr>\n</table>\n' 44598c2ecf20Sopenharmony_ci devtl.html += thtml 44608c2ecf20Sopenharmony_ci if testfail: 44618c2ecf20Sopenharmony_ci devtl.html += html_fail.format(testfail) 44628c2ecf20Sopenharmony_ci 44638c2ecf20Sopenharmony_ci # time scale for potentially multiple datasets 44648c2ecf20Sopenharmony_ci t0 = testruns[0].start 44658c2ecf20Sopenharmony_ci tMax = testruns[-1].end 44668c2ecf20Sopenharmony_ci tTotal = tMax - t0 44678c2ecf20Sopenharmony_ci 44688c2ecf20Sopenharmony_ci # determine the maximum number of rows we need to draw 44698c2ecf20Sopenharmony_ci fulllist = [] 44708c2ecf20Sopenharmony_ci threadlist = [] 44718c2ecf20Sopenharmony_ci pscnt = 0 44728c2ecf20Sopenharmony_ci devcnt = 0 44738c2ecf20Sopenharmony_ci for data in testruns: 44748c2ecf20Sopenharmony_ci data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen) 44758c2ecf20Sopenharmony_ci for group in data.devicegroups: 44768c2ecf20Sopenharmony_ci devlist = [] 44778c2ecf20Sopenharmony_ci for phase in group: 44788c2ecf20Sopenharmony_ci for devname in sorted(data.tdevlist[phase]): 44798c2ecf20Sopenharmony_ci d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname]) 44808c2ecf20Sopenharmony_ci devlist.append(d) 44818c2ecf20Sopenharmony_ci if d.isa('kth'): 44828c2ecf20Sopenharmony_ci threadlist.append(d) 44838c2ecf20Sopenharmony_ci else: 44848c2ecf20Sopenharmony_ci if d.isa('ps'): 44858c2ecf20Sopenharmony_ci pscnt += 1 44868c2ecf20Sopenharmony_ci else: 44878c2ecf20Sopenharmony_ci devcnt += 1 44888c2ecf20Sopenharmony_ci fulllist.append(d) 44898c2ecf20Sopenharmony_ci if sysvals.mixedphaseheight: 44908c2ecf20Sopenharmony_ci devtl.getPhaseRows(devlist) 44918c2ecf20Sopenharmony_ci if not sysvals.mixedphaseheight: 44928c2ecf20Sopenharmony_ci if len(threadlist) > 0 and len(fulllist) > 0: 44938c2ecf20Sopenharmony_ci if pscnt > 0 and devcnt > 0: 44948c2ecf20Sopenharmony_ci msg = 'user processes & device pm callbacks' 44958c2ecf20Sopenharmony_ci elif pscnt > 0: 44968c2ecf20Sopenharmony_ci msg = 'user processes' 44978c2ecf20Sopenharmony_ci else: 44988c2ecf20Sopenharmony_ci msg = 'device pm callbacks' 44998c2ecf20Sopenharmony_ci d = testruns[0].addHorizontalDivider(msg, testruns[-1].end) 45008c2ecf20Sopenharmony_ci fulllist.insert(0, d) 45018c2ecf20Sopenharmony_ci devtl.getPhaseRows(fulllist) 45028c2ecf20Sopenharmony_ci if len(threadlist) > 0: 45038c2ecf20Sopenharmony_ci d = testruns[0].addHorizontalDivider('asynchronous kernel threads', testruns[-1].end) 45048c2ecf20Sopenharmony_ci threadlist.insert(0, d) 45058c2ecf20Sopenharmony_ci devtl.getPhaseRows(threadlist, devtl.rows) 45068c2ecf20Sopenharmony_ci devtl.calcTotalRows() 45078c2ecf20Sopenharmony_ci 45088c2ecf20Sopenharmony_ci # draw the full timeline 45098c2ecf20Sopenharmony_ci devtl.createZoomBox(sysvals.suspendmode, len(testruns)) 45108c2ecf20Sopenharmony_ci for data in testruns: 45118c2ecf20Sopenharmony_ci # draw each test run and block chronologically 45128c2ecf20Sopenharmony_ci phases = {'suspend':[],'resume':[]} 45138c2ecf20Sopenharmony_ci for phase in data.sortedPhases(): 45148c2ecf20Sopenharmony_ci if data.dmesg[phase]['start'] >= data.tSuspended: 45158c2ecf20Sopenharmony_ci phases['resume'].append(phase) 45168c2ecf20Sopenharmony_ci else: 45178c2ecf20Sopenharmony_ci phases['suspend'].append(phase) 45188c2ecf20Sopenharmony_ci # now draw the actual timeline blocks 45198c2ecf20Sopenharmony_ci for dir in phases: 45208c2ecf20Sopenharmony_ci # draw suspend and resume blocks separately 45218c2ecf20Sopenharmony_ci bname = '%s%d' % (dir[0], data.testnumber) 45228c2ecf20Sopenharmony_ci if dir == 'suspend': 45238c2ecf20Sopenharmony_ci m0 = data.start 45248c2ecf20Sopenharmony_ci mMax = data.tSuspended 45258c2ecf20Sopenharmony_ci left = '%f' % (((m0-t0)*100.0)/tTotal) 45268c2ecf20Sopenharmony_ci else: 45278c2ecf20Sopenharmony_ci m0 = data.tSuspended 45288c2ecf20Sopenharmony_ci mMax = data.end 45298c2ecf20Sopenharmony_ci # in an x2 run, remove any gap between blocks 45308c2ecf20Sopenharmony_ci if len(testruns) > 1 and data.testnumber == 0: 45318c2ecf20Sopenharmony_ci mMax = testruns[1].start 45328c2ecf20Sopenharmony_ci left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal) 45338c2ecf20Sopenharmony_ci mTotal = mMax - m0 45348c2ecf20Sopenharmony_ci # if a timeline block is 0 length, skip altogether 45358c2ecf20Sopenharmony_ci if mTotal == 0: 45368c2ecf20Sopenharmony_ci continue 45378c2ecf20Sopenharmony_ci width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal) 45388c2ecf20Sopenharmony_ci devtl.html += devtl.html_tblock.format(bname, left, width, devtl.scaleH) 45398c2ecf20Sopenharmony_ci for b in phases[dir]: 45408c2ecf20Sopenharmony_ci # draw the phase color background 45418c2ecf20Sopenharmony_ci phase = data.dmesg[b] 45428c2ecf20Sopenharmony_ci length = phase['end']-phase['start'] 45438c2ecf20Sopenharmony_ci left = '%f' % (((phase['start']-m0)*100.0)/mTotal) 45448c2ecf20Sopenharmony_ci width = '%f' % ((length*100.0)/mTotal) 45458c2ecf20Sopenharmony_ci devtl.html += devtl.html_phase.format(left, width, \ 45468c2ecf20Sopenharmony_ci '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ 45478c2ecf20Sopenharmony_ci data.dmesg[b]['color'], '') 45488c2ecf20Sopenharmony_ci for e in data.errorinfo[dir]: 45498c2ecf20Sopenharmony_ci # draw red lines for any kernel errors found 45508c2ecf20Sopenharmony_ci type, t, idx1, idx2 = e 45518c2ecf20Sopenharmony_ci id = '%d_%d' % (idx1, idx2) 45528c2ecf20Sopenharmony_ci right = '%f' % (((mMax-t)*100.0)/mTotal) 45538c2ecf20Sopenharmony_ci devtl.html += html_error.format(right, id, type) 45548c2ecf20Sopenharmony_ci for b in phases[dir]: 45558c2ecf20Sopenharmony_ci # draw the devices for this phase 45568c2ecf20Sopenharmony_ci phaselist = data.dmesg[b]['list'] 45578c2ecf20Sopenharmony_ci for d in sorted(data.tdevlist[b]): 45588c2ecf20Sopenharmony_ci dname = d if '[' not in d else d.split('[')[0] 45598c2ecf20Sopenharmony_ci name, dev = dname, phaselist[d] 45608c2ecf20Sopenharmony_ci drv = xtraclass = xtrainfo = xtrastyle = '' 45618c2ecf20Sopenharmony_ci if 'htmlclass' in dev: 45628c2ecf20Sopenharmony_ci xtraclass = dev['htmlclass'] 45638c2ecf20Sopenharmony_ci if 'color' in dev: 45648c2ecf20Sopenharmony_ci xtrastyle = 'background:%s;' % dev['color'] 45658c2ecf20Sopenharmony_ci if(d in sysvals.devprops): 45668c2ecf20Sopenharmony_ci name = sysvals.devprops[d].altName(d) 45678c2ecf20Sopenharmony_ci xtraclass = sysvals.devprops[d].xtraClass() 45688c2ecf20Sopenharmony_ci xtrainfo = sysvals.devprops[d].xtraInfo() 45698c2ecf20Sopenharmony_ci elif xtraclass == ' kth': 45708c2ecf20Sopenharmony_ci xtrainfo = ' kernel_thread' 45718c2ecf20Sopenharmony_ci if('drv' in dev and dev['drv']): 45728c2ecf20Sopenharmony_ci drv = ' {%s}' % dev['drv'] 45738c2ecf20Sopenharmony_ci rowheight = devtl.phaseRowHeight(data.testnumber, b, dev['row']) 45748c2ecf20Sopenharmony_ci rowtop = devtl.phaseRowTop(data.testnumber, b, dev['row']) 45758c2ecf20Sopenharmony_ci top = '%.3f' % (rowtop + devtl.scaleH) 45768c2ecf20Sopenharmony_ci left = '%f' % (((dev['start']-m0)*100)/mTotal) 45778c2ecf20Sopenharmony_ci width = '%f' % (((dev['end']-dev['start'])*100)/mTotal) 45788c2ecf20Sopenharmony_ci length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) 45798c2ecf20Sopenharmony_ci title = name+drv+xtrainfo+length 45808c2ecf20Sopenharmony_ci if sysvals.suspendmode == 'command': 45818c2ecf20Sopenharmony_ci title += sysvals.testcommand 45828c2ecf20Sopenharmony_ci elif xtraclass == ' ps': 45838c2ecf20Sopenharmony_ci if 'suspend' in b: 45848c2ecf20Sopenharmony_ci title += 'pre_suspend_process' 45858c2ecf20Sopenharmony_ci else: 45868c2ecf20Sopenharmony_ci title += 'post_resume_process' 45878c2ecf20Sopenharmony_ci else: 45888c2ecf20Sopenharmony_ci title += b 45898c2ecf20Sopenharmony_ci devtl.html += devtl.html_device.format(dev['id'], \ 45908c2ecf20Sopenharmony_ci title, left, top, '%.3f'%rowheight, width, \ 45918c2ecf20Sopenharmony_ci dname+drv, xtraclass, xtrastyle) 45928c2ecf20Sopenharmony_ci if('cpuexec' in dev): 45938c2ecf20Sopenharmony_ci for t in sorted(dev['cpuexec']): 45948c2ecf20Sopenharmony_ci start, end = t 45958c2ecf20Sopenharmony_ci j = float(dev['cpuexec'][t]) / 5 45968c2ecf20Sopenharmony_ci if j > 1.0: 45978c2ecf20Sopenharmony_ci j = 1.0 45988c2ecf20Sopenharmony_ci height = '%.3f' % (rowheight/3) 45998c2ecf20Sopenharmony_ci top = '%.3f' % (rowtop + devtl.scaleH + 2*rowheight/3) 46008c2ecf20Sopenharmony_ci left = '%f' % (((start-m0)*100)/mTotal) 46018c2ecf20Sopenharmony_ci width = '%f' % ((end-start)*100/mTotal) 46028c2ecf20Sopenharmony_ci color = 'rgba(255, 0, 0, %f)' % j 46038c2ecf20Sopenharmony_ci devtl.html += \ 46048c2ecf20Sopenharmony_ci html_cpuexec.format(left, top, height, width, color) 46058c2ecf20Sopenharmony_ci if('src' not in dev): 46068c2ecf20Sopenharmony_ci continue 46078c2ecf20Sopenharmony_ci # draw any trace events for this device 46088c2ecf20Sopenharmony_ci for e in dev['src']: 46098c2ecf20Sopenharmony_ci if e.length == 0: 46108c2ecf20Sopenharmony_ci continue 46118c2ecf20Sopenharmony_ci height = '%.3f' % devtl.rowH 46128c2ecf20Sopenharmony_ci top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH)) 46138c2ecf20Sopenharmony_ci left = '%f' % (((e.time-m0)*100)/mTotal) 46148c2ecf20Sopenharmony_ci width = '%f' % (e.length*100/mTotal) 46158c2ecf20Sopenharmony_ci xtrastyle = '' 46168c2ecf20Sopenharmony_ci if e.color: 46178c2ecf20Sopenharmony_ci xtrastyle = 'background:%s;' % e.color 46188c2ecf20Sopenharmony_ci devtl.html += \ 46198c2ecf20Sopenharmony_ci html_traceevent.format(e.title(), \ 46208c2ecf20Sopenharmony_ci left, top, height, width, e.text(), '', xtrastyle) 46218c2ecf20Sopenharmony_ci # draw the time scale, try to make the number of labels readable 46228c2ecf20Sopenharmony_ci devtl.createTimeScale(m0, mMax, tTotal, dir) 46238c2ecf20Sopenharmony_ci devtl.html += '</div>\n' 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci # timeline is finished 46268c2ecf20Sopenharmony_ci devtl.html += '</div>\n</div>\n' 46278c2ecf20Sopenharmony_ci 46288c2ecf20Sopenharmony_ci # draw a legend which describes the phases by color 46298c2ecf20Sopenharmony_ci if sysvals.suspendmode != 'command': 46308c2ecf20Sopenharmony_ci phasedef = testruns[-1].phasedef 46318c2ecf20Sopenharmony_ci devtl.html += '<div class="legend">\n' 46328c2ecf20Sopenharmony_ci pdelta = 100.0/len(phasedef.keys()) 46338c2ecf20Sopenharmony_ci pmargin = pdelta / 4.0 46348c2ecf20Sopenharmony_ci for phase in sorted(phasedef, key=lambda k:phasedef[k]['order']): 46358c2ecf20Sopenharmony_ci id, p = '', phasedef[phase] 46368c2ecf20Sopenharmony_ci for word in phase.split('_'): 46378c2ecf20Sopenharmony_ci id += word[0] 46388c2ecf20Sopenharmony_ci order = '%.2f' % ((p['order'] * pdelta) + pmargin) 46398c2ecf20Sopenharmony_ci name = phase.replace('_', ' ') 46408c2ecf20Sopenharmony_ci devtl.html += devtl.html_legend.format(order, p['color'], name, id) 46418c2ecf20Sopenharmony_ci devtl.html += '</div>\n' 46428c2ecf20Sopenharmony_ci 46438c2ecf20Sopenharmony_ci hf = open(sysvals.htmlfile, 'w') 46448c2ecf20Sopenharmony_ci addCSS(hf, sysvals, len(testruns), kerror) 46458c2ecf20Sopenharmony_ci 46468c2ecf20Sopenharmony_ci # write the device timeline 46478c2ecf20Sopenharmony_ci hf.write(devtl.html) 46488c2ecf20Sopenharmony_ci hf.write('<div id="devicedetailtitle"></div>\n') 46498c2ecf20Sopenharmony_ci hf.write('<div id="devicedetail" style="display:none;">\n') 46508c2ecf20Sopenharmony_ci # draw the colored boxes for the device detail section 46518c2ecf20Sopenharmony_ci for data in testruns: 46528c2ecf20Sopenharmony_ci hf.write('<div id="devicedetail%d">\n' % data.testnumber) 46538c2ecf20Sopenharmony_ci pscolor = 'linear-gradient(to top left, #ccc, #eee)' 46548c2ecf20Sopenharmony_ci hf.write(devtl.html_phaselet.format('pre_suspend_process', \ 46558c2ecf20Sopenharmony_ci '0', '0', pscolor)) 46568c2ecf20Sopenharmony_ci for b in data.sortedPhases(): 46578c2ecf20Sopenharmony_ci phase = data.dmesg[b] 46588c2ecf20Sopenharmony_ci length = phase['end']-phase['start'] 46598c2ecf20Sopenharmony_ci left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) 46608c2ecf20Sopenharmony_ci width = '%.3f' % ((length*100.0)/tTotal) 46618c2ecf20Sopenharmony_ci hf.write(devtl.html_phaselet.format(b, left, width, \ 46628c2ecf20Sopenharmony_ci data.dmesg[b]['color'])) 46638c2ecf20Sopenharmony_ci hf.write(devtl.html_phaselet.format('post_resume_process', \ 46648c2ecf20Sopenharmony_ci '0', '0', pscolor)) 46658c2ecf20Sopenharmony_ci if sysvals.suspendmode == 'command': 46668c2ecf20Sopenharmony_ci hf.write(devtl.html_phaselet.format('cmdexec', '0', '0', pscolor)) 46678c2ecf20Sopenharmony_ci hf.write('</div>\n') 46688c2ecf20Sopenharmony_ci hf.write('</div>\n') 46698c2ecf20Sopenharmony_ci 46708c2ecf20Sopenharmony_ci # write the ftrace data (callgraph) 46718c2ecf20Sopenharmony_ci if sysvals.cgtest >= 0 and len(testruns) > sysvals.cgtest: 46728c2ecf20Sopenharmony_ci data = testruns[sysvals.cgtest] 46738c2ecf20Sopenharmony_ci else: 46748c2ecf20Sopenharmony_ci data = testruns[-1] 46758c2ecf20Sopenharmony_ci if sysvals.usecallgraph: 46768c2ecf20Sopenharmony_ci addCallgraphs(sysvals, hf, data) 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci # add the test log as a hidden div 46798c2ecf20Sopenharmony_ci if sysvals.testlog and sysvals.logmsg: 46808c2ecf20Sopenharmony_ci hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') 46818c2ecf20Sopenharmony_ci # add the dmesg log as a hidden div 46828c2ecf20Sopenharmony_ci if sysvals.dmesglog and sysvals.dmesgfile: 46838c2ecf20Sopenharmony_ci hf.write('<div id="dmesglog" style="display:none;">\n') 46848c2ecf20Sopenharmony_ci lf = sysvals.openlog(sysvals.dmesgfile, 'r') 46858c2ecf20Sopenharmony_ci for line in lf: 46868c2ecf20Sopenharmony_ci line = line.replace('<', '<').replace('>', '>') 46878c2ecf20Sopenharmony_ci hf.write(line) 46888c2ecf20Sopenharmony_ci lf.close() 46898c2ecf20Sopenharmony_ci hf.write('</div>\n') 46908c2ecf20Sopenharmony_ci # add the ftrace log as a hidden div 46918c2ecf20Sopenharmony_ci if sysvals.ftracelog and sysvals.ftracefile: 46928c2ecf20Sopenharmony_ci hf.write('<div id="ftracelog" style="display:none;">\n') 46938c2ecf20Sopenharmony_ci lf = sysvals.openlog(sysvals.ftracefile, 'r') 46948c2ecf20Sopenharmony_ci for line in lf: 46958c2ecf20Sopenharmony_ci hf.write(line) 46968c2ecf20Sopenharmony_ci lf.close() 46978c2ecf20Sopenharmony_ci hf.write('</div>\n') 46988c2ecf20Sopenharmony_ci 46998c2ecf20Sopenharmony_ci # write the footer and close 47008c2ecf20Sopenharmony_ci addScriptCode(hf, testruns) 47018c2ecf20Sopenharmony_ci hf.write('</body>\n</html>\n') 47028c2ecf20Sopenharmony_ci hf.close() 47038c2ecf20Sopenharmony_ci return True 47048c2ecf20Sopenharmony_ci 47058c2ecf20Sopenharmony_cidef addCSS(hf, sv, testcount=1, kerror=False, extra=''): 47068c2ecf20Sopenharmony_ci kernel = sv.stamp['kernel'] 47078c2ecf20Sopenharmony_ci host = sv.hostname[0].upper()+sv.hostname[1:] 47088c2ecf20Sopenharmony_ci mode = sv.suspendmode 47098c2ecf20Sopenharmony_ci if sv.suspendmode in suspendmodename: 47108c2ecf20Sopenharmony_ci mode = suspendmodename[sv.suspendmode] 47118c2ecf20Sopenharmony_ci title = host+' '+mode+' '+kernel 47128c2ecf20Sopenharmony_ci 47138c2ecf20Sopenharmony_ci # various format changes by flags 47148c2ecf20Sopenharmony_ci cgchk = 'checked' 47158c2ecf20Sopenharmony_ci cgnchk = 'not(:checked)' 47168c2ecf20Sopenharmony_ci if sv.cgexp: 47178c2ecf20Sopenharmony_ci cgchk = 'not(:checked)' 47188c2ecf20Sopenharmony_ci cgnchk = 'checked' 47198c2ecf20Sopenharmony_ci 47208c2ecf20Sopenharmony_ci hoverZ = 'z-index:8;' 47218c2ecf20Sopenharmony_ci if sv.usedevsrc: 47228c2ecf20Sopenharmony_ci hoverZ = '' 47238c2ecf20Sopenharmony_ci 47248c2ecf20Sopenharmony_ci devlistpos = 'absolute' 47258c2ecf20Sopenharmony_ci if testcount > 1: 47268c2ecf20Sopenharmony_ci devlistpos = 'relative' 47278c2ecf20Sopenharmony_ci 47288c2ecf20Sopenharmony_ci scaleTH = 20 47298c2ecf20Sopenharmony_ci if kerror: 47308c2ecf20Sopenharmony_ci scaleTH = 60 47318c2ecf20Sopenharmony_ci 47328c2ecf20Sopenharmony_ci # write the html header first (html head, css code, up to body start) 47338c2ecf20Sopenharmony_ci html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ 47348c2ecf20Sopenharmony_ci <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 47358c2ecf20Sopenharmony_ci <title>'+title+'</title>\n\ 47368c2ecf20Sopenharmony_ci <style type=\'text/css\'>\n\ 47378c2ecf20Sopenharmony_ci body {overflow-y:scroll;}\n\ 47388c2ecf20Sopenharmony_ci .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ 47398c2ecf20Sopenharmony_ci .stamp.sysinfo {font:10px Arial;}\n\ 47408c2ecf20Sopenharmony_ci .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ 47418c2ecf20Sopenharmony_ci .callgraph article * {padding-left:28px;}\n\ 47428c2ecf20Sopenharmony_ci h1 {color:black;font:bold 30px Times;}\n\ 47438c2ecf20Sopenharmony_ci t0 {color:black;font:bold 30px Times;}\n\ 47448c2ecf20Sopenharmony_ci t1 {color:black;font:30px Times;}\n\ 47458c2ecf20Sopenharmony_ci t2 {color:black;font:25px Times;}\n\ 47468c2ecf20Sopenharmony_ci t3 {color:black;font:20px Times;white-space:nowrap;}\n\ 47478c2ecf20Sopenharmony_ci t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ 47488c2ecf20Sopenharmony_ci cS {font:bold 13px Times;}\n\ 47498c2ecf20Sopenharmony_ci table {width:100%;}\n\ 47508c2ecf20Sopenharmony_ci .gray {background:rgba(80,80,80,0.1);}\n\ 47518c2ecf20Sopenharmony_ci .green {background:rgba(204,255,204,0.4);}\n\ 47528c2ecf20Sopenharmony_ci .purple {background:rgba(128,0,128,0.2);}\n\ 47538c2ecf20Sopenharmony_ci .yellow {background:rgba(255,255,204,0.4);}\n\ 47548c2ecf20Sopenharmony_ci .blue {background:rgba(169,208,245,0.4);}\n\ 47558c2ecf20Sopenharmony_ci .time1 {font:22px Arial;border:1px solid;}\n\ 47568c2ecf20Sopenharmony_ci .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ 47578c2ecf20Sopenharmony_ci .testfail {font:bold 22px Arial;color:red;border:1px dashed;}\n\ 47588c2ecf20Sopenharmony_ci td {text-align:center;}\n\ 47598c2ecf20Sopenharmony_ci r {color:#500000;font:15px Tahoma;}\n\ 47608c2ecf20Sopenharmony_ci n {color:#505050;font:15px Tahoma;}\n\ 47618c2ecf20Sopenharmony_ci .tdhl {color:red;}\n\ 47628c2ecf20Sopenharmony_ci .hide {display:none;}\n\ 47638c2ecf20Sopenharmony_ci .pf {display:none;}\n\ 47648c2ecf20Sopenharmony_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\ 47658c2ecf20Sopenharmony_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\ 47668c2ecf20Sopenharmony_ci .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ 47678c2ecf20Sopenharmony_ci .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ 47688c2ecf20Sopenharmony_ci .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ 47698c2ecf20Sopenharmony_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\ 47708c2ecf20Sopenharmony_ci .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ 47718c2ecf20Sopenharmony_ci .thread:hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 47728c2ecf20Sopenharmony_ci .thread.sec,.thread.sec:hover {background:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ 47738c2ecf20Sopenharmony_ci .hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 47748c2ecf20Sopenharmony_ci .hover.sync {background:white;}\n\ 47758c2ecf20Sopenharmony_ci .hover.bg,.hover.kth,.hover.sync,.hover.ps {background:white;}\n\ 47768c2ecf20Sopenharmony_ci .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ 47778c2ecf20Sopenharmony_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\ 47788c2ecf20Sopenharmony_ci .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ 47798c2ecf20Sopenharmony_ci .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ 47808c2ecf20Sopenharmony_ci .phaselet {float:left;overflow:hidden;border:0px;text-align:center;min-height:100px;font-size:24px;}\n\ 47818c2ecf20Sopenharmony_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\ 47828c2ecf20Sopenharmony_ci .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\ 47838c2ecf20Sopenharmony_ci .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ 47848c2ecf20Sopenharmony_ci .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ 47858c2ecf20Sopenharmony_ci button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ 47868c2ecf20Sopenharmony_ci .btnfmt {position:relative;float:right;height:25px;width:auto;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ 47878c2ecf20Sopenharmony_ci .devlist {position:'+devlistpos+';width:190px;}\n\ 47888c2ecf20Sopenharmony_ci a:link {color:white;text-decoration:none;}\n\ 47898c2ecf20Sopenharmony_ci a:visited {color:white;}\n\ 47908c2ecf20Sopenharmony_ci a:hover {color:white;}\n\ 47918c2ecf20Sopenharmony_ci a:active {color:white;}\n\ 47928c2ecf20Sopenharmony_ci .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ 47938c2ecf20Sopenharmony_ci #devicedetail {min-height:100px;box-shadow:5px 5px 20px black;}\n\ 47948c2ecf20Sopenharmony_ci .tblock {position:absolute;height:100%;background:#ddd;}\n\ 47958c2ecf20Sopenharmony_ci .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ 47968c2ecf20Sopenharmony_ci .bg {z-index:1;}\n\ 47978c2ecf20Sopenharmony_ci'+extra+'\ 47988c2ecf20Sopenharmony_ci </style>\n</head>\n<body>\n' 47998c2ecf20Sopenharmony_ci hf.write(html_header) 48008c2ecf20Sopenharmony_ci 48018c2ecf20Sopenharmony_ci# Function: addScriptCode 48028c2ecf20Sopenharmony_ci# Description: 48038c2ecf20Sopenharmony_ci# Adds the javascript code to the output html 48048c2ecf20Sopenharmony_ci# Arguments: 48058c2ecf20Sopenharmony_ci# hf: the open html file pointer 48068c2ecf20Sopenharmony_ci# testruns: array of Data objects from parseKernelLog or parseTraceLog 48078c2ecf20Sopenharmony_cidef addScriptCode(hf, testruns): 48088c2ecf20Sopenharmony_ci t0 = testruns[0].start * 1000 48098c2ecf20Sopenharmony_ci tMax = testruns[-1].end * 1000 48108c2ecf20Sopenharmony_ci # create an array in javascript memory with the device details 48118c2ecf20Sopenharmony_ci detail = ' var devtable = [];\n' 48128c2ecf20Sopenharmony_ci for data in testruns: 48138c2ecf20Sopenharmony_ci topo = data.deviceTopology() 48148c2ecf20Sopenharmony_ci detail += ' devtable[%d] = "%s";\n' % (data.testnumber, topo) 48158c2ecf20Sopenharmony_ci detail += ' var bounds = [%f,%f];\n' % (t0, tMax) 48168c2ecf20Sopenharmony_ci # add the code which will manipulate the data in the browser 48178c2ecf20Sopenharmony_ci script_code = \ 48188c2ecf20Sopenharmony_ci '<script type="text/javascript">\n'+detail+\ 48198c2ecf20Sopenharmony_ci ' var resolution = -1;\n'\ 48208c2ecf20Sopenharmony_ci ' var dragval = [0, 0];\n'\ 48218c2ecf20Sopenharmony_ci ' function redrawTimescale(t0, tMax, tS) {\n'\ 48228c2ecf20Sopenharmony_ci ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;">\';\n'\ 48238c2ecf20Sopenharmony_ci ' var tTotal = tMax - t0;\n'\ 48248c2ecf20Sopenharmony_ci ' var list = document.getElementsByClassName("tblock");\n'\ 48258c2ecf20Sopenharmony_ci ' for (var i = 0; i < list.length; i++) {\n'\ 48268c2ecf20Sopenharmony_ci ' var timescale = list[i].getElementsByClassName("timescale")[0];\n'\ 48278c2ecf20Sopenharmony_ci ' var m0 = t0 + (tTotal*parseFloat(list[i].style.left)/100);\n'\ 48288c2ecf20Sopenharmony_ci ' var mTotal = tTotal*parseFloat(list[i].style.width)/100;\n'\ 48298c2ecf20Sopenharmony_ci ' var mMax = m0 + mTotal;\n'\ 48308c2ecf20Sopenharmony_ci ' var html = "";\n'\ 48318c2ecf20Sopenharmony_ci ' var divTotal = Math.floor(mTotal/tS) + 1;\n'\ 48328c2ecf20Sopenharmony_ci ' if(divTotal > 1000) continue;\n'\ 48338c2ecf20Sopenharmony_ci ' var divEdge = (mTotal - tS*(divTotal-1))*100/mTotal;\n'\ 48348c2ecf20Sopenharmony_ci ' var pos = 0.0, val = 0.0;\n'\ 48358c2ecf20Sopenharmony_ci ' for (var j = 0; j < divTotal; j++) {\n'\ 48368c2ecf20Sopenharmony_ci ' var htmlline = "";\n'\ 48378c2ecf20Sopenharmony_ci ' var mode = list[i].id[5];\n'\ 48388c2ecf20Sopenharmony_ci ' if(mode == "s") {\n'\ 48398c2ecf20Sopenharmony_ci ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\ 48408c2ecf20Sopenharmony_ci ' val = (j-divTotal+1)*tS;\n'\ 48418c2ecf20Sopenharmony_ci ' if(j == divTotal - 1)\n'\ 48428c2ecf20Sopenharmony_ci ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S→</cS></div>\';\n'\ 48438c2ecf20Sopenharmony_ci ' else\n'\ 48448c2ecf20Sopenharmony_ci ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 48458c2ecf20Sopenharmony_ci ' } else {\n'\ 48468c2ecf20Sopenharmony_ci ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ 48478c2ecf20Sopenharmony_ci ' val = (j)*tS;\n'\ 48488c2ecf20Sopenharmony_ci ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 48498c2ecf20Sopenharmony_ci ' if(j == 0)\n'\ 48508c2ecf20Sopenharmony_ci ' if(mode == "r")\n'\ 48518c2ecf20Sopenharmony_ci ' htmlline = rline+"<cS>←R</cS></div>";\n'\ 48528c2ecf20Sopenharmony_ci ' else\n'\ 48538c2ecf20Sopenharmony_ci ' htmlline = rline+"<cS>0ms</div>";\n'\ 48548c2ecf20Sopenharmony_ci ' }\n'\ 48558c2ecf20Sopenharmony_ci ' html += htmlline;\n'\ 48568c2ecf20Sopenharmony_ci ' }\n'\ 48578c2ecf20Sopenharmony_ci ' timescale.innerHTML = html;\n'\ 48588c2ecf20Sopenharmony_ci ' }\n'\ 48598c2ecf20Sopenharmony_ci ' }\n'\ 48608c2ecf20Sopenharmony_ci ' function zoomTimeline() {\n'\ 48618c2ecf20Sopenharmony_ci ' var dmesg = document.getElementById("dmesg");\n'\ 48628c2ecf20Sopenharmony_ci ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 48638c2ecf20Sopenharmony_ci ' var left = zoombox.scrollLeft;\n'\ 48648c2ecf20Sopenharmony_ci ' var val = parseFloat(dmesg.style.width);\n'\ 48658c2ecf20Sopenharmony_ci ' var newval = 100;\n'\ 48668c2ecf20Sopenharmony_ci ' var sh = window.outerWidth / 2;\n'\ 48678c2ecf20Sopenharmony_ci ' if(this.id == "zoomin") {\n'\ 48688c2ecf20Sopenharmony_ci ' newval = val * 1.2;\n'\ 48698c2ecf20Sopenharmony_ci ' if(newval > 910034) newval = 910034;\n'\ 48708c2ecf20Sopenharmony_ci ' dmesg.style.width = newval+"%";\n'\ 48718c2ecf20Sopenharmony_ci ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 48728c2ecf20Sopenharmony_ci ' } else if (this.id == "zoomout") {\n'\ 48738c2ecf20Sopenharmony_ci ' newval = val / 1.2;\n'\ 48748c2ecf20Sopenharmony_ci ' if(newval < 100) newval = 100;\n'\ 48758c2ecf20Sopenharmony_ci ' dmesg.style.width = newval+"%";\n'\ 48768c2ecf20Sopenharmony_ci ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ 48778c2ecf20Sopenharmony_ci ' } else {\n'\ 48788c2ecf20Sopenharmony_ci ' zoombox.scrollLeft = 0;\n'\ 48798c2ecf20Sopenharmony_ci ' dmesg.style.width = "100%";\n'\ 48808c2ecf20Sopenharmony_ci ' }\n'\ 48818c2ecf20Sopenharmony_ci ' var tS = [10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1];\n'\ 48828c2ecf20Sopenharmony_ci ' var t0 = bounds[0];\n'\ 48838c2ecf20Sopenharmony_ci ' var tMax = bounds[1];\n'\ 48848c2ecf20Sopenharmony_ci ' var tTotal = tMax - t0;\n'\ 48858c2ecf20Sopenharmony_ci ' var wTotal = tTotal * 100.0 / newval;\n'\ 48868c2ecf20Sopenharmony_ci ' var idx = 7*window.innerWidth/1100;\n'\ 48878c2ecf20Sopenharmony_ci ' for(var i = 0; (i < tS.length)&&((wTotal / tS[i]) < idx); i++);\n'\ 48888c2ecf20Sopenharmony_ci ' if(i >= tS.length) i = tS.length - 1;\n'\ 48898c2ecf20Sopenharmony_ci ' if(tS[i] == resolution) return;\n'\ 48908c2ecf20Sopenharmony_ci ' resolution = tS[i];\n'\ 48918c2ecf20Sopenharmony_ci ' redrawTimescale(t0, tMax, tS[i]);\n'\ 48928c2ecf20Sopenharmony_ci ' }\n'\ 48938c2ecf20Sopenharmony_ci ' function deviceName(title) {\n'\ 48948c2ecf20Sopenharmony_ci ' var name = title.slice(0, title.indexOf(" ("));\n'\ 48958c2ecf20Sopenharmony_ci ' return name;\n'\ 48968c2ecf20Sopenharmony_ci ' }\n'\ 48978c2ecf20Sopenharmony_ci ' function deviceHover() {\n'\ 48988c2ecf20Sopenharmony_ci ' var name = deviceName(this.title);\n'\ 48998c2ecf20Sopenharmony_ci ' var dmesg = document.getElementById("dmesg");\n'\ 49008c2ecf20Sopenharmony_ci ' var dev = dmesg.getElementsByClassName("thread");\n'\ 49018c2ecf20Sopenharmony_ci ' var cpu = -1;\n'\ 49028c2ecf20Sopenharmony_ci ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 49038c2ecf20Sopenharmony_ci ' cpu = parseInt(name.slice(7));\n'\ 49048c2ecf20Sopenharmony_ci ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 49058c2ecf20Sopenharmony_ci ' cpu = parseInt(name.slice(8));\n'\ 49068c2ecf20Sopenharmony_ci ' for (var i = 0; i < dev.length; i++) {\n'\ 49078c2ecf20Sopenharmony_ci ' dname = deviceName(dev[i].title);\n'\ 49088c2ecf20Sopenharmony_ci ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 49098c2ecf20Sopenharmony_ci ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 49108c2ecf20Sopenharmony_ci ' (name == dname))\n'\ 49118c2ecf20Sopenharmony_ci ' {\n'\ 49128c2ecf20Sopenharmony_ci ' dev[i].className = "hover "+cname;\n'\ 49138c2ecf20Sopenharmony_ci ' } else {\n'\ 49148c2ecf20Sopenharmony_ci ' dev[i].className = cname;\n'\ 49158c2ecf20Sopenharmony_ci ' }\n'\ 49168c2ecf20Sopenharmony_ci ' }\n'\ 49178c2ecf20Sopenharmony_ci ' }\n'\ 49188c2ecf20Sopenharmony_ci ' function deviceUnhover() {\n'\ 49198c2ecf20Sopenharmony_ci ' var dmesg = document.getElementById("dmesg");\n'\ 49208c2ecf20Sopenharmony_ci ' var dev = dmesg.getElementsByClassName("thread");\n'\ 49218c2ecf20Sopenharmony_ci ' for (var i = 0; i < dev.length; i++) {\n'\ 49228c2ecf20Sopenharmony_ci ' dev[i].className = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ 49238c2ecf20Sopenharmony_ci ' }\n'\ 49248c2ecf20Sopenharmony_ci ' }\n'\ 49258c2ecf20Sopenharmony_ci ' function deviceTitle(title, total, cpu) {\n'\ 49268c2ecf20Sopenharmony_ci ' var prefix = "Total";\n'\ 49278c2ecf20Sopenharmony_ci ' if(total.length > 3) {\n'\ 49288c2ecf20Sopenharmony_ci ' prefix = "Average";\n'\ 49298c2ecf20Sopenharmony_ci ' total[1] = (total[1]+total[3])/2;\n'\ 49308c2ecf20Sopenharmony_ci ' total[2] = (total[2]+total[4])/2;\n'\ 49318c2ecf20Sopenharmony_ci ' }\n'\ 49328c2ecf20Sopenharmony_ci ' var devtitle = document.getElementById("devicedetailtitle");\n'\ 49338c2ecf20Sopenharmony_ci ' var name = deviceName(title);\n'\ 49348c2ecf20Sopenharmony_ci ' if(cpu >= 0) name = "CPU"+cpu;\n'\ 49358c2ecf20Sopenharmony_ci ' var driver = "";\n'\ 49368c2ecf20Sopenharmony_ci ' var tS = "<t2>(</t2>";\n'\ 49378c2ecf20Sopenharmony_ci ' var tR = "<t2>)</t2>";\n'\ 49388c2ecf20Sopenharmony_ci ' if(total[1] > 0)\n'\ 49398c2ecf20Sopenharmony_ci ' tS = "<t2>("+prefix+" Suspend:</t2><t0> "+total[1].toFixed(3)+" ms</t0> ";\n'\ 49408c2ecf20Sopenharmony_ci ' if(total[2] > 0)\n'\ 49418c2ecf20Sopenharmony_ci ' tR = " <t2>"+prefix+" Resume:</t2><t0> "+total[2].toFixed(3)+" ms<t2>)</t2></t0>";\n'\ 49428c2ecf20Sopenharmony_ci ' var s = title.indexOf("{");\n'\ 49438c2ecf20Sopenharmony_ci ' var e = title.indexOf("}");\n'\ 49448c2ecf20Sopenharmony_ci ' if((s >= 0) && (e >= 0))\n'\ 49458c2ecf20Sopenharmony_ci ' driver = title.slice(s+1, e) + " <t1>@</t1> ";\n'\ 49468c2ecf20Sopenharmony_ci ' if(total[1] > 0 && total[2] > 0)\n'\ 49478c2ecf20Sopenharmony_ci ' devtitle.innerHTML = "<t0>"+driver+name+"</t0> "+tS+tR;\n'\ 49488c2ecf20Sopenharmony_ci ' else\n'\ 49498c2ecf20Sopenharmony_ci ' devtitle.innerHTML = "<t0>"+title+"</t0>";\n'\ 49508c2ecf20Sopenharmony_ci ' return name;\n'\ 49518c2ecf20Sopenharmony_ci ' }\n'\ 49528c2ecf20Sopenharmony_ci ' function deviceDetail() {\n'\ 49538c2ecf20Sopenharmony_ci ' var devinfo = document.getElementById("devicedetail");\n'\ 49548c2ecf20Sopenharmony_ci ' devinfo.style.display = "block";\n'\ 49558c2ecf20Sopenharmony_ci ' var name = deviceName(this.title);\n'\ 49568c2ecf20Sopenharmony_ci ' var cpu = -1;\n'\ 49578c2ecf20Sopenharmony_ci ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ 49588c2ecf20Sopenharmony_ci ' cpu = parseInt(name.slice(7));\n'\ 49598c2ecf20Sopenharmony_ci ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ 49608c2ecf20Sopenharmony_ci ' cpu = parseInt(name.slice(8));\n'\ 49618c2ecf20Sopenharmony_ci ' var dmesg = document.getElementById("dmesg");\n'\ 49628c2ecf20Sopenharmony_ci ' var dev = dmesg.getElementsByClassName("thread");\n'\ 49638c2ecf20Sopenharmony_ci ' var idlist = [];\n'\ 49648c2ecf20Sopenharmony_ci ' var pdata = [[]];\n'\ 49658c2ecf20Sopenharmony_ci ' if(document.getElementById("devicedetail1"))\n'\ 49668c2ecf20Sopenharmony_ci ' pdata = [[], []];\n'\ 49678c2ecf20Sopenharmony_ci ' var pd = pdata[0];\n'\ 49688c2ecf20Sopenharmony_ci ' var total = [0.0, 0.0, 0.0];\n'\ 49698c2ecf20Sopenharmony_ci ' for (var i = 0; i < dev.length; i++) {\n'\ 49708c2ecf20Sopenharmony_ci ' dname = deviceName(dev[i].title);\n'\ 49718c2ecf20Sopenharmony_ci ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ 49728c2ecf20Sopenharmony_ci ' (name == dname))\n'\ 49738c2ecf20Sopenharmony_ci ' {\n'\ 49748c2ecf20Sopenharmony_ci ' idlist[idlist.length] = dev[i].id;\n'\ 49758c2ecf20Sopenharmony_ci ' var tidx = 1;\n'\ 49768c2ecf20Sopenharmony_ci ' if(dev[i].id[0] == "a") {\n'\ 49778c2ecf20Sopenharmony_ci ' pd = pdata[0];\n'\ 49788c2ecf20Sopenharmony_ci ' } else {\n'\ 49798c2ecf20Sopenharmony_ci ' if(pdata.length == 1) pdata[1] = [];\n'\ 49808c2ecf20Sopenharmony_ci ' if(total.length == 3) total[3]=total[4]=0.0;\n'\ 49818c2ecf20Sopenharmony_ci ' pd = pdata[1];\n'\ 49828c2ecf20Sopenharmony_ci ' tidx = 3;\n'\ 49838c2ecf20Sopenharmony_ci ' }\n'\ 49848c2ecf20Sopenharmony_ci ' var info = dev[i].title.split(" ");\n'\ 49858c2ecf20Sopenharmony_ci ' var pname = info[info.length-1];\n'\ 49868c2ecf20Sopenharmony_ci ' pd[pname] = parseFloat(info[info.length-3].slice(1));\n'\ 49878c2ecf20Sopenharmony_ci ' total[0] += pd[pname];\n'\ 49888c2ecf20Sopenharmony_ci ' if(pname.indexOf("suspend") >= 0)\n'\ 49898c2ecf20Sopenharmony_ci ' total[tidx] += pd[pname];\n'\ 49908c2ecf20Sopenharmony_ci ' else\n'\ 49918c2ecf20Sopenharmony_ci ' total[tidx+1] += pd[pname];\n'\ 49928c2ecf20Sopenharmony_ci ' }\n'\ 49938c2ecf20Sopenharmony_ci ' }\n'\ 49948c2ecf20Sopenharmony_ci ' var devname = deviceTitle(this.title, total, cpu);\n'\ 49958c2ecf20Sopenharmony_ci ' var left = 0.0;\n'\ 49968c2ecf20Sopenharmony_ci ' for (var t = 0; t < pdata.length; t++) {\n'\ 49978c2ecf20Sopenharmony_ci ' pd = pdata[t];\n'\ 49988c2ecf20Sopenharmony_ci ' devinfo = document.getElementById("devicedetail"+t);\n'\ 49998c2ecf20Sopenharmony_ci ' var phases = devinfo.getElementsByClassName("phaselet");\n'\ 50008c2ecf20Sopenharmony_ci ' for (var i = 0; i < phases.length; i++) {\n'\ 50018c2ecf20Sopenharmony_ci ' if(phases[i].id in pd) {\n'\ 50028c2ecf20Sopenharmony_ci ' var w = 100.0*pd[phases[i].id]/total[0];\n'\ 50038c2ecf20Sopenharmony_ci ' var fs = 32;\n'\ 50048c2ecf20Sopenharmony_ci ' if(w < 8) fs = 4*w | 0;\n'\ 50058c2ecf20Sopenharmony_ci ' var fs2 = fs*3/4;\n'\ 50068c2ecf20Sopenharmony_ci ' phases[i].style.width = w+"%";\n'\ 50078c2ecf20Sopenharmony_ci ' phases[i].style.left = left+"%";\n'\ 50088c2ecf20Sopenharmony_ci ' phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\ 50098c2ecf20Sopenharmony_ci ' left += w;\n'\ 50108c2ecf20Sopenharmony_ci ' var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\ 50118c2ecf20Sopenharmony_ci ' var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";\n'\ 50128c2ecf20Sopenharmony_ci ' phases[i].innerHTML = time+pname;\n'\ 50138c2ecf20Sopenharmony_ci ' } else {\n'\ 50148c2ecf20Sopenharmony_ci ' phases[i].style.width = "0%";\n'\ 50158c2ecf20Sopenharmony_ci ' phases[i].style.left = left+"%";\n'\ 50168c2ecf20Sopenharmony_ci ' }\n'\ 50178c2ecf20Sopenharmony_ci ' }\n'\ 50188c2ecf20Sopenharmony_ci ' }\n'\ 50198c2ecf20Sopenharmony_ci ' if(typeof devstats !== \'undefined\')\n'\ 50208c2ecf20Sopenharmony_ci ' callDetail(this.id, this.title);\n'\ 50218c2ecf20Sopenharmony_ci ' var cglist = document.getElementById("callgraphs");\n'\ 50228c2ecf20Sopenharmony_ci ' if(!cglist) return;\n'\ 50238c2ecf20Sopenharmony_ci ' var cg = cglist.getElementsByClassName("atop");\n'\ 50248c2ecf20Sopenharmony_ci ' if(cg.length < 10) return;\n'\ 50258c2ecf20Sopenharmony_ci ' for (var i = 0; i < cg.length; i++) {\n'\ 50268c2ecf20Sopenharmony_ci ' cgid = cg[i].id.split("x")[0]\n'\ 50278c2ecf20Sopenharmony_ci ' if(idlist.indexOf(cgid) >= 0) {\n'\ 50288c2ecf20Sopenharmony_ci ' cg[i].style.display = "block";\n'\ 50298c2ecf20Sopenharmony_ci ' } else {\n'\ 50308c2ecf20Sopenharmony_ci ' cg[i].style.display = "none";\n'\ 50318c2ecf20Sopenharmony_ci ' }\n'\ 50328c2ecf20Sopenharmony_ci ' }\n'\ 50338c2ecf20Sopenharmony_ci ' }\n'\ 50348c2ecf20Sopenharmony_ci ' function callDetail(devid, devtitle) {\n'\ 50358c2ecf20Sopenharmony_ci ' if(!(devid in devstats) || devstats[devid].length < 1)\n'\ 50368c2ecf20Sopenharmony_ci ' return;\n'\ 50378c2ecf20Sopenharmony_ci ' var list = devstats[devid];\n'\ 50388c2ecf20Sopenharmony_ci ' var tmp = devtitle.split(" ");\n'\ 50398c2ecf20Sopenharmony_ci ' var name = tmp[0], phase = tmp[tmp.length-1];\n'\ 50408c2ecf20Sopenharmony_ci ' var dd = document.getElementById(phase);\n'\ 50418c2ecf20Sopenharmony_ci ' var total = parseFloat(tmp[1].slice(1));\n'\ 50428c2ecf20Sopenharmony_ci ' var mlist = [];\n'\ 50438c2ecf20Sopenharmony_ci ' var maxlen = 0;\n'\ 50448c2ecf20Sopenharmony_ci ' var info = []\n'\ 50458c2ecf20Sopenharmony_ci ' for(var i in list) {\n'\ 50468c2ecf20Sopenharmony_ci ' if(list[i][0] == "@") {\n'\ 50478c2ecf20Sopenharmony_ci ' info = list[i].split("|");\n'\ 50488c2ecf20Sopenharmony_ci ' continue;\n'\ 50498c2ecf20Sopenharmony_ci ' }\n'\ 50508c2ecf20Sopenharmony_ci ' var tmp = list[i].split("|");\n'\ 50518c2ecf20Sopenharmony_ci ' var t = parseFloat(tmp[0]), f = tmp[1], c = parseInt(tmp[2]);\n'\ 50528c2ecf20Sopenharmony_ci ' var p = (t*100.0/total).toFixed(2);\n'\ 50538c2ecf20Sopenharmony_ci ' mlist[mlist.length] = [f, c, t.toFixed(2), p+"%"];\n'\ 50548c2ecf20Sopenharmony_ci ' if(f.length > maxlen)\n'\ 50558c2ecf20Sopenharmony_ci ' maxlen = f.length;\n'\ 50568c2ecf20Sopenharmony_ci ' }\n'\ 50578c2ecf20Sopenharmony_ci ' var pad = 5;\n'\ 50588c2ecf20Sopenharmony_ci ' if(mlist.length == 0) pad = 30;\n'\ 50598c2ecf20Sopenharmony_ci ' var html = \'<div style="padding-top:\'+pad+\'px"><t3> <b>\'+name+\':</b>\';\n'\ 50608c2ecf20Sopenharmony_ci ' if(info.length > 2)\n'\ 50618c2ecf20Sopenharmony_ci ' html += " start=<b>"+info[1]+"</b>, end=<b>"+info[2]+"</b>";\n'\ 50628c2ecf20Sopenharmony_ci ' if(info.length > 3)\n'\ 50638c2ecf20Sopenharmony_ci ' html += ", length<i>(w/o overhead)</i>=<b>"+info[3]+" ms</b>";\n'\ 50648c2ecf20Sopenharmony_ci ' if(info.length > 4)\n'\ 50658c2ecf20Sopenharmony_ci ' html += ", return=<b>"+info[4]+"</b>";\n'\ 50668c2ecf20Sopenharmony_ci ' html += "</t3></div>";\n'\ 50678c2ecf20Sopenharmony_ci ' if(mlist.length > 0) {\n'\ 50688c2ecf20Sopenharmony_ci ' html += \'<table class=fstat style="padding-top:\'+(maxlen*5)+\'px;"><tr><th>Function</th>\';\n'\ 50698c2ecf20Sopenharmony_ci ' for(var i in mlist)\n'\ 50708c2ecf20Sopenharmony_ci ' html += "<td class=vt>"+mlist[i][0]+"</td>";\n'\ 50718c2ecf20Sopenharmony_ci ' html += "</tr><tr><th>Calls</th>";\n'\ 50728c2ecf20Sopenharmony_ci ' for(var i in mlist)\n'\ 50738c2ecf20Sopenharmony_ci ' html += "<td>"+mlist[i][1]+"</td>";\n'\ 50748c2ecf20Sopenharmony_ci ' html += "</tr><tr><th>Time(ms)</th>";\n'\ 50758c2ecf20Sopenharmony_ci ' for(var i in mlist)\n'\ 50768c2ecf20Sopenharmony_ci ' html += "<td>"+mlist[i][2]+"</td>";\n'\ 50778c2ecf20Sopenharmony_ci ' html += "</tr><tr><th>Percent</th>";\n'\ 50788c2ecf20Sopenharmony_ci ' for(var i in mlist)\n'\ 50798c2ecf20Sopenharmony_ci ' html += "<td>"+mlist[i][3]+"</td>";\n'\ 50808c2ecf20Sopenharmony_ci ' html += "</tr></table>";\n'\ 50818c2ecf20Sopenharmony_ci ' }\n'\ 50828c2ecf20Sopenharmony_ci ' dd.innerHTML = html;\n'\ 50838c2ecf20Sopenharmony_ci ' var height = (maxlen*5)+100;\n'\ 50848c2ecf20Sopenharmony_ci ' dd.style.height = height+"px";\n'\ 50858c2ecf20Sopenharmony_ci ' document.getElementById("devicedetail").style.height = height+"px";\n'\ 50868c2ecf20Sopenharmony_ci ' }\n'\ 50878c2ecf20Sopenharmony_ci ' function callSelect() {\n'\ 50888c2ecf20Sopenharmony_ci ' var cglist = document.getElementById("callgraphs");\n'\ 50898c2ecf20Sopenharmony_ci ' if(!cglist) return;\n'\ 50908c2ecf20Sopenharmony_ci ' var cg = cglist.getElementsByClassName("atop");\n'\ 50918c2ecf20Sopenharmony_ci ' for (var i = 0; i < cg.length; i++) {\n'\ 50928c2ecf20Sopenharmony_ci ' if(this.id == cg[i].id) {\n'\ 50938c2ecf20Sopenharmony_ci ' cg[i].style.display = "block";\n'\ 50948c2ecf20Sopenharmony_ci ' } else {\n'\ 50958c2ecf20Sopenharmony_ci ' cg[i].style.display = "none";\n'\ 50968c2ecf20Sopenharmony_ci ' }\n'\ 50978c2ecf20Sopenharmony_ci ' }\n'\ 50988c2ecf20Sopenharmony_ci ' }\n'\ 50998c2ecf20Sopenharmony_ci ' function devListWindow(e) {\n'\ 51008c2ecf20Sopenharmony_ci ' var win = window.open();\n'\ 51018c2ecf20Sopenharmony_ci ' var html = "<title>"+e.target.innerHTML+"</title>"+\n'\ 51028c2ecf20Sopenharmony_ci ' "<style type=\\"text/css\\">"+\n'\ 51038c2ecf20Sopenharmony_ci ' " ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\ 51048c2ecf20Sopenharmony_ci ' "</style>"\n'\ 51058c2ecf20Sopenharmony_ci ' var dt = devtable[0];\n'\ 51068c2ecf20Sopenharmony_ci ' if(e.target.id != "devlist1")\n'\ 51078c2ecf20Sopenharmony_ci ' dt = devtable[1];\n'\ 51088c2ecf20Sopenharmony_ci ' win.document.write(html+dt);\n'\ 51098c2ecf20Sopenharmony_ci ' }\n'\ 51108c2ecf20Sopenharmony_ci ' function errWindow() {\n'\ 51118c2ecf20Sopenharmony_ci ' var range = this.id.split("_");\n'\ 51128c2ecf20Sopenharmony_ci ' var idx1 = parseInt(range[0]);\n'\ 51138c2ecf20Sopenharmony_ci ' var idx2 = parseInt(range[1]);\n'\ 51148c2ecf20Sopenharmony_ci ' var win = window.open();\n'\ 51158c2ecf20Sopenharmony_ci ' var log = document.getElementById("dmesglog");\n'\ 51168c2ecf20Sopenharmony_ci ' var title = "<title>dmesg log</title>";\n'\ 51178c2ecf20Sopenharmony_ci ' var text = log.innerHTML.split("\\n");\n'\ 51188c2ecf20Sopenharmony_ci ' var html = "";\n'\ 51198c2ecf20Sopenharmony_ci ' for(var i = 0; i < text.length; i++) {\n'\ 51208c2ecf20Sopenharmony_ci ' if(i == idx1) {\n'\ 51218c2ecf20Sopenharmony_ci ' html += "<e id=target>"+text[i]+"</e>\\n";\n'\ 51228c2ecf20Sopenharmony_ci ' } else if(i > idx1 && i <= idx2) {\n'\ 51238c2ecf20Sopenharmony_ci ' html += "<e>"+text[i]+"</e>\\n";\n'\ 51248c2ecf20Sopenharmony_ci ' } else {\n'\ 51258c2ecf20Sopenharmony_ci ' html += text[i]+"\\n";\n'\ 51268c2ecf20Sopenharmony_ci ' }\n'\ 51278c2ecf20Sopenharmony_ci ' }\n'\ 51288c2ecf20Sopenharmony_ci ' win.document.write("<style>e{color:red}</style>"+title+"<pre>"+html+"</pre>");\n'\ 51298c2ecf20Sopenharmony_ci ' win.location.hash = "#target";\n'\ 51308c2ecf20Sopenharmony_ci ' win.document.close();\n'\ 51318c2ecf20Sopenharmony_ci ' }\n'\ 51328c2ecf20Sopenharmony_ci ' function logWindow(e) {\n'\ 51338c2ecf20Sopenharmony_ci ' var name = e.target.id.slice(4);\n'\ 51348c2ecf20Sopenharmony_ci ' var win = window.open();\n'\ 51358c2ecf20Sopenharmony_ci ' var log = document.getElementById(name+"log");\n'\ 51368c2ecf20Sopenharmony_ci ' var title = "<title>"+document.title.split(" ")[0]+" "+name+" log</title>";\n'\ 51378c2ecf20Sopenharmony_ci ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ 51388c2ecf20Sopenharmony_ci ' win.document.close();\n'\ 51398c2ecf20Sopenharmony_ci ' }\n'\ 51408c2ecf20Sopenharmony_ci ' function onMouseDown(e) {\n'\ 51418c2ecf20Sopenharmony_ci ' dragval[0] = e.clientX;\n'\ 51428c2ecf20Sopenharmony_ci ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ 51438c2ecf20Sopenharmony_ci ' document.onmousemove = onMouseMove;\n'\ 51448c2ecf20Sopenharmony_ci ' }\n'\ 51458c2ecf20Sopenharmony_ci ' function onMouseMove(e) {\n'\ 51468c2ecf20Sopenharmony_ci ' var zoombox = document.getElementById("dmesgzoombox");\n'\ 51478c2ecf20Sopenharmony_ci ' zoombox.scrollLeft = dragval[1] + dragval[0] - e.clientX;\n'\ 51488c2ecf20Sopenharmony_ci ' }\n'\ 51498c2ecf20Sopenharmony_ci ' function onMouseUp(e) {\n'\ 51508c2ecf20Sopenharmony_ci ' document.onmousemove = null;\n'\ 51518c2ecf20Sopenharmony_ci ' }\n'\ 51528c2ecf20Sopenharmony_ci ' function onKeyPress(e) {\n'\ 51538c2ecf20Sopenharmony_ci ' var c = e.charCode;\n'\ 51548c2ecf20Sopenharmony_ci ' if(c != 42 && c != 43 && c != 45) return;\n'\ 51558c2ecf20Sopenharmony_ci ' var click = document.createEvent("Events");\n'\ 51568c2ecf20Sopenharmony_ci ' click.initEvent("click", true, false);\n'\ 51578c2ecf20Sopenharmony_ci ' if(c == 43) \n'\ 51588c2ecf20Sopenharmony_ci ' document.getElementById("zoomin").dispatchEvent(click);\n'\ 51598c2ecf20Sopenharmony_ci ' else if(c == 45)\n'\ 51608c2ecf20Sopenharmony_ci ' document.getElementById("zoomout").dispatchEvent(click);\n'\ 51618c2ecf20Sopenharmony_ci ' else if(c == 42)\n'\ 51628c2ecf20Sopenharmony_ci ' document.getElementById("zoomdef").dispatchEvent(click);\n'\ 51638c2ecf20Sopenharmony_ci ' }\n'\ 51648c2ecf20Sopenharmony_ci ' window.addEventListener("resize", function () {zoomTimeline();});\n'\ 51658c2ecf20Sopenharmony_ci ' window.addEventListener("load", function () {\n'\ 51668c2ecf20Sopenharmony_ci ' var dmesg = document.getElementById("dmesg");\n'\ 51678c2ecf20Sopenharmony_ci ' dmesg.style.width = "100%"\n'\ 51688c2ecf20Sopenharmony_ci ' dmesg.onmousedown = onMouseDown;\n'\ 51698c2ecf20Sopenharmony_ci ' document.onmouseup = onMouseUp;\n'\ 51708c2ecf20Sopenharmony_ci ' document.onkeypress = onKeyPress;\n'\ 51718c2ecf20Sopenharmony_ci ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ 51728c2ecf20Sopenharmony_ci ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ 51738c2ecf20Sopenharmony_ci ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ 51748c2ecf20Sopenharmony_ci ' var list = document.getElementsByClassName("err");\n'\ 51758c2ecf20Sopenharmony_ci ' for (var i = 0; i < list.length; i++)\n'\ 51768c2ecf20Sopenharmony_ci ' list[i].onclick = errWindow;\n'\ 51778c2ecf20Sopenharmony_ci ' var list = document.getElementsByClassName("logbtn");\n'\ 51788c2ecf20Sopenharmony_ci ' for (var i = 0; i < list.length; i++)\n'\ 51798c2ecf20Sopenharmony_ci ' list[i].onclick = logWindow;\n'\ 51808c2ecf20Sopenharmony_ci ' list = document.getElementsByClassName("devlist");\n'\ 51818c2ecf20Sopenharmony_ci ' for (var i = 0; i < list.length; i++)\n'\ 51828c2ecf20Sopenharmony_ci ' list[i].onclick = devListWindow;\n'\ 51838c2ecf20Sopenharmony_ci ' var dev = dmesg.getElementsByClassName("thread");\n'\ 51848c2ecf20Sopenharmony_ci ' for (var i = 0; i < dev.length; i++) {\n'\ 51858c2ecf20Sopenharmony_ci ' dev[i].onclick = deviceDetail;\n'\ 51868c2ecf20Sopenharmony_ci ' dev[i].onmouseover = deviceHover;\n'\ 51878c2ecf20Sopenharmony_ci ' dev[i].onmouseout = deviceUnhover;\n'\ 51888c2ecf20Sopenharmony_ci ' }\n'\ 51898c2ecf20Sopenharmony_ci ' var dev = dmesg.getElementsByClassName("srccall");\n'\ 51908c2ecf20Sopenharmony_ci ' for (var i = 0; i < dev.length; i++)\n'\ 51918c2ecf20Sopenharmony_ci ' dev[i].onclick = callSelect;\n'\ 51928c2ecf20Sopenharmony_ci ' zoomTimeline();\n'\ 51938c2ecf20Sopenharmony_ci ' });\n'\ 51948c2ecf20Sopenharmony_ci '</script>\n' 51958c2ecf20Sopenharmony_ci hf.write(script_code); 51968c2ecf20Sopenharmony_ci 51978c2ecf20Sopenharmony_cidef setRuntimeSuspend(before=True): 51988c2ecf20Sopenharmony_ci global sysvals 51998c2ecf20Sopenharmony_ci sv = sysvals 52008c2ecf20Sopenharmony_ci if sv.rs == 0: 52018c2ecf20Sopenharmony_ci return 52028c2ecf20Sopenharmony_ci if before: 52038c2ecf20Sopenharmony_ci # runtime suspend disable or enable 52048c2ecf20Sopenharmony_ci if sv.rs > 0: 52058c2ecf20Sopenharmony_ci sv.rstgt, sv.rsval, sv.rsdir = 'on', 'auto', 'enabled' 52068c2ecf20Sopenharmony_ci else: 52078c2ecf20Sopenharmony_ci sv.rstgt, sv.rsval, sv.rsdir = 'auto', 'on', 'disabled' 52088c2ecf20Sopenharmony_ci pprint('CONFIGURING RUNTIME SUSPEND...') 52098c2ecf20Sopenharmony_ci sv.rslist = deviceInfo(sv.rstgt) 52108c2ecf20Sopenharmony_ci for i in sv.rslist: 52118c2ecf20Sopenharmony_ci sv.setVal(sv.rsval, i) 52128c2ecf20Sopenharmony_ci pprint('runtime suspend %s on all devices (%d changed)' % (sv.rsdir, len(sv.rslist))) 52138c2ecf20Sopenharmony_ci pprint('waiting 5 seconds...') 52148c2ecf20Sopenharmony_ci time.sleep(5) 52158c2ecf20Sopenharmony_ci else: 52168c2ecf20Sopenharmony_ci # runtime suspend re-enable or re-disable 52178c2ecf20Sopenharmony_ci for i in sv.rslist: 52188c2ecf20Sopenharmony_ci sv.setVal(sv.rstgt, i) 52198c2ecf20Sopenharmony_ci pprint('runtime suspend settings restored on %d devices' % len(sv.rslist)) 52208c2ecf20Sopenharmony_ci 52218c2ecf20Sopenharmony_ci# Function: executeSuspend 52228c2ecf20Sopenharmony_ci# Description: 52238c2ecf20Sopenharmony_ci# Execute system suspend through the sysfs interface, then copy the output 52248c2ecf20Sopenharmony_ci# dmesg and ftrace files to the test output directory. 52258c2ecf20Sopenharmony_cidef executeSuspend(quiet=False): 52268c2ecf20Sopenharmony_ci pm = ProcessMonitor() 52278c2ecf20Sopenharmony_ci tp = sysvals.tpath 52288c2ecf20Sopenharmony_ci if sysvals.wifi: 52298c2ecf20Sopenharmony_ci wifi = sysvals.checkWifi() 52308c2ecf20Sopenharmony_ci testdata = [] 52318c2ecf20Sopenharmony_ci # run these commands to prepare the system for suspend 52328c2ecf20Sopenharmony_ci if sysvals.display: 52338c2ecf20Sopenharmony_ci if not quiet: 52348c2ecf20Sopenharmony_ci pprint('SET DISPLAY TO %s' % sysvals.display.upper()) 52358c2ecf20Sopenharmony_ci displayControl(sysvals.display) 52368c2ecf20Sopenharmony_ci time.sleep(1) 52378c2ecf20Sopenharmony_ci if sysvals.sync: 52388c2ecf20Sopenharmony_ci if not quiet: 52398c2ecf20Sopenharmony_ci pprint('SYNCING FILESYSTEMS') 52408c2ecf20Sopenharmony_ci call('sync', shell=True) 52418c2ecf20Sopenharmony_ci # mark the start point in the kernel ring buffer just as we start 52428c2ecf20Sopenharmony_ci sysvals.initdmesg() 52438c2ecf20Sopenharmony_ci # start ftrace 52448c2ecf20Sopenharmony_ci if(sysvals.usecallgraph or sysvals.usetraceevents): 52458c2ecf20Sopenharmony_ci if not quiet: 52468c2ecf20Sopenharmony_ci pprint('START TRACING') 52478c2ecf20Sopenharmony_ci sysvals.fsetVal('1', 'tracing_on') 52488c2ecf20Sopenharmony_ci if sysvals.useprocmon: 52498c2ecf20Sopenharmony_ci pm.start() 52508c2ecf20Sopenharmony_ci sysvals.cmdinfo(True) 52518c2ecf20Sopenharmony_ci # execute however many s/r runs requested 52528c2ecf20Sopenharmony_ci for count in range(1,sysvals.execcount+1): 52538c2ecf20Sopenharmony_ci # x2delay in between test runs 52548c2ecf20Sopenharmony_ci if(count > 1 and sysvals.x2delay > 0): 52558c2ecf20Sopenharmony_ci sysvals.fsetVal('WAIT %d' % sysvals.x2delay, 'trace_marker') 52568c2ecf20Sopenharmony_ci time.sleep(sysvals.x2delay/1000.0) 52578c2ecf20Sopenharmony_ci sysvals.fsetVal('WAIT END', 'trace_marker') 52588c2ecf20Sopenharmony_ci # start message 52598c2ecf20Sopenharmony_ci if sysvals.testcommand != '': 52608c2ecf20Sopenharmony_ci pprint('COMMAND START') 52618c2ecf20Sopenharmony_ci else: 52628c2ecf20Sopenharmony_ci if(sysvals.rtcwake): 52638c2ecf20Sopenharmony_ci pprint('SUSPEND START') 52648c2ecf20Sopenharmony_ci else: 52658c2ecf20Sopenharmony_ci pprint('SUSPEND START (press a key to resume)') 52668c2ecf20Sopenharmony_ci # set rtcwake 52678c2ecf20Sopenharmony_ci if(sysvals.rtcwake): 52688c2ecf20Sopenharmony_ci if not quiet: 52698c2ecf20Sopenharmony_ci pprint('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime) 52708c2ecf20Sopenharmony_ci sysvals.rtcWakeAlarmOn() 52718c2ecf20Sopenharmony_ci # start of suspend trace marker 52728c2ecf20Sopenharmony_ci if(sysvals.usecallgraph or sysvals.usetraceevents): 52738c2ecf20Sopenharmony_ci sysvals.fsetVal(datetime.now().strftime(sysvals.tmstart), 'trace_marker') 52748c2ecf20Sopenharmony_ci # predelay delay 52758c2ecf20Sopenharmony_ci if(count == 1 and sysvals.predelay > 0): 52768c2ecf20Sopenharmony_ci sysvals.fsetVal('WAIT %d' % sysvals.predelay, 'trace_marker') 52778c2ecf20Sopenharmony_ci time.sleep(sysvals.predelay/1000.0) 52788c2ecf20Sopenharmony_ci sysvals.fsetVal('WAIT END', 'trace_marker') 52798c2ecf20Sopenharmony_ci # initiate suspend or command 52808c2ecf20Sopenharmony_ci tdata = {'error': ''} 52818c2ecf20Sopenharmony_ci if sysvals.testcommand != '': 52828c2ecf20Sopenharmony_ci res = call(sysvals.testcommand+' 2>&1', shell=True); 52838c2ecf20Sopenharmony_ci if res != 0: 52848c2ecf20Sopenharmony_ci tdata['error'] = 'cmd returned %d' % res 52858c2ecf20Sopenharmony_ci else: 52868c2ecf20Sopenharmony_ci mode = sysvals.suspendmode 52878c2ecf20Sopenharmony_ci if sysvals.memmode and os.path.exists(sysvals.mempowerfile): 52888c2ecf20Sopenharmony_ci mode = 'mem' 52898c2ecf20Sopenharmony_ci pf = open(sysvals.mempowerfile, 'w') 52908c2ecf20Sopenharmony_ci pf.write(sysvals.memmode) 52918c2ecf20Sopenharmony_ci pf.close() 52928c2ecf20Sopenharmony_ci if sysvals.diskmode and os.path.exists(sysvals.diskpowerfile): 52938c2ecf20Sopenharmony_ci mode = 'disk' 52948c2ecf20Sopenharmony_ci pf = open(sysvals.diskpowerfile, 'w') 52958c2ecf20Sopenharmony_ci pf.write(sysvals.diskmode) 52968c2ecf20Sopenharmony_ci pf.close() 52978c2ecf20Sopenharmony_ci if mode == 'freeze' and sysvals.haveTurbostat(): 52988c2ecf20Sopenharmony_ci # execution will pause here 52998c2ecf20Sopenharmony_ci turbo = sysvals.turbostat() 53008c2ecf20Sopenharmony_ci if turbo: 53018c2ecf20Sopenharmony_ci tdata['turbo'] = turbo 53028c2ecf20Sopenharmony_ci else: 53038c2ecf20Sopenharmony_ci pf = open(sysvals.powerfile, 'w') 53048c2ecf20Sopenharmony_ci pf.write(mode) 53058c2ecf20Sopenharmony_ci # execution will pause here 53068c2ecf20Sopenharmony_ci try: 53078c2ecf20Sopenharmony_ci pf.close() 53088c2ecf20Sopenharmony_ci except Exception as e: 53098c2ecf20Sopenharmony_ci tdata['error'] = str(e) 53108c2ecf20Sopenharmony_ci if(sysvals.rtcwake): 53118c2ecf20Sopenharmony_ci sysvals.rtcWakeAlarmOff() 53128c2ecf20Sopenharmony_ci # postdelay delay 53138c2ecf20Sopenharmony_ci if(count == sysvals.execcount and sysvals.postdelay > 0): 53148c2ecf20Sopenharmony_ci sysvals.fsetVal('WAIT %d' % sysvals.postdelay, 'trace_marker') 53158c2ecf20Sopenharmony_ci time.sleep(sysvals.postdelay/1000.0) 53168c2ecf20Sopenharmony_ci sysvals.fsetVal('WAIT END', 'trace_marker') 53178c2ecf20Sopenharmony_ci # return from suspend 53188c2ecf20Sopenharmony_ci pprint('RESUME COMPLETE') 53198c2ecf20Sopenharmony_ci if(sysvals.usecallgraph or sysvals.usetraceevents): 53208c2ecf20Sopenharmony_ci sysvals.fsetVal(datetime.now().strftime(sysvals.tmend), 'trace_marker') 53218c2ecf20Sopenharmony_ci if sysvals.wifi and wifi: 53228c2ecf20Sopenharmony_ci tdata['wifi'] = sysvals.pollWifi(wifi) 53238c2ecf20Sopenharmony_ci if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'): 53248c2ecf20Sopenharmony_ci tdata['fw'] = getFPDT(False) 53258c2ecf20Sopenharmony_ci testdata.append(tdata) 53268c2ecf20Sopenharmony_ci cmdafter = sysvals.cmdinfo(False) 53278c2ecf20Sopenharmony_ci # stop ftrace 53288c2ecf20Sopenharmony_ci if(sysvals.usecallgraph or sysvals.usetraceevents): 53298c2ecf20Sopenharmony_ci if sysvals.useprocmon: 53308c2ecf20Sopenharmony_ci pm.stop() 53318c2ecf20Sopenharmony_ci sysvals.fsetVal('0', 'tracing_on') 53328c2ecf20Sopenharmony_ci # grab a copy of the dmesg output 53338c2ecf20Sopenharmony_ci if not quiet: 53348c2ecf20Sopenharmony_ci pprint('CAPTURING DMESG') 53358c2ecf20Sopenharmony_ci sysvals.getdmesg(testdata) 53368c2ecf20Sopenharmony_ci # grab a copy of the ftrace output 53378c2ecf20Sopenharmony_ci if(sysvals.usecallgraph or sysvals.usetraceevents): 53388c2ecf20Sopenharmony_ci if not quiet: 53398c2ecf20Sopenharmony_ci pprint('CAPTURING TRACE') 53408c2ecf20Sopenharmony_ci op = sysvals.writeDatafileHeader(sysvals.ftracefile, testdata) 53418c2ecf20Sopenharmony_ci fp = open(tp+'trace', 'r') 53428c2ecf20Sopenharmony_ci for line in fp: 53438c2ecf20Sopenharmony_ci op.write(line) 53448c2ecf20Sopenharmony_ci op.close() 53458c2ecf20Sopenharmony_ci sysvals.fsetVal('', 'trace') 53468c2ecf20Sopenharmony_ci sysvals.platforminfo(cmdafter) 53478c2ecf20Sopenharmony_ci 53488c2ecf20Sopenharmony_cidef readFile(file): 53498c2ecf20Sopenharmony_ci if os.path.islink(file): 53508c2ecf20Sopenharmony_ci return os.readlink(file).split('/')[-1] 53518c2ecf20Sopenharmony_ci else: 53528c2ecf20Sopenharmony_ci return sysvals.getVal(file).strip() 53538c2ecf20Sopenharmony_ci 53548c2ecf20Sopenharmony_ci# Function: ms2nice 53558c2ecf20Sopenharmony_ci# Description: 53568c2ecf20Sopenharmony_ci# Print out a very concise time string in minutes and seconds 53578c2ecf20Sopenharmony_ci# Output: 53588c2ecf20Sopenharmony_ci# The time string, e.g. "1901m16s" 53598c2ecf20Sopenharmony_cidef ms2nice(val): 53608c2ecf20Sopenharmony_ci val = int(val) 53618c2ecf20Sopenharmony_ci h = val // 3600000 53628c2ecf20Sopenharmony_ci m = (val // 60000) % 60 53638c2ecf20Sopenharmony_ci s = (val // 1000) % 60 53648c2ecf20Sopenharmony_ci if h > 0: 53658c2ecf20Sopenharmony_ci return '%d:%02d:%02d' % (h, m, s) 53668c2ecf20Sopenharmony_ci if m > 0: 53678c2ecf20Sopenharmony_ci return '%02d:%02d' % (m, s) 53688c2ecf20Sopenharmony_ci return '%ds' % s 53698c2ecf20Sopenharmony_ci 53708c2ecf20Sopenharmony_cidef yesno(val): 53718c2ecf20Sopenharmony_ci list = {'enabled':'A', 'disabled':'S', 'auto':'E', 'on':'D', 53728c2ecf20Sopenharmony_ci 'active':'A', 'suspended':'S', 'suspending':'S'} 53738c2ecf20Sopenharmony_ci if val not in list: 53748c2ecf20Sopenharmony_ci return ' ' 53758c2ecf20Sopenharmony_ci return list[val] 53768c2ecf20Sopenharmony_ci 53778c2ecf20Sopenharmony_ci# Function: deviceInfo 53788c2ecf20Sopenharmony_ci# Description: 53798c2ecf20Sopenharmony_ci# Detect all the USB hosts and devices currently connected and add 53808c2ecf20Sopenharmony_ci# a list of USB device names to sysvals for better timeline readability 53818c2ecf20Sopenharmony_cidef deviceInfo(output=''): 53828c2ecf20Sopenharmony_ci if not output: 53838c2ecf20Sopenharmony_ci pprint('LEGEND\n'\ 53848c2ecf20Sopenharmony_ci '---------------------------------------------------------------------------------------------\n'\ 53858c2ecf20Sopenharmony_ci ' A = async/sync PM queue (A/S) C = runtime active children\n'\ 53868c2ecf20Sopenharmony_ci ' R = runtime suspend enabled/disabled (E/D) rACTIVE = runtime active (min/sec)\n'\ 53878c2ecf20Sopenharmony_ci ' S = runtime status active/suspended (A/S) rSUSPEND = runtime suspend (min/sec)\n'\ 53888c2ecf20Sopenharmony_ci ' U = runtime usage count\n'\ 53898c2ecf20Sopenharmony_ci '---------------------------------------------------------------------------------------------\n'\ 53908c2ecf20Sopenharmony_ci 'DEVICE NAME A R S U C rACTIVE rSUSPEND\n'\ 53918c2ecf20Sopenharmony_ci '---------------------------------------------------------------------------------------------') 53928c2ecf20Sopenharmony_ci 53938c2ecf20Sopenharmony_ci res = [] 53948c2ecf20Sopenharmony_ci tgtval = 'runtime_status' 53958c2ecf20Sopenharmony_ci lines = dict() 53968c2ecf20Sopenharmony_ci for dirname, dirnames, filenames in os.walk('/sys/devices'): 53978c2ecf20Sopenharmony_ci if(not re.match('.*/power', dirname) or 53988c2ecf20Sopenharmony_ci 'control' not in filenames or 53998c2ecf20Sopenharmony_ci tgtval not in filenames): 54008c2ecf20Sopenharmony_ci continue 54018c2ecf20Sopenharmony_ci name = '' 54028c2ecf20Sopenharmony_ci dirname = dirname[:-6] 54038c2ecf20Sopenharmony_ci device = dirname.split('/')[-1] 54048c2ecf20Sopenharmony_ci power = dict() 54058c2ecf20Sopenharmony_ci power[tgtval] = readFile('%s/power/%s' % (dirname, tgtval)) 54068c2ecf20Sopenharmony_ci # only list devices which support runtime suspend 54078c2ecf20Sopenharmony_ci if power[tgtval] not in ['active', 'suspended', 'suspending']: 54088c2ecf20Sopenharmony_ci continue 54098c2ecf20Sopenharmony_ci for i in ['product', 'driver', 'subsystem']: 54108c2ecf20Sopenharmony_ci file = '%s/%s' % (dirname, i) 54118c2ecf20Sopenharmony_ci if os.path.exists(file): 54128c2ecf20Sopenharmony_ci name = readFile(file) 54138c2ecf20Sopenharmony_ci break 54148c2ecf20Sopenharmony_ci for i in ['async', 'control', 'runtime_status', 'runtime_usage', 54158c2ecf20Sopenharmony_ci 'runtime_active_kids', 'runtime_active_time', 54168c2ecf20Sopenharmony_ci 'runtime_suspended_time']: 54178c2ecf20Sopenharmony_ci if i in filenames: 54188c2ecf20Sopenharmony_ci power[i] = readFile('%s/power/%s' % (dirname, i)) 54198c2ecf20Sopenharmony_ci if output: 54208c2ecf20Sopenharmony_ci if power['control'] == output: 54218c2ecf20Sopenharmony_ci res.append('%s/power/control' % dirname) 54228c2ecf20Sopenharmony_ci continue 54238c2ecf20Sopenharmony_ci lines[dirname] = '%-26s %-26s %1s %1s %1s %1s %1s %10s %10s' % \ 54248c2ecf20Sopenharmony_ci (device[:26], name[:26], 54258c2ecf20Sopenharmony_ci yesno(power['async']), \ 54268c2ecf20Sopenharmony_ci yesno(power['control']), \ 54278c2ecf20Sopenharmony_ci yesno(power['runtime_status']), \ 54288c2ecf20Sopenharmony_ci power['runtime_usage'], \ 54298c2ecf20Sopenharmony_ci power['runtime_active_kids'], \ 54308c2ecf20Sopenharmony_ci ms2nice(power['runtime_active_time']), \ 54318c2ecf20Sopenharmony_ci ms2nice(power['runtime_suspended_time'])) 54328c2ecf20Sopenharmony_ci for i in sorted(lines): 54338c2ecf20Sopenharmony_ci print(lines[i]) 54348c2ecf20Sopenharmony_ci return res 54358c2ecf20Sopenharmony_ci 54368c2ecf20Sopenharmony_ci# Function: getModes 54378c2ecf20Sopenharmony_ci# Description: 54388c2ecf20Sopenharmony_ci# Determine the supported power modes on this system 54398c2ecf20Sopenharmony_ci# Output: 54408c2ecf20Sopenharmony_ci# A string list of the available modes 54418c2ecf20Sopenharmony_cidef getModes(): 54428c2ecf20Sopenharmony_ci modes = [] 54438c2ecf20Sopenharmony_ci if(os.path.exists(sysvals.powerfile)): 54448c2ecf20Sopenharmony_ci fp = open(sysvals.powerfile, 'r') 54458c2ecf20Sopenharmony_ci modes = fp.read().split() 54468c2ecf20Sopenharmony_ci fp.close() 54478c2ecf20Sopenharmony_ci if(os.path.exists(sysvals.mempowerfile)): 54488c2ecf20Sopenharmony_ci deep = False 54498c2ecf20Sopenharmony_ci fp = open(sysvals.mempowerfile, 'r') 54508c2ecf20Sopenharmony_ci for m in fp.read().split(): 54518c2ecf20Sopenharmony_ci memmode = m.strip('[]') 54528c2ecf20Sopenharmony_ci if memmode == 'deep': 54538c2ecf20Sopenharmony_ci deep = True 54548c2ecf20Sopenharmony_ci else: 54558c2ecf20Sopenharmony_ci modes.append('mem-%s' % memmode) 54568c2ecf20Sopenharmony_ci fp.close() 54578c2ecf20Sopenharmony_ci if 'mem' in modes and not deep: 54588c2ecf20Sopenharmony_ci modes.remove('mem') 54598c2ecf20Sopenharmony_ci if('disk' in modes and os.path.exists(sysvals.diskpowerfile)): 54608c2ecf20Sopenharmony_ci fp = open(sysvals.diskpowerfile, 'r') 54618c2ecf20Sopenharmony_ci for m in fp.read().split(): 54628c2ecf20Sopenharmony_ci modes.append('disk-%s' % m.strip('[]')) 54638c2ecf20Sopenharmony_ci fp.close() 54648c2ecf20Sopenharmony_ci return modes 54658c2ecf20Sopenharmony_ci 54668c2ecf20Sopenharmony_ci# Function: dmidecode 54678c2ecf20Sopenharmony_ci# Description: 54688c2ecf20Sopenharmony_ci# Read the bios tables and pull out system info 54698c2ecf20Sopenharmony_ci# Arguments: 54708c2ecf20Sopenharmony_ci# mempath: /dev/mem or custom mem path 54718c2ecf20Sopenharmony_ci# fatal: True to exit on error, False to return empty dict 54728c2ecf20Sopenharmony_ci# Output: 54738c2ecf20Sopenharmony_ci# A dict object with all available key/values 54748c2ecf20Sopenharmony_cidef dmidecode(mempath, fatal=False): 54758c2ecf20Sopenharmony_ci out = dict() 54768c2ecf20Sopenharmony_ci 54778c2ecf20Sopenharmony_ci # the list of values to retrieve, with hardcoded (type, idx) 54788c2ecf20Sopenharmony_ci info = { 54798c2ecf20Sopenharmony_ci 'bios-vendor': (0, 4), 54808c2ecf20Sopenharmony_ci 'bios-version': (0, 5), 54818c2ecf20Sopenharmony_ci 'bios-release-date': (0, 8), 54828c2ecf20Sopenharmony_ci 'system-manufacturer': (1, 4), 54838c2ecf20Sopenharmony_ci 'system-product-name': (1, 5), 54848c2ecf20Sopenharmony_ci 'system-version': (1, 6), 54858c2ecf20Sopenharmony_ci 'system-serial-number': (1, 7), 54868c2ecf20Sopenharmony_ci 'baseboard-manufacturer': (2, 4), 54878c2ecf20Sopenharmony_ci 'baseboard-product-name': (2, 5), 54888c2ecf20Sopenharmony_ci 'baseboard-version': (2, 6), 54898c2ecf20Sopenharmony_ci 'baseboard-serial-number': (2, 7), 54908c2ecf20Sopenharmony_ci 'chassis-manufacturer': (3, 4), 54918c2ecf20Sopenharmony_ci 'chassis-type': (3, 5), 54928c2ecf20Sopenharmony_ci 'chassis-version': (3, 6), 54938c2ecf20Sopenharmony_ci 'chassis-serial-number': (3, 7), 54948c2ecf20Sopenharmony_ci 'processor-manufacturer': (4, 7), 54958c2ecf20Sopenharmony_ci 'processor-version': (4, 16), 54968c2ecf20Sopenharmony_ci } 54978c2ecf20Sopenharmony_ci if(not os.path.exists(mempath)): 54988c2ecf20Sopenharmony_ci if(fatal): 54998c2ecf20Sopenharmony_ci doError('file does not exist: %s' % mempath) 55008c2ecf20Sopenharmony_ci return out 55018c2ecf20Sopenharmony_ci if(not os.access(mempath, os.R_OK)): 55028c2ecf20Sopenharmony_ci if(fatal): 55038c2ecf20Sopenharmony_ci doError('file is not readable: %s' % mempath) 55048c2ecf20Sopenharmony_ci return out 55058c2ecf20Sopenharmony_ci 55068c2ecf20Sopenharmony_ci # by default use legacy scan, but try to use EFI first 55078c2ecf20Sopenharmony_ci memaddr = 0xf0000 55088c2ecf20Sopenharmony_ci memsize = 0x10000 55098c2ecf20Sopenharmony_ci for ep in ['/sys/firmware/efi/systab', '/proc/efi/systab']: 55108c2ecf20Sopenharmony_ci if not os.path.exists(ep) or not os.access(ep, os.R_OK): 55118c2ecf20Sopenharmony_ci continue 55128c2ecf20Sopenharmony_ci fp = open(ep, 'r') 55138c2ecf20Sopenharmony_ci buf = fp.read() 55148c2ecf20Sopenharmony_ci fp.close() 55158c2ecf20Sopenharmony_ci i = buf.find('SMBIOS=') 55168c2ecf20Sopenharmony_ci if i >= 0: 55178c2ecf20Sopenharmony_ci try: 55188c2ecf20Sopenharmony_ci memaddr = int(buf[i+7:], 16) 55198c2ecf20Sopenharmony_ci memsize = 0x20 55208c2ecf20Sopenharmony_ci except: 55218c2ecf20Sopenharmony_ci continue 55228c2ecf20Sopenharmony_ci 55238c2ecf20Sopenharmony_ci # read in the memory for scanning 55248c2ecf20Sopenharmony_ci try: 55258c2ecf20Sopenharmony_ci fp = open(mempath, 'rb') 55268c2ecf20Sopenharmony_ci fp.seek(memaddr) 55278c2ecf20Sopenharmony_ci buf = fp.read(memsize) 55288c2ecf20Sopenharmony_ci except: 55298c2ecf20Sopenharmony_ci if(fatal): 55308c2ecf20Sopenharmony_ci doError('DMI table is unreachable, sorry') 55318c2ecf20Sopenharmony_ci else: 55328c2ecf20Sopenharmony_ci pprint('WARNING: /dev/mem is not readable, ignoring DMI data') 55338c2ecf20Sopenharmony_ci return out 55348c2ecf20Sopenharmony_ci fp.close() 55358c2ecf20Sopenharmony_ci 55368c2ecf20Sopenharmony_ci # search for either an SM table or DMI table 55378c2ecf20Sopenharmony_ci i = base = length = num = 0 55388c2ecf20Sopenharmony_ci while(i < memsize): 55398c2ecf20Sopenharmony_ci if buf[i:i+4] == b'_SM_' and i < memsize - 16: 55408c2ecf20Sopenharmony_ci length = struct.unpack('H', buf[i+22:i+24])[0] 55418c2ecf20Sopenharmony_ci base, num = struct.unpack('IH', buf[i+24:i+30]) 55428c2ecf20Sopenharmony_ci break 55438c2ecf20Sopenharmony_ci elif buf[i:i+5] == b'_DMI_': 55448c2ecf20Sopenharmony_ci length = struct.unpack('H', buf[i+6:i+8])[0] 55458c2ecf20Sopenharmony_ci base, num = struct.unpack('IH', buf[i+8:i+14]) 55468c2ecf20Sopenharmony_ci break 55478c2ecf20Sopenharmony_ci i += 16 55488c2ecf20Sopenharmony_ci if base == 0 and length == 0 and num == 0: 55498c2ecf20Sopenharmony_ci if(fatal): 55508c2ecf20Sopenharmony_ci doError('Neither SMBIOS nor DMI were found') 55518c2ecf20Sopenharmony_ci else: 55528c2ecf20Sopenharmony_ci return out 55538c2ecf20Sopenharmony_ci 55548c2ecf20Sopenharmony_ci # read in the SM or DMI table 55558c2ecf20Sopenharmony_ci try: 55568c2ecf20Sopenharmony_ci fp = open(mempath, 'rb') 55578c2ecf20Sopenharmony_ci fp.seek(base) 55588c2ecf20Sopenharmony_ci buf = fp.read(length) 55598c2ecf20Sopenharmony_ci except: 55608c2ecf20Sopenharmony_ci if(fatal): 55618c2ecf20Sopenharmony_ci doError('DMI table is unreachable, sorry') 55628c2ecf20Sopenharmony_ci else: 55638c2ecf20Sopenharmony_ci pprint('WARNING: /dev/mem is not readable, ignoring DMI data') 55648c2ecf20Sopenharmony_ci return out 55658c2ecf20Sopenharmony_ci fp.close() 55668c2ecf20Sopenharmony_ci 55678c2ecf20Sopenharmony_ci # scan the table for the values we want 55688c2ecf20Sopenharmony_ci count = i = 0 55698c2ecf20Sopenharmony_ci while(count < num and i <= len(buf) - 4): 55708c2ecf20Sopenharmony_ci type, size, handle = struct.unpack('BBH', buf[i:i+4]) 55718c2ecf20Sopenharmony_ci n = i + size 55728c2ecf20Sopenharmony_ci while n < len(buf) - 1: 55738c2ecf20Sopenharmony_ci if 0 == struct.unpack('H', buf[n:n+2])[0]: 55748c2ecf20Sopenharmony_ci break 55758c2ecf20Sopenharmony_ci n += 1 55768c2ecf20Sopenharmony_ci data = buf[i+size:n+2].split(b'\0') 55778c2ecf20Sopenharmony_ci for name in info: 55788c2ecf20Sopenharmony_ci itype, idxadr = info[name] 55798c2ecf20Sopenharmony_ci if itype == type: 55808c2ecf20Sopenharmony_ci idx = struct.unpack('B', buf[i+idxadr:i+idxadr+1])[0] 55818c2ecf20Sopenharmony_ci if idx > 0 and idx < len(data) - 1: 55828c2ecf20Sopenharmony_ci s = data[idx-1].decode('utf-8') 55838c2ecf20Sopenharmony_ci if s.strip() and s.strip().lower() != 'to be filled by o.e.m.': 55848c2ecf20Sopenharmony_ci out[name] = s 55858c2ecf20Sopenharmony_ci i = n + 2 55868c2ecf20Sopenharmony_ci count += 1 55878c2ecf20Sopenharmony_ci return out 55888c2ecf20Sopenharmony_ci 55898c2ecf20Sopenharmony_cidef displayControl(cmd): 55908c2ecf20Sopenharmony_ci xset, ret = 'timeout 10 xset -d :0.0 {0}', 0 55918c2ecf20Sopenharmony_ci if sysvals.sudouser: 55928c2ecf20Sopenharmony_ci xset = 'sudo -u %s %s' % (sysvals.sudouser, xset) 55938c2ecf20Sopenharmony_ci if cmd == 'init': 55948c2ecf20Sopenharmony_ci ret = call(xset.format('dpms 0 0 0'), shell=True) 55958c2ecf20Sopenharmony_ci if not ret: 55968c2ecf20Sopenharmony_ci ret = call(xset.format('s off'), shell=True) 55978c2ecf20Sopenharmony_ci elif cmd == 'reset': 55988c2ecf20Sopenharmony_ci ret = call(xset.format('s reset'), shell=True) 55998c2ecf20Sopenharmony_ci elif cmd in ['on', 'off', 'standby', 'suspend']: 56008c2ecf20Sopenharmony_ci b4 = displayControl('stat') 56018c2ecf20Sopenharmony_ci ret = call(xset.format('dpms force %s' % cmd), shell=True) 56028c2ecf20Sopenharmony_ci if not ret: 56038c2ecf20Sopenharmony_ci curr = displayControl('stat') 56048c2ecf20Sopenharmony_ci sysvals.vprint('Display Switched: %s -> %s' % (b4, curr)) 56058c2ecf20Sopenharmony_ci if curr != cmd: 56068c2ecf20Sopenharmony_ci sysvals.vprint('WARNING: Display failed to change to %s' % cmd) 56078c2ecf20Sopenharmony_ci if ret: 56088c2ecf20Sopenharmony_ci sysvals.vprint('WARNING: Display failed to change to %s with xset' % cmd) 56098c2ecf20Sopenharmony_ci return ret 56108c2ecf20Sopenharmony_ci elif cmd == 'stat': 56118c2ecf20Sopenharmony_ci fp = Popen(xset.format('q').split(' '), stdout=PIPE).stdout 56128c2ecf20Sopenharmony_ci ret = 'unknown' 56138c2ecf20Sopenharmony_ci for line in fp: 56148c2ecf20Sopenharmony_ci m = re.match('[\s]*Monitor is (?P<m>.*)', ascii(line)) 56158c2ecf20Sopenharmony_ci if(m and len(m.group('m')) >= 2): 56168c2ecf20Sopenharmony_ci out = m.group('m').lower() 56178c2ecf20Sopenharmony_ci ret = out[3:] if out[0:2] == 'in' else out 56188c2ecf20Sopenharmony_ci break 56198c2ecf20Sopenharmony_ci fp.close() 56208c2ecf20Sopenharmony_ci return ret 56218c2ecf20Sopenharmony_ci 56228c2ecf20Sopenharmony_ci# Function: getFPDT 56238c2ecf20Sopenharmony_ci# Description: 56248c2ecf20Sopenharmony_ci# Read the acpi bios tables and pull out FPDT, the firmware data 56258c2ecf20Sopenharmony_ci# Arguments: 56268c2ecf20Sopenharmony_ci# output: True to output the info to stdout, False otherwise 56278c2ecf20Sopenharmony_cidef getFPDT(output): 56288c2ecf20Sopenharmony_ci rectype = {} 56298c2ecf20Sopenharmony_ci rectype[0] = 'Firmware Basic Boot Performance Record' 56308c2ecf20Sopenharmony_ci rectype[1] = 'S3 Performance Table Record' 56318c2ecf20Sopenharmony_ci prectype = {} 56328c2ecf20Sopenharmony_ci prectype[0] = 'Basic S3 Resume Performance Record' 56338c2ecf20Sopenharmony_ci prectype[1] = 'Basic S3 Suspend Performance Record' 56348c2ecf20Sopenharmony_ci 56358c2ecf20Sopenharmony_ci sysvals.rootCheck(True) 56368c2ecf20Sopenharmony_ci if(not os.path.exists(sysvals.fpdtpath)): 56378c2ecf20Sopenharmony_ci if(output): 56388c2ecf20Sopenharmony_ci doError('file does not exist: %s' % sysvals.fpdtpath) 56398c2ecf20Sopenharmony_ci return False 56408c2ecf20Sopenharmony_ci if(not os.access(sysvals.fpdtpath, os.R_OK)): 56418c2ecf20Sopenharmony_ci if(output): 56428c2ecf20Sopenharmony_ci doError('file is not readable: %s' % sysvals.fpdtpath) 56438c2ecf20Sopenharmony_ci return False 56448c2ecf20Sopenharmony_ci if(not os.path.exists(sysvals.mempath)): 56458c2ecf20Sopenharmony_ci if(output): 56468c2ecf20Sopenharmony_ci doError('file does not exist: %s' % sysvals.mempath) 56478c2ecf20Sopenharmony_ci return False 56488c2ecf20Sopenharmony_ci if(not os.access(sysvals.mempath, os.R_OK)): 56498c2ecf20Sopenharmony_ci if(output): 56508c2ecf20Sopenharmony_ci doError('file is not readable: %s' % sysvals.mempath) 56518c2ecf20Sopenharmony_ci return False 56528c2ecf20Sopenharmony_ci 56538c2ecf20Sopenharmony_ci fp = open(sysvals.fpdtpath, 'rb') 56548c2ecf20Sopenharmony_ci buf = fp.read() 56558c2ecf20Sopenharmony_ci fp.close() 56568c2ecf20Sopenharmony_ci 56578c2ecf20Sopenharmony_ci if(len(buf) < 36): 56588c2ecf20Sopenharmony_ci if(output): 56598c2ecf20Sopenharmony_ci doError('Invalid FPDT table data, should '+\ 56608c2ecf20Sopenharmony_ci 'be at least 36 bytes') 56618c2ecf20Sopenharmony_ci return False 56628c2ecf20Sopenharmony_ci 56638c2ecf20Sopenharmony_ci table = struct.unpack('4sIBB6s8sI4sI', buf[0:36]) 56648c2ecf20Sopenharmony_ci if(output): 56658c2ecf20Sopenharmony_ci pprint('\n'\ 56668c2ecf20Sopenharmony_ci 'Firmware Performance Data Table (%s)\n'\ 56678c2ecf20Sopenharmony_ci ' Signature : %s\n'\ 56688c2ecf20Sopenharmony_ci ' Table Length : %u\n'\ 56698c2ecf20Sopenharmony_ci ' Revision : %u\n'\ 56708c2ecf20Sopenharmony_ci ' Checksum : 0x%x\n'\ 56718c2ecf20Sopenharmony_ci ' OEM ID : %s\n'\ 56728c2ecf20Sopenharmony_ci ' OEM Table ID : %s\n'\ 56738c2ecf20Sopenharmony_ci ' OEM Revision : %u\n'\ 56748c2ecf20Sopenharmony_ci ' Creator ID : %s\n'\ 56758c2ecf20Sopenharmony_ci ' Creator Revision : 0x%x\n'\ 56768c2ecf20Sopenharmony_ci '' % (ascii(table[0]), ascii(table[0]), table[1], table[2], 56778c2ecf20Sopenharmony_ci table[3], ascii(table[4]), ascii(table[5]), table[6], 56788c2ecf20Sopenharmony_ci ascii(table[7]), table[8])) 56798c2ecf20Sopenharmony_ci 56808c2ecf20Sopenharmony_ci if(table[0] != b'FPDT'): 56818c2ecf20Sopenharmony_ci if(output): 56828c2ecf20Sopenharmony_ci doError('Invalid FPDT table') 56838c2ecf20Sopenharmony_ci return False 56848c2ecf20Sopenharmony_ci if(len(buf) <= 36): 56858c2ecf20Sopenharmony_ci return False 56868c2ecf20Sopenharmony_ci i = 0 56878c2ecf20Sopenharmony_ci fwData = [0, 0] 56888c2ecf20Sopenharmony_ci records = buf[36:] 56898c2ecf20Sopenharmony_ci try: 56908c2ecf20Sopenharmony_ci fp = open(sysvals.mempath, 'rb') 56918c2ecf20Sopenharmony_ci except: 56928c2ecf20Sopenharmony_ci pprint('WARNING: /dev/mem is not readable, ignoring the FPDT data') 56938c2ecf20Sopenharmony_ci return False 56948c2ecf20Sopenharmony_ci while(i < len(records)): 56958c2ecf20Sopenharmony_ci header = struct.unpack('HBB', records[i:i+4]) 56968c2ecf20Sopenharmony_ci if(header[0] not in rectype): 56978c2ecf20Sopenharmony_ci i += header[1] 56988c2ecf20Sopenharmony_ci continue 56998c2ecf20Sopenharmony_ci if(header[1] != 16): 57008c2ecf20Sopenharmony_ci i += header[1] 57018c2ecf20Sopenharmony_ci continue 57028c2ecf20Sopenharmony_ci addr = struct.unpack('Q', records[i+8:i+16])[0] 57038c2ecf20Sopenharmony_ci try: 57048c2ecf20Sopenharmony_ci fp.seek(addr) 57058c2ecf20Sopenharmony_ci first = fp.read(8) 57068c2ecf20Sopenharmony_ci except: 57078c2ecf20Sopenharmony_ci if(output): 57088c2ecf20Sopenharmony_ci pprint('Bad address 0x%x in %s' % (addr, sysvals.mempath)) 57098c2ecf20Sopenharmony_ci return [0, 0] 57108c2ecf20Sopenharmony_ci rechead = struct.unpack('4sI', first) 57118c2ecf20Sopenharmony_ci recdata = fp.read(rechead[1]-8) 57128c2ecf20Sopenharmony_ci if(rechead[0] == b'FBPT'): 57138c2ecf20Sopenharmony_ci record = struct.unpack('HBBIQQQQQ', recdata[:48]) 57148c2ecf20Sopenharmony_ci if(output): 57158c2ecf20Sopenharmony_ci pprint('%s (%s)\n'\ 57168c2ecf20Sopenharmony_ci ' Reset END : %u ns\n'\ 57178c2ecf20Sopenharmony_ci ' OS Loader LoadImage Start : %u ns\n'\ 57188c2ecf20Sopenharmony_ci ' OS Loader StartImage Start : %u ns\n'\ 57198c2ecf20Sopenharmony_ci ' ExitBootServices Entry : %u ns\n'\ 57208c2ecf20Sopenharmony_ci ' ExitBootServices Exit : %u ns'\ 57218c2ecf20Sopenharmony_ci '' % (rectype[header[0]], ascii(rechead[0]), record[4], record[5], 57228c2ecf20Sopenharmony_ci record[6], record[7], record[8])) 57238c2ecf20Sopenharmony_ci elif(rechead[0] == b'S3PT'): 57248c2ecf20Sopenharmony_ci if(output): 57258c2ecf20Sopenharmony_ci pprint('%s (%s)' % (rectype[header[0]], ascii(rechead[0]))) 57268c2ecf20Sopenharmony_ci j = 0 57278c2ecf20Sopenharmony_ci while(j < len(recdata)): 57288c2ecf20Sopenharmony_ci prechead = struct.unpack('HBB', recdata[j:j+4]) 57298c2ecf20Sopenharmony_ci if(prechead[0] not in prectype): 57308c2ecf20Sopenharmony_ci continue 57318c2ecf20Sopenharmony_ci if(prechead[0] == 0): 57328c2ecf20Sopenharmony_ci record = struct.unpack('IIQQ', recdata[j:j+prechead[1]]) 57338c2ecf20Sopenharmony_ci fwData[1] = record[2] 57348c2ecf20Sopenharmony_ci if(output): 57358c2ecf20Sopenharmony_ci pprint(' %s\n'\ 57368c2ecf20Sopenharmony_ci ' Resume Count : %u\n'\ 57378c2ecf20Sopenharmony_ci ' FullResume : %u ns\n'\ 57388c2ecf20Sopenharmony_ci ' AverageResume : %u ns'\ 57398c2ecf20Sopenharmony_ci '' % (prectype[prechead[0]], record[1], 57408c2ecf20Sopenharmony_ci record[2], record[3])) 57418c2ecf20Sopenharmony_ci elif(prechead[0] == 1): 57428c2ecf20Sopenharmony_ci record = struct.unpack('QQ', recdata[j+4:j+prechead[1]]) 57438c2ecf20Sopenharmony_ci fwData[0] = record[1] - record[0] 57448c2ecf20Sopenharmony_ci if(output): 57458c2ecf20Sopenharmony_ci pprint(' %s\n'\ 57468c2ecf20Sopenharmony_ci ' SuspendStart : %u ns\n'\ 57478c2ecf20Sopenharmony_ci ' SuspendEnd : %u ns\n'\ 57488c2ecf20Sopenharmony_ci ' SuspendTime : %u ns'\ 57498c2ecf20Sopenharmony_ci '' % (prectype[prechead[0]], record[0], 57508c2ecf20Sopenharmony_ci record[1], fwData[0])) 57518c2ecf20Sopenharmony_ci 57528c2ecf20Sopenharmony_ci j += prechead[1] 57538c2ecf20Sopenharmony_ci if(output): 57548c2ecf20Sopenharmony_ci pprint('') 57558c2ecf20Sopenharmony_ci i += header[1] 57568c2ecf20Sopenharmony_ci fp.close() 57578c2ecf20Sopenharmony_ci return fwData 57588c2ecf20Sopenharmony_ci 57598c2ecf20Sopenharmony_ci# Function: statusCheck 57608c2ecf20Sopenharmony_ci# Description: 57618c2ecf20Sopenharmony_ci# Verify that the requested command and options will work, and 57628c2ecf20Sopenharmony_ci# print the results to the terminal 57638c2ecf20Sopenharmony_ci# Output: 57648c2ecf20Sopenharmony_ci# True if the test will work, False if not 57658c2ecf20Sopenharmony_cidef statusCheck(probecheck=False): 57668c2ecf20Sopenharmony_ci status = '' 57678c2ecf20Sopenharmony_ci 57688c2ecf20Sopenharmony_ci pprint('Checking this system (%s)...' % platform.node()) 57698c2ecf20Sopenharmony_ci 57708c2ecf20Sopenharmony_ci # check we have root access 57718c2ecf20Sopenharmony_ci res = sysvals.colorText('NO (No features of this tool will work!)') 57728c2ecf20Sopenharmony_ci if(sysvals.rootCheck(False)): 57738c2ecf20Sopenharmony_ci res = 'YES' 57748c2ecf20Sopenharmony_ci pprint(' have root access: %s' % res) 57758c2ecf20Sopenharmony_ci if(res != 'YES'): 57768c2ecf20Sopenharmony_ci pprint(' Try running this script with sudo') 57778c2ecf20Sopenharmony_ci return 'missing root access' 57788c2ecf20Sopenharmony_ci 57798c2ecf20Sopenharmony_ci # check sysfs is mounted 57808c2ecf20Sopenharmony_ci res = sysvals.colorText('NO (No features of this tool will work!)') 57818c2ecf20Sopenharmony_ci if(os.path.exists(sysvals.powerfile)): 57828c2ecf20Sopenharmony_ci res = 'YES' 57838c2ecf20Sopenharmony_ci pprint(' is sysfs mounted: %s' % res) 57848c2ecf20Sopenharmony_ci if(res != 'YES'): 57858c2ecf20Sopenharmony_ci return 'sysfs is missing' 57868c2ecf20Sopenharmony_ci 57878c2ecf20Sopenharmony_ci # check target mode is a valid mode 57888c2ecf20Sopenharmony_ci if sysvals.suspendmode != 'command': 57898c2ecf20Sopenharmony_ci res = sysvals.colorText('NO') 57908c2ecf20Sopenharmony_ci modes = getModes() 57918c2ecf20Sopenharmony_ci if(sysvals.suspendmode in modes): 57928c2ecf20Sopenharmony_ci res = 'YES' 57938c2ecf20Sopenharmony_ci else: 57948c2ecf20Sopenharmony_ci status = '%s mode is not supported' % sysvals.suspendmode 57958c2ecf20Sopenharmony_ci pprint(' is "%s" a valid power mode: %s' % (sysvals.suspendmode, res)) 57968c2ecf20Sopenharmony_ci if(res == 'NO'): 57978c2ecf20Sopenharmony_ci pprint(' valid power modes are: %s' % modes) 57988c2ecf20Sopenharmony_ci pprint(' please choose one with -m') 57998c2ecf20Sopenharmony_ci 58008c2ecf20Sopenharmony_ci # check if ftrace is available 58018c2ecf20Sopenharmony_ci res = sysvals.colorText('NO') 58028c2ecf20Sopenharmony_ci ftgood = sysvals.verifyFtrace() 58038c2ecf20Sopenharmony_ci if(ftgood): 58048c2ecf20Sopenharmony_ci res = 'YES' 58058c2ecf20Sopenharmony_ci elif(sysvals.usecallgraph): 58068c2ecf20Sopenharmony_ci status = 'ftrace is not properly supported' 58078c2ecf20Sopenharmony_ci pprint(' is ftrace supported: %s' % res) 58088c2ecf20Sopenharmony_ci 58098c2ecf20Sopenharmony_ci # check if kprobes are available 58108c2ecf20Sopenharmony_ci if sysvals.usekprobes: 58118c2ecf20Sopenharmony_ci res = sysvals.colorText('NO') 58128c2ecf20Sopenharmony_ci sysvals.usekprobes = sysvals.verifyKprobes() 58138c2ecf20Sopenharmony_ci if(sysvals.usekprobes): 58148c2ecf20Sopenharmony_ci res = 'YES' 58158c2ecf20Sopenharmony_ci else: 58168c2ecf20Sopenharmony_ci sysvals.usedevsrc = False 58178c2ecf20Sopenharmony_ci pprint(' are kprobes supported: %s' % res) 58188c2ecf20Sopenharmony_ci 58198c2ecf20Sopenharmony_ci # what data source are we using 58208c2ecf20Sopenharmony_ci res = 'DMESG' 58218c2ecf20Sopenharmony_ci if(ftgood): 58228c2ecf20Sopenharmony_ci sysvals.usetraceevents = True 58238c2ecf20Sopenharmony_ci for e in sysvals.traceevents: 58248c2ecf20Sopenharmony_ci if not os.path.exists(sysvals.epath+e): 58258c2ecf20Sopenharmony_ci sysvals.usetraceevents = False 58268c2ecf20Sopenharmony_ci if(sysvals.usetraceevents): 58278c2ecf20Sopenharmony_ci res = 'FTRACE (all trace events found)' 58288c2ecf20Sopenharmony_ci pprint(' timeline data source: %s' % res) 58298c2ecf20Sopenharmony_ci 58308c2ecf20Sopenharmony_ci # check if rtcwake 58318c2ecf20Sopenharmony_ci res = sysvals.colorText('NO') 58328c2ecf20Sopenharmony_ci if(sysvals.rtcpath != ''): 58338c2ecf20Sopenharmony_ci res = 'YES' 58348c2ecf20Sopenharmony_ci elif(sysvals.rtcwake): 58358c2ecf20Sopenharmony_ci status = 'rtcwake is not properly supported' 58368c2ecf20Sopenharmony_ci pprint(' is rtcwake supported: %s' % res) 58378c2ecf20Sopenharmony_ci 58388c2ecf20Sopenharmony_ci # check info commands 58398c2ecf20Sopenharmony_ci pprint(' optional commands this tool may use for info:') 58408c2ecf20Sopenharmony_ci no = sysvals.colorText('MISSING') 58418c2ecf20Sopenharmony_ci yes = sysvals.colorText('FOUND', 32) 58428c2ecf20Sopenharmony_ci for c in ['turbostat', 'mcelog', 'lspci', 'lsusb']: 58438c2ecf20Sopenharmony_ci if c == 'turbostat': 58448c2ecf20Sopenharmony_ci res = yes if sysvals.haveTurbostat() else no 58458c2ecf20Sopenharmony_ci else: 58468c2ecf20Sopenharmony_ci res = yes if sysvals.getExec(c) else no 58478c2ecf20Sopenharmony_ci pprint(' %s: %s' % (c, res)) 58488c2ecf20Sopenharmony_ci 58498c2ecf20Sopenharmony_ci if not probecheck: 58508c2ecf20Sopenharmony_ci return status 58518c2ecf20Sopenharmony_ci 58528c2ecf20Sopenharmony_ci # verify kprobes 58538c2ecf20Sopenharmony_ci if sysvals.usekprobes: 58548c2ecf20Sopenharmony_ci for name in sysvals.tracefuncs: 58558c2ecf20Sopenharmony_ci sysvals.defaultKprobe(name, sysvals.tracefuncs[name]) 58568c2ecf20Sopenharmony_ci if sysvals.usedevsrc: 58578c2ecf20Sopenharmony_ci for name in sysvals.dev_tracefuncs: 58588c2ecf20Sopenharmony_ci sysvals.defaultKprobe(name, sysvals.dev_tracefuncs[name]) 58598c2ecf20Sopenharmony_ci sysvals.addKprobes(True) 58608c2ecf20Sopenharmony_ci 58618c2ecf20Sopenharmony_ci return status 58628c2ecf20Sopenharmony_ci 58638c2ecf20Sopenharmony_ci# Function: doError 58648c2ecf20Sopenharmony_ci# Description: 58658c2ecf20Sopenharmony_ci# generic error function for catastrphic failures 58668c2ecf20Sopenharmony_ci# Arguments: 58678c2ecf20Sopenharmony_ci# msg: the error message to print 58688c2ecf20Sopenharmony_ci# help: True if printHelp should be called after, False otherwise 58698c2ecf20Sopenharmony_cidef doError(msg, help=False): 58708c2ecf20Sopenharmony_ci if(help == True): 58718c2ecf20Sopenharmony_ci printHelp() 58728c2ecf20Sopenharmony_ci pprint('ERROR: %s\n' % msg) 58738c2ecf20Sopenharmony_ci sysvals.outputResult({'error':msg}) 58748c2ecf20Sopenharmony_ci sys.exit(1) 58758c2ecf20Sopenharmony_ci 58768c2ecf20Sopenharmony_ci# Function: getArgInt 58778c2ecf20Sopenharmony_ci# Description: 58788c2ecf20Sopenharmony_ci# pull out an integer argument from the command line with checks 58798c2ecf20Sopenharmony_cidef getArgInt(name, args, min, max, main=True): 58808c2ecf20Sopenharmony_ci if main: 58818c2ecf20Sopenharmony_ci try: 58828c2ecf20Sopenharmony_ci arg = next(args) 58838c2ecf20Sopenharmony_ci except: 58848c2ecf20Sopenharmony_ci doError(name+': no argument supplied', True) 58858c2ecf20Sopenharmony_ci else: 58868c2ecf20Sopenharmony_ci arg = args 58878c2ecf20Sopenharmony_ci try: 58888c2ecf20Sopenharmony_ci val = int(arg) 58898c2ecf20Sopenharmony_ci except: 58908c2ecf20Sopenharmony_ci doError(name+': non-integer value given', True) 58918c2ecf20Sopenharmony_ci if(val < min or val > max): 58928c2ecf20Sopenharmony_ci doError(name+': value should be between %d and %d' % (min, max), True) 58938c2ecf20Sopenharmony_ci return val 58948c2ecf20Sopenharmony_ci 58958c2ecf20Sopenharmony_ci# Function: getArgFloat 58968c2ecf20Sopenharmony_ci# Description: 58978c2ecf20Sopenharmony_ci# pull out a float argument from the command line with checks 58988c2ecf20Sopenharmony_cidef getArgFloat(name, args, min, max, main=True): 58998c2ecf20Sopenharmony_ci if main: 59008c2ecf20Sopenharmony_ci try: 59018c2ecf20Sopenharmony_ci arg = next(args) 59028c2ecf20Sopenharmony_ci except: 59038c2ecf20Sopenharmony_ci doError(name+': no argument supplied', True) 59048c2ecf20Sopenharmony_ci else: 59058c2ecf20Sopenharmony_ci arg = args 59068c2ecf20Sopenharmony_ci try: 59078c2ecf20Sopenharmony_ci val = float(arg) 59088c2ecf20Sopenharmony_ci except: 59098c2ecf20Sopenharmony_ci doError(name+': non-numerical value given', True) 59108c2ecf20Sopenharmony_ci if(val < min or val > max): 59118c2ecf20Sopenharmony_ci doError(name+': value should be between %f and %f' % (min, max), True) 59128c2ecf20Sopenharmony_ci return val 59138c2ecf20Sopenharmony_ci 59148c2ecf20Sopenharmony_cidef processData(live=False, quiet=False): 59158c2ecf20Sopenharmony_ci if not quiet: 59168c2ecf20Sopenharmony_ci pprint('PROCESSING: %s' % sysvals.htmlfile) 59178c2ecf20Sopenharmony_ci sysvals.vprint('usetraceevents=%s, usetracemarkers=%s, usekprobes=%s' % \ 59188c2ecf20Sopenharmony_ci (sysvals.usetraceevents, sysvals.usetracemarkers, sysvals.usekprobes)) 59198c2ecf20Sopenharmony_ci error = '' 59208c2ecf20Sopenharmony_ci if(sysvals.usetraceevents): 59218c2ecf20Sopenharmony_ci testruns, error = parseTraceLog(live) 59228c2ecf20Sopenharmony_ci if sysvals.dmesgfile: 59238c2ecf20Sopenharmony_ci for data in testruns: 59248c2ecf20Sopenharmony_ci data.extractErrorInfo() 59258c2ecf20Sopenharmony_ci else: 59268c2ecf20Sopenharmony_ci testruns = loadKernelLog() 59278c2ecf20Sopenharmony_ci for data in testruns: 59288c2ecf20Sopenharmony_ci parseKernelLog(data) 59298c2ecf20Sopenharmony_ci if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): 59308c2ecf20Sopenharmony_ci appendIncompleteTraceLog(testruns) 59318c2ecf20Sopenharmony_ci if not sysvals.stamp: 59328c2ecf20Sopenharmony_ci pprint('ERROR: data does not include the expected stamp') 59338c2ecf20Sopenharmony_ci return (testruns, {'error': 'timeline generation failed'}) 59348c2ecf20Sopenharmony_ci shown = ['bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr', 59358c2ecf20Sopenharmony_ci 'memsz', 'mode', 'numcpu', 'plat', 'time', 'wifi'] 59368c2ecf20Sopenharmony_ci sysvals.vprint('System Info:') 59378c2ecf20Sopenharmony_ci for key in sorted(sysvals.stamp): 59388c2ecf20Sopenharmony_ci if key in shown: 59398c2ecf20Sopenharmony_ci sysvals.vprint(' %-8s : %s' % (key.upper(), sysvals.stamp[key])) 59408c2ecf20Sopenharmony_ci sysvals.vprint('Command:\n %s' % sysvals.cmdline) 59418c2ecf20Sopenharmony_ci for data in testruns: 59428c2ecf20Sopenharmony_ci if data.turbostat: 59438c2ecf20Sopenharmony_ci idx, s = 0, 'Turbostat:\n ' 59448c2ecf20Sopenharmony_ci for val in data.turbostat.split('|'): 59458c2ecf20Sopenharmony_ci idx += len(val) + 1 59468c2ecf20Sopenharmony_ci if idx >= 80: 59478c2ecf20Sopenharmony_ci idx = 0 59488c2ecf20Sopenharmony_ci s += '\n ' 59498c2ecf20Sopenharmony_ci s += val + ' ' 59508c2ecf20Sopenharmony_ci sysvals.vprint(s) 59518c2ecf20Sopenharmony_ci data.printDetails() 59528c2ecf20Sopenharmony_ci if len(sysvals.platinfo) > 0: 59538c2ecf20Sopenharmony_ci sysvals.vprint('\nPlatform Info:') 59548c2ecf20Sopenharmony_ci for info in sysvals.platinfo: 59558c2ecf20Sopenharmony_ci sysvals.vprint('[%s - %s]' % (info[0], info[1])) 59568c2ecf20Sopenharmony_ci sysvals.vprint(info[2]) 59578c2ecf20Sopenharmony_ci sysvals.vprint('') 59588c2ecf20Sopenharmony_ci if sysvals.cgdump: 59598c2ecf20Sopenharmony_ci for data in testruns: 59608c2ecf20Sopenharmony_ci data.debugPrint() 59618c2ecf20Sopenharmony_ci sys.exit(0) 59628c2ecf20Sopenharmony_ci if len(testruns) < 1: 59638c2ecf20Sopenharmony_ci pprint('ERROR: Not enough test data to build a timeline') 59648c2ecf20Sopenharmony_ci return (testruns, {'error': 'timeline generation failed'}) 59658c2ecf20Sopenharmony_ci sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile) 59668c2ecf20Sopenharmony_ci createHTML(testruns, error) 59678c2ecf20Sopenharmony_ci if not quiet: 59688c2ecf20Sopenharmony_ci pprint('DONE: %s' % sysvals.htmlfile) 59698c2ecf20Sopenharmony_ci data = testruns[0] 59708c2ecf20Sopenharmony_ci stamp = data.stamp 59718c2ecf20Sopenharmony_ci stamp['suspend'], stamp['resume'] = data.getTimeValues() 59728c2ecf20Sopenharmony_ci if data.fwValid: 59738c2ecf20Sopenharmony_ci stamp['fwsuspend'], stamp['fwresume'] = data.fwSuspend, data.fwResume 59748c2ecf20Sopenharmony_ci if error: 59758c2ecf20Sopenharmony_ci stamp['error'] = error 59768c2ecf20Sopenharmony_ci return (testruns, stamp) 59778c2ecf20Sopenharmony_ci 59788c2ecf20Sopenharmony_ci# Function: rerunTest 59798c2ecf20Sopenharmony_ci# Description: 59808c2ecf20Sopenharmony_ci# generate an output from an existing set of ftrace/dmesg logs 59818c2ecf20Sopenharmony_cidef rerunTest(htmlfile=''): 59828c2ecf20Sopenharmony_ci if sysvals.ftracefile: 59838c2ecf20Sopenharmony_ci doesTraceLogHaveTraceEvents() 59848c2ecf20Sopenharmony_ci if not sysvals.dmesgfile and not sysvals.usetraceevents: 59858c2ecf20Sopenharmony_ci doError('recreating this html output requires a dmesg file') 59868c2ecf20Sopenharmony_ci if htmlfile: 59878c2ecf20Sopenharmony_ci sysvals.htmlfile = htmlfile 59888c2ecf20Sopenharmony_ci else: 59898c2ecf20Sopenharmony_ci sysvals.setOutputFile() 59908c2ecf20Sopenharmony_ci if os.path.exists(sysvals.htmlfile): 59918c2ecf20Sopenharmony_ci if not os.path.isfile(sysvals.htmlfile): 59928c2ecf20Sopenharmony_ci doError('a directory already exists with this name: %s' % sysvals.htmlfile) 59938c2ecf20Sopenharmony_ci elif not os.access(sysvals.htmlfile, os.W_OK): 59948c2ecf20Sopenharmony_ci doError('missing permission to write to %s' % sysvals.htmlfile) 59958c2ecf20Sopenharmony_ci testruns, stamp = processData() 59968c2ecf20Sopenharmony_ci sysvals.resetlog() 59978c2ecf20Sopenharmony_ci return stamp 59988c2ecf20Sopenharmony_ci 59998c2ecf20Sopenharmony_ci# Function: runTest 60008c2ecf20Sopenharmony_ci# Description: 60018c2ecf20Sopenharmony_ci# execute a suspend/resume, gather the logs, and generate the output 60028c2ecf20Sopenharmony_cidef runTest(n=0, quiet=False): 60038c2ecf20Sopenharmony_ci # prepare for the test 60048c2ecf20Sopenharmony_ci sysvals.initFtrace(quiet) 60058c2ecf20Sopenharmony_ci sysvals.initTestOutput('suspend') 60068c2ecf20Sopenharmony_ci 60078c2ecf20Sopenharmony_ci # execute the test 60088c2ecf20Sopenharmony_ci executeSuspend(quiet) 60098c2ecf20Sopenharmony_ci sysvals.cleanupFtrace() 60108c2ecf20Sopenharmony_ci if sysvals.skiphtml: 60118c2ecf20Sopenharmony_ci sysvals.outputResult({}, n) 60128c2ecf20Sopenharmony_ci sysvals.sudoUserchown(sysvals.testdir) 60138c2ecf20Sopenharmony_ci return 60148c2ecf20Sopenharmony_ci testruns, stamp = processData(True, quiet) 60158c2ecf20Sopenharmony_ci for data in testruns: 60168c2ecf20Sopenharmony_ci del data 60178c2ecf20Sopenharmony_ci sysvals.sudoUserchown(sysvals.testdir) 60188c2ecf20Sopenharmony_ci sysvals.outputResult(stamp, n) 60198c2ecf20Sopenharmony_ci if 'error' in stamp: 60208c2ecf20Sopenharmony_ci return 2 60218c2ecf20Sopenharmony_ci return 0 60228c2ecf20Sopenharmony_ci 60238c2ecf20Sopenharmony_cidef find_in_html(html, start, end, firstonly=True): 60248c2ecf20Sopenharmony_ci cnt, out, list = len(html), [], [] 60258c2ecf20Sopenharmony_ci if firstonly: 60268c2ecf20Sopenharmony_ci m = re.search(start, html) 60278c2ecf20Sopenharmony_ci if m: 60288c2ecf20Sopenharmony_ci list.append(m) 60298c2ecf20Sopenharmony_ci else: 60308c2ecf20Sopenharmony_ci list = re.finditer(start, html) 60318c2ecf20Sopenharmony_ci for match in list: 60328c2ecf20Sopenharmony_ci s = match.end() 60338c2ecf20Sopenharmony_ci e = cnt if (len(out) < 1 or s + 10000 > cnt) else s + 10000 60348c2ecf20Sopenharmony_ci m = re.search(end, html[s:e]) 60358c2ecf20Sopenharmony_ci if not m: 60368c2ecf20Sopenharmony_ci break 60378c2ecf20Sopenharmony_ci e = s + m.start() 60388c2ecf20Sopenharmony_ci str = html[s:e] 60398c2ecf20Sopenharmony_ci if end == 'ms': 60408c2ecf20Sopenharmony_ci num = re.search(r'[-+]?\d*\.\d+|\d+', str) 60418c2ecf20Sopenharmony_ci str = num.group() if num else 'NaN' 60428c2ecf20Sopenharmony_ci if firstonly: 60438c2ecf20Sopenharmony_ci return str 60448c2ecf20Sopenharmony_ci out.append(str) 60458c2ecf20Sopenharmony_ci if firstonly: 60468c2ecf20Sopenharmony_ci return '' 60478c2ecf20Sopenharmony_ci return out 60488c2ecf20Sopenharmony_ci 60498c2ecf20Sopenharmony_cidef data_from_html(file, outpath, issues, fulldetail=False): 60508c2ecf20Sopenharmony_ci html = open(file, 'r').read() 60518c2ecf20Sopenharmony_ci sysvals.htmlfile = os.path.relpath(file, outpath) 60528c2ecf20Sopenharmony_ci # extract general info 60538c2ecf20Sopenharmony_ci suspend = find_in_html(html, 'Kernel Suspend', 'ms') 60548c2ecf20Sopenharmony_ci resume = find_in_html(html, 'Kernel Resume', 'ms') 60558c2ecf20Sopenharmony_ci sysinfo = find_in_html(html, '<div class="stamp sysinfo">', '</div>') 60568c2ecf20Sopenharmony_ci line = find_in_html(html, '<div class="stamp">', '</div>') 60578c2ecf20Sopenharmony_ci stmp = line.split() 60588c2ecf20Sopenharmony_ci if not suspend or not resume or len(stmp) != 8: 60598c2ecf20Sopenharmony_ci return False 60608c2ecf20Sopenharmony_ci try: 60618c2ecf20Sopenharmony_ci dt = datetime.strptime(' '.join(stmp[3:]), '%B %d %Y, %I:%M:%S %p') 60628c2ecf20Sopenharmony_ci except: 60638c2ecf20Sopenharmony_ci return False 60648c2ecf20Sopenharmony_ci sysvals.hostname = stmp[0] 60658c2ecf20Sopenharmony_ci tstr = dt.strftime('%Y/%m/%d %H:%M:%S') 60668c2ecf20Sopenharmony_ci error = find_in_html(html, '<table class="testfail"><tr><td>', '</td>') 60678c2ecf20Sopenharmony_ci if error: 60688c2ecf20Sopenharmony_ci m = re.match('[a-z0-9]* failed in (?P<p>\S*).*', error) 60698c2ecf20Sopenharmony_ci if m: 60708c2ecf20Sopenharmony_ci result = 'fail in %s' % m.group('p') 60718c2ecf20Sopenharmony_ci else: 60728c2ecf20Sopenharmony_ci result = 'fail' 60738c2ecf20Sopenharmony_ci else: 60748c2ecf20Sopenharmony_ci result = 'pass' 60758c2ecf20Sopenharmony_ci # extract error info 60768c2ecf20Sopenharmony_ci tp, ilist = False, [] 60778c2ecf20Sopenharmony_ci extra = dict() 60788c2ecf20Sopenharmony_ci log = find_in_html(html, '<div id="dmesglog" style="display:none;">', 60798c2ecf20Sopenharmony_ci '</div>').strip() 60808c2ecf20Sopenharmony_ci if log: 60818c2ecf20Sopenharmony_ci d = Data(0) 60828c2ecf20Sopenharmony_ci d.end = 999999999 60838c2ecf20Sopenharmony_ci d.dmesgtext = log.split('\n') 60848c2ecf20Sopenharmony_ci tp = d.extractErrorInfo() 60858c2ecf20Sopenharmony_ci for msg in tp.msglist: 60868c2ecf20Sopenharmony_ci sysvals.errorSummary(issues, msg) 60878c2ecf20Sopenharmony_ci if stmp[2] == 'freeze': 60888c2ecf20Sopenharmony_ci extra = d.turbostatInfo() 60898c2ecf20Sopenharmony_ci elist = dict() 60908c2ecf20Sopenharmony_ci for dir in d.errorinfo: 60918c2ecf20Sopenharmony_ci for err in d.errorinfo[dir]: 60928c2ecf20Sopenharmony_ci if err[0] not in elist: 60938c2ecf20Sopenharmony_ci elist[err[0]] = 0 60948c2ecf20Sopenharmony_ci elist[err[0]] += 1 60958c2ecf20Sopenharmony_ci for i in elist: 60968c2ecf20Sopenharmony_ci ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i) 60978c2ecf20Sopenharmony_ci wifi = find_in_html(html, 'Wifi Resume: ', '</td>') 60988c2ecf20Sopenharmony_ci if wifi: 60998c2ecf20Sopenharmony_ci extra['wifi'] = wifi 61008c2ecf20Sopenharmony_ci low = find_in_html(html, 'freeze time: <b>', ' ms</b>') 61018c2ecf20Sopenharmony_ci if low and 'waking' in low: 61028c2ecf20Sopenharmony_ci issue = 'FREEZEWAKE' 61038c2ecf20Sopenharmony_ci match = [i for i in issues if i['match'] == issue] 61048c2ecf20Sopenharmony_ci if len(match) > 0: 61058c2ecf20Sopenharmony_ci match[0]['count'] += 1 61068c2ecf20Sopenharmony_ci if sysvals.hostname not in match[0]['urls']: 61078c2ecf20Sopenharmony_ci match[0]['urls'][sysvals.hostname] = [sysvals.htmlfile] 61088c2ecf20Sopenharmony_ci elif sysvals.htmlfile not in match[0]['urls'][sysvals.hostname]: 61098c2ecf20Sopenharmony_ci match[0]['urls'][sysvals.hostname].append(sysvals.htmlfile) 61108c2ecf20Sopenharmony_ci else: 61118c2ecf20Sopenharmony_ci issues.append({ 61128c2ecf20Sopenharmony_ci 'match': issue, 'count': 1, 'line': issue, 61138c2ecf20Sopenharmony_ci 'urls': {sysvals.hostname: [sysvals.htmlfile]}, 61148c2ecf20Sopenharmony_ci }) 61158c2ecf20Sopenharmony_ci ilist.append(issue) 61168c2ecf20Sopenharmony_ci # extract device info 61178c2ecf20Sopenharmony_ci devices = dict() 61188c2ecf20Sopenharmony_ci for line in html.split('\n'): 61198c2ecf20Sopenharmony_ci m = re.match(' *<div id=\"[a,0-9]*\" *title=\"(?P<title>.*)\" class=\"thread.*', line) 61208c2ecf20Sopenharmony_ci if not m or 'thread kth' in line or 'thread sec' in line: 61218c2ecf20Sopenharmony_ci continue 61228c2ecf20Sopenharmony_ci m = re.match('(?P<n>.*) \((?P<t>[0-9,\.]*) ms\) (?P<p>.*)', m.group('title')) 61238c2ecf20Sopenharmony_ci if not m: 61248c2ecf20Sopenharmony_ci continue 61258c2ecf20Sopenharmony_ci name, time, phase = m.group('n'), m.group('t'), m.group('p') 61268c2ecf20Sopenharmony_ci if ' async' in name or ' sync' in name: 61278c2ecf20Sopenharmony_ci name = ' '.join(name.split(' ')[:-1]) 61288c2ecf20Sopenharmony_ci if phase.startswith('suspend'): 61298c2ecf20Sopenharmony_ci d = 'suspend' 61308c2ecf20Sopenharmony_ci elif phase.startswith('resume'): 61318c2ecf20Sopenharmony_ci d = 'resume' 61328c2ecf20Sopenharmony_ci else: 61338c2ecf20Sopenharmony_ci continue 61348c2ecf20Sopenharmony_ci if d not in devices: 61358c2ecf20Sopenharmony_ci devices[d] = dict() 61368c2ecf20Sopenharmony_ci if name not in devices[d]: 61378c2ecf20Sopenharmony_ci devices[d][name] = 0.0 61388c2ecf20Sopenharmony_ci devices[d][name] += float(time) 61398c2ecf20Sopenharmony_ci # create worst device info 61408c2ecf20Sopenharmony_ci worst = dict() 61418c2ecf20Sopenharmony_ci for d in ['suspend', 'resume']: 61428c2ecf20Sopenharmony_ci worst[d] = {'name':'', 'time': 0.0} 61438c2ecf20Sopenharmony_ci dev = devices[d] if d in devices else 0 61448c2ecf20Sopenharmony_ci if dev and len(dev.keys()) > 0: 61458c2ecf20Sopenharmony_ci n = sorted(dev, key=lambda k:(dev[k], k), reverse=True)[0] 61468c2ecf20Sopenharmony_ci worst[d]['name'], worst[d]['time'] = n, dev[n] 61478c2ecf20Sopenharmony_ci data = { 61488c2ecf20Sopenharmony_ci 'mode': stmp[2], 61498c2ecf20Sopenharmony_ci 'host': stmp[0], 61508c2ecf20Sopenharmony_ci 'kernel': stmp[1], 61518c2ecf20Sopenharmony_ci 'sysinfo': sysinfo, 61528c2ecf20Sopenharmony_ci 'time': tstr, 61538c2ecf20Sopenharmony_ci 'result': result, 61548c2ecf20Sopenharmony_ci 'issues': ' '.join(ilist), 61558c2ecf20Sopenharmony_ci 'suspend': suspend, 61568c2ecf20Sopenharmony_ci 'resume': resume, 61578c2ecf20Sopenharmony_ci 'devlist': devices, 61588c2ecf20Sopenharmony_ci 'sus_worst': worst['suspend']['name'], 61598c2ecf20Sopenharmony_ci 'sus_worsttime': worst['suspend']['time'], 61608c2ecf20Sopenharmony_ci 'res_worst': worst['resume']['name'], 61618c2ecf20Sopenharmony_ci 'res_worsttime': worst['resume']['time'], 61628c2ecf20Sopenharmony_ci 'url': sysvals.htmlfile, 61638c2ecf20Sopenharmony_ci } 61648c2ecf20Sopenharmony_ci for key in extra: 61658c2ecf20Sopenharmony_ci data[key] = extra[key] 61668c2ecf20Sopenharmony_ci if fulldetail: 61678c2ecf20Sopenharmony_ci data['funclist'] = find_in_html(html, '<div title="', '" class="traceevent"', False) 61688c2ecf20Sopenharmony_ci if tp: 61698c2ecf20Sopenharmony_ci for arg in ['-multi ', '-info ']: 61708c2ecf20Sopenharmony_ci if arg in tp.cmdline: 61718c2ecf20Sopenharmony_ci data['target'] = tp.cmdline[tp.cmdline.find(arg):].split()[1] 61728c2ecf20Sopenharmony_ci break 61738c2ecf20Sopenharmony_ci return data 61748c2ecf20Sopenharmony_ci 61758c2ecf20Sopenharmony_cidef genHtml(subdir, force=False): 61768c2ecf20Sopenharmony_ci for dirname, dirnames, filenames in os.walk(subdir): 61778c2ecf20Sopenharmony_ci sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = '' 61788c2ecf20Sopenharmony_ci for filename in filenames: 61798c2ecf20Sopenharmony_ci file = os.path.join(dirname, filename) 61808c2ecf20Sopenharmony_ci if sysvals.usable(file): 61818c2ecf20Sopenharmony_ci if(re.match('.*_dmesg.txt', filename)): 61828c2ecf20Sopenharmony_ci sysvals.dmesgfile = file 61838c2ecf20Sopenharmony_ci elif(re.match('.*_ftrace.txt', filename)): 61848c2ecf20Sopenharmony_ci sysvals.ftracefile = file 61858c2ecf20Sopenharmony_ci sysvals.setOutputFile() 61868c2ecf20Sopenharmony_ci if (sysvals.dmesgfile or sysvals.ftracefile) and sysvals.htmlfile and \ 61878c2ecf20Sopenharmony_ci (force or not sysvals.usable(sysvals.htmlfile)): 61888c2ecf20Sopenharmony_ci pprint('FTRACE: %s' % sysvals.ftracefile) 61898c2ecf20Sopenharmony_ci if sysvals.dmesgfile: 61908c2ecf20Sopenharmony_ci pprint('DMESG : %s' % sysvals.dmesgfile) 61918c2ecf20Sopenharmony_ci rerunTest() 61928c2ecf20Sopenharmony_ci 61938c2ecf20Sopenharmony_ci# Function: runSummary 61948c2ecf20Sopenharmony_ci# Description: 61958c2ecf20Sopenharmony_ci# create a summary of tests in a sub-directory 61968c2ecf20Sopenharmony_cidef runSummary(subdir, local=True, genhtml=False): 61978c2ecf20Sopenharmony_ci inpath = os.path.abspath(subdir) 61988c2ecf20Sopenharmony_ci outpath = os.path.abspath('.') if local else inpath 61998c2ecf20Sopenharmony_ci pprint('Generating a summary of folder:\n %s' % inpath) 62008c2ecf20Sopenharmony_ci if genhtml: 62018c2ecf20Sopenharmony_ci genHtml(subdir) 62028c2ecf20Sopenharmony_ci target, issues, testruns = '', [], [] 62038c2ecf20Sopenharmony_ci desc = {'host':[],'mode':[],'kernel':[]} 62048c2ecf20Sopenharmony_ci for dirname, dirnames, filenames in os.walk(subdir): 62058c2ecf20Sopenharmony_ci for filename in filenames: 62068c2ecf20Sopenharmony_ci if(not re.match('.*.html', filename)): 62078c2ecf20Sopenharmony_ci continue 62088c2ecf20Sopenharmony_ci data = data_from_html(os.path.join(dirname, filename), outpath, issues) 62098c2ecf20Sopenharmony_ci if(not data): 62108c2ecf20Sopenharmony_ci continue 62118c2ecf20Sopenharmony_ci if 'target' in data: 62128c2ecf20Sopenharmony_ci target = data['target'] 62138c2ecf20Sopenharmony_ci testruns.append(data) 62148c2ecf20Sopenharmony_ci for key in desc: 62158c2ecf20Sopenharmony_ci if data[key] not in desc[key]: 62168c2ecf20Sopenharmony_ci desc[key].append(data[key]) 62178c2ecf20Sopenharmony_ci pprint('Summary files:') 62188c2ecf20Sopenharmony_ci if len(desc['host']) == len(desc['mode']) == len(desc['kernel']) == 1: 62198c2ecf20Sopenharmony_ci title = '%s %s %s' % (desc['host'][0], desc['kernel'][0], desc['mode'][0]) 62208c2ecf20Sopenharmony_ci if target: 62218c2ecf20Sopenharmony_ci title += ' %s' % target 62228c2ecf20Sopenharmony_ci else: 62238c2ecf20Sopenharmony_ci title = inpath 62248c2ecf20Sopenharmony_ci createHTMLSummarySimple(testruns, os.path.join(outpath, 'summary.html'), title) 62258c2ecf20Sopenharmony_ci pprint(' summary.html - tabular list of test data found') 62268c2ecf20Sopenharmony_ci createHTMLDeviceSummary(testruns, os.path.join(outpath, 'summary-devices.html'), title) 62278c2ecf20Sopenharmony_ci pprint(' summary-devices.html - kernel device list sorted by total execution time') 62288c2ecf20Sopenharmony_ci createHTMLIssuesSummary(testruns, issues, os.path.join(outpath, 'summary-issues.html'), title) 62298c2ecf20Sopenharmony_ci pprint(' summary-issues.html - kernel issues found sorted by frequency') 62308c2ecf20Sopenharmony_ci 62318c2ecf20Sopenharmony_ci# Function: checkArgBool 62328c2ecf20Sopenharmony_ci# Description: 62338c2ecf20Sopenharmony_ci# check if a boolean string value is true or false 62348c2ecf20Sopenharmony_cidef checkArgBool(name, value): 62358c2ecf20Sopenharmony_ci if value in switchvalues: 62368c2ecf20Sopenharmony_ci if value in switchoff: 62378c2ecf20Sopenharmony_ci return False 62388c2ecf20Sopenharmony_ci return True 62398c2ecf20Sopenharmony_ci doError('invalid boolean --> (%s: %s), use "true/false" or "1/0"' % (name, value), True) 62408c2ecf20Sopenharmony_ci return False 62418c2ecf20Sopenharmony_ci 62428c2ecf20Sopenharmony_ci# Function: configFromFile 62438c2ecf20Sopenharmony_ci# Description: 62448c2ecf20Sopenharmony_ci# Configure the script via the info in a config file 62458c2ecf20Sopenharmony_cidef configFromFile(file): 62468c2ecf20Sopenharmony_ci Config = configparser.ConfigParser() 62478c2ecf20Sopenharmony_ci 62488c2ecf20Sopenharmony_ci Config.read(file) 62498c2ecf20Sopenharmony_ci sections = Config.sections() 62508c2ecf20Sopenharmony_ci overridekprobes = False 62518c2ecf20Sopenharmony_ci overridedevkprobes = False 62528c2ecf20Sopenharmony_ci if 'Settings' in sections: 62538c2ecf20Sopenharmony_ci for opt in Config.options('Settings'): 62548c2ecf20Sopenharmony_ci value = Config.get('Settings', opt).lower() 62558c2ecf20Sopenharmony_ci option = opt.lower() 62568c2ecf20Sopenharmony_ci if(option == 'verbose'): 62578c2ecf20Sopenharmony_ci sysvals.verbose = checkArgBool(option, value) 62588c2ecf20Sopenharmony_ci elif(option == 'addlogs'): 62598c2ecf20Sopenharmony_ci sysvals.dmesglog = sysvals.ftracelog = checkArgBool(option, value) 62608c2ecf20Sopenharmony_ci elif(option == 'dev'): 62618c2ecf20Sopenharmony_ci sysvals.usedevsrc = checkArgBool(option, value) 62628c2ecf20Sopenharmony_ci elif(option == 'proc'): 62638c2ecf20Sopenharmony_ci sysvals.useprocmon = checkArgBool(option, value) 62648c2ecf20Sopenharmony_ci elif(option == 'x2'): 62658c2ecf20Sopenharmony_ci if checkArgBool(option, value): 62668c2ecf20Sopenharmony_ci sysvals.execcount = 2 62678c2ecf20Sopenharmony_ci elif(option == 'callgraph'): 62688c2ecf20Sopenharmony_ci sysvals.usecallgraph = checkArgBool(option, value) 62698c2ecf20Sopenharmony_ci elif(option == 'override-timeline-functions'): 62708c2ecf20Sopenharmony_ci overridekprobes = checkArgBool(option, value) 62718c2ecf20Sopenharmony_ci elif(option == 'override-dev-timeline-functions'): 62728c2ecf20Sopenharmony_ci overridedevkprobes = checkArgBool(option, value) 62738c2ecf20Sopenharmony_ci elif(option == 'skiphtml'): 62748c2ecf20Sopenharmony_ci sysvals.skiphtml = checkArgBool(option, value) 62758c2ecf20Sopenharmony_ci elif(option == 'sync'): 62768c2ecf20Sopenharmony_ci sysvals.sync = checkArgBool(option, value) 62778c2ecf20Sopenharmony_ci elif(option == 'rs' or option == 'runtimesuspend'): 62788c2ecf20Sopenharmony_ci if value in switchvalues: 62798c2ecf20Sopenharmony_ci if value in switchoff: 62808c2ecf20Sopenharmony_ci sysvals.rs = -1 62818c2ecf20Sopenharmony_ci else: 62828c2ecf20Sopenharmony_ci sysvals.rs = 1 62838c2ecf20Sopenharmony_ci else: 62848c2ecf20Sopenharmony_ci doError('invalid value --> (%s: %s), use "enable/disable"' % (option, value), True) 62858c2ecf20Sopenharmony_ci elif(option == 'display'): 62868c2ecf20Sopenharmony_ci disopt = ['on', 'off', 'standby', 'suspend'] 62878c2ecf20Sopenharmony_ci if value not in disopt: 62888c2ecf20Sopenharmony_ci doError('invalid value --> (%s: %s), use %s' % (option, value, disopt), True) 62898c2ecf20Sopenharmony_ci sysvals.display = value 62908c2ecf20Sopenharmony_ci elif(option == 'gzip'): 62918c2ecf20Sopenharmony_ci sysvals.gzip = checkArgBool(option, value) 62928c2ecf20Sopenharmony_ci elif(option == 'cgfilter'): 62938c2ecf20Sopenharmony_ci sysvals.setCallgraphFilter(value) 62948c2ecf20Sopenharmony_ci elif(option == 'cgskip'): 62958c2ecf20Sopenharmony_ci if value in switchoff: 62968c2ecf20Sopenharmony_ci sysvals.cgskip = '' 62978c2ecf20Sopenharmony_ci else: 62988c2ecf20Sopenharmony_ci sysvals.cgskip = sysvals.configFile(val) 62998c2ecf20Sopenharmony_ci if(not sysvals.cgskip): 63008c2ecf20Sopenharmony_ci doError('%s does not exist' % sysvals.cgskip) 63018c2ecf20Sopenharmony_ci elif(option == 'cgtest'): 63028c2ecf20Sopenharmony_ci sysvals.cgtest = getArgInt('cgtest', value, 0, 1, False) 63038c2ecf20Sopenharmony_ci elif(option == 'cgphase'): 63048c2ecf20Sopenharmony_ci d = Data(0) 63058c2ecf20Sopenharmony_ci if value not in d.phasedef: 63068c2ecf20Sopenharmony_ci doError('invalid phase --> (%s: %s), valid phases are %s'\ 63078c2ecf20Sopenharmony_ci % (option, value, d.phasedef.keys()), True) 63088c2ecf20Sopenharmony_ci sysvals.cgphase = value 63098c2ecf20Sopenharmony_ci elif(option == 'fadd'): 63108c2ecf20Sopenharmony_ci file = sysvals.configFile(value) 63118c2ecf20Sopenharmony_ci if(not file): 63128c2ecf20Sopenharmony_ci doError('%s does not exist' % value) 63138c2ecf20Sopenharmony_ci sysvals.addFtraceFilterFunctions(file) 63148c2ecf20Sopenharmony_ci elif(option == 'result'): 63158c2ecf20Sopenharmony_ci sysvals.result = value 63168c2ecf20Sopenharmony_ci elif(option == 'multi'): 63178c2ecf20Sopenharmony_ci nums = value.split() 63188c2ecf20Sopenharmony_ci if len(nums) != 2: 63198c2ecf20Sopenharmony_ci doError('multi requires 2 integers (exec_count and delay)', True) 63208c2ecf20Sopenharmony_ci sysvals.multiinit(nums[0], nums[1]) 63218c2ecf20Sopenharmony_ci elif(option == 'devicefilter'): 63228c2ecf20Sopenharmony_ci sysvals.setDeviceFilter(value) 63238c2ecf20Sopenharmony_ci elif(option == 'expandcg'): 63248c2ecf20Sopenharmony_ci sysvals.cgexp = checkArgBool(option, value) 63258c2ecf20Sopenharmony_ci elif(option == 'srgap'): 63268c2ecf20Sopenharmony_ci if checkArgBool(option, value): 63278c2ecf20Sopenharmony_ci sysvals.srgap = 5 63288c2ecf20Sopenharmony_ci elif(option == 'mode'): 63298c2ecf20Sopenharmony_ci sysvals.suspendmode = value 63308c2ecf20Sopenharmony_ci elif(option == 'command' or option == 'cmd'): 63318c2ecf20Sopenharmony_ci sysvals.testcommand = value 63328c2ecf20Sopenharmony_ci elif(option == 'x2delay'): 63338c2ecf20Sopenharmony_ci sysvals.x2delay = getArgInt('x2delay', value, 0, 60000, False) 63348c2ecf20Sopenharmony_ci elif(option == 'predelay'): 63358c2ecf20Sopenharmony_ci sysvals.predelay = getArgInt('predelay', value, 0, 60000, False) 63368c2ecf20Sopenharmony_ci elif(option == 'postdelay'): 63378c2ecf20Sopenharmony_ci sysvals.postdelay = getArgInt('postdelay', value, 0, 60000, False) 63388c2ecf20Sopenharmony_ci elif(option == 'maxdepth'): 63398c2ecf20Sopenharmony_ci sysvals.max_graph_depth = getArgInt('maxdepth', value, 0, 1000, False) 63408c2ecf20Sopenharmony_ci elif(option == 'rtcwake'): 63418c2ecf20Sopenharmony_ci if value in switchoff: 63428c2ecf20Sopenharmony_ci sysvals.rtcwake = False 63438c2ecf20Sopenharmony_ci else: 63448c2ecf20Sopenharmony_ci sysvals.rtcwake = True 63458c2ecf20Sopenharmony_ci sysvals.rtcwaketime = getArgInt('rtcwake', value, 0, 3600, False) 63468c2ecf20Sopenharmony_ci elif(option == 'timeprec'): 63478c2ecf20Sopenharmony_ci sysvals.setPrecision(getArgInt('timeprec', value, 0, 6, False)) 63488c2ecf20Sopenharmony_ci elif(option == 'mindev'): 63498c2ecf20Sopenharmony_ci sysvals.mindevlen = getArgFloat('mindev', value, 0.0, 10000.0, False) 63508c2ecf20Sopenharmony_ci elif(option == 'callloop-maxgap'): 63518c2ecf20Sopenharmony_ci sysvals.callloopmaxgap = getArgFloat('callloop-maxgap', value, 0.0, 1.0, False) 63528c2ecf20Sopenharmony_ci elif(option == 'callloop-maxlen'): 63538c2ecf20Sopenharmony_ci sysvals.callloopmaxgap = getArgFloat('callloop-maxlen', value, 0.0, 1.0, False) 63548c2ecf20Sopenharmony_ci elif(option == 'mincg'): 63558c2ecf20Sopenharmony_ci sysvals.mincglen = getArgFloat('mincg', value, 0.0, 10000.0, False) 63568c2ecf20Sopenharmony_ci elif(option == 'bufsize'): 63578c2ecf20Sopenharmony_ci sysvals.bufsize = getArgInt('bufsize', value, 1, 1024*1024*8, False) 63588c2ecf20Sopenharmony_ci elif(option == 'output-dir'): 63598c2ecf20Sopenharmony_ci sysvals.outdir = sysvals.setOutputFolder(value) 63608c2ecf20Sopenharmony_ci 63618c2ecf20Sopenharmony_ci if sysvals.suspendmode == 'command' and not sysvals.testcommand: 63628c2ecf20Sopenharmony_ci doError('No command supplied for mode "command"') 63638c2ecf20Sopenharmony_ci 63648c2ecf20Sopenharmony_ci # compatibility errors 63658c2ecf20Sopenharmony_ci if sysvals.usedevsrc and sysvals.usecallgraph: 63668c2ecf20Sopenharmony_ci doError('-dev is not compatible with -f') 63678c2ecf20Sopenharmony_ci if sysvals.usecallgraph and sysvals.useprocmon: 63688c2ecf20Sopenharmony_ci doError('-proc is not compatible with -f') 63698c2ecf20Sopenharmony_ci 63708c2ecf20Sopenharmony_ci if overridekprobes: 63718c2ecf20Sopenharmony_ci sysvals.tracefuncs = dict() 63728c2ecf20Sopenharmony_ci if overridedevkprobes: 63738c2ecf20Sopenharmony_ci sysvals.dev_tracefuncs = dict() 63748c2ecf20Sopenharmony_ci 63758c2ecf20Sopenharmony_ci kprobes = dict() 63768c2ecf20Sopenharmony_ci kprobesec = 'dev_timeline_functions_'+platform.machine() 63778c2ecf20Sopenharmony_ci if kprobesec in sections: 63788c2ecf20Sopenharmony_ci for name in Config.options(kprobesec): 63798c2ecf20Sopenharmony_ci text = Config.get(kprobesec, name) 63808c2ecf20Sopenharmony_ci kprobes[name] = (text, True) 63818c2ecf20Sopenharmony_ci kprobesec = 'timeline_functions_'+platform.machine() 63828c2ecf20Sopenharmony_ci if kprobesec in sections: 63838c2ecf20Sopenharmony_ci for name in Config.options(kprobesec): 63848c2ecf20Sopenharmony_ci if name in kprobes: 63858c2ecf20Sopenharmony_ci doError('Duplicate timeline function found "%s"' % (name)) 63868c2ecf20Sopenharmony_ci text = Config.get(kprobesec, name) 63878c2ecf20Sopenharmony_ci kprobes[name] = (text, False) 63888c2ecf20Sopenharmony_ci 63898c2ecf20Sopenharmony_ci for name in kprobes: 63908c2ecf20Sopenharmony_ci function = name 63918c2ecf20Sopenharmony_ci format = name 63928c2ecf20Sopenharmony_ci color = '' 63938c2ecf20Sopenharmony_ci args = dict() 63948c2ecf20Sopenharmony_ci text, dev = kprobes[name] 63958c2ecf20Sopenharmony_ci data = text.split() 63968c2ecf20Sopenharmony_ci i = 0 63978c2ecf20Sopenharmony_ci for val in data: 63988c2ecf20Sopenharmony_ci # bracketted strings are special formatting, read them separately 63998c2ecf20Sopenharmony_ci if val[0] == '[' and val[-1] == ']': 64008c2ecf20Sopenharmony_ci for prop in val[1:-1].split(','): 64018c2ecf20Sopenharmony_ci p = prop.split('=') 64028c2ecf20Sopenharmony_ci if p[0] == 'color': 64038c2ecf20Sopenharmony_ci try: 64048c2ecf20Sopenharmony_ci color = int(p[1], 16) 64058c2ecf20Sopenharmony_ci color = '#'+p[1] 64068c2ecf20Sopenharmony_ci except: 64078c2ecf20Sopenharmony_ci color = p[1] 64088c2ecf20Sopenharmony_ci continue 64098c2ecf20Sopenharmony_ci # first real arg should be the format string 64108c2ecf20Sopenharmony_ci if i == 0: 64118c2ecf20Sopenharmony_ci format = val 64128c2ecf20Sopenharmony_ci # all other args are actual function args 64138c2ecf20Sopenharmony_ci else: 64148c2ecf20Sopenharmony_ci d = val.split('=') 64158c2ecf20Sopenharmony_ci args[d[0]] = d[1] 64168c2ecf20Sopenharmony_ci i += 1 64178c2ecf20Sopenharmony_ci if not function or not format: 64188c2ecf20Sopenharmony_ci doError('Invalid kprobe: %s' % name) 64198c2ecf20Sopenharmony_ci for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format): 64208c2ecf20Sopenharmony_ci if arg not in args: 64218c2ecf20Sopenharmony_ci doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) 64228c2ecf20Sopenharmony_ci if (dev and name in sysvals.dev_tracefuncs) or (not dev and name in sysvals.tracefuncs): 64238c2ecf20Sopenharmony_ci doError('Duplicate timeline function found "%s"' % (name)) 64248c2ecf20Sopenharmony_ci 64258c2ecf20Sopenharmony_ci kp = { 64268c2ecf20Sopenharmony_ci 'name': name, 64278c2ecf20Sopenharmony_ci 'func': function, 64288c2ecf20Sopenharmony_ci 'format': format, 64298c2ecf20Sopenharmony_ci sysvals.archargs: args 64308c2ecf20Sopenharmony_ci } 64318c2ecf20Sopenharmony_ci if color: 64328c2ecf20Sopenharmony_ci kp['color'] = color 64338c2ecf20Sopenharmony_ci if dev: 64348c2ecf20Sopenharmony_ci sysvals.dev_tracefuncs[name] = kp 64358c2ecf20Sopenharmony_ci else: 64368c2ecf20Sopenharmony_ci sysvals.tracefuncs[name] = kp 64378c2ecf20Sopenharmony_ci 64388c2ecf20Sopenharmony_ci# Function: printHelp 64398c2ecf20Sopenharmony_ci# Description: 64408c2ecf20Sopenharmony_ci# print out the help text 64418c2ecf20Sopenharmony_cidef printHelp(): 64428c2ecf20Sopenharmony_ci pprint('\n%s v%s\n'\ 64438c2ecf20Sopenharmony_ci 'Usage: sudo sleepgraph <options> <commands>\n'\ 64448c2ecf20Sopenharmony_ci '\n'\ 64458c2ecf20Sopenharmony_ci 'Description:\n'\ 64468c2ecf20Sopenharmony_ci ' This tool is designed to assist kernel and OS developers in optimizing\n'\ 64478c2ecf20Sopenharmony_ci ' their linux stack\'s suspend/resume time. Using a kernel image built\n'\ 64488c2ecf20Sopenharmony_ci ' with a few extra options enabled, the tool will execute a suspend and\n'\ 64498c2ecf20Sopenharmony_ci ' capture dmesg and ftrace data until resume is complete. This data is\n'\ 64508c2ecf20Sopenharmony_ci ' transformed into a device timeline and an optional callgraph to give\n'\ 64518c2ecf20Sopenharmony_ci ' a detailed view of which devices/subsystems are taking the most\n'\ 64528c2ecf20Sopenharmony_ci ' time in suspend/resume.\n'\ 64538c2ecf20Sopenharmony_ci '\n'\ 64548c2ecf20Sopenharmony_ci ' If no specific command is given, the default behavior is to initiate\n'\ 64558c2ecf20Sopenharmony_ci ' a suspend/resume and capture the dmesg/ftrace output as an html timeline.\n'\ 64568c2ecf20Sopenharmony_ci '\n'\ 64578c2ecf20Sopenharmony_ci ' Generates output files in subdirectory: suspend-yymmdd-HHMMSS\n'\ 64588c2ecf20Sopenharmony_ci ' HTML output: <hostname>_<mode>.html\n'\ 64598c2ecf20Sopenharmony_ci ' raw dmesg output: <hostname>_<mode>_dmesg.txt\n'\ 64608c2ecf20Sopenharmony_ci ' raw ftrace output: <hostname>_<mode>_ftrace.txt\n'\ 64618c2ecf20Sopenharmony_ci '\n'\ 64628c2ecf20Sopenharmony_ci 'Options:\n'\ 64638c2ecf20Sopenharmony_ci ' -h Print this help text\n'\ 64648c2ecf20Sopenharmony_ci ' -v Print the current tool version\n'\ 64658c2ecf20Sopenharmony_ci ' -config fn Pull arguments and config options from file fn\n'\ 64668c2ecf20Sopenharmony_ci ' -verbose Print extra information during execution and analysis\n'\ 64678c2ecf20Sopenharmony_ci ' -m mode Mode to initiate for suspend (default: %s)\n'\ 64688c2ecf20Sopenharmony_ci ' -o name Overrides the output subdirectory name when running a new test\n'\ 64698c2ecf20Sopenharmony_ci ' default: suspend-{date}-{time}\n'\ 64708c2ecf20Sopenharmony_ci ' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)\n'\ 64718c2ecf20Sopenharmony_ci ' -addlogs Add the dmesg and ftrace logs to the html output\n'\ 64728c2ecf20Sopenharmony_ci ' -noturbostat Dont use turbostat in freeze mode (default: disabled)\n'\ 64738c2ecf20Sopenharmony_ci ' -srgap Add a visible gap in the timeline between sus/res (default: disabled)\n'\ 64748c2ecf20Sopenharmony_ci ' -skiphtml Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\ 64758c2ecf20Sopenharmony_ci ' -result fn Export a results table to a text file for parsing.\n'\ 64768c2ecf20Sopenharmony_ci ' -wifi If a wifi connection is available, check that it reconnects after resume.\n'\ 64778c2ecf20Sopenharmony_ci ' [testprep]\n'\ 64788c2ecf20Sopenharmony_ci ' -sync Sync the filesystems before starting the test\n'\ 64798c2ecf20Sopenharmony_ci ' -rs on/off Enable/disable runtime suspend for all devices, restore all after test\n'\ 64808c2ecf20Sopenharmony_ci ' -display m Change the display mode to m for the test (on/off/standby/suspend)\n'\ 64818c2ecf20Sopenharmony_ci ' [advanced]\n'\ 64828c2ecf20Sopenharmony_ci ' -gzip Gzip the trace and dmesg logs to save space\n'\ 64838c2ecf20Sopenharmony_ci ' -cmd {s} Run the timeline over a custom command, e.g. "sync -d"\n'\ 64848c2ecf20Sopenharmony_ci ' -proc Add usermode process info into the timeline (default: disabled)\n'\ 64858c2ecf20Sopenharmony_ci ' -dev Add kernel function calls and threads to the timeline (default: disabled)\n'\ 64868c2ecf20Sopenharmony_ci ' -x2 Run two suspend/resumes back to back (default: disabled)\n'\ 64878c2ecf20Sopenharmony_ci ' -x2delay t Include t ms delay between multiple test runs (default: 0 ms)\n'\ 64888c2ecf20Sopenharmony_ci ' -predelay t Include t ms delay before 1st suspend (default: 0 ms)\n'\ 64898c2ecf20Sopenharmony_ci ' -postdelay t Include t ms delay after last resume (default: 0 ms)\n'\ 64908c2ecf20Sopenharmony_ci ' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 64918c2ecf20Sopenharmony_ci ' -multi n d Execute <n> consecutive tests at <d> seconds intervals. If <n> is followed\n'\ 64928c2ecf20Sopenharmony_ci ' by a "d", "h", or "m" execute for <n> days, hours, or mins instead.\n'\ 64938c2ecf20Sopenharmony_ci ' The outputs will be created in a new subdirectory with a summary page.\n'\ 64948c2ecf20Sopenharmony_ci ' -maxfail n Abort a -multi run after n consecutive fails (default is 0 = never abort)\n'\ 64958c2ecf20Sopenharmony_ci ' [debug]\n'\ 64968c2ecf20Sopenharmony_ci ' -f Use ftrace to create device callgraphs (default: disabled)\n'\ 64978c2ecf20Sopenharmony_ci ' -ftop Use ftrace on the top level call: "%s" (default: disabled)\n'\ 64988c2ecf20Sopenharmony_ci ' -maxdepth N limit the callgraph data to N call levels (default: 0=all)\n'\ 64998c2ecf20Sopenharmony_ci ' -expandcg pre-expand the callgraph data in the html output (default: disabled)\n'\ 65008c2ecf20Sopenharmony_ci ' -fadd file Add functions to be graphed in the timeline from a list in a text file\n'\ 65018c2ecf20Sopenharmony_ci ' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names\n'\ 65028c2ecf20Sopenharmony_ci ' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\ 65038c2ecf20Sopenharmony_ci ' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)\n'\ 65048c2ecf20Sopenharmony_ci ' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)\n'\ 65058c2ecf20Sopenharmony_ci ' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)\n'\ 65068c2ecf20Sopenharmony_ci ' -cgfilter S Filter the callgraph output in the timeline\n'\ 65078c2ecf20Sopenharmony_ci ' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\ 65088c2ecf20Sopenharmony_ci ' -bufsize N Set trace buffer size to N kilo-bytes (default: all of free memory)\n'\ 65098c2ecf20Sopenharmony_ci ' -devdump Print out all the raw device data for each phase\n'\ 65108c2ecf20Sopenharmony_ci ' -cgdump Print out all the raw callgraph data\n'\ 65118c2ecf20Sopenharmony_ci '\n'\ 65128c2ecf20Sopenharmony_ci 'Other commands:\n'\ 65138c2ecf20Sopenharmony_ci ' -modes List available suspend modes\n'\ 65148c2ecf20Sopenharmony_ci ' -status Test to see if the system is enabled to run this tool\n'\ 65158c2ecf20Sopenharmony_ci ' -fpdt Print out the contents of the ACPI Firmware Performance Data Table\n'\ 65168c2ecf20Sopenharmony_ci ' -wificheck Print out wifi connection info\n'\ 65178c2ecf20Sopenharmony_ci ' -x<mode> Test xset by toggling the given mode (on/off/standby/suspend)\n'\ 65188c2ecf20Sopenharmony_ci ' -sysinfo Print out system info extracted from BIOS\n'\ 65198c2ecf20Sopenharmony_ci ' -devinfo Print out the pm settings of all devices which support runtime suspend\n'\ 65208c2ecf20Sopenharmony_ci ' -cmdinfo Print out all the platform info collected before and after suspend/resume\n'\ 65218c2ecf20Sopenharmony_ci ' -flist Print the list of functions currently being captured in ftrace\n'\ 65228c2ecf20Sopenharmony_ci ' -flistall Print all functions capable of being captured in ftrace\n'\ 65238c2ecf20Sopenharmony_ci ' -summary dir Create a summary of tests in this dir [-genhtml builds missing html]\n'\ 65248c2ecf20Sopenharmony_ci ' [redo]\n'\ 65258c2ecf20Sopenharmony_ci ' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)\n'\ 65268c2ecf20Sopenharmony_ci ' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)\n'\ 65278c2ecf20Sopenharmony_ci '' % (sysvals.title, sysvals.version, sysvals.suspendmode, sysvals.ftopfunc)) 65288c2ecf20Sopenharmony_ci return True 65298c2ecf20Sopenharmony_ci 65308c2ecf20Sopenharmony_ci# ----------------- MAIN -------------------- 65318c2ecf20Sopenharmony_ci# exec start (skipped if script is loaded as library) 65328c2ecf20Sopenharmony_ciif __name__ == '__main__': 65338c2ecf20Sopenharmony_ci genhtml = False 65348c2ecf20Sopenharmony_ci cmd = '' 65358c2ecf20Sopenharmony_ci simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall', 65368c2ecf20Sopenharmony_ci '-devinfo', '-status', '-xon', '-xoff', '-xstandby', '-xsuspend', 65378c2ecf20Sopenharmony_ci '-xinit', '-xreset', '-xstat', '-wificheck', '-cmdinfo'] 65388c2ecf20Sopenharmony_ci if '-f' in sys.argv: 65398c2ecf20Sopenharmony_ci sysvals.cgskip = sysvals.configFile('cgskip.txt') 65408c2ecf20Sopenharmony_ci # loop through the command line arguments 65418c2ecf20Sopenharmony_ci args = iter(sys.argv[1:]) 65428c2ecf20Sopenharmony_ci for arg in args: 65438c2ecf20Sopenharmony_ci if(arg == '-m'): 65448c2ecf20Sopenharmony_ci try: 65458c2ecf20Sopenharmony_ci val = next(args) 65468c2ecf20Sopenharmony_ci except: 65478c2ecf20Sopenharmony_ci doError('No mode supplied', True) 65488c2ecf20Sopenharmony_ci if val == 'command' and not sysvals.testcommand: 65498c2ecf20Sopenharmony_ci doError('No command supplied for mode "command"', True) 65508c2ecf20Sopenharmony_ci sysvals.suspendmode = val 65518c2ecf20Sopenharmony_ci elif(arg in simplecmds): 65528c2ecf20Sopenharmony_ci cmd = arg[1:] 65538c2ecf20Sopenharmony_ci elif(arg == '-h'): 65548c2ecf20Sopenharmony_ci printHelp() 65558c2ecf20Sopenharmony_ci sys.exit(0) 65568c2ecf20Sopenharmony_ci elif(arg == '-v'): 65578c2ecf20Sopenharmony_ci pprint("Version %s" % sysvals.version) 65588c2ecf20Sopenharmony_ci sys.exit(0) 65598c2ecf20Sopenharmony_ci elif(arg == '-x2'): 65608c2ecf20Sopenharmony_ci sysvals.execcount = 2 65618c2ecf20Sopenharmony_ci elif(arg == '-x2delay'): 65628c2ecf20Sopenharmony_ci sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000) 65638c2ecf20Sopenharmony_ci elif(arg == '-predelay'): 65648c2ecf20Sopenharmony_ci sysvals.predelay = getArgInt('-predelay', args, 0, 60000) 65658c2ecf20Sopenharmony_ci elif(arg == '-postdelay'): 65668c2ecf20Sopenharmony_ci sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000) 65678c2ecf20Sopenharmony_ci elif(arg == '-f'): 65688c2ecf20Sopenharmony_ci sysvals.usecallgraph = True 65698c2ecf20Sopenharmony_ci elif(arg == '-ftop'): 65708c2ecf20Sopenharmony_ci sysvals.usecallgraph = True 65718c2ecf20Sopenharmony_ci sysvals.ftop = True 65728c2ecf20Sopenharmony_ci sysvals.usekprobes = False 65738c2ecf20Sopenharmony_ci elif(arg == '-skiphtml'): 65748c2ecf20Sopenharmony_ci sysvals.skiphtml = True 65758c2ecf20Sopenharmony_ci elif(arg == '-cgdump'): 65768c2ecf20Sopenharmony_ci sysvals.cgdump = True 65778c2ecf20Sopenharmony_ci elif(arg == '-devdump'): 65788c2ecf20Sopenharmony_ci sysvals.devdump = True 65798c2ecf20Sopenharmony_ci elif(arg == '-genhtml'): 65808c2ecf20Sopenharmony_ci genhtml = True 65818c2ecf20Sopenharmony_ci elif(arg == '-addlogs'): 65828c2ecf20Sopenharmony_ci sysvals.dmesglog = sysvals.ftracelog = True 65838c2ecf20Sopenharmony_ci elif(arg == '-nologs'): 65848c2ecf20Sopenharmony_ci sysvals.dmesglog = sysvals.ftracelog = False 65858c2ecf20Sopenharmony_ci elif(arg == '-addlogdmesg'): 65868c2ecf20Sopenharmony_ci sysvals.dmesglog = True 65878c2ecf20Sopenharmony_ci elif(arg == '-addlogftrace'): 65888c2ecf20Sopenharmony_ci sysvals.ftracelog = True 65898c2ecf20Sopenharmony_ci elif(arg == '-noturbostat'): 65908c2ecf20Sopenharmony_ci sysvals.tstat = False 65918c2ecf20Sopenharmony_ci elif(arg == '-verbose'): 65928c2ecf20Sopenharmony_ci sysvals.verbose = True 65938c2ecf20Sopenharmony_ci elif(arg == '-proc'): 65948c2ecf20Sopenharmony_ci sysvals.useprocmon = True 65958c2ecf20Sopenharmony_ci elif(arg == '-dev'): 65968c2ecf20Sopenharmony_ci sysvals.usedevsrc = True 65978c2ecf20Sopenharmony_ci elif(arg == '-sync'): 65988c2ecf20Sopenharmony_ci sysvals.sync = True 65998c2ecf20Sopenharmony_ci elif(arg == '-wifi'): 66008c2ecf20Sopenharmony_ci sysvals.wifi = True 66018c2ecf20Sopenharmony_ci elif(arg == '-gzip'): 66028c2ecf20Sopenharmony_ci sysvals.gzip = True 66038c2ecf20Sopenharmony_ci elif(arg == '-info'): 66048c2ecf20Sopenharmony_ci try: 66058c2ecf20Sopenharmony_ci val = next(args) 66068c2ecf20Sopenharmony_ci except: 66078c2ecf20Sopenharmony_ci doError('-info requires one string argument', True) 66088c2ecf20Sopenharmony_ci elif(arg == '-rs'): 66098c2ecf20Sopenharmony_ci try: 66108c2ecf20Sopenharmony_ci val = next(args) 66118c2ecf20Sopenharmony_ci except: 66128c2ecf20Sopenharmony_ci doError('-rs requires "enable" or "disable"', True) 66138c2ecf20Sopenharmony_ci if val.lower() in switchvalues: 66148c2ecf20Sopenharmony_ci if val.lower() in switchoff: 66158c2ecf20Sopenharmony_ci sysvals.rs = -1 66168c2ecf20Sopenharmony_ci else: 66178c2ecf20Sopenharmony_ci sysvals.rs = 1 66188c2ecf20Sopenharmony_ci else: 66198c2ecf20Sopenharmony_ci doError('invalid option: %s, use "enable/disable" or "on/off"' % val, True) 66208c2ecf20Sopenharmony_ci elif(arg == '-display'): 66218c2ecf20Sopenharmony_ci try: 66228c2ecf20Sopenharmony_ci val = next(args) 66238c2ecf20Sopenharmony_ci except: 66248c2ecf20Sopenharmony_ci doError('-display requires an mode value', True) 66258c2ecf20Sopenharmony_ci disopt = ['on', 'off', 'standby', 'suspend'] 66268c2ecf20Sopenharmony_ci if val.lower() not in disopt: 66278c2ecf20Sopenharmony_ci doError('valid display mode values are %s' % disopt, True) 66288c2ecf20Sopenharmony_ci sysvals.display = val.lower() 66298c2ecf20Sopenharmony_ci elif(arg == '-maxdepth'): 66308c2ecf20Sopenharmony_ci sysvals.max_graph_depth = getArgInt('-maxdepth', args, 0, 1000) 66318c2ecf20Sopenharmony_ci elif(arg == '-rtcwake'): 66328c2ecf20Sopenharmony_ci try: 66338c2ecf20Sopenharmony_ci val = next(args) 66348c2ecf20Sopenharmony_ci except: 66358c2ecf20Sopenharmony_ci doError('No rtcwake time supplied', True) 66368c2ecf20Sopenharmony_ci if val.lower() in switchoff: 66378c2ecf20Sopenharmony_ci sysvals.rtcwake = False 66388c2ecf20Sopenharmony_ci else: 66398c2ecf20Sopenharmony_ci sysvals.rtcwake = True 66408c2ecf20Sopenharmony_ci sysvals.rtcwaketime = getArgInt('-rtcwake', val, 0, 3600, False) 66418c2ecf20Sopenharmony_ci elif(arg == '-timeprec'): 66428c2ecf20Sopenharmony_ci sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6)) 66438c2ecf20Sopenharmony_ci elif(arg == '-mindev'): 66448c2ecf20Sopenharmony_ci sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0) 66458c2ecf20Sopenharmony_ci elif(arg == '-mincg'): 66468c2ecf20Sopenharmony_ci sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0) 66478c2ecf20Sopenharmony_ci elif(arg == '-bufsize'): 66488c2ecf20Sopenharmony_ci sysvals.bufsize = getArgInt('-bufsize', args, 1, 1024*1024*8) 66498c2ecf20Sopenharmony_ci elif(arg == '-cgtest'): 66508c2ecf20Sopenharmony_ci sysvals.cgtest = getArgInt('-cgtest', args, 0, 1) 66518c2ecf20Sopenharmony_ci elif(arg == '-cgphase'): 66528c2ecf20Sopenharmony_ci try: 66538c2ecf20Sopenharmony_ci val = next(args) 66548c2ecf20Sopenharmony_ci except: 66558c2ecf20Sopenharmony_ci doError('No phase name supplied', True) 66568c2ecf20Sopenharmony_ci d = Data(0) 66578c2ecf20Sopenharmony_ci if val not in d.phasedef: 66588c2ecf20Sopenharmony_ci doError('invalid phase --> (%s: %s), valid phases are %s'\ 66598c2ecf20Sopenharmony_ci % (arg, val, d.phasedef.keys()), True) 66608c2ecf20Sopenharmony_ci sysvals.cgphase = val 66618c2ecf20Sopenharmony_ci elif(arg == '-cgfilter'): 66628c2ecf20Sopenharmony_ci try: 66638c2ecf20Sopenharmony_ci val = next(args) 66648c2ecf20Sopenharmony_ci except: 66658c2ecf20Sopenharmony_ci doError('No callgraph functions supplied', True) 66668c2ecf20Sopenharmony_ci sysvals.setCallgraphFilter(val) 66678c2ecf20Sopenharmony_ci elif(arg == '-skipkprobe'): 66688c2ecf20Sopenharmony_ci try: 66698c2ecf20Sopenharmony_ci val = next(args) 66708c2ecf20Sopenharmony_ci except: 66718c2ecf20Sopenharmony_ci doError('No kprobe functions supplied', True) 66728c2ecf20Sopenharmony_ci sysvals.skipKprobes(val) 66738c2ecf20Sopenharmony_ci elif(arg == '-cgskip'): 66748c2ecf20Sopenharmony_ci try: 66758c2ecf20Sopenharmony_ci val = next(args) 66768c2ecf20Sopenharmony_ci except: 66778c2ecf20Sopenharmony_ci doError('No file supplied', True) 66788c2ecf20Sopenharmony_ci if val.lower() in switchoff: 66798c2ecf20Sopenharmony_ci sysvals.cgskip = '' 66808c2ecf20Sopenharmony_ci else: 66818c2ecf20Sopenharmony_ci sysvals.cgskip = sysvals.configFile(val) 66828c2ecf20Sopenharmony_ci if(not sysvals.cgskip): 66838c2ecf20Sopenharmony_ci doError('%s does not exist' % sysvals.cgskip) 66848c2ecf20Sopenharmony_ci elif(arg == '-callloop-maxgap'): 66858c2ecf20Sopenharmony_ci sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', args, 0.0, 1.0) 66868c2ecf20Sopenharmony_ci elif(arg == '-callloop-maxlen'): 66878c2ecf20Sopenharmony_ci sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0) 66888c2ecf20Sopenharmony_ci elif(arg == '-cmd'): 66898c2ecf20Sopenharmony_ci try: 66908c2ecf20Sopenharmony_ci val = next(args) 66918c2ecf20Sopenharmony_ci except: 66928c2ecf20Sopenharmony_ci doError('No command string supplied', True) 66938c2ecf20Sopenharmony_ci sysvals.testcommand = val 66948c2ecf20Sopenharmony_ci sysvals.suspendmode = 'command' 66958c2ecf20Sopenharmony_ci elif(arg == '-expandcg'): 66968c2ecf20Sopenharmony_ci sysvals.cgexp = True 66978c2ecf20Sopenharmony_ci elif(arg == '-srgap'): 66988c2ecf20Sopenharmony_ci sysvals.srgap = 5 66998c2ecf20Sopenharmony_ci elif(arg == '-maxfail'): 67008c2ecf20Sopenharmony_ci sysvals.maxfail = getArgInt('-maxfail', args, 0, 1000000) 67018c2ecf20Sopenharmony_ci elif(arg == '-multi'): 67028c2ecf20Sopenharmony_ci try: 67038c2ecf20Sopenharmony_ci c, d = next(args), next(args) 67048c2ecf20Sopenharmony_ci except: 67058c2ecf20Sopenharmony_ci doError('-multi requires two values', True) 67068c2ecf20Sopenharmony_ci sysvals.multiinit(c, d) 67078c2ecf20Sopenharmony_ci elif(arg == '-o'): 67088c2ecf20Sopenharmony_ci try: 67098c2ecf20Sopenharmony_ci val = next(args) 67108c2ecf20Sopenharmony_ci except: 67118c2ecf20Sopenharmony_ci doError('No subdirectory name supplied', True) 67128c2ecf20Sopenharmony_ci sysvals.outdir = sysvals.setOutputFolder(val) 67138c2ecf20Sopenharmony_ci elif(arg == '-config'): 67148c2ecf20Sopenharmony_ci try: 67158c2ecf20Sopenharmony_ci val = next(args) 67168c2ecf20Sopenharmony_ci except: 67178c2ecf20Sopenharmony_ci doError('No text file supplied', True) 67188c2ecf20Sopenharmony_ci file = sysvals.configFile(val) 67198c2ecf20Sopenharmony_ci if(not file): 67208c2ecf20Sopenharmony_ci doError('%s does not exist' % val) 67218c2ecf20Sopenharmony_ci configFromFile(file) 67228c2ecf20Sopenharmony_ci elif(arg == '-fadd'): 67238c2ecf20Sopenharmony_ci try: 67248c2ecf20Sopenharmony_ci val = next(args) 67258c2ecf20Sopenharmony_ci except: 67268c2ecf20Sopenharmony_ci doError('No text file supplied', True) 67278c2ecf20Sopenharmony_ci file = sysvals.configFile(val) 67288c2ecf20Sopenharmony_ci if(not file): 67298c2ecf20Sopenharmony_ci doError('%s does not exist' % val) 67308c2ecf20Sopenharmony_ci sysvals.addFtraceFilterFunctions(file) 67318c2ecf20Sopenharmony_ci elif(arg == '-dmesg'): 67328c2ecf20Sopenharmony_ci try: 67338c2ecf20Sopenharmony_ci val = next(args) 67348c2ecf20Sopenharmony_ci except: 67358c2ecf20Sopenharmony_ci doError('No dmesg file supplied', True) 67368c2ecf20Sopenharmony_ci sysvals.notestrun = True 67378c2ecf20Sopenharmony_ci sysvals.dmesgfile = val 67388c2ecf20Sopenharmony_ci if(os.path.exists(sysvals.dmesgfile) == False): 67398c2ecf20Sopenharmony_ci doError('%s does not exist' % sysvals.dmesgfile) 67408c2ecf20Sopenharmony_ci elif(arg == '-ftrace'): 67418c2ecf20Sopenharmony_ci try: 67428c2ecf20Sopenharmony_ci val = next(args) 67438c2ecf20Sopenharmony_ci except: 67448c2ecf20Sopenharmony_ci doError('No ftrace file supplied', True) 67458c2ecf20Sopenharmony_ci sysvals.notestrun = True 67468c2ecf20Sopenharmony_ci sysvals.ftracefile = val 67478c2ecf20Sopenharmony_ci if(os.path.exists(sysvals.ftracefile) == False): 67488c2ecf20Sopenharmony_ci doError('%s does not exist' % sysvals.ftracefile) 67498c2ecf20Sopenharmony_ci elif(arg == '-summary'): 67508c2ecf20Sopenharmony_ci try: 67518c2ecf20Sopenharmony_ci val = next(args) 67528c2ecf20Sopenharmony_ci except: 67538c2ecf20Sopenharmony_ci doError('No directory supplied', True) 67548c2ecf20Sopenharmony_ci cmd = 'summary' 67558c2ecf20Sopenharmony_ci sysvals.outdir = val 67568c2ecf20Sopenharmony_ci sysvals.notestrun = True 67578c2ecf20Sopenharmony_ci if(os.path.isdir(val) == False): 67588c2ecf20Sopenharmony_ci doError('%s is not accesible' % val) 67598c2ecf20Sopenharmony_ci elif(arg == '-filter'): 67608c2ecf20Sopenharmony_ci try: 67618c2ecf20Sopenharmony_ci val = next(args) 67628c2ecf20Sopenharmony_ci except: 67638c2ecf20Sopenharmony_ci doError('No devnames supplied', True) 67648c2ecf20Sopenharmony_ci sysvals.setDeviceFilter(val) 67658c2ecf20Sopenharmony_ci elif(arg == '-result'): 67668c2ecf20Sopenharmony_ci try: 67678c2ecf20Sopenharmony_ci val = next(args) 67688c2ecf20Sopenharmony_ci except: 67698c2ecf20Sopenharmony_ci doError('No result file supplied', True) 67708c2ecf20Sopenharmony_ci sysvals.result = val 67718c2ecf20Sopenharmony_ci sysvals.signalHandlerInit() 67728c2ecf20Sopenharmony_ci else: 67738c2ecf20Sopenharmony_ci doError('Invalid argument: '+arg, True) 67748c2ecf20Sopenharmony_ci 67758c2ecf20Sopenharmony_ci # compatibility errors 67768c2ecf20Sopenharmony_ci if(sysvals.usecallgraph and sysvals.usedevsrc): 67778c2ecf20Sopenharmony_ci doError('-dev is not compatible with -f') 67788c2ecf20Sopenharmony_ci if(sysvals.usecallgraph and sysvals.useprocmon): 67798c2ecf20Sopenharmony_ci doError('-proc is not compatible with -f') 67808c2ecf20Sopenharmony_ci 67818c2ecf20Sopenharmony_ci if sysvals.usecallgraph and sysvals.cgskip: 67828c2ecf20Sopenharmony_ci sysvals.vprint('Using cgskip file: %s' % sysvals.cgskip) 67838c2ecf20Sopenharmony_ci sysvals.setCallgraphBlacklist(sysvals.cgskip) 67848c2ecf20Sopenharmony_ci 67858c2ecf20Sopenharmony_ci # callgraph size cannot exceed device size 67868c2ecf20Sopenharmony_ci if sysvals.mincglen < sysvals.mindevlen: 67878c2ecf20Sopenharmony_ci sysvals.mincglen = sysvals.mindevlen 67888c2ecf20Sopenharmony_ci 67898c2ecf20Sopenharmony_ci # remove existing buffers before calculating memory 67908c2ecf20Sopenharmony_ci if(sysvals.usecallgraph or sysvals.usedevsrc): 67918c2ecf20Sopenharmony_ci sysvals.fsetVal('16', 'buffer_size_kb') 67928c2ecf20Sopenharmony_ci sysvals.cpuInfo() 67938c2ecf20Sopenharmony_ci 67948c2ecf20Sopenharmony_ci # just run a utility command and exit 67958c2ecf20Sopenharmony_ci if(cmd != ''): 67968c2ecf20Sopenharmony_ci ret = 0 67978c2ecf20Sopenharmony_ci if(cmd == 'status'): 67988c2ecf20Sopenharmony_ci if not statusCheck(True): 67998c2ecf20Sopenharmony_ci ret = 1 68008c2ecf20Sopenharmony_ci elif(cmd == 'fpdt'): 68018c2ecf20Sopenharmony_ci if not getFPDT(True): 68028c2ecf20Sopenharmony_ci ret = 1 68038c2ecf20Sopenharmony_ci elif(cmd == 'sysinfo'): 68048c2ecf20Sopenharmony_ci sysvals.printSystemInfo(True) 68058c2ecf20Sopenharmony_ci elif(cmd == 'devinfo'): 68068c2ecf20Sopenharmony_ci deviceInfo() 68078c2ecf20Sopenharmony_ci elif(cmd == 'modes'): 68088c2ecf20Sopenharmony_ci pprint(getModes()) 68098c2ecf20Sopenharmony_ci elif(cmd == 'flist'): 68108c2ecf20Sopenharmony_ci sysvals.getFtraceFilterFunctions(True) 68118c2ecf20Sopenharmony_ci elif(cmd == 'flistall'): 68128c2ecf20Sopenharmony_ci sysvals.getFtraceFilterFunctions(False) 68138c2ecf20Sopenharmony_ci elif(cmd == 'summary'): 68148c2ecf20Sopenharmony_ci runSummary(sysvals.outdir, True, genhtml) 68158c2ecf20Sopenharmony_ci elif(cmd in ['xon', 'xoff', 'xstandby', 'xsuspend', 'xinit', 'xreset']): 68168c2ecf20Sopenharmony_ci sysvals.verbose = True 68178c2ecf20Sopenharmony_ci ret = displayControl(cmd[1:]) 68188c2ecf20Sopenharmony_ci elif(cmd == 'xstat'): 68198c2ecf20Sopenharmony_ci pprint('Display Status: %s' % displayControl('stat').upper()) 68208c2ecf20Sopenharmony_ci elif(cmd == 'wificheck'): 68218c2ecf20Sopenharmony_ci dev = sysvals.checkWifi() 68228c2ecf20Sopenharmony_ci if dev: 68238c2ecf20Sopenharmony_ci print('%s is connected' % sysvals.wifiDetails(dev)) 68248c2ecf20Sopenharmony_ci else: 68258c2ecf20Sopenharmony_ci print('No wifi connection found') 68268c2ecf20Sopenharmony_ci elif(cmd == 'cmdinfo'): 68278c2ecf20Sopenharmony_ci for out in sysvals.cmdinfo(False, True): 68288c2ecf20Sopenharmony_ci print('[%s - %s]\n%s\n' % out) 68298c2ecf20Sopenharmony_ci sys.exit(ret) 68308c2ecf20Sopenharmony_ci 68318c2ecf20Sopenharmony_ci # if instructed, re-analyze existing data files 68328c2ecf20Sopenharmony_ci if(sysvals.notestrun): 68338c2ecf20Sopenharmony_ci stamp = rerunTest(sysvals.outdir) 68348c2ecf20Sopenharmony_ci sysvals.outputResult(stamp) 68358c2ecf20Sopenharmony_ci sys.exit(0) 68368c2ecf20Sopenharmony_ci 68378c2ecf20Sopenharmony_ci # verify that we can run a test 68388c2ecf20Sopenharmony_ci error = statusCheck() 68398c2ecf20Sopenharmony_ci if(error): 68408c2ecf20Sopenharmony_ci doError(error) 68418c2ecf20Sopenharmony_ci 68428c2ecf20Sopenharmony_ci # extract mem/disk extra modes and convert 68438c2ecf20Sopenharmony_ci mode = sysvals.suspendmode 68448c2ecf20Sopenharmony_ci if mode.startswith('mem'): 68458c2ecf20Sopenharmony_ci memmode = mode.split('-', 1)[-1] if '-' in mode else 'deep' 68468c2ecf20Sopenharmony_ci if memmode == 'shallow': 68478c2ecf20Sopenharmony_ci mode = 'standby' 68488c2ecf20Sopenharmony_ci elif memmode == 's2idle': 68498c2ecf20Sopenharmony_ci mode = 'freeze' 68508c2ecf20Sopenharmony_ci else: 68518c2ecf20Sopenharmony_ci mode = 'mem' 68528c2ecf20Sopenharmony_ci sysvals.memmode = memmode 68538c2ecf20Sopenharmony_ci sysvals.suspendmode = mode 68548c2ecf20Sopenharmony_ci if mode.startswith('disk-'): 68558c2ecf20Sopenharmony_ci sysvals.diskmode = mode.split('-', 1)[-1] 68568c2ecf20Sopenharmony_ci sysvals.suspendmode = 'disk' 68578c2ecf20Sopenharmony_ci 68588c2ecf20Sopenharmony_ci sysvals.systemInfo(dmidecode(sysvals.mempath)) 68598c2ecf20Sopenharmony_ci 68608c2ecf20Sopenharmony_ci setRuntimeSuspend(True) 68618c2ecf20Sopenharmony_ci if sysvals.display: 68628c2ecf20Sopenharmony_ci displayControl('init') 68638c2ecf20Sopenharmony_ci failcnt, ret = 0, 0 68648c2ecf20Sopenharmony_ci if sysvals.multitest['run']: 68658c2ecf20Sopenharmony_ci # run multiple tests in a separate subdirectory 68668c2ecf20Sopenharmony_ci if not sysvals.outdir: 68678c2ecf20Sopenharmony_ci if 'time' in sysvals.multitest: 68688c2ecf20Sopenharmony_ci s = '-%dm' % sysvals.multitest['time'] 68698c2ecf20Sopenharmony_ci else: 68708c2ecf20Sopenharmony_ci s = '-x%d' % sysvals.multitest['count'] 68718c2ecf20Sopenharmony_ci sysvals.outdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S'+s) 68728c2ecf20Sopenharmony_ci if not os.path.isdir(sysvals.outdir): 68738c2ecf20Sopenharmony_ci os.makedirs(sysvals.outdir) 68748c2ecf20Sopenharmony_ci sysvals.sudoUserchown(sysvals.outdir) 68758c2ecf20Sopenharmony_ci finish = datetime.now() 68768c2ecf20Sopenharmony_ci if 'time' in sysvals.multitest: 68778c2ecf20Sopenharmony_ci finish += timedelta(minutes=sysvals.multitest['time']) 68788c2ecf20Sopenharmony_ci for i in range(sysvals.multitest['count']): 68798c2ecf20Sopenharmony_ci sysvals.multistat(True, i, finish) 68808c2ecf20Sopenharmony_ci if i != 0 and sysvals.multitest['delay'] > 0: 68818c2ecf20Sopenharmony_ci pprint('Waiting %d seconds...' % (sysvals.multitest['delay'])) 68828c2ecf20Sopenharmony_ci time.sleep(sysvals.multitest['delay']) 68838c2ecf20Sopenharmony_ci fmt = 'suspend-%y%m%d-%H%M%S' 68848c2ecf20Sopenharmony_ci sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt)) 68858c2ecf20Sopenharmony_ci ret = runTest(i+1, True) 68868c2ecf20Sopenharmony_ci failcnt = 0 if not ret else failcnt + 1 68878c2ecf20Sopenharmony_ci if sysvals.maxfail > 0 and failcnt >= sysvals.maxfail: 68888c2ecf20Sopenharmony_ci pprint('Maximum fail count of %d reached, aborting multitest' % (sysvals.maxfail)) 68898c2ecf20Sopenharmony_ci break 68908c2ecf20Sopenharmony_ci time.sleep(5) 68918c2ecf20Sopenharmony_ci sysvals.resetlog() 68928c2ecf20Sopenharmony_ci sysvals.multistat(False, i, finish) 68938c2ecf20Sopenharmony_ci if 'time' in sysvals.multitest and datetime.now() >= finish: 68948c2ecf20Sopenharmony_ci break 68958c2ecf20Sopenharmony_ci if not sysvals.skiphtml: 68968c2ecf20Sopenharmony_ci runSummary(sysvals.outdir, False, False) 68978c2ecf20Sopenharmony_ci sysvals.sudoUserchown(sysvals.outdir) 68988c2ecf20Sopenharmony_ci else: 68998c2ecf20Sopenharmony_ci if sysvals.outdir: 69008c2ecf20Sopenharmony_ci sysvals.testdir = sysvals.outdir 69018c2ecf20Sopenharmony_ci # run the test in the current directory 69028c2ecf20Sopenharmony_ci ret = runTest() 69038c2ecf20Sopenharmony_ci if sysvals.display: 69048c2ecf20Sopenharmony_ci displayControl('reset') 69058c2ecf20Sopenharmony_ci setRuntimeSuspend(False) 69068c2ecf20Sopenharmony_ci sys.exit(ret) 6907