Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/tools/power/pm-graph/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 233 kB image not shown  

Quelle  sleepgraph.py   Sprache: Python

 
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-only
#
# Tool for analyzing suspend/resume timing
# Copyright (c) 2013, Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# Authors:
#  Todd Brandt <todd.e.brandt@linux.intel.com>
#
# Links:
#  Home Page
#    https://www.intel.com/content/www/us/en/developer/topic-technology/open/pm-graph/overview.html
#  Source repo
#    git@github.com:intel/pm-graph
#
# Description:
#  This tool is designed to assist kernel and OS developers in optimizing
#  their linux stack's suspend/resume time. Using a kernel image built
#  with a few extra options enabled, the tool will execute a suspend and
#  will capture dmesg and ftrace data until resume is complete. This data
#  is transformed into a device timeline and a callgraph to give a quick
#  and detailed view of which devices and callbacks are taking the most
#  time in suspend/resume. The output is a single html file which can be
#  viewed in firefox or chrome.
#
#  The following kernel build options are required:
#  CONFIG_DEVMEM=y
#  CONFIG_PM_DEBUG=y
#  CONFIG_PM_SLEEP_DEBUG=y
#  CONFIG_FTRACE=y
#  CONFIG_FUNCTION_TRACER=y
#  CONFIG_FUNCTION_GRAPH_TRACER=y
#  CONFIG_KPROBES=y
#  CONFIG_KPROBES_ON_FTRACE=y
#
#  For kernel versions older than 3.15:
#  The following additional kernel parameters are required:
#  (e.g. in file /etc/default/grub)
#  GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=16M ..."
#

# ----------------- LIBRARIES --------------------

import sys
import time
import os
import string
import re
import platform
import signal
import codecs
from datetime import datetime, timedelta
import struct
import configparser
import gzip
from threading import Thread
from subprocess import call, Popen, PIPE
import base64
import traceback

debugtiming = False
mystarttime = time.time()
def pprint(msg):
 if debugtiming:
  print('[%09.3f] %s' % (time.time()-mystarttime, msg))
 else:
  print(msg)
 sys.stdout.flush()

def ascii(text):
 return text.decode('ascii''ignore')

# ----------------- CLASSES --------------------

# Class: SystemValues
# Description:
#  A global, single-instance container used to
#  store system values and test parameters
class SystemValues:
 title = 'SleepGraph'
 version = '5.13'
 ansi = False
 rs = 0
 display = ''
 gzip = False
 sync = False
 wifi = False
 netfix = False
 verbose = False
 testlog = True
 dmesglog = True
 ftracelog = False
 acpidebug = True
 tstat = True
 wifitrace = False
 mindevlen = 0.0001
 mincglen = 0.0
 cgphase = ''
 cgtest = -1
 cgskip = ''
 maxfail = 0
 multitest = {'run'False'count': 1000000, 'delay': 0}
 max_graph_depth = 0
 callloopmaxgap = 0.0001
 callloopmaxlen = 0.005
 bufsize = 0
 cpucount = 0
 memtotal = 204800
 memfree = 204800
 osversion = ''
 srgap = 0
 cgexp = False
 testdir = ''
 outdir = ''
 tpath = '/sys/kernel/tracing/'
 fpdtpath = '/sys/firmware/acpi/tables/FPDT'
 epath = '/sys/kernel/tracing/events/power/'
 pmdpath = '/sys/power/pm_debug_messages'
 s0ixpath = '/sys/module/intel_pmc_core/parameters/warn_on_s0ix_failures'
 s0ixres = '/sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us'
 acpipath='/sys/module/acpi/parameters/debug_level'
 traceevents = [
  'suspend_resume',
  'wakeup_source_activate',
  'wakeup_source_deactivate',
  'device_pm_callback_end',
  'device_pm_callback_start'
 ]
 logmsg = ''
 testcommand = ''
 mempath = '/dev/mem'
 powerfile = '/sys/power/state'
 mempowerfile = '/sys/power/mem_sleep'
 diskpowerfile = '/sys/power/disk'
 suspendmode = 'mem'
 memmode = ''
 diskmode = ''
 hostname = 'localhost'
 prefix = 'test'
 teststamp = ''
 sysstamp = ''
 dmesgstart = 0.0
 dmesgfile = ''
 ftracefile = ''
 htmlfile = 'output.html'
 result = ''
 rtcwake = True
 rtcwaketime = 15
 rtcpath = ''
 devicefilter = []
 cgfilter = []
 stamp = 0
 execcount = 1
 x2delay = 0
 skiphtml = False
 usecallgraph = False
 ftopfunc = 'pm_suspend'
 ftop = False
 usetraceevents = False
 usetracemarkers = True
 useftrace = True
 usekprobes = True
 usedevsrc = False
 useprocmon = False
 notestrun = False
 cgdump = False
 devdump = False
 mixedphaseheight = True
 devprops = dict()
 cfgdef = dict()
 platinfo = []
 predelay = 0
 postdelay = 0
 tmstart = 'SUSPEND START %Y%m%d-%H:%M:%S.%f'
 tmend = 'RESUME COMPLETE %Y%m%d-%H:%M:%S.%f'
 tracefuncs = {
  'async_synchronize_full': {},
  'sys_sync': {},
  'ksys_sync': {},
  '__pm_notifier_call_chain': {},
  'pm_prepare_console': {},
  'pm_notifier_call_chain': {},
  'freeze_processes': {},
  'freeze_kernel_threads': {},
  'pm_restrict_gfp_mask': {},
  'acpi_suspend_begin': {},
  'acpi_hibernation_begin': {},
  'acpi_hibernation_enter': {},
  'acpi_hibernation_leave': {},
  'acpi_pm_freeze': {},
  'acpi_pm_thaw': {},
  'acpi_s2idle_end': {},
  'acpi_s2idle_sync': {},
  'acpi_s2idle_begin': {},
  'acpi_s2idle_prepare': {},
  'acpi_s2idle_prepare_late': {},
  'acpi_s2idle_wake': {},
  'acpi_s2idle_wakeup': {},
  'acpi_s2idle_restore': {},
  'acpi_s2idle_restore_early': {},
  'hibernate_preallocate_memory': {},
  'create_basic_memory_bitmaps': {},
  'swsusp_write': {},
  'console_suspend_all': {},
  'acpi_pm_prepare': {},
  'syscore_suspend': {},
  'arch_enable_nonboot_cpus_end': {},
  'syscore_resume': {},
  'acpi_pm_finish': {},
  'console_resume_all': {},
  'acpi_pm_end': {},
  'pm_restore_gfp_mask': {},
  'thaw_processes': {},
  'pm_restore_console': {},
  'CPU_OFF': {
   'func':'_cpu_down',
   'args_x86_64': {'cpu':'%di:s32'},
   'format''CPU_OFF[{cpu}]'
  },
  'CPU_ON': {
   'func':'_cpu_up',
   'args_x86_64': {'cpu':'%di:s32'},
   'format''CPU_ON[{cpu}]'
  },
 }
 dev_tracefuncs = {
  # general wait/delay/sleep
  'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 },
  'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
  'udelay': { 'func':'__const_udelay''args_x86_64': {'loops':'%di:s32'}, 'ub': 1 },
  'usleep_range': {
   'func':'usleep_range_state',
   'args_x86_64': {'min':'%di:s32''max':'%si:s32'},
   'ub': 1
  },
  'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath''ub': 1 },
  'acpi_os_stall': {'ub': 1},
  'rt_mutex_slowlock': {'ub': 1},
  # ACPI
  'acpi_resume_power_resources': {},
  'acpi_ps_execute_method': { 'args_x86_64': {
   'fullpath':'+0(+40(%di)):string',
  }},
  # mei_me
  'mei_reset': {},
  # filesystem
  'ext4_sync_fs': {},
  # 80211
  'ath10k_bmi_read_memory': { 'args_x86_64': {'length':'%cx:s32'} },
  'ath10k_bmi_write_memory': { 'args_x86_64': {'length':'%cx:s32'} },
  'ath10k_bmi_fast_download': { 'args_x86_64': {'length':'%cx:s32'} },
  'iwlagn_mac_start': {},
  'iwlagn_alloc_bcast_station': {},
  'iwl_trans_pcie_start_hw': {},
  'iwl_trans_pcie_start_fw': {},
  'iwl_run_init_ucode': {},
  'iwl_load_ucode_wait_alive': {},
  'iwl_alive_start': {},
  'iwlagn_mac_stop': {},
  'iwlagn_mac_suspend': {},
  'iwlagn_mac_resume': {},
  'iwlagn_mac_add_interface': {},
  'iwlagn_mac_remove_interface': {},
  'iwlagn_mac_change_interface': {},
  'iwlagn_mac_config': {},
  'iwlagn_configure_filter': {},
  'iwlagn_mac_hw_scan': {},
  'iwlagn_bss_info_changed': {},
  'iwlagn_mac_channel_switch': {},
  'iwlagn_mac_flush': {},
  # ATA
  'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} },
  # i915
  'i915_gem_resume': {},
  'i915_restore_state': {},
  'intel_opregion_setup': {},
  'g4x_pre_enable_dp': {},
  'vlv_pre_enable_dp': {},
  'chv_pre_enable_dp': {},
  'g4x_enable_dp': {},
  'vlv_enable_dp': {},
  'intel_hpd_init': {},
  'intel_opregion_register': {},
  'intel_dp_detect': {},
  'intel_hdmi_detect': {},
  'intel_opregion_init': {},
  'intel_fbdev_set_suspend': {},
 }
 infocmds = [
  [0, 'sysinfo''uname''-a'],
  [0, 'cpuinfo''head''-7''/proc/cpuinfo'],
  [0, 'kparams''cat''/proc/cmdline'],
  [0, 'mcelog''mcelog'],
  [0, 'pcidevices''lspci''-tv'],
  [0, 'usbdevices''lsusb''-tv'],
  [0, 'acpidevices''sh''-c''ls -l /sys/bus/acpi/devices/*/physical_node'],
  [0, 's0ix_require''cat''/sys/kernel/debug/pmc_core/substate_requirements'],
  [0, 's0ix_debug''cat''/sys/kernel/debug/pmc_core/slp_s0_debug_status'],
  [0, 'ethtool''ethtool''{ethdev}'],
  [1, 's0ix_residency''cat''/sys/kernel/debug/pmc_core/slp_s0_residency_usec'],
  [1, 'interrupts''cat''/proc/interrupts'],
  [1, 'wakeups''cat''/sys/kernel/debug/wakeup_sources'],
  [2, 'gpecounts''sh''-c''grep -v invalid /sys/firmware/acpi/interrupts/*'],
  [2, 'suspendstats''sh''-c''grep -v invalid /sys/power/suspend_stats/*'],
  [2, 'cpuidle''sh''-c''grep -v invalid /sys/devices/system/cpu/cpu*/cpuidle/state*/s2idle/*'],
  [2, 'battery''sh''-c''grep -v invalid /sys/class/power_supply/*/*'],
  [2, 'thermal''sh''-c''grep . /sys/class/thermal/thermal_zone*/temp'],
 ]
 cgblacklist = []
 kprobes = dict()
 timeformat = '%.3f'
 cmdline = '%s %s' % \
   (os.path.basename(sys.argv[0]), ' '.join(sys.argv[1:]))
 sudouser = ''
 def __init__(self):
  self.archargs = 'args_'+platform.machine()
  self.hostname = platform.node()
  if(self.hostname == ''):
   self.hostname = 'localhost'
  rtc = "rtc0"
  if os.path.exists('/dev/rtc'):
   rtc = os.readlink('/dev/rtc')
  rtc = '/sys/class/rtc/'+rtc
  if os.path.exists(rtc) and os.path.exists(rtc+'/date'and \
   os.path.exists(rtc+'/time'and os.path.exists(rtc+'/wakealarm'):
   self.rtcpath = rtc
  if (hasattr(sys.stdout, 'isatty'and sys.stdout.isatty()):
   self.ansi = True
  self.testdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S')
  if os.getuid() == 0 and 'SUDO_USER' in os.environ and \
   os.environ['SUDO_USER']:
   self.sudouser = os.environ['SUDO_USER']
 def resetlog(self):
  self.logmsg = ''
  self.platinfo = []
 def vprint(self, msg):
  self.logmsg += msg+'\n'
  if self.verbose or msg.startswith('WARNING:'):
   pprint(msg)
 def signalHandler(self, signum, frame):
  signame = self.signames[signum] if signum in self.signames else 'UNKNOWN'
  if signame in ['SIGUSR1''SIGUSR2''SIGSEGV']:
   traceback.print_stack()
   stack = traceback.format_list(traceback.extract_stack())
   self.outputResult({'stack':stack})
   if signame == 'SIGUSR1':
    return
  msg = '%s caused a tool exit, line %d' % (signame, frame.f_lineno)
  pprint(msg)
  self.outputResult({'error':msg})
  os.kill(os.getpid(), signal.SIGKILL)
  sys.exit(3)
 def signalHandlerInit(self):
  capture = ['BUS''SYS''XCPU''XFSZ''PWR''HUP''INT''QUIT',
   'ILL''ABRT''FPE''SEGV''TERM''USR1''USR2']
  self.signames = dict()
  for i in capture:
   s = 'SIG'+i
   try:
    signum = getattr(signal, s)
    signal.signal(signum, self.signalHandler)
   except:
    continue
   self.signames[signum] = s
 def rootCheck(self, fatal=True):
  if(os.access(self.powerfile, os.W_OK)):
   return True
  if fatal:
   msg = 'This command requires sysfs mount and root access'
   pprint('ERROR: %s\n' % msg)
   self.outputResult({'error':msg})
   sys.exit(1)
  return False
 def rootUser(self, fatal=False):
  if 'USER' in os.environ and os.environ['USER'] == 'root':
   return True
  if fatal:
   msg = 'This command must be run as root'
   pprint('ERROR: %s\n' % msg)
   self.outputResult({'error':msg})
   sys.exit(1)
  return False
 def usable(self, file, ishtml=False):
  if not os.path.exists(file) or os.path.getsize(file) < 1:
   return False
  if ishtml:
   try:
    fp = open(file, 'r')
    res = fp.read(1000)
    fp.close()
   except:
    return False
   if '' not in res:
    return False
  return True
 def getExec(self, cmd):
  try:
   fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout
   out = ascii(fp.read()).strip()
   fp.close()
  except:
   out = ''
  if out:
   return out
  for path in ['/sbin''/bin''/usr/sbin''/usr/bin',
   '/usr/local/sbin''/usr/local/bin']:
   cmdfull = os.path.join(path, cmd)
   if os.path.exists(cmdfull):
    return cmdfull
  return out
 def setPrecision(self, num):
  if num < 0 or num > 6:
   return
  self.timeformat = '%.{0}f'.format(num)
 def setOutputFolder(self, value):
  args = dict()
  n = datetime.now()
  args['date'] = n.strftime('%y%m%d')
  args['time'] = n.strftime('%H%M%S')
  args['hostname'] = args['host'] = self.hostname
  args['mode'] = self.suspendmode
  return value.format(**args)
 def setOutputFile(self):
  if self.dmesgfile != '':
   m = re.match(r'(?P.*)_dmesg\.txt.*', self.dmesgfile)
   if(m):
    self.htmlfile = m.group('name')+'.html'
  if self.ftracefile != '':
   m = re.match(r'(?P.*)_ftrace\.txt.*', self.ftracefile)
   if(m):
    self.htmlfile = m.group('name')+'.html'
 def systemInfo(self, info):
  p = m = ''
  if 'baseboard-manufacturer' in info:
   m = info['baseboard-manufacturer']
  elif 'system-manufacturer' in info:
   m = info['system-manufacturer']
  if 'system-product-name' in info:
   p = info['system-product-name']
  elif 'baseboard-product-name' in info:
   p = info['baseboard-product-name']
  if m[:5].lower() == 'intel' and 'baseboard-product-name' in info:
   p = info['baseboard-product-name']
  c = info['processor-version'if 'processor-version' in info else ''
  b = info['bios-version'if 'bios-version' in info else ''
  r = info['bios-release-date'if 'bios-release-date' in info else ''
  self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | biosdate:%s | numcpu:%d | memsz:%d | memfr:%d' % \
   (m, p, c, b, r, self.cpucount, self.memtotal, self.memfree)
  if self.osversion:
   self.sysstamp += ' | os:%s' % self.osversion
 def printSystemInfo(self, fatal=False):
  self.rootCheck(True)
  out = dmidecode(self.mempath, fatal)
  if len(out) < 1:
   return
  fmt = '%-24s: %s'
  if self.osversion:
   print(fmt % ('os-version', self.osversion))
  for name in sorted(out):
   print(fmt % (name, out[name]))
  print(fmt % ('cpucount', ('%d' % self.cpucount)))
  print(fmt % ('memtotal', ('%d kB' % self.memtotal)))
  print(fmt % ('memfree', ('%d kB' % self.memfree)))
 def cpuInfo(self):
  self.cpucount = 0
  if os.path.exists('/proc/cpuinfo'):
   with open('/proc/cpuinfo''r'as fp:
    for line in fp:
     if re.match(r'^processor[ \t]*:[ \t]*[0-9]*', line):
      self.cpucount += 1
  if os.path.exists('/proc/meminfo'):
   with open('/proc/meminfo''r'as fp:
    for line in fp:
     m = re.match(r'^MemTotal:[ \t]*(?P[0-9]*) *kB', line)
     if m:
      self.memtotal = int(m.group('sz'))
     m = re.match(r'^MemFree:[ \t]*(?P[0-9]*) *kB', line)
     if m:
      self.memfree = int(m.group('sz'))
  if os.path.exists('/etc/os-release'):
   with open('/etc/os-release''r'as fp:
    for line in fp:
     if line.startswith('PRETTY_NAME='):
      self.osversion = line[12:].strip().replace('"''')
 def initTestOutput(self, name):
  self.prefix = self.hostname
  v = open('/proc/version''r').read().strip()
  kver = v.split()[2]
  fmt = name+'-%m%d%y-%H%M%S'
  testtime = datetime.now().strftime(fmt)
  self.teststamp = \
   '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver
  ext = ''
  if self.gzip:
   ext = '.gz'
  self.dmesgfile = \
   self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt'+ext
  self.ftracefile = \
   self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt'+ext
  self.htmlfile = \
   self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html'
  if not os.path.isdir(self.testdir):
   os.makedirs(self.testdir)
  self.sudoUserchown(self.testdir)
 def getValueList(self, value):
  out = []
  for i in value.split(','):
   if i.strip():
    out.append(i.strip())
  return out
 def setDeviceFilter(self, value):
  self.devicefilter = self.getValueList(value)
 def setCallgraphFilter(self, value):
  self.cgfilter = self.getValueList(value)
 def skipKprobes(self, value):
  for k in self.getValueList(value):
   if k in self.tracefuncs:
    del self.tracefuncs[k]
   if k in self.dev_tracefuncs:
    del self.dev_tracefuncs[k]
 def setCallgraphBlacklist(self, file):
  self.cgblacklist = self.listFromFile(file)
 def rtcWakeAlarmOn(self):
  call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True)
  nowtime = open(self.rtcpath+'/since_epoch''r').read().strip()
  if nowtime:
   nowtime = int(nowtime)
  else:
   # if hardware time fails, use the software time
   nowtime = int(datetime.now().strftime('%s'))
  alarm = nowtime + self.rtcwaketime
  call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True)
 def rtcWakeAlarmOff(self):
  call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True)
 def initdmesg(self):
  # get the latest time stamp from the dmesg log
  lines = Popen('dmesg', stdout=PIPE).stdout.readlines()
  ktime = '0'
  for line in reversed(lines):
   line = ascii(line).replace('\r\n''')
   idx = line.find('[')
   if idx > 1:
    line = line[idx:]
   m = re.match(r'[ \t]*(\[ *)(?P[0-9\.]*)(\]) (?P.*)', line)
   if(m):
    ktime = m.group('ktime')
    break
  self.dmesgstart = float(ktime)
 def getdmesg(self, testdata):
  op = self.writeDatafileHeader(self.dmesgfile, testdata)
  # store all new dmesg lines since initdmesg was called
  fp = Popen('dmesg', stdout=PIPE).stdout
  for line in fp:
   line = ascii(line).replace('\r\n''')
   idx = line.find('[')
   if idx > 1:
    line = line[idx:]
   m = re.match(r'[ \t]*(\[ *)(?P[0-9\.]*)(\]) (?P.*)', line)
   if(not m):
    continue
   ktime = float(m.group('ktime'))
   if ktime > self.dmesgstart:
    op.write(line)
  fp.close()
  op.close()
 def listFromFile(self, file):
  list = []
  fp = open(file)
  for i in fp.read().split('\n'):
   i = i.strip()
   if i and i[0] != '#':
    list.append(i)
  fp.close()
  return list
 def addFtraceFilterFunctions(self, file):
  for i in self.listFromFile(file):
   if len(i) < 2:
    continue
   self.tracefuncs[i] = dict()
 def getFtraceFilterFunctions(self, current):
  self.rootCheck(True)
  if not current:
   call('cat '+self.tpath+'available_filter_functions', shell=True)
   return
  master = self.listFromFile(self.tpath+'available_filter_functions')
  for i in sorted(self.tracefuncs):
   if 'func' in self.tracefuncs[i]:
    i = self.tracefuncs[i]['func']
   if i in master:
    print(i)
   else:
    print(self.colorText(i))
 def setFtraceFilterFunctions(self, list):
  master = self.listFromFile(self.tpath+'available_filter_functions')
  flist = ''
  for i in list:
   if i not in master:
    continue
   if ' [' in i:
    flist += i.split(' ')[0]+'\n'
   else:
    flist += i+'\n'
  fp = open(self.tpath+'set_graph_function''w')
  fp.write(flist)
  fp.close()
 def basicKprobe(self, name):
  self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name}
 def defaultKprobe(self, name, kdata):
  k = kdata
  for field in ['name''format''func']:
   if field not in k:
    k[field] = name
  if self.archargs in k:
   k['args'] = k[self.archargs]
  else:
   k['args'] = dict()
   k['format'] = name
  self.kprobes[name] = k
 def kprobeColor(self, name):
  if name not in self.kprobes or 'color' not in self.kprobes[name]:
   return ''
  return self.kprobes[name]['color']
 def kprobeDisplayName(self, name, dataraw):
  if name not in self.kprobes:
   self.basicKprobe(name)
  data = ''
  quote=0
  # first remvoe any spaces inside quotes, and the quotes
  for c in dataraw:
   if c == '"':
    quote = (quote + 1) % 2
   if quote and c == ' ':
    data += '_'
   elif c != '"':
    data += c
  fmt, args = self.kprobes[name]['format'], self.kprobes[name]['args']
  arglist = dict()
  # now process the args
  for arg in sorted(args):
   arglist[arg] = ''
   m = re.match(r'.* '+arg+'=(?P.*) ', data);
   if m:
    arglist[arg] = m.group('arg')
   else:
    m = re.match(r'.* '+arg+'=(?P.*)', data);
    if m:
     arglist[arg] = m.group('arg')
  out = fmt.format(**arglist)
  out = out.replace(' ''_').replace('"''')
  return out
 def kprobeText(self, kname, kprobe):
  name = fmt = func = kname
  args = dict()
  if 'name' in kprobe:
   name = kprobe['name']
  if 'format' in kprobe:
   fmt = kprobe['format']
  if 'func' in kprobe:
   func = kprobe['func']
  if self.archargs in kprobe:
   args = kprobe[self.archargs]
  if 'args' in kprobe:
   args = kprobe['args']
  if re.findall('{(?P[a-z,A-Z,0-9]*)}', func):
   doError('Kprobe "%s" has format info in the function name "%s"' % (name, func))
  for arg in re.findall('{(?P[a-z,A-Z,0-9]*)}', fmt):
   if arg not in args:
    doError('Kprobe "%s" is missing argument "%s"' % (name, arg))
  val = 'p:%s_cal %s' % (name, func)
  for i in sorted(args):
   val += ' %s=%s' % (i, args[i])
  val += '\nr:%s_ret %s $retval\n' % (name, func)
  return val
 def addKprobes(self, output=False):
  if len(self.kprobes) < 1:
   return
  if output:
   pprint(' kprobe functions in this kernel:')
  # first test each kprobe
  rejects = []
  # sort kprobes: trace, ub-dev, custom, dev
  kpl = [[], [], [], []]
  linesout = len(self.kprobes)
  for name in sorted(self.kprobes):
   res = self.colorText('YES', 32)
   if not self.testKprobe(name, self.kprobes[name]):
    res = self.colorText('NO')
    rejects.append(name)
   else:
    if name in self.tracefuncs:
     kpl[0].append(name)
    elif name in self.dev_tracefuncs:
     if 'ub' in self.dev_tracefuncs[name]:
      kpl[1].append(name)
     else:
      kpl[3].append(name)
    else:
     kpl[2].append(name)
   if output:
    pprint(' %s: %s' % (name, res))
  kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3]
  # remove all failed ones from the list
  for name in rejects:
   self.kprobes.pop(name)
  # set the kprobes all at once
  self.fsetVal('''kprobe_events')
  kprobeevents = ''
  for kp in kplist:
   kprobeevents += self.kprobeText(kp, self.kprobes[kp])
  self.fsetVal(kprobeevents, 'kprobe_events')
  if output:
   check = self.fgetVal('kprobe_events')
   linesack = (len(check.split('\n')) - 1) // 2
   pprint(' kprobe functions enabled: %d/%d' % (linesack, linesout))
  self.fsetVal('1''events/kprobes/enable')
 def testKprobe(self, kname, kprobe):
  self.fsetVal('0''events/kprobes/enable')
  kprobeevents = self.kprobeText(kname, kprobe)
  if not kprobeevents:
   return False
  try:
   self.fsetVal(kprobeevents, 'kprobe_events')
   check = self.fgetVal('kprobe_events')
  except:
   return False
  linesout = len(kprobeevents.split('\n'))
  linesack = len(check.split('\n'))
  if linesack < linesout:
   return False
  return True
 def setVal(self, val, file):
  if not os.path.exists(file):
   return False
  try:
   fp = open(file, 'wb', 0)
   fp.write(val.encode())
   fp.flush()
   fp.close()
  except:
   return False
  return True
 def fsetVal(self, val, path):
  if not self.useftrace:
   return False
  return self.setVal(val, self.tpath+path)
 def getVal(self, file):
  res = ''
  if not os.path.exists(file):
   return res
  try:
   fp = open(file, 'r')
   res = fp.read()
   fp.close()
  except:
   pass
  return res
 def fgetVal(self, path):
  if not self.useftrace:
   return ''
  return self.getVal(self.tpath+path)
 def cleanupFtrace(self):
  if self.useftrace:
   self.fsetVal('0''events/kprobes/enable')
   self.fsetVal('''kprobe_events')
   self.fsetVal('1024''buffer_size_kb')
 def setupAllKprobes(self):
  for name in self.tracefuncs:
   self.defaultKprobe(name, self.tracefuncs[name])
  for name in self.dev_tracefuncs:
   self.defaultKprobe(name, self.dev_tracefuncs[name])
 def isCallgraphFunc(self, name):
  if len(self.tracefuncs) < 1 and self.suspendmode == 'command':
   return True
  for i in self.tracefuncs:
   if 'func' in self.tracefuncs[i]:
    f = self.tracefuncs[i]['func']
   else:
    f = i
   if name == f:
    return True
  return False
 def initFtrace(self, quiet=False):
  if not self.useftrace:
   return
  if not quiet:
   sysvals.printSystemInfo(False)
   pprint('INITIALIZING FTRACE')
  # turn trace off
  self.fsetVal('0''tracing_on')
  self.cleanupFtrace()
  # set the trace clock to global
  self.fsetVal('global''trace_clock')
  self.fsetVal('nop''current_tracer')
  # set trace buffer to an appropriate value
  cpus = max(1, self.cpucount)
  if self.bufsize > 0:
   tgtsize = self.bufsize
  elif self.usecallgraph or self.usedevsrc:
   bmax = (1*1024*1024) if self.suspendmode in ['disk''command'] \
    else (3*1024*1024)
   tgtsize = min(self.memfree, bmax)
  else:
   tgtsize = 65536
  while not self.fsetVal('%d' % (tgtsize // cpus), 'buffer_size_kb'):
   # if the size failed to set, lower it and keep trying
   tgtsize -= 65536
   if tgtsize < 65536:
    tgtsize = int(self.fgetVal('buffer_size_kb')) * cpus
    break
  self.vprint('Setting trace buffers to %d kB (%d kB per cpu)' % (tgtsize, tgtsize/cpus))
  # initialize the callgraph trace
  if(self.usecallgraph):
   # set trace type
   self.fsetVal('function_graph''current_tracer')
   self.fsetVal('''set_ftrace_filter')
   # temporary hack to fix https://bugzilla.kernel.org/show_bug.cgi?id=212761
   fp = open(self.tpath+'set_ftrace_notrace''w')
   fp.write('native_queued_spin_lock_slowpath\ndev_driver_string')
   fp.close()
   # set trace format options
   self.fsetVal('print-parent''trace_options')
   self.fsetVal('funcgraph-abstime''trace_options')
   self.fsetVal('funcgraph-cpu''trace_options')
   self.fsetVal('funcgraph-duration''trace_options')
   self.fsetVal('funcgraph-proc''trace_options')
   self.fsetVal('funcgraph-tail''trace_options')
   self.fsetVal('nofuncgraph-overhead''trace_options')
   self.fsetVal('context-info''trace_options')
   self.fsetVal('graph-time''trace_options')
   self.fsetVal('%d' % self.max_graph_depth, 'max_graph_depth')
   cf = ['dpm_run_callback']
   if(self.usetraceevents):
    cf += ['dpm_prepare''dpm_complete']
   for fn in self.tracefuncs:
    if 'func' in self.tracefuncs[fn]:
     cf.append(self.tracefuncs[fn]['func'])
    else:
     cf.append(fn)
   if self.ftop:
    self.setFtraceFilterFunctions([self.ftopfunc])
   else:
    self.setFtraceFilterFunctions(cf)
  # initialize the kprobe trace
  elif self.usekprobes:
   for name in self.tracefuncs:
    self.defaultKprobe(name, self.tracefuncs[name])
   if self.usedevsrc:
    for name in self.dev_tracefuncs:
     self.defaultKprobe(name, self.dev_tracefuncs[name])
   if not quiet:
    pprint('INITIALIZING KPROBES')
   self.addKprobes(self.verbose)
  if(self.usetraceevents):
   # turn trace events on
   events = iter(self.traceevents)
   for e in events:
    self.fsetVal('1''events/power/'+e+'/enable')
  # clear the trace buffer
  self.fsetVal('''trace')
 def verifyFtrace(self):
  # files needed for any trace data
  files = ['buffer_size_kb''current_tracer''trace''trace_clock',
     'trace_marker''trace_options''tracing_on']
  # legacy check for old systems
  if not os.path.exists(self.tpath+'trace'):
   self.tpath = '/sys/kernel/debug/tracing/'
  if not os.path.exists(self.epath):
   self.epath = '/sys/kernel/debug/tracing/events/power/'
  # files needed for callgraph trace data
  tp = self.tpath
  if(self.usecallgraph):
   files += [
    'available_filter_functions',
    'set_ftrace_filter',
    'set_graph_function'
   ]
  for f in files:
   if(os.path.exists(tp+f) == False):
    return False
  return True
 def verifyKprobes(self):
  # files needed for kprobes to work
  files = ['kprobe_events''events']
  tp = self.tpath
  for f in files:
   if(os.path.exists(tp+f) == False):
    return False
  return True
 def colorText(self, str, color=31):
  if not self.ansi:
   return str
  return '\x1B[%d;40m%s\x1B[m' % (color, str)
 def writeDatafileHeader(self, filename, testdata):
  fp = self.openlog(filename, 'w')
  fp.write('%s\n%s\n# command | %s\n' % (self.teststamp, self.sysstamp, self.cmdline))
  for test in testdata:
   if 'fw' in test:
    fw = test['fw']
    if(fw):
     fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1]))
   if 'turbo' in test:
    fp.write('# turbostat %s\n' % test['turbo'])
   if 'wifi' in test:
    fp.write('# wifi %s\n' % test['wifi'])
   if 'netfix' in test:
    fp.write('# netfix %s\n' % test['netfix'])
   if test['error'or len(testdata) > 1:
    fp.write('# enter_sleep_error %s\n' % test['error'])
  return fp
 def sudoUserchown(self, dir):
  if os.path.exists(dir) and self.sudouser:
   cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1'
   call(cmd.format(self.sudouser, dir), shell=True)
 def outputResult(self, testdata, num=0):
  if not self.result:
   return
  n = ''
  if num > 0:
   n = '%d' % num
  fp = open(self.result, 'a')
  if 'stack' in testdata:
   fp.write('Printing stack trace:\n')
   for line in testdata['stack']:
    fp.write(line)
   fp.close()
   self.sudoUserchown(self.result)
   return
  if 'error' in testdata:
   fp.write('result%s: fail\n' % n)
   fp.write('error%s: %s\n' % (n, testdata['error']))
  else:
   fp.write('result%s: pass\n' % n)
  if 'mode' in testdata:
   fp.write('mode%s: %s\n' % (n, testdata['mode']))
  for v in ['suspend''resume''boot''lastinit']:
   if v in testdata:
    fp.write('%s%s: %.3f\n' % (v, n, testdata[v]))
  for v in ['fwsuspend''fwresume']:
   if v in testdata:
    fp.write('%s%s: %.3f\n' % (v, n, testdata[v] / 1000000.0))
  if 'bugurl' in testdata:
   fp.write('url%s: %s\n' % (n, testdata['bugurl']))
  fp.close()
  self.sudoUserchown(self.result)
 def configFile(self, file):
  dir = os.path.dirname(os.path.realpath(__file__))
  if os.path.exists(file):
   return file
  elif os.path.exists(dir+'/'+file):
   return dir+'/'+file
  elif os.path.exists(dir+'/config/'+file):
   return dir+'/config/'+file
  return ''
 def openlog(self, filename, mode):
  isgz = self.gzip
  if mode == 'r':
   try:
    with gzip.open(filename, mode+'t'as fp:
     test = fp.read(64)
    isgz = True
   except:
    isgz = False
  if isgz:
   return gzip.open(filename, mode+'t')
  return open(filename, mode)
 def putlog(self, filename, text):
  with self.openlog(filename, 'a'as fp:
   fp.write(text)
   fp.close()
 def dlog(self, text):
  if not self.dmesgfile:
   return
  self.putlog(self.dmesgfile, '# %s\n' % text)
 def flog(self, text):
  self.putlog(self.ftracefile, text)
 def b64unzip(self, data):
  try:
   out = codecs.decode(base64.b64decode(data), 'zlib').decode()
  except:
   out = data
  return out
 def b64zip(self, data):
  out = base64.b64encode(codecs.encode(data.encode(), 'zlib')).decode()
  return out
 def platforminfo(self, cmdafter):
  # add platform info on to a completed ftrace file
  if not os.path.exists(self.ftracefile):
   return False
  footer = '#\n'

  # add test command string line if need be
  if self.suspendmode == 'command' and self.testcommand:
   footer += '# platform-testcmd: %s\n' % (self.testcommand)

  # get a list of target devices from the ftrace file
  props = dict()
  tp = TestProps()
  tf = self.openlog(self.ftracefile, 'r')
  for line in tf:
   if tp.stampInfo(line, self):
    continue
   # parse only valid lines, if this is not one move on
   m = re.match(tp.ftrace_line_fmt, line)
   if(not m or 'device_pm_callback_start' not in line):
    continue
   m = re.match(r'.*: (?P.*) (?P.*), parent: *(?P

.*), .*', m.group('msg'));
   if(not m):
    continue
   dev = m.group('d')
   if dev not in props:
    props[dev] = DevProps()
  tf.close()

  # now get the syspath for each target device
  for dirname, dirnames, filenames in os.walk('/sys/devices'):
   if(re.match(r'.*/power', dirname) and 'async' in filenames):
    dev = dirname.split('/')[-2]
    if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)):
     props[dev].syspath = dirname[:-6]

  # now fill in the properties for our target devices
  for dev in sorted(props):
   dirname = props[dev].syspath
   if not dirname or not os.path.exists(dirname):
    continue
   props[dev].isasync = False
   if os.path.exists(dirname+'/power/async'):
    fp = open(dirname+'/power/async')
    if 'enabled' in fp.read():
     props[dev].isasync = True
    fp.close()
   fields = os.listdir(dirname)
   for file in ['product''name''model''description''id''idVendor']:
    if file not in fields:
     continue
    try:
     with open(os.path.join(dirname, file), 'rb'as fp:
      props[dev].altname = ascii(fp.read())
    except:
     continue
    if file == 'idVendor':
     idv, idp = props[dev].altname.strip(), ''
     try:
      with open(os.path.join(dirname, 'idProduct'), 'rb'as fp:
       idp = ascii(fp.read()).strip()
     except:
      props[dev].altname = ''
      break
     props[dev].altname = '%s:%s' % (idv, idp)
    break
   if props[dev].altname:
    out = props[dev].altname.strip().replace('\n'' ')\
     .replace(','' ').replace(';'' ')
    props[dev].altname = out

  # add a devinfo line to the bottom of ftrace
  out = ''
  for dev in sorted(props):
   out += props[dev].out(dev)
  footer += '# platform-devinfo: %s\n' % self.b64zip(out)

  # add a line for each of these commands with their outputs
  for name, cmdline, info in cmdafter:
   footer += '# platform-%s: %s | %s\n' % (name, cmdline, self.b64zip(info))
  self.flog(footer)
  return True
 def commonPrefix(self, list):
  if len(list) < 2:
   return ''
  prefix = list[0]
  for s in list[1:]:
   while s[:len(prefix)] != prefix and prefix:
    prefix = prefix[:len(prefix)-1]
   if not prefix:
    break
  if '/' in prefix and prefix[-1] != '/':
   prefix = prefix[0:prefix.rfind('/')+1]
  return prefix
 def dictify(self, text, format):
  out = dict()
  header = True if format == 1 else False
  delim = ' ' if format == 1 else ':'
  for line in text.split('\n'):
   if header:
    header, out['@'] = False, line
    continue
   line = line.strip()
   if delim in line:
    data = line.split(delim, 1)
    num = re.search(r'[\d]+', data[1])
    if format == 2 and num:
     out[data[0].strip()] = num.group()
    else:
     out[data[0].strip()] = data[1]
  return out
 def cmdinfovar(self, arg):
  if arg == 'ethdev':
   try:
    cmd = [self.getExec('ip'), '-4''-o''-br''addr']
    fp = Popen(cmd, stdout=PIPE, stderr=PIPE).stdout
    info = ascii(fp.read()).strip()
    fp.close()
   except:
    return 'iptoolcrash'
   for line in info.split('\n'):
    if line[0] == 'e' and 'UP' in line:
     return line.split()[0]
   return 'nodevicefound'
  return 'unknown'
 def cmdinfo(self, begin, debug=False):
  out = []
  if begin:
   self.cmd1 = dict()
  for cargs in self.infocmds:
   delta, name, args = cargs[0], cargs[1], cargs[2:]
   for i in range(len(args)):
    if args[i][0] == '{' and args[i][-1] == '}':
     args[i] = self.cmdinfovar(args[i][1:-1])
   cmdline, cmdpath = ' '.join(args[0:]), self.getExec(args[0])
   if not cmdpath or (begin and not delta):
    continue
   self.dlog('[%s]' % cmdline)
   try:
    fp = Popen([cmdpath]+args[1:], stdout=PIPE, stderr=PIPE).stdout
    info = ascii(fp.read()).strip()
    fp.close()
   except:
    continue
   if not debug and begin:
    self.cmd1[name] = self.dictify(info, delta)
   elif not debug and delta and name in self.cmd1:
    before, after = self.cmd1[name], self.dictify(info, delta)
    dinfo = ('\t%s\n' % before['@']) if '@' in before and len(before) > 1 else ''
    prefix = self.commonPrefix(list(before.keys()))
    for key in sorted(before):
     if key in after and before[key] != after[key]:
      title = key.replace(prefix, '')
      if delta == 2:
       dinfo += '\t%s : %s -> %s\n' % \
        (title, before[key].strip(), after[key].strip())
      else:
       dinfo += '%10s (start) : %s\n%10s (after) : %s\n' % \
        (title, before[key], title, after[key])
    dinfo = '\tnothing changed' if not dinfo else dinfo.rstrip()
    out.append((name, cmdline, dinfo))
   else:
    out.append((name, cmdline, '\tnothing' if not info else info))
  return out
 def testVal(self, file, fmt='basic', value=''):
  if file == 'restoreall':
   for f in self.cfgdef:
    if os.path.exists(f):
     fp = open(f, 'w')
     fp.write(self.cfgdef[f])
     fp.close()
   self.cfgdef = dict()
  elif value and os.path.exists(file):
   fp = open(file, 'r+')
   if fmt == 'radio':
    m = re.match(r'.*\[(?P.*)\].*', fp.read())
    if m:
     self.cfgdef[file] = m.group('v')
   elif fmt == 'acpi':
    line = fp.read().strip().split('\n')[-1]
    m = re.match(r'.* (?P[0-9A-Fx]*) .*', line)
    if m:
     self.cfgdef[file] = m.group('v')
   else:
    self.cfgdef[file] = fp.read().strip()
   fp.write(value)
   fp.close()
 def s0ixSupport(self):
  if not os.path.exists(self.s0ixres) or not os.path.exists(self.mempowerfile):
   return False
  fp = open(sysvals.mempowerfile, 'r')
  data = fp.read().strip()
  fp.close()
  if '[s2idle]' in data:
   return True
  return False
 def haveTurbostat(self):
  if not self.tstat:
   return False
  cmd = self.getExec('turbostat')
  if not cmd:
   return False
  fp = Popen([cmd, '-v'], stdout=PIPE, stderr=PIPE).stderr
  out = ascii(fp.read()).strip()
  fp.close()
  if re.match(r'turbostat version .*', out):
   self.vprint(out)
   return True
  return False
 def turbostat(self, s0ixready):
  cmd = self.getExec('turbostat')
  rawout = keyline = valline = ''
  fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile)
  fp = Popen(['sh''-c', fullcmd], stdout=PIPE, stderr=PIPE)
  for line in fp.stderr:
   line = ascii(line)
   rawout += line
   if keyline and valline:
    continue
   if re.match(r'(?i)Avg_MHz.*', line):
    keyline = line.strip().split()
   elif keyline:
    valline = line.strip().split()
  fp.wait()
  if not keyline or not valline or len(keyline) != len(valline):
   errmsg = 'unrecognized turbostat output:\n'+rawout.strip()
   self.vprint(errmsg)
   if not self.verbose:
    pprint(errmsg)
   return (fp.returncode, '')
  if self.verbose:
   pprint(rawout.strip())
  out = []
  for key in keyline:
   idx = keyline.index(key)
   val = valline[idx]
   if key == 'SYS%LPI' and not s0ixready and re.match(r'^[0\.]*$', val):
    continue
   out.append('%s=%s' % (key, val))
  return (fp.returncode, '|'.join(out))
 def netfixon(self, net='both'):
  cmd = self.getExec('netfix')
  if not cmd:
   return ''
  fp = Popen([cmd, '-s', net, 'on'], stdout=PIPE, stderr=PIPE).stdout
  out = ascii(fp.read()).strip()
  fp.close()
  return out
 def wifiDetails(self, dev):
  try:
   info = open('/sys/class/net/%s/device/uevent' % dev, 'r').read().strip()
  except:
   return dev
  vals = [dev]
  for prop in info.split('\n'):
   if prop.startswith('DRIVER='or prop.startswith('PCI_ID='):
    vals.append(prop.split('=')[-1])
  return ':'.join(vals)
 def checkWifi(self, dev=''):
  try:
   w = open('/proc/net/wireless''r').read().strip()
  except:
   return ''
  for line in reversed(w.split('\n')):
   m = re.match(r' *(?P.*): (?P[0-9a-f]*) .*', line)
   if not m or (dev and dev != m.group('dev')):
    continue
   return m.group('dev')
  return ''
 def pollWifi(self, dev, timeout=10):
  start = time.time()
  while (time.time() - start) < timeout:
   w = self.checkWifi(dev)
   if w:
    return '%s reconnected %.2f' % \
     (self.wifiDetails(dev), max(0, time.time() - start))
   time.sleep(0.01)
  return '%s timeout %d' % (self.wifiDetails(dev), timeout)
 def errorSummary(self, errinfo, msg):
  found = False
  for entry in errinfo:
   if re.match(entry['match'], msg):
    entry['count'] += 1
    if self.hostname not in entry['urls']:
     entry['urls'][self.hostname] = [self.htmlfile]
    elif self.htmlfile not in entry['urls'][self.hostname]:
     entry['urls'][self.hostname].append(self.htmlfile)
    found = True
    break
  if found:
   return
  arr = msg.split()
  for j in range(len(arr)):
   if re.match(r'^[0-9,\-\.]*$', arr[j]):
    arr[j] = r'[0-9,\-\.]*'
   else:
    arr[j] = arr[j]\
     .replace('\\', r'\\\\').replace(']', r'\]').replace('[', r'\[')\
     .replace('.', r'\.').replace('+', r'\+').replace('*', r'\*')\
     .replace('(', r'\(').replace(')', r'\)').replace('}', r'\}')\
     .replace('{', r'\{')
  mstr = ' *'.join(arr)
  entry = {
   'line': msg,
   'match': mstr,
   'count': 1,
   'urls': {self.hostname: [self.htmlfile]}
  }
  errinfo.append(entry)
 def multistat(self, start, idx, finish):
  if 'time' in self.multitest:
   id = '%d Duration=%dmin' % (idx+1, self.multitest['time'])
  else:
   id = '%d/%d' % (idx+1, self.multitest['count'])
  t = time.time()
  if 'start' not in self.multitest:
   self.multitest['start'] = self.multitest['last'] = t
   self.multitest['total'] = 0.0
   pprint('TEST (%s) START' % id)
   return
  dt = t - self.multitest['last']
  if not start:
   if idx == 0 and self.multitest['delay'] > 0:
    self.multitest['total'] += self.multitest['delay']
   pprint('TEST (%s) COMPLETE -- Duration %.1fs' % (id, dt))
   return
  self.multitest['total'] += dt
  self.multitest['last'] = t
  avg = self.multitest['total'] / idx
  if 'time' in self.multitest:
   left = finish - datetime.now()
   left -= timedelta(microseconds=left.microseconds)
  else:
   left = timedelta(seconds=((self.multitest['count'] - idx) * int(avg)))
  pprint('TEST (%s) START - Avg Duration %.1fs, Time left %s' % \
   (id, avg, str(left)))
 def multiinit(self, c, d):
  sz, unit = 'count''m'
  if c.endswith('d'or c.endswith('h'or c.endswith('m'):
   sz, unit, c = 'time', c[-1], c[:-1]
  self.multitest['run'] = True
  self.multitest[sz] = getArgInt('multi: n d (exec count)', c, 1, 1000000, False)
  self.multitest['delay'] = getArgInt('multi: n d (delay between tests)', d, 0, 3600, False)
  if unit == 'd':
   self.multitest[sz] *= 1440
  elif unit == 'h':
   self.multitest[sz] *= 60
 def displayControl(self, cmd):
  xset, ret = 'timeout 10 xset -d :0.0 {0}', 0
  if self.sudouser:
   xset = 'sudo -u %s %s' % (self.sudouser, xset)
  if cmd == 'init':
   ret = call(xset.format('dpms 0 0 0'), shell=True)
   if not ret:
    ret = call(xset.format('s off'), shell=True)
  elif cmd == 'reset':
   ret = call(xset.format('s reset'), shell=True)
  elif cmd in ['on''off''standby''suspend']:
   b4 = self.displayControl('stat')
   ret = call(xset.format('dpms force %s' % cmd), shell=True)
   if not ret:
    curr = self.displayControl('stat')
    self.vprint('Display Switched: %s -> %s' % (b4, curr))
    if curr != cmd:
     self.vprint('WARNING: Display failed to change to %s' % cmd)
   if ret:
    self.vprint('WARNING: Display failed to change to %s with xset' % cmd)
    return ret
  elif cmd == 'stat':
   fp = Popen(xset.format('q').split(' '), stdout=PIPE).stdout
   ret = 'unknown'
   for line in fp:
    m = re.match(r'[\s]*Monitor is (?P.*)', ascii(line))
    if(m and len(m.group('m')) >= 2):
     out = m.group('m').lower()
     ret = out[3:] if out[0:2] == 'in' else out
     break
   fp.close()
  return ret
 def setRuntimeSuspend(self, before=True):
  if before:
   # runtime suspend disable or enable
   if self.rs > 0:
    self.rstgt, self.rsval, self.rsdir = 'on''auto''enabled'
   else:
    self.rstgt, self.rsval, self.rsdir = 'auto''on''disabled'
   pprint('CONFIGURING RUNTIME SUSPEND...')
   self.rslist = deviceInfo(self.rstgt)
   for i in self.rslist:
    self.setVal(self.rsval, i)
   pprint('runtime suspend %s on all devices (%d changed)' % (self.rsdir, len(self.rslist)))
   pprint('waiting 5 seconds...')
   time.sleep(5)
  else:
   # runtime suspend re-enable or re-disable
   for i in self.rslist:
    self.setVal(self.rstgt, i)
   pprint('runtime suspend settings restored on %d devices' % len(self.rslist))
 def start(self, pm):
  if self.useftrace:
   self.dlog('start ftrace tracing')
   self.fsetVal('1''tracing_on')
   if self.useprocmon:
    self.dlog('start the process monitor')
    pm.start()
 def stop(self, pm):
  if self.useftrace:
   if self.useprocmon:
    self.dlog('stop the process monitor')
    pm.stop()
   self.dlog('stop ftrace tracing')
   self.fsetVal('0''tracing_on')

sysvals = SystemValues()
switchvalues = ['enable''disable''on''off''true''false''1''0']
switchoff = ['disable''off''false''0']
suspendmodename = {
 'standby''standby (S1)',
 'freeze''freeze (S2idle)',
 'mem''suspend (S3)',
 'disk''hibernate (S4)'
}

# Class: DevProps
# Description:
#  Simple class which holds property values collected
#  for all the devices used in the timeline.
class DevProps:
 def __init__(self):
  self.syspath = ''
  self.altname = ''
  self.isasync = True
  self.xtraclass = ''
  self.xtrainfo = ''
 def out(self, dev):
  return '%s,%s,%d;' % (dev, self.altname, self.isasync)
 def debug(self, dev):
  pprint('%s:\n\taltname = %s\n\t async = %s' % (dev, self.altname, self.isasync))
 def altName(self, dev):
  if not self.altname or self.altname == dev:
   return dev
  return '%s [%s]' % (self.altname, dev)
 def xtraClass(self):
  if self.xtraclass:
   return ' '+self.xtraclass
  if not self.isasync:
   return ' sync'
  return ''
 def xtraInfo(self):
  if self.xtraclass:
   return ' '+self.xtraclass
  if self.isasync:
   return ' (async)'
  return ' (sync)'

# Class: DeviceNode
# Description:
#  A container used to create a device hierachy, with a single root node
#  and a tree of child nodes. Used by Data.deviceTopology()
class DeviceNode:
 def __init__(self, nodename, nodedepth):
  self.name = nodename
  self.children = []
  self.depth = nodedepth

# Class: Data
# Description:
#  The primary container for suspend/resume test data. There is one for
#  each test run. The data is organized into a cronological hierarchy:
#  Data.dmesg {
# phases {
# 10 sequential, non-overlapping phases of S/R
# contents: times for phase start/end, order/color data for html
# devlist {
# device callback or action list for this phase
# device {
# a single device callback or generic action
# contents: start/stop times, pid/cpu/driver info
# parents/children, html id for timeline/callgraph
# optionally includes an ftrace callgraph
# optionally includes dev/ps data
# }
# }
# }
# }
#
class Data:
 phasedef = {
  'suspend_prepare': {'order': 0, 'color''#CCFFCC'},
          'suspend': {'order': 1, 'color''#88FF88'},
     'suspend_late': {'order': 2, 'color''#00AA00'},
    'suspend_noirq': {'order': 3, 'color''#008888'},
  'suspend_machine': {'order': 4, 'color''#0000FF'},
   'resume_machine': {'order': 5, 'color''#FF0000'},
     'resume_noirq': {'order': 6, 'color''#FF9900'},
     'resume_early': {'order': 7, 'color''#FFCC00'},
           'resume': {'order': 8, 'color''#FFFF88'},
  'resume_complete': {'order': 9, 'color''#FFFFCC'},
 }
 errlist = {
  'HWERROR' : r'.*\[ *Hardware Error *\].*',
  'FWBUG'   : r'.*\[ *Firmware Bug *\].*',
  'TASKFAIL': r'.*Freezing .*after *.*',
  'BUG'     : r'(?i).*\bBUG\b.*',
  'ERROR'   : r'(?i).*\bERROR\b.*',
  'WARNING' : r'(?i).*\bWARNING\b.*',
  'FAULT'   : r'(?i).*\bFAULT\b.*',
  'FAIL'    : r'(?i).*\bFAILED\b.*',
  'INVALID' : r'(?i).*\bINVALID\b.*',
  'CRASH'   : r'(?i).*\bCRASHED\b.*',
  'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*',
  'ABORT'   : r'(?i).*\bABORT\b.*',
  'IRQ'     : r'.*\bgenirq: .*',
  'ACPI'    : r'.*\bACPI *(?P[A-Za-z]*) *Error[: ].*',
  'DISKFULL': r'.*\bNo space left on device.*',
  'USBERR'  : r'.*usb .*device .*, error [0-9-]*',
  'ATAERR'  : r' *ata[0-9\.]*: .*failed.*',
  'MEIERR'  : r' *mei.*: .*failed.*',
  'TPMERR'  : r'(?i) *tpm *tpm[0-9]*: .*error.*',
 }
 def __init__(self, num):
  idchar = 'abcdefghij'
  self.start = 0.0 # test start
  self.end = 0.0   # test end
  self.hwstart = 0 # rtc test start
  self.hwend = 0   # rtc test end
  self.tSuspended = 0.0 # low-level suspend start
  self.tResumed = 0.0   # low-level resume start
  self.tKernSus = 0.0   # kernel level suspend start
  self.tKernRes = 0.0   # kernel level resume end
  self.fwValid = False  # is firmware data available
  self.fwSuspend = 0    # time spent in firmware suspend
  self.fwResume = 0     # time spent in firmware resume
  self.html_device_id = 0
  self.stamp = 0
  self.outfile = ''
  self.kerror = False
  self.wifi = dict()
  self.turbostat = 0
  self.enterfail = ''
  self.currphase = ''
  self.pstl = dict()    # process timeline
  self.testnumber = num
  self.idstr = idchar[num]
  self.dmesgtext = []   # dmesg text file in memory
  self.dmesg = dict()   # root data structure
  self.errorinfo = {'suspend':[],'resume':[]}
  self.tLow = []        # time spent in low-level suspends (standby/freeze)
  self.devpids = []
  self.devicegroups = 0
 def sortedPhases(self):
  return sorted(self.dmesg, key=lambda k:self.dmesg[k]['order'])
 def initDevicegroups(self):
  # called when phases are all finished being added
  for phase in sorted(self.dmesg.keys()):
   if '*' in phase:
    p = phase.split('*')
    pnew = '%s%d' % (p[0], len(p))
    self.dmesg[pnew] = self.dmesg.pop(phase)
  self.devicegroups = []
  for phase in self.sortedPhases():
   self.devicegroups.append([phase])
 def nextPhase(self, phase, offset):
  order = self.dmesg[phase]['order'] + offset
  for p in self.dmesg:
   if self.dmesg[p]['order'] == order:
    return p
  return ''
 def lastPhase(self, depth=1):
  plist = self.sortedPhases()
  if len(plist) < depth:
   return ''
  return plist[-1*depth]
 def turbostatInfo(self):
  tp = TestProps()
  out = {'syslpi':'N/A','pkgpc10':'N/A'}
  for line in self.dmesgtext:
   m = re.match(tp.tstatfmt, line)
   if not m:
    continue
   for i in m.group('t').split('|'):
    if 'SYS%LPI' in i:
     out['syslpi'] = i.split('=')[-1]+'%'
    elif 'pc10' in i:
     out['pkgpc10'] = i.split('=')[-1]+'%'
   break
  return out
 def extractErrorInfo(self):
  lf = self.dmesgtext
  if len(self.dmesgtext) < 1 and sysvals.dmesgfile:
   lf = sysvals.openlog(sysvals.dmesgfile, 'r')
  i = 0
  tp = TestProps()
  list = []
  for line in lf:
   i += 1
   if tp.stampInfo(line, sysvals):
    continue
   m = re.match(r'[ \t]*(\[ *)(?P[0-9\.]*)(\]) (?P.*)', line)
   if not m:
    continue
   t = float(m.group('ktime'))
   if t < self.start or t > self.end:
    continue
   dir = 'suspend' if t < self.tSuspended else 'resume'
   msg = m.group('msg')
   if re.match(r'capability: warning: .*', msg):
    continue
   for err in self.errlist:
    if re.match(self.errlist[err], msg):
     list.append((msg, err, dir, t, i, i))
     self.kerror = True
     break
  tp.msglist = []
  for msg, type, dir, t, idx1, idx2 in list:
   tp.msglist.append(msg)
   self.errorinfo[dir].append((type, t, idx1, idx2))
  if self.kerror:
   sysvals.dmesglog = True
  if len(self.dmesgtext) < 1 and sysvals.dmesgfile:
   lf.close()
  return tp
 def setStart(self, time, msg=''):
  self.start = time
  if msg:
   try:
    self.hwstart = datetime.strptime(msg, sysvals.tmstart)
   except:
    self.hwstart = 0
 def setEnd(self, time, msg=''):
  self.end = time
  if msg:
   try:
    self.hwend = datetime.strptime(msg, sysvals.tmend)
   except:
    self.hwend = 0
 def isTraceEventOutsideDeviceCalls(self, pid, time):
  for phase in self.sortedPhases():
   list = self.dmesg[phase]['list']
   for dev in list:
    d = list[dev]
    if(d['pid'] == pid and time >= d['start'] and
     time < d['end']):
     return False
  return True
 def sourcePhase(self, start):
  for phase in self.sortedPhases():
   if 'machine' in phase:
    continue
   pend = self.dmesg[phase]['end']
   if start <= pend:
    return phase
  return 'resume_complete' if 'resume_complete' in self.dmesg else ''
 def sourceDevice(self, phaselist, start, end, pid, type):
  tgtdev = ''
  for phase in phaselist:
   list = self.dmesg[phase]['list']
   for devname in list:
    dev = list[devname]
    # pid must match
    if dev['pid'] != pid:
     continue
    devS = dev['start']
    devE = dev['end']
    if type == 'device':
     # device target event is entirely inside the source boundary
     if(start < devS or start >= devE or end <= devS or end > devE):
      continue
    elif type == 'thread':
     # thread target event will expand the source boundary
     if start < devS:
      dev['start'] = start
     if end > devE:
      dev['end'] = end
    tgtdev = dev
    break
  return tgtdev
 def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata):
  # try to place the call in a device
  phases = self.sortedPhases()
  tgtdev = self.sourceDevice(phases, start, end, pid, 'device')
  # calls with device pids that occur outside device bounds are dropped
  # TODO: include these somehow
  if not tgtdev and pid in self.devpids:
   return False
  # try to place the call in a thread
  if not tgtdev:
   tgtdev = self.sourceDevice(phases, start, end, pid, 'thread')
  # create new thread blocks, expand as new calls are found
  if not tgtdev:
   if proc == '<...>':
    threadname = 'kthread-%d' % (pid)
   else:
    threadname = '%s-%d' % (proc, pid)
   tgtphase = self.sourcePhase(start)
   if not tgtphase:
    return False
   self.newAction(tgtphase, threadname, pid, '', start, end, ''' kth''')
   return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata)
  # this should not happen
  if not tgtdev:
   sysvals.vprint('[%f - %f] %s-%d %s %s %s' % \
    (start, end, proc, pid, kprobename, cdata, rdata))
   return False
  # place the call data inside the src element of the tgtdev
  if('src' not in tgtdev):
   tgtdev['src'] = []
  dtf = sysvals.dev_tracefuncs
  ubiquitous = False
  if kprobename in dtf and 'ub' in dtf[kprobename]:
   ubiquitous = True
  mc = re.match(r'\(.*\) *(?P.*)', cdata)
  mr = re.match(r'\((?P\S*).* arg1=(?P.*)', rdata)
  if mc and mr:
   c = mr.group('caller').split('+')[0]
   a = mc.group('args').strip()
   r = mr.group('ret')
   if len(r) > 6:
    r = ''
   else:
    r = 'ret=%s ' % r
   if ubiquitous and c in dtf and 'ub' in dtf[c]:
    return False
  else:
   return False
  color = sysvals.kprobeColor(kprobename)
  e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color)
  tgtdev['src'].append(e)
  return True
 def overflowDevices(self):
  # get a list of devices that extend beyond the end of this test run
  devlist = []
  for phase in self.sortedPhases():
   list = self.dmesg[phase]['list']
   for devname in list:
    dev = list[devname]
    if dev['end'] > self.end:
     devlist.append(dev)
  return devlist
 def mergeOverlapDevices(self, devlist):
  # merge any devices that overlap devlist
  for dev in devlist:
   devname = dev['name']
   for phase in self.sortedPhases():
    list = self.dmesg[phase]['list']
    if devname not in list:
     continue
    tdev = list[devname]
    o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start'])
    if o <= 0:
     continue
    dev['end'] = tdev['end']
    if 'src' not in dev or 'src' not in tdev:
     continue
    dev['src'] += tdev['src']
    del list[devname]
 def usurpTouchingThread(self, name, dev):
  # the caller test has priority of this thread, give it to him
  for phase in self.sortedPhases():
   list = self.dmesg[phase]['list']
   if name in list:
    tdev = list[name]
    if tdev['start'] - dev['end'] < 0.1:
     dev['end'] = tdev['end']
     if 'src' not in dev:
      dev['src'] = []
     if 'src' in tdev:
      dev['src'] += tdev['src']
     del list[name]
    break
 def stitchTouchingThreads(self, testlist):
  # merge any threads between tests that touch
  for phase in self.sortedPhases():
   list = self.dmesg[phase]['list']
   for devname in list:
    dev = list[devname]
    if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']:
     continue
    for data in testlist:
     data.usurpTouchingThread(devname, dev)
 def optimizeDevSrc(self):
  # merge any src call loops to reduce timeline size
  for phase in self.sortedPhases():
   list = self.dmesg[phase]['list']
   for dev in list:
    if 'src' not in list[dev]:
     continue
    src = list[dev]['src']
    p = 0
    for e in sorted(src, key=lambda event: event.time):
     if not p or not e.repeat(p):
      p = e
      continue
     # e is another iteration of p, move it into p
     p.end = e.end
     p.length = p.end - p.time
     p.count += 1
     src.remove(e)
 def trimTimeVal(self, t, t0, dT, left):
  if left:
   if(t > t0):
    if(t - dT < t0):
     return t0
    return t - dT
   else:
    return t
  else:
   if(t < t0 + dT):
    if(t > t0):
     return t0 + dT
    return t + dT
   else:
    return t
 def trimTime(self, t0, dT, left):
  self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left)
  self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left)
  self.start = self.trimTimeVal(self.start, t0, dT, left)
  self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left)
  self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left)
  self.end = self.trimTimeVal(self.end, t0, dT, left)
  for phase in self.sortedPhases():
   p = self.dmesg[phase]
   p['start'] = self.trimTimeVal(p['start'], t0, dT, left)
   p['end'] = self.trimTimeVal(p['end'], t0, dT, left)
   list = p['list']
   for name in list:
    d = list[name]
    d['start'] = self.trimTimeVal(d['start'], t0, dT, left)
    d['end'] = self.trimTimeVal(d['end'], t0, dT, left)
    d['length'] = d['end'] - d['start']
    if('ftrace' in d):
     cg = d['ftrace']
     cg.start = self.trimTimeVal(cg.start, t0, dT, left)
     cg.end = self.trimTimeVal(cg.end, t0, dT, left)
     for line in cg.list:
      line.time = self.trimTimeVal(line.time, t0, dT, left)
    if('src' in d):
     for e in d['src']:
      e.time = self.trimTimeVal(e.time, t0, dT, left)
      e.end = self.trimTimeVal(e.end, t0, dT, left)
      e.length = e.end - e.time
    if('cpuexec' in d):
     cpuexec = dict()
     for e in d['cpuexec']:
      c0, cN = e
      c0 = self.trimTimeVal(c0, t0, dT, left)
      cN = self.trimTimeVal(cN, t0, dT, left)
      cpuexec[(c0, cN)] = d['cpuexec'][e]
     d['cpuexec'] = cpuexec
  for dir in ['suspend''resume']:
   list = []
   for e in self.errorinfo[dir]:
    type, tm, idx1, idx2 = e
    tm = self.trimTimeVal(tm, t0, dT, left)
    list.append((type, tm, idx1, idx2))
   self.errorinfo[dir] = list
 def trimFreezeTime(self, tZero):
  # trim out any standby or freeze clock time
  lp = ''
  for phase in self.sortedPhases():
   if 'resume_machine' in phase and 'suspend_machine' in lp:
    tS, tR = self.dmesg[lp]['end'], self.dmesg[phase]['start']
    tL = tR - tS
    if tL <= 0:
     continue
    left = True if tR > tZero else False
    self.trimTime(tS, tL, left)
    if 'waking' in self.dmesg[lp]:
     tCnt = self.dmesg[lp]['waking'][0]
     if self.dmesg[lp]['waking'][1] >= 0.001:
      tTry = '%.0f' % (round(self.dmesg[lp]['waking'][1] * 1000))
     else:
      tTry = '%.3f' % (self.dmesg[lp]['waking'][1] * 1000)
     text = '%.0f (%s ms waking %d times)' % (tL * 1000, tTry, tCnt)
    else:
     text = '%.0f' % (tL * 1000)
    self.tLow.append(text)
   lp = phase
 def getMemTime(self):
  if not self.hwstart or not self.hwend:
   return
  stime = (self.tSuspended - self.start) * 1000000
  rtime = (self.end - self.tResumed) * 1000000
  hws = self.hwstart + timedelta(microseconds=stime)
  hwr = self.hwend - timedelta(microseconds=rtime)
  self.tLow.append('%.0f'%((hwr - hws).total_seconds() * 1000))
 def getTimeValues(self):
  s = (self.tSuspended - self.tKernSus) * 1000
  r = (self.tKernRes - self.tResumed) * 1000
  return (max(s, 0), max(r, 0))
 def setPhase(self, phase, ktime, isbegin, order=-1):
  if(isbegin):
   # phase start over current phase
   if self.currphase:
    if 'resume_machine' not in self.currphase:
     sysvals.vprint('WARNING: phase %s failed to end' % self.currphase)
    self.dmesg[self.currphase]['end'] = ktime
   phases = self.dmesg.keys()
   color = self.phasedef[phase]['color']
   count = len(phases) if order < 0 else order
   # create unique name for every new phase
   while phase in phases:
    phase += '*'
   self.dmesg[phase] = {'list': dict(), 'start': -1.0, 'end': -1.0,
    'row': 0, 'color': color, 'order': count}
   self.dmesg[phase]['start'] = ktime
   self.currphase = phase
  else:
   # phase end without a start
   if phase not in self.currphase:
    if self.currphase:
     sysvals.vprint('WARNING: %s ended instead of %s, ftrace corruption?' % (phase, self.currphase))
    else:
     sysvals.vprint('WARNING: %s ended without a start, ftrace corruption?' % phase)
     return phase
   phase = self.currphase
   self.dmesg[phase]['end'] = ktime
   self.currphase = ''
  return phase
 def sortedDevices(self, phase):
  list = self.dmesg[phase]['list']
  return sorted(list, key=lambda k:list[k]['start'])
 def fixupInitcalls(self, phase):
  # if any calls never returned, clip them at system resume end
  phaselist = self.dmesg[phase]['list']
  for devname in phaselist:
   dev = phaselist[devname]
   if(dev['end'] < 0):
    for p in self.sortedPhases():
     if self.dmesg[p]['end'] > dev['start']:
      dev['end'] = self.dmesg[p]['end']
      break
    sysvals.vprint('%s (%s): callback didnt return' % (devname, phase))
 def deviceFilter(self, devicefilter):
  for phase in self.sortedPhases():
   list = self.dmesg[phase]['list']
   rmlist = []
   for name in list:
    keep = False
    for filter in devicefilter:
     if filter in name or \
      ('drv' in list[name] and filter in list[name]['drv']):
      keep = True
    if not keep:
     rmlist.append(name)
   for name in rmlist:
    del list[name]
 def fixupInitcallsThatDidntReturn(self):
  # if any calls never returned, clip them at system resume end
  for phase in self.sortedPhases():
   self.fixupInitcalls(phase)
 def phaseOverlap(self, phases):
  rmgroups = []
  newgroup = []
  for group in self.devicegroups:
   for phase in phases:
    if phase not in group:
     continue
    for p in group:
     if p not in newgroup:
      newgroup.append(p)
    if group not in rmgroups:
     rmgroups.append(group)
  for group in rmgroups:
   self.devicegroups.remove(group)
  self.devicegroups.append(newgroup)
 def newActionGlobal(self, name, start, end, pid=-1, color=''):
  # which phase is this device callback or action in
  phases = self.sortedPhases()
  targetphase = 'none'
  htmlclass = ''
  overlap = 0.0
  myphases = []
  for phase in phases:
   pstart = self.dmesg[phase]['start']
   pend = self.dmesg[phase]['end']
   # see if the action overlaps this phase
   o = max(0, min(end, pend) - max(start, pstart))
   if o > 0:
    myphases.append(phase)
   # set the target phase to the one that overlaps most
   if o > overlap:
    if overlap > 0 and phase == 'post_resume':
     continue
    targetphase = phase
    overlap = o
  # if no target phase was found, pin it to the edge
  if targetphase == 'none':
   p0start = self.dmesg[phases[0]]['start']
   if start <= p0start:
    targetphase = phases[0]
   else:
    targetphase = phases[-1]
  if pid == -2:
   htmlclass = ' bg'
  elif pid == -3:
   htmlclass = ' ps'
  if len(myphases) > 1:
   htmlclass = ' bg'
   self.phaseOverlap(myphases)
  if targetphase in phases:
   newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color)
   return (targetphase, newname)
  return False
 def newAction(self, phase, name, pid, parent, start, end, drv, htmlclass='', color=''):
  # new device callback for a specific phase
  self.html_device_id += 1
  devid = '%s%d' % (self.idstr, self.html_device_id)
  list = self.dmesg[phase]['list']
  length = -1.0
  if(start >= 0 and end >= 0):
   length = end - start
  if pid >= -2:
   i = 2
   origname = name
   while(name in list):
    name = '%s[%d]' % (origname, i)
    i += 1
  list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid,
   'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv }
  if htmlclass:
   list[name]['htmlclass'] = htmlclass
  if color:
   list[name]['color'] = color
  return name
 def findDevice(self, phase, name):
  list = self.dmesg[phase]['list']
  mydev = ''
  for devname in sorted(list):
   if name == devname or re.match(r'^%s\[(?P[0-9]*)\]$' % name, devname):
    mydev = devname
  if mydev:
   return list[mydev]
  return False
 def deviceChildren(self, devname, phase):
  devlist = []
  list = self.dmesg[phase]['list']
  for child in list:
   if(list[child]['par'] == devname):
    devlist.append(child)
  return devlist
 def maxDeviceNameSize(self, phase):
  size = 0
  for name in self.dmesg[phase]['list']:
   if len(name) > size:
    size = len(name)
  return size
 def printDetails(self):
  sysvals.vprint('Timeline Details:')
  sysvals.vprint(' test start: %f' % self.start)
  sysvals.vprint('kernel suspend start: %f' % self.tKernSus)
  tS = tR = False
  for phase in self.sortedPhases():
   devlist = self.dmesg[phase]['list']
   dc, ps, pe = len(devlist), self.dmesg[phase]['start'], self.dmesg[phase]['end']
   if not tS and ps >= self.tSuspended:
    sysvals.vprint(' machine suspended: %f' % self.tSuspended)
    tS = True
   if not tR and ps >= self.tResumed:
    sysvals.vprint(' machine resumed: %f' % self.tResumed)
    tR = True
   sysvals.vprint('%20s: %f - %f (%d devices)' % (phase, ps, pe, dc))
   if sysvals.devdump:
    sysvals.vprint(''.join('-' for i in range(80)))
    maxname = '%d' % self.maxDeviceNameSize(phase)
    fmt = '%3d) %'+maxname+'s - %f - %f'
    c = 1
    for name in sorted(devlist):
     s = devlist[name]['start']
     e = devlist[name]['end']
     sysvals.vprint(fmt % (c, name, s, e))
     c += 1
    sysvals.vprint(''.join('-' for i in range(80)))
  sysvals.vprint(' kernel resume end: %f' % self.tKernRes)
  sysvals.vprint(' test end: %f' % self.end)
 def deviceChildrenAllPhases(self, devname):
--> --------------------

--> maximum size reached

--> --------------------


Messung V0.5
C=93 H=87 G=89

¤ Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.0.69Bemerkung:  ¤

*Bot Zugriff






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.