diff options
| -rwxr-xr-x | scripts/analyze_suspend.py | 3817 |
1 files changed, 2981 insertions, 836 deletions
diff --git a/scripts/analyze_suspend.py b/scripts/analyze_suspend.py index 4f2cc12dc7c7..93e1fd40f430 100755 --- a/scripts/analyze_suspend.py +++ b/scripts/analyze_suspend.py | |||
| @@ -36,146 +36,392 @@ | |||
| 36 | # CONFIG_FUNCTION_TRACER=y | 36 | # CONFIG_FUNCTION_TRACER=y |
| 37 | # CONFIG_FUNCTION_GRAPH_TRACER=y | 37 | # CONFIG_FUNCTION_GRAPH_TRACER=y |
| 38 | # | 38 | # |
| 39 | # For kernel versions older than 3.15: | ||
| 39 | # The following additional kernel parameters are required: | 40 | # The following additional kernel parameters are required: |
| 40 | # (e.g. in file /etc/default/grub) | 41 | # (e.g. in file /etc/default/grub) |
| 41 | # GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=16M ..." | 42 | # GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=16M ..." |
| 42 | # | 43 | # |
| 43 | 44 | ||
| 45 | # ----------------- LIBRARIES -------------------- | ||
| 46 | |||
| 44 | import sys | 47 | import sys |
| 45 | import time | 48 | import time |
| 46 | import os | 49 | import os |
| 47 | import string | 50 | import string |
| 48 | import re | 51 | import re |
| 49 | import array | ||
| 50 | import platform | 52 | import platform |
| 51 | import datetime | 53 | from datetime import datetime |
| 52 | import struct | 54 | import struct |
| 53 | 55 | ||
| 54 | # -- classes -- | 56 | # ----------------- CLASSES -------------------- |
| 55 | 57 | ||
| 58 | # Class: SystemValues | ||
| 59 | # Description: | ||
| 60 | # A global, single-instance container used to | ||
| 61 | # store system values and test parameters | ||
| 56 | class SystemValues: | 62 | class SystemValues: |
| 57 | testdir = "." | 63 | version = 3.0 |
| 58 | tpath = "/sys/kernel/debug/tracing/" | 64 | verbose = False |
| 59 | mempath = "/dev/mem" | 65 | testdir = '.' |
| 60 | powerfile = "/sys/power/state" | 66 | tpath = '/sys/kernel/debug/tracing/' |
| 61 | suspendmode = "mem" | 67 | fpdtpath = '/sys/firmware/acpi/tables/FPDT' |
| 62 | prefix = "test" | 68 | epath = '/sys/kernel/debug/tracing/events/power/' |
| 63 | teststamp = "" | 69 | traceevents = [ |
| 64 | dmesgfile = "" | 70 | 'suspend_resume', |
| 65 | ftracefile = "" | 71 | 'device_pm_callback_end', |
| 66 | htmlfile = "" | 72 | 'device_pm_callback_start' |
| 73 | ] | ||
| 74 | modename = { | ||
| 75 | 'freeze': 'Suspend-To-Idle (S0)', | ||
| 76 | 'standby': 'Power-On Suspend (S1)', | ||
| 77 | 'mem': 'Suspend-to-RAM (S3)', | ||
| 78 | 'disk': 'Suspend-to-disk (S4)' | ||
| 79 | } | ||
| 80 | mempath = '/dev/mem' | ||
| 81 | powerfile = '/sys/power/state' | ||
| 82 | suspendmode = 'mem' | ||
| 83 | hostname = 'localhost' | ||
| 84 | prefix = 'test' | ||
| 85 | teststamp = '' | ||
| 86 | dmesgfile = '' | ||
| 87 | ftracefile = '' | ||
| 88 | htmlfile = '' | ||
| 67 | rtcwake = False | 89 | rtcwake = False |
| 90 | rtcwaketime = 10 | ||
| 91 | rtcpath = '' | ||
| 92 | android = False | ||
| 93 | adb = 'adb' | ||
| 94 | devicefilter = [] | ||
| 95 | stamp = 0 | ||
| 96 | execcount = 1 | ||
| 97 | x2delay = 0 | ||
| 98 | usecallgraph = False | ||
| 99 | usetraceevents = False | ||
| 100 | usetraceeventsonly = False | ||
| 101 | notestrun = False | ||
| 102 | altdevname = dict() | ||
| 103 | postresumetime = 0 | ||
| 104 | tracertypefmt = '# tracer: (?P<t>.*)' | ||
| 105 | firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' | ||
| 106 | postresumefmt = '# post resume time (?P<t>[0-9]*)$' | ||
| 107 | stampfmt = '# suspend-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ | ||
| 108 | '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ | ||
| 109 | ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' | ||
| 110 | def __init__(self): | ||
| 111 | self.hostname = platform.node() | ||
| 112 | if(self.hostname == ''): | ||
| 113 | self.hostname = 'localhost' | ||
| 114 | rtc = "rtc0" | ||
| 115 | if os.path.exists('/dev/rtc'): | ||
| 116 | rtc = os.readlink('/dev/rtc') | ||
| 117 | rtc = '/sys/class/rtc/'+rtc | ||
| 118 | if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \ | ||
| 119 | os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'): | ||
| 120 | self.rtcpath = rtc | ||
| 68 | def setOutputFile(self): | 121 | def setOutputFile(self): |
| 69 | if((self.htmlfile == "") and (self.dmesgfile != "")): | 122 | if((self.htmlfile == '') and (self.dmesgfile != '')): |
| 70 | m = re.match(r"(?P<name>.*)_dmesg\.txt$", self.dmesgfile) | 123 | m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile) |
| 71 | if(m): | 124 | if(m): |
| 72 | self.htmlfile = m.group("name")+".html" | 125 | self.htmlfile = m.group('name')+'.html' |
| 73 | if((self.htmlfile == "") and (self.ftracefile != "")): | 126 | if((self.htmlfile == '') and (self.ftracefile != '')): |
| 74 | m = re.match(r"(?P<name>.*)_ftrace\.txt$", self.ftracefile) | 127 | m = re.match('(?P<name>.*)_ftrace\.txt$', self.ftracefile) |
| 75 | if(m): | 128 | if(m): |
| 76 | self.htmlfile = m.group("name")+".html" | 129 | self.htmlfile = m.group('name')+'.html' |
| 77 | if(self.htmlfile == ""): | 130 | if(self.htmlfile == ''): |
| 78 | self.htmlfile = "output.html" | 131 | self.htmlfile = 'output.html' |
| 79 | def initTestOutput(self): | 132 | def initTestOutput(self, subdir): |
| 80 | hostname = platform.node() | 133 | if(not self.android): |
| 81 | if(hostname != ""): | 134 | self.prefix = self.hostname |
| 82 | self.prefix = hostname | 135 | v = open('/proc/version', 'r').read().strip() |
| 83 | v = os.popen("cat /proc/version").read().strip() | 136 | kver = string.split(v)[2] |
| 84 | kver = string.split(v)[2] | 137 | else: |
| 85 | self.testdir = os.popen("date \"+suspend-%m%d%y-%H%M%S\"").read().strip() | 138 | self.prefix = 'android' |
| 86 | self.teststamp = "# "+self.testdir+" "+self.prefix+" "+self.suspendmode+" "+kver | 139 | v = os.popen(self.adb+' shell cat /proc/version').read().strip() |
| 87 | self.dmesgfile = self.testdir+"/"+self.prefix+"_"+self.suspendmode+"_dmesg.txt" | 140 | kver = string.split(v)[2] |
| 88 | self.ftracefile = self.testdir+"/"+self.prefix+"_"+self.suspendmode+"_ftrace.txt" | 141 | testtime = datetime.now().strftime('suspend-%m%d%y-%H%M%S') |
| 89 | self.htmlfile = self.testdir+"/"+self.prefix+"_"+self.suspendmode+".html" | 142 | if(subdir != "."): |
| 143 | self.testdir = subdir+"/"+testtime | ||
| 144 | else: | ||
| 145 | self.testdir = testtime | ||
| 146 | self.teststamp = \ | ||
| 147 | '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver | ||
| 148 | self.dmesgfile = \ | ||
| 149 | self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt' | ||
| 150 | self.ftracefile = \ | ||
| 151 | self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt' | ||
| 152 | self.htmlfile = \ | ||
| 153 | self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' | ||
| 90 | os.mkdir(self.testdir) | 154 | os.mkdir(self.testdir) |
| 155 | def setDeviceFilter(self, devnames): | ||
| 156 | self.devicefilter = string.split(devnames) | ||
| 157 | def rtcWakeAlarm(self): | ||
| 158 | os.system('echo 0 > '+self.rtcpath+'/wakealarm') | ||
| 159 | outD = open(self.rtcpath+'/date', 'r').read().strip() | ||
| 160 | outT = open(self.rtcpath+'/time', 'r').read().strip() | ||
| 161 | mD = re.match('^(?P<y>[0-9]*)-(?P<m>[0-9]*)-(?P<d>[0-9]*)', outD) | ||
| 162 | mT = re.match('^(?P<h>[0-9]*):(?P<m>[0-9]*):(?P<s>[0-9]*)', outT) | ||
| 163 | if(mD and mT): | ||
| 164 | # get the current time from hardware | ||
| 165 | utcoffset = int((datetime.now() - datetime.utcnow()).total_seconds()) | ||
| 166 | dt = datetime(\ | ||
| 167 | int(mD.group('y')), int(mD.group('m')), int(mD.group('d')), | ||
| 168 | int(mT.group('h')), int(mT.group('m')), int(mT.group('s'))) | ||
| 169 | nowtime = int(dt.strftime('%s')) + utcoffset | ||
| 170 | else: | ||
| 171 | # if hardware time fails, use the software time | ||
| 172 | nowtime = int(datetime.now().strftime('%s')) | ||
| 173 | alarm = nowtime + self.rtcwaketime | ||
| 174 | os.system('echo %d > %s/wakealarm' % (alarm, self.rtcpath)) | ||
| 91 | 175 | ||
| 176 | sysvals = SystemValues() | ||
| 177 | |||
| 178 | # Class: DeviceNode | ||
| 179 | # Description: | ||
| 180 | # A container used to create a device hierachy, with a single root node | ||
| 181 | # and a tree of child nodes. Used by Data.deviceTopology() | ||
| 182 | class DeviceNode: | ||
| 183 | name = '' | ||
| 184 | children = 0 | ||
| 185 | depth = 0 | ||
| 186 | def __init__(self, nodename, nodedepth): | ||
| 187 | self.name = nodename | ||
| 188 | self.children = [] | ||
| 189 | self.depth = nodedepth | ||
| 190 | |||
| 191 | # Class: Data | ||
| 192 | # Description: | ||
| 193 | # The primary container for suspend/resume test data. There is one for | ||
| 194 | # each test run. The data is organized into a cronological hierarchy: | ||
| 195 | # | ||
