Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
4bee16d7
Commit
4bee16d7
authored
Apr 24, 2020
by
Rafael J. Wysocki
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'pm-tools'
* pm-tools: pm-graph v5.6
parents
09beebd8
2c9a583b
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
619 additions
and
371 deletions
+619
-371
tools/power/pm-graph/Makefile
tools/power/pm-graph/Makefile
+4
-0
tools/power/pm-graph/README
tools/power/pm-graph/README
+114
-10
tools/power/pm-graph/bootgraph.py
tools/power/pm-graph/bootgraph.py
+1
-1
tools/power/pm-graph/sleepgraph.8
tools/power/pm-graph/sleepgraph.8
+49
-16
tools/power/pm-graph/sleepgraph.py
tools/power/pm-graph/sleepgraph.py
+451
-344
No files found.
tools/power/pm-graph/Makefile
View file @
4bee16d7
...
@@ -41,6 +41,10 @@ uninstall :
...
@@ -41,6 +41,10 @@ uninstall :
if
[
-d
$(DESTDIR)$(PREFIX)/lib/pm-graph/config
]
;
then
\
if
[
-d
$(DESTDIR)$(PREFIX)/lib/pm-graph/config
]
;
then
\
rmdir
$(DESTDIR)$(PREFIX)/lib/pm-graph/config;
\
rmdir
$(DESTDIR)$(PREFIX)/lib/pm-graph/config;
\
fi;
fi;
rm
-f
$(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__/*
if
[
-d
$(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__
]
;
then
\
rmdir
$(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__;
\
fi;
rm
-f
$(DESTDIR)$(PREFIX)/lib/pm-graph/*
rm
-f
$(DESTDIR)$(PREFIX)/lib/pm-graph/*
if
[
-d
$(DESTDIR)$(PREFIX)/lib/pm-graph
]
;
then
\
if
[
-d
$(DESTDIR)$(PREFIX)/lib/pm-graph
]
;
then
\
rmdir
$(DESTDIR)$(PREFIX)/lib/pm-graph;
\
rmdir
$(DESTDIR)$(PREFIX)/lib/pm-graph;
\
...
...
tools/power/pm-graph/README
View file @
4bee16d7
p m - g r a p h
_
_ __ _ __ ___ __ _ _ __ __ _ _ __ | |__
| '_ \| '_ ` _ \ _____ / _` | '__/ _` | '_ \| '_ \
| |_) | | | | | |_____| (_| | | | (_| | |_) | | | |
| .__/|_| |_| |_| \__, |_| \__,_| .__/|_| |_|
|_| |___/ |_|
pm-graph: suspend/resume/boot timing analysis tools
pm-graph: suspend/resume/boot timing analysis tools
Version: 5.
5
Version: 5.
6
Author: Todd Brandt <todd.e.brandt@intel.com>
Author: Todd Brandt <todd.e.brandt@intel.com>
Home Page: https://01.org/pm-graph
Home Page: https://01.org/pm-graph
...
@@ -18,10 +23,6 @@
...
@@ -18,10 +23,6 @@
- upstream version in git:
- upstream version in git:
https://github.com/intel/pm-graph/
https://github.com/intel/pm-graph/
Requirements:
- runs with python2 or python3, choice is made by /usr/bin/python link
- python2 now requires python-configparser be installed
Table of Contents
Table of Contents
- Overview
- Overview
- Setup
- Setup
...
@@ -29,6 +30,8 @@
...
@@ -29,6 +30,8 @@
- Basic Usage
- Basic Usage
- Dev Mode Usage
- Dev Mode Usage
- Proc Mode Usage
- Proc Mode Usage
- Endurance Testing
- Usage Examples
- Configuration Files
- Configuration Files
- Usage Examples
- Usage Examples
- Config File Options
- Config File Options
...
@@ -54,15 +57,18 @@
...
@@ -54,15 +57,18 @@
| SETUP |
| SETUP |
------------------------------------------------------------------
------------------------------------------------------------------
These packages are required to execute the scripts
Package Requirements
- runs with python2 or python3, choice is made by /usr/bin/python link
- python
- python
- python-requests
- python-configparser (for python2 sleepgraph)
- python-requests (for googlesheet.py)
- linux-tools-common (for turbostat usage in sleepgraph)
Ubuntu:
Ubuntu:
sudo apt-get install python python-
requests
sudo apt-get install python python-
configparser python-requests linux-tools-common
Fedora:
Fedora:
sudo dnf install python python-
requests
sudo dnf install python python-
configparser python-requests linux-tools-common
The tools can most easily be installed via git clone and make install
The tools can most easily be installed via git clone and make install
...
@@ -190,6 +196,104 @@ _______________
...
@@ -190,6 +196,104 @@ _______________
%> sudo ./sleepgraph.py -config config/suspend-proc.cfg
%> sudo ./sleepgraph.py -config config/suspend-proc.cfg
------------------------------------------------------------------
| ENDURANCE TESTING |
------------------------------------------------------------------
The best way to gauge the health of a system is to run a series of
suspend/resumes over an extended period and analyze the behavior. This can be
accomplished with sleepgraph's -multi argument. You specify two numbers: the
number of tests to run OR the duration in days, hours, or minutes, and the
delay in seconds between them. For instance, -multi 20 5: execute 20 tests with
a 5 second delay between each, or -multi 24h 0: execute tests over a 24 hour
period with no delay between tests. You can include any other options you like
to generate the data you want. It's most useful to collect dev mode timelines
as the kprobes don't alter the performance much and you get more insight.
On completion, the output folder contains a series of folders for the
individual test data and a set of summary pages in the root. The summary.html
file is a tabular list of the tests with relevant info and links. The
summary-issue.html and summary-devices.html files include data taken from
all tests on kernel issues and device performance. The folder looks like this:
suspend-xN-{date}-{time}:
summary.html
summary-issues.html
summary-devices.html
suspend-{date}-{time} (1)
suspend-{date}-{time} (2)
...
These are the relevant arguments to use for testing:
-m mode
Mode to initiate for suspend e.g. mem, freeze, standby (default: mem).
-rtcwake t
Use rtcwake to autoresume after t seconds (default: 15).
-gzip (optional)
Gzip the trace and dmesg logs to save space. The tool can also read in
gzipped logs for processing. This reduces the multitest folder size.
-dev (optional)
Add kernel source calls and threads to the timeline (default: disabled).
-multi n d
Execute n consecutive tests at d seconds intervals. The outputs will be
created in a new subdirectory: suspend-xN-{date}-{time}. When the multitest
run is done, the -summary command is called automatically to create summary
html files for all the data (unless you use -skiphtml). -skiphtml will
speed up the testing by not creating timelines or summary html files. You
can then run the tool again at a later time with -summary and -genhtml to
create the timelines.
-skiphtml (optional)
Run the test and capture the trace logs, but skip the timeline and summary
html generation. This can greatly speed up overall testing. You can then
copy the data to a faster host machine and run -summary -genhtml to
generate the timelines and summary.
These are the relevant commands to use after testing is complete:
-summary indir
Generate or regenerate the summary for a -multi test run. Creates three
files: summary.html, summary-issues.html, and summary-devices.html in the
current folder. summary.html is a table of tests with relevant info sorted
by kernel/host/mode, and links to the test html files. summary-issues.html
is a list of kernel issues found in dmesg from all the tests.
summary-devices.html is a list of devices and times from all the tests.
-genhtml
Used with -summary to regenerate any missing html timelines from their
dmesg and ftrace logs. This will require a significant amount of time if
there are thousands of tests.
Usage Examples
_______________
A multitest is initiated like this:
%> sudo ./sleepgraph.py -m mem -rtcwake 10 -dev -gzip -multi 2000 0
or you can skip timeline generation in order to speed things up
%> sudo ./sleepgraph.py -m mem -rtcwake 10 -dev -gzip -multi 2000 0 -skiphtml
The tool will produce an output folder with all the test subfolders inside.
Each test subfolder contains the dmesg/ftrace logs and/or the html timeline
depending on whether you used the -skiphtml option. The root folder contains
the summary.html files.
The summary for an existing multitest is generated like this:
%> cd suspend-x2000-{date}-{time}
%> sleepgraph.py -summary .
or if you need to generate the html timelines you can use -genhtml
%> cd suspend-xN-{date}-{time}
%> sleepgraph.py -summary . -genhtml
------------------------------------------------------------------
------------------------------------------------------------------
| CONFIGURATION FILES |
| CONFIGURATION FILES |
...
...
tools/power/pm-graph/bootgraph.py
View file @
4bee16d7
#!/usr/bin/
python
#!/usr/bin/
env python3
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-License-Identifier: GPL-2.0-only
#
#
# Tool for analyzing boot timing
# Tool for analyzing boot timing
...
...
tools/power/pm-graph/sleepgraph.8
View file @
4bee16d7
...
@@ -74,8 +74,10 @@ after the test is complete.
...
@@ -74,8 +74,10 @@ after the test is complete.
Switch the display to the requested mode for the test using the xset command.
Switch the display to the requested mode for the test using the xset command.
This helps maintain the consistency of test data for better comparison.
This helps maintain the consistency of test data for better comparison.
.TP
.TP
\fB-skiphtml\fR
\fB-wifi\fR
Run the test and capture the trace logs, but skip the timeline generation.
If a wifi connection is available, check that it reconnects after resume. Include
the reconnect time in the total resume time calculation and treat wifi timeouts
as resume failures.
.SS "advanced"
.SS "advanced"
.TP
.TP
...
@@ -117,8 +119,24 @@ Include \fIt\fR ms delay before 1st suspend (default: 0 ms).
...
@@ -117,8 +119,24 @@ Include \fIt\fR ms delay before 1st suspend (default: 0 ms).
Include \fIt\fR ms delay after last resume (default: 0 ms).
Include \fIt\fR ms delay after last resume (default: 0 ms).
.TP
.TP
\fB-multi \fIn d\fR
\fB-multi \fIn d\fR
Execute \fIn\fR consecutive tests at \fId\fR seconds intervals. The outputs will
Used for endurance testing. If \fIn\fR is entirely numeric, it's treated as a count:
be created in a new subdirectory with a summary page: suspend-xN-{date}-{time}.
Execute \fIn\fR consecutive tests at \fId\fR second intervals.
If \fIn\fR is an integer followed by a "d", "h", or "m", it's treated as a duration:
Execute tests continuously over \fIn\fR days, hours, or minutes at \fId\fR second intervals.
The outputs will be created in a new subdirectory, for count: suspend-{date}-{time}-xN,
for duration: suspend-{date}-{time}-Nm. When the multitest run is done, the \fI-summary\fR
command is called automatically to create summary html files for all the data (unless you
use \fI-skiphtml\fR). \fI-skiphtml\fR will speed up the testing by not creating timelines
or summary html files. You can then run the tool again at a later time with \fI-summary\fR
and \fI-genhtml\fR to create the timelines.
.TP
\fB-maxfail \fIn\fR
Abort a -multi run after \fIn\fR consecutive fails. 0 means never abort (default = 0).
.TP
\fB-skiphtml\fR
Run the test and capture the trace logs, but skip the timeline generation.
You can generate the html timelines later with \fI-dmesg\fR & \fI-ftrace\fR, or
by running \fI-summary\fR and \fI-genhtml\fR.
.SS "ftrace debug"
.SS "ftrace debug"
.TP
.TP
...
@@ -173,11 +191,20 @@ Set trace buffer size to N kilo-bytes (default: all of free memory up to 3GB)
...
@@ -173,11 +191,20 @@ Set trace buffer size to N kilo-bytes (default: all of free memory up to 3GB)
.SH COMMANDS
.SH COMMANDS
.TP
.TP
\fB-summary \fIindir\fR
\fB-summary \fIindir\fR
Create a summary page of all tests in \fIindir\fR. Creates summary.html
Create a set of summary pages for all tests in \fIindir\fR recursively.
in the current folder. The output page is a table of tests with
Creates summary.html, summary-issues.html, and summary-devices.html in the current folder.
suspend and resume values sorted by suspend mode, host, and kernel.
summary.html is a table of tests with relevant info sorted by kernel/host/mode,
Includes test averages by mode and links to the test html files.
and links to the test html files. It identifies the minimum, maximum, and median
Use -genhtml to include tests with missing html.
suspend and resume times for you with highlights and links in the header.
summary-issues.html is a list of kernel issues found in dmesg from all the tests.
summary-devices.html is a list of devices and times from all the tests.
Use \fI-genhtml\fR to regenerate any tests with missing html.
.TP
\fB-genhtml\fR
Used with \fI-summary\fR to regenerate any missing html timelines from their
dmesg and ftrace logs. This will require a significant amount of time if there
are thousands of tests.
.TP
.TP
\fB-modes\fR
\fB-modes\fR
List available suspend modes.
List available suspend modes.
...
@@ -189,10 +216,7 @@ with any options you intend to use to see if they will work.
...
@@ -189,10 +216,7 @@ with any options you intend to use to see if they will work.
\fB-fpdt\fR
\fB-fpdt\fR
Print out the contents of the ACPI Firmware Performance Data Table.
Print out the contents of the ACPI Firmware Performance Data Table.
.TP
.TP
\fB-battery\fR
\fB-wificheck\fR
Print out battery status and current charge.
.TP
\fB-wifi\fR
Print out wifi status and connection details.
Print out wifi status and connection details.
.TP
.TP
\fB-xon/-xoff/-xstandby/-xsuspend\fR
\fB-xon/-xoff/-xstandby/-xsuspend\fR
...
@@ -208,6 +232,9 @@ Print out system info extracted from BIOS. Reads /dev/mem directly instead of go
...
@@ -208,6 +232,9 @@ Print out system info extracted from BIOS. Reads /dev/mem directly instead of go
\fB-devinfo\fR
\fB-devinfo\fR
Print out the pm settings of all devices which support runtime suspend.
Print out the pm settings of all devices which support runtime suspend.
.TP
.TP
\fB-cmdinfo\fR
Print out all the platform data collected from the system that makes it into the logs.
.TP
\fB-flist\fR
\fB-flist\fR
Print the list of ftrace functions currently being captured. Functions
Print the list of ftrace functions currently being captured. Functions
that are not available as symbols in the current kernel are shown in red.
that are not available as symbols in the current kernel are shown in red.
...
@@ -272,14 +299,20 @@ Run two suspends back to back, include a 500ms delay before, after, and in betwe
...
@@ -272,14 +299,20 @@ Run two suspends back to back, include a 500ms delay before, after, and in betwe
.IP
.IP
\f(CW$ sudo sleepgraph -m mem -rtcwake 15 -x2 -predelay 500 -x2delay 500 -postdelay 500\fR
\f(CW$ sudo sleepgraph -m mem -rtcwake 15 -x2 -predelay 500 -x2delay 500 -postdelay 500\fR
.PP
.PP
Execute a suspend using a custom command.
.IP
\f(CW$ sudo sleepgraph -cmd "echo mem > /sys/power/state" -rtcwake 15\fR
.PP
.SS "endurance testing using -multi"
.PP
Do a batch run of 10 freezes with 30 seconds delay between runs.
Do a batch run of 10 freezes with 30 seconds delay between runs.
.IP
.IP
\f(CW$ sudo sleepgraph -m freeze -rtcwake 15 -multi 10 30\fR
\f(CW$ sudo sleepgraph -m freeze -rtcwake 15 -multi 10 30\fR
.PP
.PP
Execute a suspend using a custom command
.
Do a batch run of freezes for 24 hours
.
.IP
.IP
\f(CW$ sudo sleepgraph -cmd "echo mem > /sys/power/state" -rtcwake 15\fR
\f(CW$ sudo sleepgraph -m freeze -rtcwake 15 -multi 24h 0\fR
.PP
.SS "adding callgraph data"
.SS "adding callgraph data"
Add device callgraphs. Limit the trace depth and only show callgraphs 10ms or larger.
Add device callgraphs. Limit the trace depth and only show callgraphs 10ms or larger.
...
...
tools/power/pm-graph/sleepgraph.py
View file @
4bee16d7
#!/usr/bin/
python
#!/usr/bin/
env python3
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-License-Identifier: GPL-2.0-only
#
#
# Tool for analyzing suspend/resume timing
# Tool for analyzing suspend/resume timing
...
@@ -58,7 +58,7 @@ import re
...
@@ -58,7 +58,7 @@ import re
import
platform
import
platform
import
signal
import
signal
import
codecs
import
codecs
from
datetime
import
datetime
from
datetime
import
datetime
,
timedelta
import
struct
import
struct
import
configparser
import
configparser
import
gzip
import
gzip
...
@@ -81,12 +81,13 @@ def ascii(text):
...
@@ -81,12 +81,13 @@ def ascii(text):
# store system values and test parameters
# store system values and test parameters
class
SystemValues
:
class
SystemValues
:
title
=
'SleepGraph'
title
=
'SleepGraph'
version
=
'5.
5
'
version
=
'5.
6
'
ansi
=
False
ansi
=
False
rs
=
0
rs
=
0
display
=
''
display
=
''
gzip
=
False
gzip
=
False
sync
=
False
sync
=
False
wifi
=
False
verbose
=
False
verbose
=
False
testlog
=
True
testlog
=
True
dmesglog
=
True
dmesglog
=
True
...
@@ -97,7 +98,8 @@ class SystemValues:
...
@@ -97,7 +98,8 @@ class SystemValues:
cgphase
=
''
cgphase
=
''
cgtest
=
-
1
cgtest
=
-
1
cgskip
=
''
cgskip
=
''
multitest
=
{
'run'
:
False
,
'count'
:
0
,
'delay'
:
0
}
maxfail
=
0
multitest
=
{
'run'
:
False
,
'count'
:
1000000
,
'delay'
:
0
}
max_graph_depth
=
0
max_graph_depth
=
0
callloopmaxgap
=
0.0001
callloopmaxgap
=
0.0001
callloopmaxlen
=
0.005
callloopmaxlen
=
0.005
...
@@ -148,7 +150,7 @@ class SystemValues:
...
@@ -148,7 +150,7 @@ class SystemValues:
x2delay
=
0
x2delay
=
0
skiphtml
=
False
skiphtml
=
False
usecallgraph
=
False
usecallgraph
=
False
ftopfunc
=
'
suspend_devices_and_enter
'
ftopfunc
=
'
pm_suspend
'
ftop
=
False
ftop
=
False
usetraceevents
=
False
usetraceevents
=
False
usetracemarkers
=
True
usetracemarkers
=
True
...
@@ -164,6 +166,8 @@ class SystemValues:
...
@@ -164,6 +166,8 @@ class SystemValues:
predelay
=
0
predelay
=
0
postdelay
=
0
postdelay
=
0
pmdebug
=
''
pmdebug
=
''
tmstart
=
'SUSPEND START %Y%m%d-%H:%M:%S.%f'
tmend
=
'RESUME COMPLETE %Y%m%d-%H:%M:%S.%f'
tracefuncs
=
{
tracefuncs
=
{
'sys_sync'
:
{},
'sys_sync'
:
{},
'ksys_sync'
:
{},
'ksys_sync'
:
{},
...
@@ -183,9 +187,11 @@ class SystemValues:
...
@@ -183,9 +187,11 @@ class SystemValues:
'acpi_s2idle_sync'
:
{},
'acpi_s2idle_sync'
:
{},
'acpi_s2idle_begin'
:
{},
'acpi_s2idle_begin'
:
{},
'acpi_s2idle_prepare'
:
{},
'acpi_s2idle_prepare'
:
{},
'acpi_s2idle_prepare_late'
:
{},
'acpi_s2idle_wake'
:
{},
'acpi_s2idle_wake'
:
{},
'acpi_s2idle_wakeup'
:
{},
'acpi_s2idle_wakeup'
:
{},
'acpi_s2idle_restore'
:
{},
'acpi_s2idle_restore'
:
{},
'acpi_s2idle_restore_early'
:
{},
'hibernate_preallocate_memory'
:
{},
'hibernate_preallocate_memory'
:
{},
'create_basic_memory_bitmaps'
:
{},
'create_basic_memory_bitmaps'
:
{},
'swsusp_write'
:
{},
'swsusp_write'
:
{},
...
@@ -270,12 +276,23 @@ class SystemValues:
...
@@ -270,12 +276,23 @@ class SystemValues:
'intel_opregion_init'
:
{},
'intel_opregion_init'
:
{},
'intel_fbdev_set_suspend'
:
{},
'intel_fbdev_set_suspend'
:
{},
}
}
infocmds
=
[
[
0
,
'kparams'
,
'cat'
,
'/proc/cmdline'
],
[
0
,
'mcelog'
,
'mcelog'
],
[
0
,
'pcidevices'
,
'lspci'
,
'-tv'
],
[
0
,
'usbdevices'
,
'lsusb'
,
'-t'
],
[
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/*/*'
],
]
cgblacklist
=
[]
cgblacklist
=
[]
kprobes
=
dict
()
kprobes
=
dict
()
timeformat
=
'%.3f'
timeformat
=
'%.3f'
cmdline
=
'%s %s'
%
\
cmdline
=
'%s %s'
%
\
(
os
.
path
.
basename
(
sys
.
argv
[
0
]),
' '
.
join
(
sys
.
argv
[
1
:]))
(
os
.
path
.
basename
(
sys
.
argv
[
0
]),
' '
.
join
(
sys
.
argv
[
1
:]))
kparams
=
''
sudouser
=
''
sudouser
=
''
def
__init__
(
self
):
def
__init__
(
self
):
self
.
archargs
=
'args_'
+
platform
.
machine
()
self
.
archargs
=
'args_'
+
platform
.
machine
()
...
@@ -295,6 +312,9 @@ class SystemValues:
...
@@ -295,6 +312,9 @@ class SystemValues:
if
os
.
getuid
()
==
0
and
'SUDO_USER'
in
os
.
environ
and
\
if
os
.
getuid
()
==
0
and
'SUDO_USER'
in
os
.
environ
and
\
os
.
environ
[
'SUDO_USER'
]:
os
.
environ
[
'SUDO_USER'
]:
self
.
sudouser
=
os
.
environ
[
'SUDO_USER'
]
self
.
sudouser
=
os
.
environ
[
'SUDO_USER'
]
def
resetlog
(
self
):
self
.
logmsg
=
''
self
.
platinfo
=
[]
def
vprint
(
self
,
msg
):
def
vprint
(
self
,
msg
):
self
.
logmsg
+=
msg
+
'
\
n
'
self
.
logmsg
+=
msg
+
'
\
n
'
if
self
.
verbose
or
msg
.
startswith
(
'WARNING:'
):
if
self
.
verbose
or
msg
.
startswith
(
'WARNING:'
):
...
@@ -304,11 +324,11 @@ class SystemValues:
...
@@ -304,11 +324,11 @@ class SystemValues:
return
return
signame
=
self
.
signames
[
signum
]
if
signum
in
self
.
signames
else
'UNKNOWN'
signame
=
self
.
signames
[
signum
]
if
signum
in
self
.
signames
else
'UNKNOWN'
msg
=
'Signal %s caused a tool exit, line %d'
%
(
signame
,
frame
.
f_lineno
)
msg
=
'Signal %s caused a tool exit, line %d'
%
(
signame
,
frame
.
f_lineno
)
s
ysvals
.
outputResult
({
'error'
:
msg
})
s
elf
.
outputResult
({
'error'
:
msg
})
sys
.
exit
(
3
)
sys
.
exit
(
3
)
def
signalHandlerInit
(
self
):
def
signalHandlerInit
(
self
):
capture
=
[
'BUS'
,
'SYS'
,
'XCPU'
,
'XFSZ'
,
'PWR'
,
'HUP'
,
'INT'
,
'QUIT'
,
capture
=
[
'BUS'
,
'SYS'
,
'XCPU'
,
'XFSZ'
,
'PWR'
,
'HUP'
,
'INT'
,
'QUIT'
,
'ILL'
,
'ABRT'
,
'FPE'
,
'SEGV'
,
'TERM'
,
'TSTP'
]
'ILL'
,
'ABRT'
,
'FPE'
,
'SEGV'
,
'TERM'
]
self
.
signames
=
dict
()
self
.
signames
=
dict
()
for
i
in
capture
:
for
i
in
capture
:
s
=
'SIG'
+
i
s
=
'SIG'
+
i
...
@@ -336,6 +356,8 @@ class SystemValues:
...
@@ -336,6 +356,8 @@ class SystemValues:
self
.
outputResult
({
'error'
:
msg
})
self
.
outputResult
({
'error'
:
msg
})
sys
.
exit
(
1
)
sys
.
exit
(
1
)
return
False
return
False
def
usable
(
self
,
file
):
return
(
os
.
path
.
exists
(
file
)
and
os
.
path
.
getsize
(
file
)
>
0
)
def
getExec
(
self
,
cmd
):
def
getExec
(
self
,
cmd
):
try
:
try
:
fp
=
Popen
([
'which'
,
cmd
],
stdout
=
PIPE
,
stderr
=
PIPE
).
stdout
fp
=
Popen
([
'which'
,
cmd
],
stdout
=
PIPE
,
stderr
=
PIPE
).
stdout
...
@@ -389,12 +411,6 @@ class SystemValues:
...
@@ -389,12 +411,6 @@ class SystemValues:
r
=
info
[
'bios-release-date'
]
if
'bios-release-date'
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'
%
\
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
)
(
m
,
p
,
c
,
b
,
r
,
self
.
cpucount
,
self
.
memtotal
,
self
.
memfree
)
try
:
kcmd
=
open
(
'/proc/cmdline'
,
'r'
).
read
().
strip
()
except
:
kcmd
=
''
if
kcmd
:
self
.
sysstamp
+=
'
\
n
# kparams | %s'
%
kcmd
def
printSystemInfo
(
self
,
fatal
=
False
):
def
printSystemInfo
(
self
,
fatal
=
False
):
self
.
rootCheck
(
True
)
self
.
rootCheck
(
True
)
out
=
dmidecode
(
self
.
mempath
,
fatal
)
out
=
dmidecode
(
self
.
mempath
,
fatal
)
...
@@ -441,6 +457,7 @@ class SystemValues:
...
@@ -441,6 +457,7 @@ class SystemValues:
self
.
testdir
+
'/'
+
self
.
prefix
+
'_'
+
self
.
suspendmode
+
'.html'
self
.
testdir
+
'/'
+
self
.
prefix
+
'_'
+
self
.
suspendmode
+
'.html'
if
not
os
.
path
.
isdir
(
self
.
testdir
):
if
not
os
.
path
.
isdir
(
self
.
testdir
):
os
.
makedirs
(
self
.
testdir
)
os
.
makedirs
(
self
.
testdir
)
self
.
sudoUserchown
(
self
.
testdir
)
def
getValueList
(
self
,
value
):
def
getValueList
(
self
,
value
):
out
=
[]
out
=
[]
for
i
in
value
.
split
(
','
):
for
i
in
value
.
split
(
','
):
...
@@ -486,7 +503,7 @@ class SystemValues:
...
@@ -486,7 +503,7 @@ class SystemValues:
fp
.
close
()
fp
.
close
()
self
.
dmesgstart
=
float
(
ktime
)
self
.
dmesgstart
=
float
(
ktime
)
def
getdmesg
(
self
,
testdata
):
def
getdmesg
(
self
,
testdata
):
op
=
self
.
writeDatafileHeader
(
s
ysvals
.
dmesgfile
,
testdata
)
op
=
self
.
writeDatafileHeader
(
s
elf
.
dmesgfile
,
testdata
)
# store all new dmesg lines since initdmesg was called
# store all new dmesg lines since initdmesg was called
fp
=
Popen
(
'dmesg'
,
stdout
=
PIPE
).
stdout
fp
=
Popen
(
'dmesg'
,
stdout
=
PIPE
).
stdout
for
line
in
fp
:
for
line
in
fp
:
...
@@ -716,8 +733,9 @@ class SystemValues:
...
@@ -716,8 +733,9 @@ class SystemValues:
if
name
==
f
:
if
name
==
f
:
return
True
return
True
return
False
return
False
def
initFtrace
(
self
):
def
initFtrace
(
self
,
quiet
=
False
):
self
.
printSystemInfo
(
False
)
if
not
quiet
:
sysvals
.
printSystemInfo
(
False
)
pprint
(
'INITIALIZING FTRACE...'
)
pprint
(
'INITIALIZING FTRACE...'
)
# turn trace off
# turn trace off
self
.
fsetVal
(
'0'
,
'tracing_on'
)
self
.
fsetVal
(
'0'
,
'tracing_on'
)
...
@@ -746,7 +764,7 @@ class SystemValues:
...
@@ -746,7 +764,7 @@ class SystemValues:
if
tgtsize
<
65536
:
if
tgtsize
<
65536
:
tgtsize
=
int
(
self
.
fgetVal
(
'buffer_size_kb'
))
*
cpus
tgtsize
=
int
(
self
.
fgetVal
(
'buffer_size_kb'
))
*
cpus
break
break
p
print
(
'Setting trace buffers to %d kB (%d kB per cpu)'
%
(
tgtsize
,
tgtsize
/
cpus
))
self
.
v
print
(
'Setting trace buffers to %d kB (%d kB per cpu)'
%
(
tgtsize
,
tgtsize
/
cpus
))
# initialize the callgraph trace
# initialize the callgraph trace
if
(
self
.
usecallgraph
):
if
(
self
.
usecallgraph
):
# set trace type
# set trace type
...
@@ -782,6 +800,7 @@ class SystemValues:
...
@@ -782,6 +800,7 @@ class SystemValues:
if
self
.
usedevsrc
:
if
self
.
usedevsrc
:
for
name
in
self
.
dev_tracefuncs
:
for
name
in
self
.
dev_tracefuncs
:
self
.
defaultKprobe
(
name
,
self
.
dev_tracefuncs
[
name
])
self
.
defaultKprobe
(
name
,
self
.
dev_tracefuncs
[
name
])
if
not
quiet
:
pprint
(
'INITIALIZING KPROBES...'
)
pprint
(
'INITIALIZING KPROBES...'
)
self
.
addKprobes
(
self
.
verbose
)
self
.
addKprobes
(
self
.
verbose
)
if
(
self
.
usetraceevents
):
if
(
self
.
usetraceevents
):
...
@@ -827,21 +846,10 @@ class SystemValues:
...
@@ -827,21 +846,10 @@ class SystemValues:
fw
=
test
[
'fw'
]
fw
=
test
[
'fw'
]
if
(
fw
):
if
(
fw
):
fp
.
write
(
'# fwsuspend %u fwresume %u
\
n
'
%
(
fw
[
0
],
fw
[
1
]))
fp
.
write
(
'# fwsuspend %u fwresume %u
\
n
'
%
(
fw
[
0
],
fw
[
1
]))
if
'mcelog'
in
test
:
fp
.
write
(
'# mcelog %s
\
n
'
%
test
[
'mcelog'
])
if
'turbo'
in
test
:
if
'turbo'
in
test
:
fp
.
write
(
'# turbostat %s
\
n
'
%
test
[
'turbo'
])
fp
.
write
(
'# turbostat %s
\
n
'
%
test
[
'turbo'
])
if
'bat'
in
test
:
(
a1
,
c1
),
(
a2
,
c2
)
=
test
[
'bat'
]
fp
.
write
(
'# battery %s %d %s %d
\
n
'
%
(
a1
,
c1
,
a2
,
c2
))
if
'wifi'
in
test
:
if
'wifi'
in
test
:
wstr
=
[]
fp
.
write
(
'# wifi %s
\
n
'
%
test
[
'wifi'
])
for
wifi
in
test
[
'wifi'
]:
tmp
=
[]
for
key
in
sorted
(
wifi
):
tmp
.
append
(
'%s:%s'
%
(
key
,
wifi
[
key
]))
wstr
.
append
(
'|'
.
join
(
tmp
))
fp
.
write
(
'# wifi %s
\
n
'
%
(
','
.
join
(
wstr
)))
if
test
[
'error'
]
or
len
(
testdata
)
>
1
:
if
test
[
'error'
]
or
len
(
testdata
)
>
1
:
fp
.
write
(
'# enter_sleep_error %s
\
n
'
%
test
[
'error'
])
fp
.
write
(
'# enter_sleep_error %s
\
n
'
%
test
[
'error'
])
return
fp
return
fp
...
@@ -901,23 +909,7 @@ class SystemValues:
...
@@ -901,23 +909,7 @@ class SystemValues:
def
b64zip
(
self
,
data
):
def
b64zip
(
self
,
data
):
out
=
base64
.
b64encode
(
codecs
.
encode
(
data
.
encode
(),
'zlib'
)).
decode
()
out
=
base64
.
b64encode
(
codecs
.
encode
(
data
.
encode
(),
'zlib'
)).
decode
()
return
out
return
out
def
mcelog
(
self
,
clear
=
False
):
def
platforminfo
(
self
,
cmdafter
):
cmd
=
self
.
getExec
(
'mcelog'
)
if
not
cmd
:
return
''
if
clear
:
call
(
cmd
+
' > /dev/null 2>&1'
,
shell
=
True
)
return
''
try
:
fp
=
Popen
([
cmd
],
stdout
=
PIPE
,
stderr
=
PIPE
).
stdout
out
=
ascii
(
fp
.
read
()).
strip
()
fp
.
close
()
except
:
return
''
if
not
out
:
return
''
return
self
.
b64zip
(
out
)
def
platforminfo
(
self
):
# add platform info on to a completed ftrace file
# add platform info on to a completed ftrace file
if
not
os
.
path
.
exists
(
self
.
ftracefile
):
if
not
os
.
path
.
exists
(
self
.
ftracefile
):
return
False
return
False
...
@@ -1001,31 +993,76 @@ class SystemValues:
...
@@ -1001,31 +993,76 @@ class SystemValues:
footer
+=
'# platform-devinfo: %s
\
n
'
%
self
.
b64zip
(
out
)
footer
+=
'# platform-devinfo: %s
\
n
'
%
self
.
b64zip
(
out
)
# add a line for each of these commands with their outputs
# add a line for each of these commands with their outputs
cmds
=
[
for
name
,
cmdline
,
info
in
cmdafter
:
[
'pcidevices'
,
'lspci'
,
'-tv'
],
footer
+=
'# platform-%s: %s | %s
\
n
'
%
(
name
,
cmdline
,
self
.
b64zip
(
info
))
[
'interrupts'
,
'cat'
,
'/proc/interrupts'
],
[
'gpecounts'
,
'sh'
,
'-c'
,
'grep -v invalid /sys/firmware/acpi/interrupts/gpe*'
],
with
self
.
openlog
(
self
.
ftracefile
,
'a'
)
as
fp
:
]
fp
.
write
(
footer
)
for
cargs
in
cmds
:
return
True
name
=
cargs
[
0
]
def
commonPrefix
(
self
,
list
):
cmdline
=
' '
.
join
(
cargs
[
1
:])
if
len
(
list
)
<
2
:
cmdpath
=
self
.
getExec
(
cargs
[
1
])
return
''
if
not
cmdpath
:
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 cmdinfo(self, begin, debug=False):
out = []
if begin:
self.cmd1 = dict()
for cargs in self.infocmds:
delta, name = cargs[0], cargs[1]
cmdline, cmdpath = '
'.join(cargs[2:]), self.getExec(cargs[2])
if not cmdpath or (begin and not delta):
continue
continue
cmd
=
[
cmdpath
]
+
cargs
[
2
:]
try:
try:
fp
=
Popen
(
cmd
,
stdout
=
PIPE
,
stderr
=
PIPE
).
stdout
fp = Popen(
[cmdpath]+cargs[3:]
, stdout=PIPE, stderr=PIPE).stdout
info = ascii(fp.read()).strip()
info = ascii(fp.read()).strip()
fp.close()
fp.close()
except:
except:
continue
continue
if
not
info
:
if not debug and begin:
continue
self.cmd1[name] = self.dictify(info, delta)
footer
+=
'# platform-%s: %s | %s
\
n
'
%
(
name
,
cmdline
,
self
.
b64zip
(
info
))
elif not debug and delta and name in self.cmd1:
before, after = self.cmd1[name], self.dictify(info, delta)
with
self
.
openlog
(
self
.
ftracefile
,
'a'
)
as
fp
:
dinfo = ('
\
t
%
s
\
n
' % before['
@
']) if '
@
' in before else ''
fp
.
write
(
footer
)
prefix = self.commonPrefix(list(before.keys()))
return
True
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 += '
%
10
s
(
start
)
:
%
s
\
n
%
10
s
(
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 haveTurbostat(self):
def haveTurbostat(self):
if not self.tstat:
if not self.tstat:
return False
return False
...
@@ -1035,8 +1072,8 @@ class SystemValues:
...
@@ -1035,8 +1072,8 @@ class SystemValues:
fp = Popen([cmd, '
-
v
'], stdout=PIPE, stderr=PIPE).stderr
fp = Popen([cmd, '
-
v
'], stdout=PIPE, stderr=PIPE).stderr
out = ascii(fp.read()).strip()
out = ascii(fp.read()).strip()
fp.close()
fp.close()
if
re
.
match
(
'turbostat version
[0-9
\
.]*
.*
'
, out):
if re.match('
turbostat
version
.
*
', out):
s
ysvals
.vprint(out)
s
elf
.vprint(out)
return True
return True
return False
return False
def turbostat(self):
def turbostat(self):
...
@@ -1056,11 +1093,11 @@ class SystemValues:
...
@@ -1056,11 +1093,11 @@ class SystemValues:
fp.close()
fp.close()
if not keyline or not valline or len(keyline) != len(valline):
if not keyline or not valline or len(keyline) != len(valline):
errmsg = '
unrecognized
turbostat
output
:
\
n
'+rawout.strip()
errmsg = '
unrecognized
turbostat
output
:
\
n
'+rawout.strip()
s
ysvals
.vprint(errmsg)
s
elf
.vprint(errmsg)
if not s
ysvals
.verbose:
if not s
elf
.verbose:
pprint(errmsg)
pprint(errmsg)
return ''
return ''
if s
ysvals
.verbose:
if s
elf
.verbose:
pprint(rawout.strip())
pprint(rawout.strip())
out = []
out = []
for key in keyline:
for key in keyline:
...
@@ -1068,30 +1105,36 @@ class SystemValues:
...
@@ -1068,30 +1105,36 @@ class SystemValues:
val = valline[idx]
val = valline[idx]
out.append('
%
s
=%
s
' % (key, val))
out.append('
%
s
=%
s
' % (key, val))
return '
|
'.join(out)
return '
|
'.join(out)
def checkWifi(self):
def wifiDetails(self, dev):
out = dict()
try:
iwcmd, ifcmd = self.getExec('
iwconfig
'), self.getExec('
ifconfig
')
info = open('
/
sys
/
class
/
net
/%
s
/
device
/
uevent
' % dev, 'r').read().strip()
if not iwcmd or not ifcmd:
except:
return out
return dev
fp = Popen(iwcmd, stdout=PIPE, stderr=PIPE).stdout
vals = [dev]
for line in fp:
for prop in info.split('
\
n
'):
m = re.match('
(
?
P
<
dev
>
\
S
*
)
.
*
ESSID
:(
?
P
<
ess
>
\
S
*
)
', ascii(line))
if prop.startswith('
DRIVER
=
') or prop.startswith('
PCI_ID
=
'):
if not m:
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('
*
(
?
P
<
dev
>
.
*
):
(
?
P
<
stat
>
[
0
-
9
a
-
f
]
*
)
.
*
', w.split('
\
n
')[-1])
if not m or (dev and dev != m.group('
dev
')):
continue
continue
out['
device
'] = m.group('
dev
')
return m.group('
dev
')
if '"' in m.group('ess'):
return ''
out['essid'] = m.group('ess').strip('"')
def pollWifi(self, dev, timeout=60):
break
start = time.time()
fp.close()
while (time.time() - start) < timeout:
if '
device
' in out:
w = self.checkWifi(dev)
fp = Popen([ifcmd, out['
device
']], stdout=PIPE, stderr=PIPE).stdout
if w:
for line in fp:
return '
%
s
reconnected
%
.
2
f' %
\
m = re.match('
.
*
inet
(
?
P
<
ip
>
[
0
-
9
\
.]
*
)
', ascii(line))
(self.wifiDetails(dev), max(0, time.time() - start))
if m:
time.sleep(0.01)
out['
ip
'] = m.group('
ip
')
return '
%
s
timeout
%
d
' % (self.wifiDetails(dev), timeout)
break
fp.close()
return out
def errorSummary(self, errinfo, msg):
def errorSummary(self, errinfo, msg):
found = False
found = False
for entry in errinfo:
for entry in errinfo:
...
@@ -1113,8 +1156,9 @@ class SystemValues:
...
@@ -1113,8 +1156,9 @@ class SystemValues:
arr[j] = arr[j]
\
arr[j] = arr[j]
\
.replace('
\\
', '
\\\\
').replace('
]
', '
\
]
').replace('
[
', '
\
[
')
\
.replace('
\\
', '
\\\\
').replace('
]
', '
\
]
').replace('
[
', '
\
[
')
\
.replace('
.
', '
\
.
').replace('
+
', '
\
+
').replace('
*
', '
\
*
')
\
.replace('
.
', '
\
.
').replace('
+
', '
\
+
').replace('
*
', '
\
*
')
\
.replace('
(
', '
\
(
').replace('
)
', '
\
)
')
.replace('
(
', '
\
(
').replace('
)
', '
\
)
').replace('
}
', '
\
}
')
\
mstr = '
'.join(arr)
.replace('
{
', '
\
{
')
mstr = '
*
'.join(arr)
entry = {
entry = {
'
line
': msg,
'
line
': msg,
'
match
': mstr,
'
match
': mstr,
...
@@ -1122,6 +1166,44 @@ class SystemValues:
...
@@ -1122,6 +1166,44 @@ class SystemValues:
'
urls
': {self.hostname: [self.htmlfile]}
'
urls
': {self.hostname: [self.htmlfile]}
}
}
errinfo.append(entry)
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
%
.
1
fs
' % (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
%
.
1
fs
,
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
sysvals = SystemValues()
sysvals = SystemValues()
switchvalues = ['
enable
', '
disable
', '
on
', '
off
', '
true
', '
false
', '
1
', '
0
']
switchvalues = ['
enable
', '
disable
', '
on
', '
off
', '
true
', '
false
', '
1
', '
0
']
...
@@ -1210,25 +1292,30 @@ class Data:
...
@@ -1210,25 +1292,30 @@ class Data:
'resume_complete'
:
{
'order'
:
9
,
'color'
:
'#FFFFCC'
},
'resume_complete'
:
{
'order'
:
9
,
'color'
:
'#FFFFCC'
},
}
}
errlist
=
{
errlist
=
{
'HWERROR'
:
'.*
\
[ *H
a
rdware Error *
\
].*
'
,
'HWERROR'
:
r'.*\
[ *H
ardware Error *\
].*
',
'
FWBUG
' : '
.
*
\
[
*
Firmware
Bug
*
\
].
*
',
'
FWBUG
' : r'
.
*
\
[
*
Firmware
Bug
*
\
].
*
',
'
BUG
' : '
.
*
BUG
.
*
',
'
BUG
' : r'
(
?
i
).
*
\
bBUG
\
b
.
*
',
'
ERROR
' : '
.
*
ERROR
.
*
',
'
ERROR
' : r'
(
?
i
).
*
\
bERROR
\
b
.
*
',
'
WARNING
' : '
.
*
WARNING
.
*
',
'
WARNING
' : r'
(
?
i
).
*
\
bWARNING
\
b
.
*
',
'
IRQ
' : '
.
*
genirq
:
.
*
',
'
FAULT
' : r'
(
?
i
).
*
\
bFAULT
\
b
.
*
',
'
TASKFAIL
': '
.
*
Freezing
of
tasks
*
.
*
',
'
FAIL
' : r'
(
?
i
).
*
\
bFAILED
\
b
.
*
',
'
ACPI
' : '
.
*
ACPI
*
(
?
P
<
b
>
[
A
-
Za
-
z
]
*
)
*
Error
[:
].
*
',
'
INVALID
' : r'
(
?
i
).
*
\
bINVALID
\
b
.
*
',
'
DEVFAIL
' : '
.
*
failed
to
(
?
P
<
b
>
[
a
-
z
]
*
)
async
:
.
*
',
'
CRASH
' : r'
(
?
i
).
*
\
bCRASHED
\
b
.
*
',
'
DISKFULL
': '
.
*
No
space
left
on
device
.
*
',
'
IRQ
' : r'
.
*
\
bgenirq
:
.
*
',
'
USBERR
' : '
.
*
usb
.
*
device
.
*
,
error
[
0
-
9
-
]
*
',
'
TASKFAIL
': r'
.
*
Freezing
of
tasks
*
.
*
',
'
ATAERR
' : '
*
ata
[
0
-
9
\
.]
*
:
.
*
failed
.
*
',
'
ACPI
' : r'
.
*
\
bACPI
*
(
?
P
<
b
>
[
A
-
Za
-
z
]
*
)
*
Error
[:
].
*
',
'
MEIERR
' : '
*
mei
.
*
:
.
*
failed
.
*
',
'
DISKFULL
': r'
.
*
\
bNo
space
left
on
device
.
*
',
'
TPMERR
' : '
(
?
i
)
*
tpm
*
tpm
[
0
-
9
]
*
:
.
*
error
.
*
',
'
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):
def __init__(self, num):
idchar = '
abcdefghij
'
idchar = '
abcdefghij
'
self.start = 0.0 # test start
self.start = 0.0 # test start
self.end = 0.0 # test end
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.tSuspended = 0.0 # low-level suspend start
self.tResumed = 0.0 # low-level resume start
self.tResumed = 0.0 # low-level resume start
self.tKernSus = 0.0 # kernel level suspend start
self.tKernSus = 0.0 # kernel level suspend start
...
@@ -1240,10 +1327,8 @@ class Data:
...
@@ -1240,10 +1327,8 @@ class Data:
self.stamp = 0
self.stamp = 0
self.outfile = ''
self.outfile = ''
self.kerror = False
self.kerror = False
self.battery = 0
self.wifi = dict()
self.wifi = 0
self.turbostat = 0
self.turbostat = 0
self.mcelog = 0
self.enterfail = ''
self.enterfail = ''
self.currphase = ''
self.currphase = ''
self.pstl = dict() # process timeline
self.pstl = dict() # process timeline
...
@@ -1308,6 +1393,8 @@ class Data:
...
@@ -1308,6 +1393,8 @@ class Data:
continue
continue
dir = '
suspend
' if t < self.tSuspended else '
resume
'
dir = '
suspend
' if t < self.tSuspended else '
resume
'
msg = m.group('
msg
')
msg = m.group('
msg
')
if re.match('
capability
:
warning
:
.
*
', msg):
continue
for err in self.errlist:
for err in self.errlist:
if re.match(self.errlist[err], msg):
if re.match(self.errlist[err], msg):
list.append((msg, err, dir, t, i, i))
list.append((msg, err, dir, t, i, i))
...
@@ -1316,17 +1403,26 @@ class Data:
...
@@ -1316,17 +1403,26 @@ class Data:
msglist = []
msglist = []
for msg, type, dir, t, idx1, idx2 in list:
for msg, type, dir, t, idx1, idx2 in list:
msglist.append(msg)
msglist.append(msg)
sysvals.vprint('
kernel
%
s
found
in
%
s
at
%
f' % (type, dir, t))
self.errorinfo[dir].append((type, t, idx1, idx2))
self.errorinfo[dir].append((type, t, idx1, idx2))
if self.kerror:
if self.kerror:
sysvals.dmesglog = True
sysvals.dmesglog = True
if len(self.dmesgtext) < 1 and sysvals.dmesgfile:
if len(self.dmesgtext) < 1 and sysvals.dmesgfile:
lf.close()
lf.close()
return msglist
return msglist
def setStart(self, time):
def setStart(self, time
, msg=''
):
self.start = time
self.start = time
def setEnd(self, time):
if msg:
try:
self.hwstart = datetime.strptime(msg, sysvals.tmstart)
except:
self.hwstart = 0
def setEnd(self, time, msg=''):
self.end = time
self.end = time
if msg:
try:
self.hwend = datetime.strptime(msg, sysvals.tmend)
except:
self.hwend = 0
def isTraceEventOutsideDeviceCalls(self, pid, time):
def isTraceEventOutsideDeviceCalls(self, pid, time):
for phase in self.sortedPhases():
for phase in self.sortedPhases():
list = self.dmesg[phase]['
list
']
list = self.dmesg[phase]['
list
']
...
@@ -1546,6 +1642,14 @@ class Data:
...
@@ -1546,6 +1642,14 @@ class Data:
self.trimTime(tS, tL, left)
self.trimTime(tS, tL, left)
self.tLow.append('
%
.
0
f'%(tL*1000))
self.tLow.append('
%
.
0
f'%(tL*1000))
lp = phase
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('
%
.
0
f'%((hwr - hws).total_seconds() * 1000))
def getTimeValues(self):
def getTimeValues(self):
sktime = (self.tSuspended - self.tKernSus) * 1000
sktime = (self.tSuspended - self.tKernSus) * 1000
rktime = (self.tKernRes - self.tResumed) * 1000
rktime = (self.tKernRes - self.tResumed) * 1000
...
@@ -1883,9 +1987,9 @@ class Data:
...
@@ -1883,9 +1987,9 @@ class Data:
c = self.addProcessUsageEvent(ps, tres)
c = self.addProcessUsageEvent(ps, tres)
if c > 0:
if c > 0:
sysvals.vprint('
%
25
s
(
res
):
%
d
' % (ps, c))
sysvals.vprint('
%
25
s
(
res
):
%
d
' % (ps, c))
def handleEndMarker(self, time):
def handleEndMarker(self, time
, msg=''
):
dm = self.dmesg
dm = self.dmesg
self.setEnd(time)
self.setEnd(time
, msg
)
self.initDevicegroups()
self.initDevicegroups()
# give suspend_prepare an end if needed
# give suspend_prepare an end if needed
if '
suspend_prepare
' in dm and dm['
suspend_prepare
']['
end
'] < 0:
if '
suspend_prepare
' in dm and dm['
suspend_prepare
']['
end
'] < 0:
...
@@ -2071,7 +2175,7 @@ class FTraceLine:
...
@@ -2071,7 +2175,7 @@ class FTraceLine:
if not self.fevent:
if not self.fevent:
return False
return False
if sysvals.usetracemarkers:
if sysvals.usetracemarkers:
if(self.name
== 'SUSPEND START'
):
if(self.name
.startswith('SUSPEND START')
):
return True
return True
return False
return False
else:
else:
...
@@ -2084,7 +2188,7 @@ class FTraceLine:
...
@@ -2084,7 +2188,7 @@ class FTraceLine:
if not self.fevent:
if not self.fevent:
return False
return False
if sysvals.usetracemarkers:
if sysvals.usetracemarkers:
if(self.name
== 'RESUME COMPLETE'
):
if(self.name
.startswith('RESUME COMPLETE')
):
return True
return True
return False
return False
else:
else:
...
@@ -2444,7 +2548,7 @@ class Timeline:
...
@@ -2444,7 +2548,7 @@ class Timeline:
def createHeader(self, sv, stamp):
def createHeader(self, sv, stamp):
if(not stamp['time']):
if(not stamp['time']):
return
return
self.html += '<div class="
version
"><a href="
https
:
//
01.
org
/
suspendresume
">%s v%s</a></div>'
\
self.html += '<div class="
version
"><a href="
https
:
//
01.
org
/
pm
-
graph
">%s v%s</a></div>'
\
% (sv.title, sv.version)
% (sv.title, sv.version)
if sv.logmsg and sv.testlog:
if sv.logmsg and sv.testlog:
self.html += '<button id="
showtest
" class="
logbtn
btnfmt
">log</button>'
self.html += '<button id="
showtest
" class="
logbtn
btnfmt
">log</button>'
...
@@ -2670,14 +2774,11 @@ class TestProps:
...
@@ -2670,14 +2774,11 @@ class TestProps:
stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+
\
stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+
\
'(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+
\
'(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+
\
' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$'
' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$'
batteryfmt = '^# battery (?P<a1>
\
w*) (?P<c
1
>
\
d*) (?P<
a
2>
\
w*) (?P<c
2
>
\
d*)
'
wififmt = '^# wifi *(?P<d>
\
S*) *(?P<s>
\
S*) *(?P<t>[0-9
\
.]+).*
'
wififmt = '^# wifi (?P<w>.*)'
tstatfmt = '^# turbostat (?P<t>
\
S*)
'
tstatfmt = '^# turbostat (?P<t>
\
S*)
'
mcelogfmt = '^# mcelog (?P<m>
\
S*)
'
testerrfmt = '^# enter_sleep_error (?P<e>.*)'
testerrfmt = '^# enter_sleep_error (?P<e>.*)'
sysinfofmt = '^# sysinfo .*'
sysinfofmt = '^# sysinfo .*'
cmdlinefmt = '^# command
\
| (?P<cmd>.*)
'
cmdlinefmt = '^# command
\
| (?P<cmd>.*)
'
kparamsfmt = '^# kparams
\
| (?P<kp>.*)
'
devpropfmt = '# Device Properties: .*'
devpropfmt = '# Device Properties: .*'
pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)'
pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)'
tracertypefmt = '# tracer: (?P<t>.*)'
tracertypefmt = '# tracer: (?P<t>.*)'
...
@@ -2695,11 +2796,8 @@ class TestProps:
...
@@ -2695,11 +2796,8 @@ class TestProps:
self.stamp = ''
self.stamp = ''
self.sysinfo = ''
self.sysinfo = ''
self.cmdline = ''
self.cmdline = ''
self.kparams = ''
self.testerror = []
self.testerror = []
self.mcelog = []
self.turbostat = []
self.turbostat = []
self.battery = []
self.wifi = []
self.wifi = []
self.fwdata = []
self.fwdata = []
self.ftrace_line_fmt = self.ftrace_line_fmt_nop
self.ftrace_line_fmt = self.ftrace_line_fmt_nop
...
@@ -2721,21 +2819,12 @@ class TestProps:
...
@@ -2721,21 +2819,12 @@ class TestProps:
elif re.match(self.sysinfofmt, line):
elif re.match(self.sysinfofmt, line):
self.sysinfo = line
self.sysinfo = line
return True
return True
elif re.match(self.kparamsfmt, line):
self.kparams = line
return True
elif re.match(self.cmdlinefmt, line):
elif re.match(self.cmdlinefmt, line):
self.cmdline = line
self.cmdline = line
return True
return True
elif re.match(self.mcelogfmt, line):
self.mcelog.append(line)
return True
elif re.match(self.tstatfmt, line):
elif re.match(self.tstatfmt, line):
self.turbostat.append(line)
self.turbostat.append(line)
return True
return True
elif re.match(self.batteryfmt, line):
self.battery.append(line)
return True
elif re.match(self.wififmt, line):
elif re.match(self.wififmt, line):
self.wifi.append(line)
self.wifi.append(line)
return True
return True
...
@@ -2749,6 +2838,8 @@ class TestProps:
...
@@ -2749,6 +2838,8 @@ class TestProps:
def parseStamp(self, data, sv):
def parseStamp(self, data, sv):
# global test data
# global test data
m = re.match(self.stampfmt, self.stamp)
m = re.match(self.stampfmt, self.stamp)
if not self.stamp or not m:
doError('data does not include the expected stamp')
data.stamp = {'time': '', 'host': '', 'mode': ''}
data.stamp = {'time': '', 'host': '', 'mode': ''}
dt = datetime(int(m.group('y'))+2000, int(m.group('m')),
dt = datetime(int(m.group('y'))+2000, int(m.group('m')),
int(m.group('d')), int(m.group('H')), int(m.group('M')),
int(m.group('d')), int(m.group('H')), int(m.group('M')),
...
@@ -2780,10 +2871,6 @@ class TestProps:
...
@@ -2780,10 +2871,6 @@ class TestProps:
m = re.match(self.cmdlinefmt, self.cmdline)
m = re.match(self.cmdlinefmt, self.cmdline)
if m:
if m:
sv.cmdline = m.group('cmd')
sv.cmdline = m.group('cmd')
if self.kparams:
m = re.match(self.kparamsfmt, self.kparams)
if m:
sv.kparams = m.group('kp')
if not sv.stamp:
if not sv.stamp:
sv.stamp = data.stamp
sv.stamp = data.stamp
# firmware data
# firmware data
...
@@ -2793,26 +2880,18 @@ class TestProps:
...
@@ -2793,26 +2880,18 @@ class TestProps:
data.fwSuspend, data.fwResume = int(m.group('s')), int(m.group('r'))
data.fwSuspend, data.fwResume = int(m.group('s')), int(m.group('r'))
if(data.fwSuspend > 0 or data.fwResume > 0):
if(data.fwSuspend > 0 or data.fwResume > 0):
data.fwValid = True
data.fwValid = True
# mcelog data
if len(self.mcelog) > data.testnumber:
m = re.match(self.mcelogfmt, self.mcelog[data.testnumber])
if m:
data.mcelog = sv.b64unzip(m.group('m'))
# turbostat data
# turbostat data
if len(self.turbostat) > data.testnumber:
if len(self.turbostat) > data.testnumber:
m = re.match(self.tstatfmt, self.turbostat[data.testnumber])
m = re.match(self.tstatfmt, self.turbostat[data.testnumber])
if m:
if m:
data.turbostat = m.group('t')
data.turbostat = m.group('t')
# battery data
if len(self.battery) > data.testnumber:
m = re.match(self.batteryfmt, self.battery[data.testnumber])
if m:
data.battery = m.groups()
# wifi data
# wifi data
if len(self.wifi) > data.testnumber:
if len(self.wifi) > data.testnumber:
m = re.match(self.wififmt, self.wifi[data.testnumber])
m = re.match(self.wififmt, self.wifi[data.testnumber])
if m:
if m:
data.wifi = m.group('w')
data.wifi = {'dev': m.group('d'), 'stat': m.group('s'),
'time': float(m.group('t'))}
data.stamp['wifi'] = m.group('d')
# sleep mode enter errors
# sleep mode enter errors
if len(self.testerror) > data.testnumber:
if len(self.testerror) > data.testnumber:
m = re.match(self.testerrfmt, self.testerror[data.testnumber])
m = re.match(self.testerrfmt, self.testerror[data.testnumber])
...
@@ -3012,13 +3091,13 @@ def appendIncompleteTraceLog(testruns):
...
@@ -3012,13 +3091,13 @@ def appendIncompleteTraceLog(testruns):
if(t.startMarker()):
if(t.startMarker()):
data = testrun[testidx].data
data = testrun[testidx].data
tp.parseStamp(data, sysvals)
tp.parseStamp(data, sysvals)
data.setStart(t.time)
data.setStart(t.time
, t.name
)
continue
continue
if(not data):
if(not data):
continue
continue
# find the end of resume
# find the end of resume
if(t.endMarker()):
if(t.endMarker()):
data.setEnd(t.time)
data.setEnd(t.time
, t.name
)
testidx += 1
testidx += 1
if(testidx >= testcnt):
if(testidx >= testcnt):
break
break
...
@@ -3081,7 +3160,7 @@ def parseTraceLog(live=False):
...
@@ -3081,7 +3160,7 @@ def parseTraceLog(live=False):
doError('%s does not exist' % sysvals.ftracefile)
doError('%s does not exist' % sysvals.ftracefile)
if not live:
if not live:
sysvals.setupAllKprobes()
sysvals.setupAllKprobes()
ksuscalls = ['pm_prepare_console']
ksuscalls = ['
ksys_sync', '
pm_prepare_console']
krescalls = ['pm_restore_console']
krescalls = ['pm_restore_console']
tracewatch = ['irq_wakeup']
tracewatch = ['irq_wakeup']
if sysvals.usekprobes:
if sysvals.usekprobes:
...
@@ -3094,7 +3173,7 @@ def parseTraceLog(live=False):
...
@@ -3094,7 +3173,7 @@ def parseTraceLog(live=False):
testruns = []
testruns = []
testdata = []
testdata = []
testrun = 0
testrun = 0
data
= 0
data
, limbo = 0, True
tf = sysvals.openlog(sysvals.ftracefile, 'r')
tf = sysvals.openlog(sysvals.ftracefile, 'r')
phase = 'suspend_prepare'
phase = 'suspend_prepare'
for line in tf:
for line in tf:
...
@@ -3141,16 +3220,16 @@ def parseTraceLog(live=False):
...
@@ -3141,16 +3220,16 @@ def parseTraceLog(live=False):
continue
continue
# find the start of suspend
# find the start of suspend
if(t.startMarker()):
if(t.startMarker()):
data
= Data(len(testdata))
data
, limbo = Data(len(testdata)), False
testdata.append(data)
testdata.append(data)
testrun = TestRun(data)
testrun = TestRun(data)
testruns.append(testrun)
testruns.append(testrun)
tp.parseStamp(data, sysvals)
tp.parseStamp(data, sysvals)
data.setStart(t.time)
data.setStart(t.time
, t.name
)
data.first_suspend_prepare = True
data.first_suspend_prepare = True
phase = data.setPhase('suspend_prepare', t.time, True)
phase = data.setPhase('suspend_prepare', t.time, True)
continue
continue
if(not data):
if(not data
or limbo
):
continue
continue
# process cpu exec line
# process cpu exec line
if t.type == 'tracing_mark_write':
if t.type == 'tracing_mark_write':
...
@@ -3167,14 +3246,16 @@ def parseTraceLog(live=False):
...
@@ -3167,14 +3246,16 @@ def parseTraceLog(live=False):
continue
continue
# find the end of resume
# find the end of resume
if(t.endMarker()):
if(t.endMarker()):
data.handleEndMarker(t.time)
if data.tKernRes == 0:
data.tKernRes = t.time
data.handleEndMarker(t.time, t.name)
if(not sysvals.usetracemarkers):
if(not sysvals.usetracemarkers):
# no trace markers? then quit and be sure to finish recording
# no trace markers? then quit and be sure to finish recording
# the event we used to trigger resume end
# the event we used to trigger resume end
if('thaw_processes' in testrun.ttemp and len(testrun.ttemp['thaw_processes']) > 0):
if('thaw_processes' in testrun.ttemp and len(testrun.ttemp['thaw_processes']) > 0):
# if an entry exists, assume this is its end
# if an entry exists, assume this is its end
testrun.ttemp['thaw_processes'][-1]['end'] = t.time
testrun.ttemp['thaw_processes'][-1]['end'] = t.time
break
limbo = True
continue
continue
# trace event processing
# trace event processing
if(t.fevent):
if(t.fevent):
...
@@ -3197,7 +3278,7 @@ def parseTraceLog(live=False):
...
@@ -3197,7 +3278,7 @@ def parseTraceLog(live=False):
# -- phase changes --
# -- phase changes --
# start of kernel suspend
# start of kernel suspend
if(re.match('suspend_enter
\
[.*
'
, t.name)):
if(re.match('suspend_enter
\
[.*
'
, t.name)):
if(isbegin):
if(isbegin
and data.tKernSus == 0
):
data.tKernSus = t.time
data.tKernSus = t.time
continue
continue
# suspend_prepare start
# suspend_prepare start
...
@@ -3225,7 +3306,7 @@ def parseTraceLog(live=False):
...
@@ -3225,7 +3306,7 @@ def parseTraceLog(live=False):
elif(re.match('machine_suspend
\
[.*
'
, t.name)):
elif(re.match('machine_suspend
\
[.*
'
, t.name)):
if(isbegin):
if(isbegin):
lp = data.lastPhase()
lp = data.lastPhase()
if lp
== 'resume_machine'
:
if lp
.startswith('resume_machine')
:
data.dmesg[lp]['end'] = t.time
data.dmesg[lp]['end'] = t.time
phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True)
phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True)
data.setPhase(phase, t.time, False)
data.setPhase(phase, t.time, False)
...
@@ -3320,7 +3401,8 @@ def parseTraceLog(live=False):
...
@@ -3320,7 +3401,8 @@ def parseTraceLog(live=False):
'proc': m_proc,
'proc': m_proc,
})
})
# start of kernel resume
# start of kernel resume
if(phase == 'suspend_prepare' and kprobename in ksuscalls):
if(data.tKernSus == 0 and phase == 'suspend_prepare'
\
and kprobename in ksuscalls):
data.tKernSus = t.time
data.tKernSus = t.time
elif(t.freturn):
elif(t.freturn):
if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1:
if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1:
...
@@ -3355,7 +3437,7 @@ def parseTraceLog(live=False):
...
@@ -3355,7 +3437,7 @@ def parseTraceLog(live=False):
sysvals.vprint('WARNING: ftrace start marker is missing')
sysvals.vprint('WARNING: ftrace start marker is missing')
if data and not data.devicegroups:
if data and not data.devicegroups:
sysvals.vprint('WARNING: ftrace end marker is missing')
sysvals.vprint('WARNING: ftrace end marker is missing')
data.handleEndMarker(t.time)
data.handleEndMarker(t.time
, t.name
)
if sysvals.suspendmode == 'command':
if sysvals.suspendmode == 'command':
for test in testruns:
for test in testruns:
...
@@ -3476,6 +3558,10 @@ def parseTraceLog(live=False):
...
@@ -3476,6 +3558,10 @@ def parseTraceLog(live=False):
data.fwValid = False
data.fwValid = False
sysvals.vprint('WARNING: phase "
%
s
" is missing!' % p)
sysvals.vprint('WARNING: phase "
%
s
" is missing!' % p)
lp = p
lp = p
if not terr and 'dev' in data.wifi and data.wifi['stat'] == 'timeout':
terr = '%s%s failed in wifi_resume <i>(%s %.0fs timeout)</i>' %
\
(sysvals.suspendmode, tn, data.wifi['dev'], data.wifi['time'])
error.append(terr)
if not terr and data.enterfail:
if not terr and data.enterfail:
pprint('test%s FAILED: enter %s failed with %s' % (tn, sysvals.suspendmode, data.enterfail))
pprint('test%s FAILED: enter %s failed with %s' % (tn, sysvals.suspendmode, data.enterfail))
terr = 'test%s failed to enter %s mode' % (tn, sysvals.suspendmode)
terr = 'test%s failed to enter %s mode' % (tn, sysvals.suspendmode)
...
@@ -3933,7 +4019,7 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
...
@@ -3933,7 +4019,7 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()]
tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()]
iMin, iMed, iMax = [0, 0], [0, 0], [0, 0]
iMin, iMed, iMax = [0, 0], [0, 0], [0, 0]
num = 0
num = 0
useturbo = False
useturbo =
usewifi =
False
lastmode = ''
lastmode = ''
cnt = dict()
cnt = dict()
for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])):
for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])):
...
@@ -3952,17 +4038,17 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
...
@@ -3952,17 +4038,17 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()]
tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()]
iMin, iMed, iMax = [0, 0], [0, 0], [0, 0]
iMin, iMed, iMax = [0, 0], [0, 0], [0, 0]
num = 0
num = 0
pkgpc10 = syslpi = ''
pkgpc10 = syslpi =
wifi =
''
if 'pkgpc10' in data and 'syslpi' in data:
if 'pkgpc10' in data and 'syslpi' in data:
pkgpc10
= data['pkgpc10']
pkgpc10
, syslpi, useturbo = data['pkgpc10'], data['syslpi'], True
syslpi = data['syslpi']
if 'wifi' in data:
useturbo =
True
wifi, usewifi = data['wifi'],
True
res = data['result']
res = data['result']
tVal = [float(data['suspend']), float(data['resume'])]
tVal = [float(data['suspend']), float(data['resume'])]
list[mode]['data'].append([data['host'], data['kernel'],
list[mode]['data'].append([data['host'], data['kernel'],
data['time'], tVal[0], tVal[1], data['url'], res,
data['time'], tVal[0], tVal[1], data['url'], res,
data['issues'], data['sus_worst'], data['sus_worsttime'],
data['issues'], data['sus_worst'], data['sus_worsttime'],
data['res_worst'], data['res_worsttime'], pkgpc10, syslpi])
data['res_worst'], data['res_worsttime'], pkgpc10, syslpi
, wifi
])
idx = len(list[mode]['data']) - 1
idx = len(list[mode]['data']) - 1
if res.startswith('fail in'):
if res.startswith('fail in'):
res = 'fail'
res = 'fail'
...
@@ -4002,7 +4088,12 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
...
@@ -4002,7 +4088,12 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
td = '
\
t
<td>{0}</td>
\
n
'
td = '
\
t
<td>{0}</td>
\
n
'
tdh = '
\
t
<td{1}>{0}</td>
\
n
'
tdh = '
\
t
<td{1}>{0}</td>
\
n
'
tdlink = '
\
t
<td><a href="
{
0
}
">html</a></td>
\
n
'
tdlink = '
\
t
<td><a href="
{
0
}
">html</a></td>
\
n
'
colspan = '14' if useturbo else '12'
cols = 12
if useturbo:
cols += 2
if usewifi:
cols += 1
colspan = '%d' % cols
# table header
# table header
html += '<table>
\
n
<tr>
\
n
' + th.format('#') +
\
html += '<table>
\
n
<tr>
\
n
' + th.format('#') +
\
...
@@ -4013,6 +4104,8 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
...
@@ -4013,6 +4104,8 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
th.format('Worst Resume Device') + th.format('RD Time')
th.format('Worst Resume Device') + th.format('RD Time')
if useturbo:
if useturbo:
html += th.format('PkgPC10') + th.format('SysLPI')
html += th.format('PkgPC10') + th.format('SysLPI')
if usewifi:
html += th.format('Wifi')
html += th.format('Detail')+'</tr>
\
n
'
html += th.format('Detail')+'</tr>
\
n
'
# export list into html
# export list into html
head = '<tr class="
head
"><td>{0}</td><td>{1}</td>'+
\
head = '<tr class="
head
"><td>{0}</td><td>{1}</td>'+
\
...
@@ -4076,6 +4169,8 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
...
@@ -4076,6 +4169,8 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
if
useturbo
:
if
useturbo
:
html
+=
td
.
format
(
d
[
12
])
# pkg_pc10
html
+=
td
.
format
(
d
[
12
])
# pkg_pc10
html
+=
td
.
format
(
d
[
13
])
# syslpi
html
+=
td
.
format
(
d
[
13
])
# syslpi
if
usewifi
:
html
+=
td
.
format
(
d
[
14
])
# wifi
html
+=
tdlink
.
format
(
d
[
5
])
if
d
[
5
]
else
td
.
format
(
''
)
# url
html
+=
tdlink
.
format
(
d
[
5
])
if
d
[
5
]
else
td
.
format
(
''
)
# url
html
+=
'</tr>
\
n
'
html
+=
'</tr>
\
n
'
num
+=
1
num
+=
1
...
@@ -4224,6 +4319,8 @@ def createHTML(testruns, testfail):
...
@@ -4224,6 +4319,8 @@ def createHTML(testruns, testfail):
kerror
=
True
kerror
=
True
if
(
sysvals
.
suspendmode
in
[
'freeze'
,
'standby'
]):
if
(
sysvals
.
suspendmode
in
[
'freeze'
,
'standby'
]):
data
.
trimFreezeTime
(
testruns
[
-
1
].
tSuspended
)
data
.
trimFreezeTime
(
testruns
[
-
1
].
tSuspended
)
else
:
data
.
getMemTime
()
# html function templates
# html function templates
html_error
=
'<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">{2}→</div>
\
n
'
html_error
=
'<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">{2}→</div>
\
n
'
...
@@ -4242,13 +4339,10 @@ def createHTML(testruns, testfail):
...
@@ -4242,13 +4339,10 @@ def createHTML(testruns, testfail):
'<td class="green">Execution Time: <b>{0} ms</b></td>'
\
'<td class="green">Execution Time: <b>{0} ms</b></td>'
\
'<td class="yellow">Command: <b>{1}</b></td>'
\
'<td class="yellow">Command: <b>{1}</b></td>'
\
'</tr>
\
n
</table>
\
n
'
'</tr>
\
n
</table>
\
n
'
html_timegroups
=
'<table class="time2">
\
n
<tr>'
\
'<td class="green" title="time from kernel enter_state({5}) to firmware mode [kernel time only]">{4}Kernel Suspend: {0} ms</td>'
\
'<td class="purple">{4}Firmware Suspend: {1} ms</td>'
\
'<td class="purple">{4}Firmware Resume: {2} ms</td>'
\
'<td class="yellow" title="time from firmware mode to return from kernel enter_state({5}) [kernel time only]">{4}Kernel Resume: {3} ms</td>'
\
'</tr>
\
n
</table>
\
n
'
html_fail
=
'<table class="testfail"><tr><td>{0}</td></tr></table>
\
n
'
html_fail
=
'<table class="testfail"><tr><td>{0}</td></tr></table>
\
n
'
html_kdesc
=
'<td class="{3}" title="time spent in kernel execution">{0}Kernel {2}: {1} ms</td>'
html_fwdesc
=
'<td class="{3}" title="time spent in firmware">{0}Firmware {2}: {1} ms</td>'
html_wifdesc
=
'<td class="yellow" title="time for wifi to reconnect after resume complete ({2})">{0}Wifi Resume: {1}</td>'
# html format variables
# html format variables
scaleH
=
20
scaleH
=
20
...
@@ -4264,13 +4358,10 @@ def createHTML(testruns, testfail):
...
@@ -4264,13 +4358,10 @@ def createHTML(testruns, testfail):
# Generate the header for this timeline
# Generate the header for this timeline
for
data
in
testruns
:
for
data
in
testruns
:
tTotal
=
data
.
end
-
data
.
start
tTotal
=
data
.
end
-
data
.
start
sktime
,
rktime
=
data
.
getTimeValues
()
if
(
tTotal
==
0
):
if
(
tTotal
==
0
):
doError
(
'No timeline data'
)
doError
(
'No timeline data'
)
if
(
len
(
data
.
tLow
)
>
0
):
low_time
=
'+'
.
join
(
data
.
tLow
)
if
sysvals
.
suspendmode
==
'command'
:
if
sysvals
.
suspendmode
==
'command'
:
run_time
=
'%.0f'
%
((
data
.
end
-
data
.
start
)
*
1000
)
run_time
=
'%.0f'
%
(
tTotal
*
1000
)
if
sysvals
.
testcommand
:
if
sysvals
.
testcommand
:
testdesc
=
sysvals
.
testcommand
testdesc
=
sysvals
.
testcommand
else
:
else
:
...
@@ -4279,43 +4370,55 @@ def createHTML(testruns, testfail):
...
@@ -4279,43 +4370,55 @@ def createHTML(testruns, testfail):
testdesc
=
ordinal
(
data
.
testnumber
+
1
)
+
' '
+
testdesc
testdesc
=
ordinal
(
data
.
testnumber
+
1
)
+
' '
+
testdesc
thtml
=
html_timetotal3
.
format
(
run_time
,
testdesc
)
thtml
=
html_timetotal3
.
format
(
run_time
,
testdesc
)
devtl
.
html
+=
thtml
devtl
.
html
+=
thtml
elif
data
.
fwValid
:
continue
suspend_time
=
'%.0f'
%
(
sktime
+
(
data
.
fwSuspend
/
1000000.0
))
# typical full suspend/resume header
resume_time
=
'%.0f'
%
(
rktime
+
(
data
.
fwResume
/
1000000.0
))
stot
,
rtot
=
sktime
,
rktime
=
data
.
getTimeValues
()
testdesc1
=
'Total'
ssrc
,
rsrc
,
testdesc
,
testdesc2
=
[
'kernel'
],
[
'kernel'
],
'Kernel'
,
''
testdesc2
=
''
if
data
.
fwValid
:
stitle
=
'time from kernel enter_state(%s) to low-power mode [kernel & firmware time]'
%
sysvals
.
suspendmode
stot
+=
(
data
.
fwSuspend
/
1000000.0
)
rtitle
=
'time from low-power mode to return from kernel enter_state(%s) [firmware & kernel time]'
%
sysvals
.
suspendmode
rtot
+=
(
data
.
fwResume
/
1000000.0
)
ssrc
.
append
(
'firmware'
)
rsrc
.
append
(
'firmware'
)
testdesc
=
'Total'
if
'time'
in
data
.
wifi
and
data
.
wifi
[
'stat'
]
!=
'timeout'
:
rtot
+=
data
.
end
-
data
.
tKernRes
+
(
data
.
wifi
[
'time'
]
*
1000.0
)
rsrc
.
append
(
'wifi'
)
testdesc
=
'Total'
suspend_time
,
resume_time
=
'%.3f'
%
stot
,
'%.3f'
%
rtot
stitle
=
'time from kernel suspend start to %s mode [%s time]'
%
\
(
sysvals
.
suspendmode
,
' & '
.
join
(
ssrc
))
rtitle
=
'time from %s mode to kernel resume complete [%s time]'
%
\
(
sysvals
.
suspendmode
,
' & '
.
join
(
rsrc
))
if
(
len
(
testruns
)
>
1
):
if
(
len
(
testruns
)
>
1
):
testdesc1
=
testdesc2
=
ordinal
(
data
.
testnumber
+
1
)
testdesc
=
testdesc2
=
ordinal
(
data
.
testnumber
+
1
)
testdesc2
+=
' '
testdesc2
+=
' '
if
(
len
(
data
.
tLow
)
==
0
):
if
(
len
(
data
.
tLow
)
==
0
):
thtml
=
html_timetotal
.
format
(
suspend_time
,
\
thtml
=
html_timetotal
.
format
(
suspend_time
,
\
resume_time
,
testdesc1
,
stitle
,
rtitle
)
resume_time
,
testdesc
,
stitle
,
rtitle
)
else
:
else
:
low_time
=
'+'
.
join
(
data
.
tLow
)
thtml
=
html_timetotal2
.
format
(
suspend_time
,
low_time
,
\
thtml
=
html_timetotal2
.
format
(
suspend_time
,
low_time
,
\
resume_time
,
testdesc1
,
stitle
,
rtitle
)
resume_time
,
testdesc
,
stitle
,
rtitle
)
devtl
.
html
+=
thtml
devtl
.
html
+=
thtml
if
not
data
.
fwValid
and
'dev'
not
in
data
.
wifi
:
continue
# extra detail when the times come from multiple sources
thtml
=
'<table class="time2">
\
n
<tr>'
thtml
+=
html_kdesc
.
format
(
testdesc2
,
'%.3f'
%
sktime
,
'Suspend'
,
'green'
)
if
data
.
fwValid
:
sftime
=
'%.3f'
%
(
data
.
fwSuspend
/
1000000.0
)
sftime
=
'%.3f'
%
(
data
.
fwSuspend
/
1000000.0
)
rftime
=
'%.3f'
%
(
data
.
fwResume
/
1000000.0
)
rftime
=
'%.3f'
%
(
data
.
fwResume
/
1000000.0
)
devtl
.
html
+=
html_timegroups
.
format
(
'%.3f'
%
sktime
,
\
thtml
+=
html_fwdesc
.
format
(
testdesc2
,
sftime
,
'Suspend'
,
'green'
)
sftime
,
rftime
,
'%.3f'
%
rktime
,
testdesc2
,
sysvals
.
suspendmode
)
thtml
+=
html_fwdesc
.
format
(
testdesc2
,
rftime
,
'Resume'
,
'yellow'
)
else
:
thtml
+=
html_kdesc
.
format
(
testdesc2
,
'%.3f'
%
rktime
,
'Resume'
,
'yellow'
)
suspend_time
=
'%.3f'
%
sktime
if
'time'
in
data
.
wifi
:
resume_time
=
'%.3f'
%
rktime
if
data
.
wifi
[
'stat'
]
!=
'timeout'
:
testdesc
=
'Kernel'
wtime
=
'%.0f ms'
%
(
data
.
end
-
data
.
tKernRes
+
(
data
.
wifi
[
'time'
]
*
1000.0
))
stitle
=
'time from kernel enter_state(%s) to firmware mode [kernel time only]'
%
sysvals
.
suspendmode
rtitle
=
'time from firmware mode to return from kernel enter_state(%s) [kernel time only]'
%
sysvals
.
suspendmode
if
(
len
(
testruns
)
>
1
):
testdesc
=
ordinal
(
data
.
testnumber
+
1
)
+
' '
+
testdesc
if
(
len
(
data
.
tLow
)
==
0
):
thtml
=
html_timetotal
.
format
(
suspend_time
,
\
resume_time
,
testdesc
,
stitle
,
rtitle
)
else
:
else
:
thtml
=
html_timetotal2
.
format
(
suspend_time
,
low_time
,
\
wtime
=
'TIMEOUT'
resume_time
,
testdesc
,
stitle
,
rtitle
)
thtml
+=
html_wifdesc
.
format
(
testdesc2
,
wtime
,
data
.
wifi
[
'dev'
])
thtml
+=
'</tr>
\
n
</table>
\
n
'
devtl
.
html
+=
thtml
devtl
.
html
+=
thtml
if
testfail
:
if
testfail
:
devtl
.
html
+=
html_fail
.
format
(
testfail
)
devtl
.
html
+=
html_fail
.
format
(
testfail
)
...
@@ -5082,28 +5185,32 @@ def setRuntimeSuspend(before=True):
...
@@ -5082,28 +5185,32 @@ def setRuntimeSuspend(before=True):
# Description:
# Description:
# Execute system suspend through the sysfs interface, then copy the output
# Execute system suspend through the sysfs interface, then copy the output
# dmesg and ftrace files to the test output directory.
# dmesg and ftrace files to the test output directory.
def
executeSuspend
():
def
executeSuspend
(
quiet
=
False
):
pm
=
ProcessMonitor
()
pm
=
ProcessMonitor
()
tp
=
sysvals
.
tpath
tp
=
sysvals
.
tpath
if
sysvals
.
wifi
:
wifi
=
sysvals
.
checkWifi
()
wifi
=
sysvals
.
checkWifi
()
testdata
=
[]
testdata
=
[]
battery
=
True
if
getBattery
()
else
False
# run these commands to prepare the system for suspend
# run these commands to prepare the system for suspend
if
sysvals
.
display
:
if
sysvals
.
display
:
if
not
quiet
:
pprint
(
'SET DISPLAY TO %s'
%
sysvals
.
display
.
upper
())
pprint
(
'SET DISPLAY TO %s'
%
sysvals
.
display
.
upper
())
displayControl
(
sysvals
.
display
)
displayControl
(
sysvals
.
display
)
time
.
sleep
(
1
)
time
.
sleep
(
1
)
if
sysvals
.
sync
:
if
sysvals
.
sync
:
if
not
quiet
:
pprint
(
'SYNCING FILESYSTEMS'
)
pprint
(
'SYNCING FILESYSTEMS'
)
call
(
'sync'
,
shell
=
True
)
call
(
'sync'
,
shell
=
True
)
# mark the start point in the kernel ring buffer just as we start
# mark the start point in the kernel ring buffer just as we start
sysvals
.
initdmesg
()
sysvals
.
initdmesg
()
# start ftrace
# start ftrace
if
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
):
if
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
):
if
not
quiet
:
pprint
(
'START TRACING'
)
pprint
(
'START TRACING'
)
sysvals
.
fsetVal
(
'1'
,
'tracing_on'
)
sysvals
.
fsetVal
(
'1'
,
'tracing_on'
)
if
sysvals
.
useprocmon
:
if
sysvals
.
useprocmon
:
pm
.
start
()
pm
.
start
()
sysvals
.
cmdinfo
(
True
)
# execute however many s/r runs requested
# execute however many s/r runs requested
for
count
in
range
(
1
,
sysvals
.
execcount
+
1
):
for
count
in
range
(
1
,
sysvals
.
execcount
+
1
):
# x2delay in between test runs
# x2delay in between test runs
...
@@ -5119,15 +5226,14 @@ def executeSuspend():
...
@@ -5119,15 +5226,14 @@ def executeSuspend():
pprint
(
'SUSPEND START'
)
pprint
(
'SUSPEND START'
)
else
:
else
:
pprint
(
'SUSPEND START (press a key to resume)'
)
pprint
(
'SUSPEND START (press a key to resume)'
)
sysvals
.
mcelog
(
True
)
bat1
=
getBattery
()
if
battery
else
False
# set rtcwake
# set rtcwake
if
(
sysvals
.
rtcwake
):
if
(
sysvals
.
rtcwake
):
if
not
quiet
:
pprint
(
'will issue an rtcwake in %d seconds'
%
sysvals
.
rtcwaketime
)
pprint
(
'will issue an rtcwake in %d seconds'
%
sysvals
.
rtcwaketime
)
sysvals
.
rtcWakeAlarmOn
()
sysvals
.
rtcWakeAlarmOn
()
# start of suspend trace marker
# start of suspend trace marker
if
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
):
if
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
):
sysvals
.
fsetVal
(
'SUSPEND START'
,
'trace_marker'
)
sysvals
.
fsetVal
(
datetime
.
now
().
strftime
(
sysvals
.
tmstart
)
,
'trace_marker'
)
# predelay delay
# predelay delay
if
(
count
==
1
and
sysvals
.
predelay
>
0
):
if
(
count
==
1
and
sysvals
.
predelay
>
0
):
sysvals
.
fsetVal
(
'WAIT %d'
%
sysvals
.
predelay
,
'trace_marker'
)
sysvals
.
fsetVal
(
'WAIT %d'
%
sysvals
.
predelay
,
'trace_marker'
)
...
@@ -5174,28 +5280,25 @@ def executeSuspend():
...
@@ -5174,28 +5280,25 @@ def executeSuspend():
# return from suspend
# return from suspend
pprint
(
'RESUME COMPLETE'
)
pprint
(
'RESUME COMPLETE'
)
if
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
):
if
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
):
sysvals
.
fsetVal
(
'RESUME COMPLETE'
,
'trace_marker'
)
sysvals
.
fsetVal
(
datetime
.
now
().
strftime
(
sysvals
.
tmend
),
'trace_marker'
)
if
sysvals
.
wifi
and
wifi
:
tdata
[
'wifi'
]
=
sysvals
.
pollWifi
(
wifi
)
if
(
sysvals
.
suspendmode
==
'mem'
or
sysvals
.
suspendmode
==
'command'
):
if
(
sysvals
.
suspendmode
==
'mem'
or
sysvals
.
suspendmode
==
'command'
):
tdata
[
'fw'
]
=
getFPDT
(
False
)
tdata
[
'fw'
]
=
getFPDT
(
False
)
mcelog
=
sysvals
.
mcelog
()
if
mcelog
:
tdata
[
'mcelog'
]
=
mcelog
bat2
=
getBattery
()
if
battery
else
False
if
battery
and
bat1
and
bat2
:
tdata
[
'bat'
]
=
(
bat1
,
bat2
)
if
'device'
in
wifi
and
'ip'
in
wifi
:
tdata
[
'wifi'
]
=
(
wifi
,
sysvals
.
checkWifi
())
testdata
.
append
(
tdata
)
testdata
.
append
(
tdata
)
cmdafter
=
sysvals
.
cmdinfo
(
False
)
# stop ftrace
# stop ftrace
if
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
):
if
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
):
if
sysvals
.
useprocmon
:
if
sysvals
.
useprocmon
:
pm
.
stop
()
pm
.
stop
()
sysvals
.
fsetVal
(
'0'
,
'tracing_on'
)
sysvals
.
fsetVal
(
'0'
,
'tracing_on'
)
# grab a copy of the dmesg output
# grab a copy of the dmesg output
if
not
quiet
:
pprint
(
'CAPTURING DMESG'
)
pprint
(
'CAPTURING DMESG'
)
sysvals
.
getdmesg
(
testdata
)
sysvals
.
getdmesg
(
testdata
)
# grab a copy of the ftrace output
# grab a copy of the ftrace output
if
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
):
if
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
):
if
not
quiet
:
pprint
(
'CAPTURING TRACE'
)
pprint
(
'CAPTURING TRACE'
)
op
=
sysvals
.
writeDatafileHeader
(
sysvals
.
ftracefile
,
testdata
)
op
=
sysvals
.
writeDatafileHeader
(
sysvals
.
ftracefile
,
testdata
)
fp
=
open
(
tp
+
'trace'
,
'r'
)
fp
=
open
(
tp
+
'trace'
,
'r'
)
...
@@ -5203,8 +5306,7 @@ def executeSuspend():
...
@@ -5203,8 +5306,7 @@ def executeSuspend():
op
.
write
(
line
)
op
.
write
(
line
)
op
.
close
()
op
.
close
()
sysvals
.
fsetVal
(
''
,
'trace'
)
sysvals
.
fsetVal
(
''
,
'trace'
)
sysvals
.
platforminfo
()
sysvals
.
platforminfo
(
cmdafter
)
return
testdata
def
readFile
(
file
):
def
readFile
(
file
):
if
os
.
path
.
islink
(
file
):
if
os
.
path
.
islink
(
file
):
...
@@ -5447,25 +5549,6 @@ def dmidecode(mempath, fatal=False):
...
@@ -5447,25 +5549,6 @@ def dmidecode(mempath, fatal=False):
count
+=
1
count
+=
1
return
out
return
out
def
getBattery
():
p
,
charge
,
bat
=
'/sys/class/power_supply'
,
0
,
{}
if
not
os
.
path
.
exists
(
p
):
return
False
for
d
in
os
.
listdir
(
p
):
type
=
sysvals
.
getVal
(
os
.
path
.
join
(
p
,
d
,
'type'
)).
strip
().
lower
()
if
type
!=
'battery'
:
continue
for
v
in
[
'status'
,
'energy_now'
,
'capacity_now'
]:
bat
[
v
]
=
sysvals
.
getVal
(
os
.
path
.
join
(
p
,
d
,
v
)).
strip
().
lower
()
break
if
'status'
not
in
bat
:
return
False
ac
=
False
if
'discharging'
in
bat
[
'status'
]
else
True
for
v
in
[
'energy_now'
,
'capacity_now'
]:
if
v
in
bat
and
bat
[
v
]:
charge
=
int
(
bat
[
v
])
return
(
ac
,
charge
)
def
displayControl
(
cmd
):
def
displayControl
(
cmd
):
xset
,
ret
=
'timeout 10 xset -d :0.0 {0}'
,
0
xset
,
ret
=
'timeout 10 xset -d :0.0 {0}'
,
0
if
sysvals
.
sudouser
:
if
sysvals
.
sudouser
:
...
@@ -5715,6 +5798,17 @@ def statusCheck(probecheck=False):
...
@@ -5715,6 +5798,17 @@ def statusCheck(probecheck=False):
status
=
'rtcwake is not properly supported'
status
=
'rtcwake is not properly supported'
pprint
(
' is rtcwake supported: %s'
%
res
)
pprint
(
' is rtcwake supported: %s'
%
res
)
# check info commands
pprint
(
' optional commands this tool may use for info:'
)
no
=
sysvals
.
colorText
(
'MISSING'
)
yes
=
sysvals
.
colorText
(
'FOUND'
,
32
)
for
c
in
[
'turbostat'
,
'mcelog'
,
'lspci'
,
'lsusb'
]:
if
c
==
'turbostat'
:
res
=
yes
if
sysvals
.
haveTurbostat
()
else
no
else
:
res
=
yes
if
sysvals
.
getExec
(
c
)
else
no
pprint
(
' %s: %s'
%
(
c
,
res
))
if
not
probecheck
:
if
not
probecheck
:
return
status
return
status
...
@@ -5780,7 +5874,8 @@ def getArgFloat(name, args, min, max, main=True):
...
@@ -5780,7 +5874,8 @@ def getArgFloat(name, args, min, max, main=True):
doError
(
name
+
': value should be between %f and %f'
%
(
min
,
max
),
True
)
doError
(
name
+
': value should be between %f and %f'
%
(
min
,
max
),
True
)
return
val
return
val
def
processData
(
live
=
False
):
def
processData
(
live
=
False
,
quiet
=
False
):
if
not
quiet
:
pprint
(
'PROCESSING DATA'
)
pprint
(
'PROCESSING DATA'
)
sysvals
.
vprint
(
'usetraceevents=%s, usetracemarkers=%s, usekprobes=%s'
%
\
sysvals
.
vprint
(
'usetraceevents=%s, usetracemarkers=%s, usekprobes=%s'
%
\
(
sysvals
.
usetraceevents
,
sysvals
.
usetracemarkers
,
sysvals
.
usekprobes
))
(
sysvals
.
usetraceevents
,
sysvals
.
usetracemarkers
,
sysvals
.
usekprobes
))
...
@@ -5796,20 +5891,17 @@ def processData(live=False):
...
@@ -5796,20 +5891,17 @@ def processData(live=False):
parseKernelLog
(
data
)
parseKernelLog
(
data
)
if
(
sysvals
.
ftracefile
and
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
)):
if
(
sysvals
.
ftracefile
and
(
sysvals
.
usecallgraph
or
sysvals
.
usetraceevents
)):
appendIncompleteTraceLog
(
testruns
)
appendIncompleteTraceLog
(
testruns
)
if
not
sysvals
.
stamp
:
pprint
(
'ERROR: data does not include the expected stamp'
)
return
(
testruns
,
{
'error'
:
'timeline generation failed'
})
shown
=
[
'bios'
,
'biosdate'
,
'cpu'
,
'host'
,
'kernel'
,
'man'
,
'memfr'
,
shown
=
[
'bios'
,
'biosdate'
,
'cpu'
,
'host'
,
'kernel'
,
'man'
,
'memfr'
,
'memsz'
,
'mode'
,
'numcpu'
,
'plat'
,
'time'
]
'memsz'
,
'mode'
,
'numcpu'
,
'plat'
,
'time'
,
'wifi'
]
sysvals
.
vprint
(
'System Info:'
)
sysvals
.
vprint
(
'System Info:'
)
for
key
in
sorted
(
sysvals
.
stamp
):
for
key
in
sorted
(
sysvals
.
stamp
):
if
key
in
shown
:
if
key
in
shown
:
sysvals
.
vprint
(
' %-8s : %s'
%
(
key
.
upper
(),
sysvals
.
stamp
[
key
]))
sysvals
.
vprint
(
' %-8s : %s'
%
(
key
.
upper
(),
sysvals
.
stamp
[
key
]))
if
sysvals
.
kparams
:
sysvals
.
vprint
(
'Kparams:
\
n
%s'
%
sysvals
.
kparams
)
sysvals
.
vprint
(
'Command:
\
n
%s'
%
sysvals
.
cmdline
)
sysvals
.
vprint
(
'Command:
\
n
%s'
%
sysvals
.
cmdline
)
for
data
in
testruns
:
for
data
in
testruns
:
if
data
.
mcelog
:
sysvals
.
vprint
(
'MCELOG Data:'
)
for
line
in
data
.
mcelog
.
split
(
'
\
n
'
):
sysvals
.
vprint
(
' %s'
%
line
)
if
data
.
turbostat
:
if
data
.
turbostat
:
idx
,
s
=
0
,
'Turbostat:
\
n
'
idx
,
s
=
0
,
'Turbostat:
\
n
'
for
val
in
data
.
turbostat
.
split
(
'|'
):
for
val
in
data
.
turbostat
.
split
(
'|'
):
...
@@ -5819,21 +5911,11 @@ def processData(live=False):
...
@@ -5819,21 +5911,11 @@ def processData(live=False):
s
+=
'
\
n
'
s
+=
'
\
n
'
s
+=
val
+
' '
s
+=
val
+
' '
sysvals
.
vprint
(
s
)
sysvals
.
vprint
(
s
)
if
data
.
battery
:
a1
,
c1
,
a2
,
c2
=
data
.
battery
s
=
'Battery:
\
n
Before - AC: %s, Charge: %d
\
n
After - AC: %s, Charge: %d'
%
\
(
a1
,
int
(
c1
),
a2
,
int
(
c2
))
sysvals
.
vprint
(
s
)
if
data
.
wifi
:
w
=
data
.
wifi
.
replace
(
'|'
,
' '
).
split
(
','
)
s
=
'Wifi:
\
n
Before %s
\
n
After %s'
%
\
(
w
[
0
],
w
[
1
])
sysvals
.
vprint
(
s
)
data
.
printDetails
()
data
.
printDetails
()
if
len
(
sysvals
.
platinfo
)
>
0
:
if
len
(
sysvals
.
platinfo
)
>
0
:
sysvals
.
vprint
(
'
\
n
Platform Info:'
)
sysvals
.
vprint
(
'
\
n
Platform Info:'
)
for
info
in
sysvals
.
platinfo
:
for
info
in
sysvals
.
platinfo
:
sysvals
.
vprint
(
info
[
0
]
+
' - '
+
info
[
1
]
)
sysvals
.
vprint
(
'[%s - %s]'
%
(
info
[
0
],
info
[
1
])
)
sysvals
.
vprint
(
info
[
2
])
sysvals
.
vprint
(
info
[
2
])
sysvals
.
vprint
(
''
)
sysvals
.
vprint
(
''
)
if
sysvals
.
cgdump
:
if
sysvals
.
cgdump
:
...
@@ -5845,6 +5927,7 @@ def processData(live=False):
...
@@ -5845,6 +5927,7 @@ def processData(live=False):
return
(
testruns
,
{
'error'
:
'timeline generation failed'
})
return
(
testruns
,
{
'error'
:
'timeline generation failed'
})
sysvals
.
vprint
(
'Creating the html timeline (%s)...'
%
sysvals
.
htmlfile
)
sysvals
.
vprint
(
'Creating the html timeline (%s)...'
%
sysvals
.
htmlfile
)
createHTML
(
testruns
,
error
)
createHTML
(
testruns
,
error
)
if
not
quiet
:
pprint
(
'DONE'
)
pprint
(
'DONE'
)
data
=
testruns
[
0
]
data
=
testruns
[
0
]
stamp
=
data
.
stamp
stamp
=
data
.
stamp
...
@@ -5872,31 +5955,28 @@ def rerunTest(htmlfile=''):
...
@@ -5872,31 +5955,28 @@ def rerunTest(htmlfile=''):
doError
(
'a directory already exists with this name: %s'
%
sysvals
.
htmlfile
)
doError
(
'a directory already exists with this name: %s'
%
sysvals
.
htmlfile
)
elif
not
os
.
access
(
sysvals
.
htmlfile
,
os
.
W_OK
):
elif
not
os
.
access
(
sysvals
.
htmlfile
,
os
.
W_OK
):
doError
(
'missing permission to write to %s'
%
sysvals
.
htmlfile
)
doError
(
'missing permission to write to %s'
%
sysvals
.
htmlfile
)
testruns
,
stamp
=
processData
(
False
)
testruns
,
stamp
=
processData
()
sysvals
.
logmsg
=
''
sysvals
.
resetlog
()
return
stamp
return
stamp
# Function: runTest
# Function: runTest
# Description:
# Description:
# execute a suspend/resume, gather the logs, and generate the output
# execute a suspend/resume, gather the logs, and generate the output
def
runTest
(
n
=
0
):
def
runTest
(
n
=
0
,
quiet
=
False
):
# prepare for the test
# prepare for the test
sysvals
.
initFtrace
()
sysvals
.
initFtrace
(
quiet
)
sysvals
.
initTestOutput
(
'suspend'
)
sysvals
.
initTestOutput
(
'suspend'
)
# execute the test
# execute the test
testdata
=
executeSuspend
(
)
executeSuspend
(
quiet
)
sysvals
.
cleanupFtrace
()
sysvals
.
cleanupFtrace
()
if
sysvals
.
skiphtml
:
if
sysvals
.
skiphtml
:
sysvals
.
outputResult
({},
n
)
sysvals
.
sudoUserchown
(
sysvals
.
testdir
)
sysvals
.
sudoUserchown
(
sysvals
.
testdir
)
return
return
if
not
testdata
[
0
][
'error'
]:
testruns
,
stamp
=
processData
(
True
,
quiet
)
testruns
,
stamp
=
processData
(
True
)
for
data
in
testruns
:
for
data
in
testruns
:
del
data
del
data
else
:
stamp
=
testdata
[
0
]
sysvals
.
sudoUserchown
(
sysvals
.
testdir
)
sysvals
.
sudoUserchown
(
sysvals
.
testdir
)
sysvals
.
outputResult
(
stamp
,
n
)
sysvals
.
outputResult
(
stamp
,
n
)
if
'error'
in
stamp
:
if
'error'
in
stamp
:
...
@@ -5904,13 +5984,14 @@ def runTest(n=0):
...
@@ -5904,13 +5984,14 @@ def runTest(n=0):
return
0
return
0
def
find_in_html
(
html
,
start
,
end
,
firstonly
=
True
):
def
find_in_html
(
html
,
start
,
end
,
firstonly
=
True
):
n
,
out
=
0
,
[]
n
,
cnt
,
out
=
0
,
len
(
html
),
[]
while
n
<
len
(
html
):
while
n
<
cnt
:
m
=
re
.
search
(
start
,
html
[
n
:])
e
=
cnt
if
(
n
+
10000
>
cnt
or
n
==
0
)
else
n
+
10000
m
=
re
.
search
(
start
,
html
[
n
:
e
])
if
not
m
:
if
not
m
:
break
break
i
=
m
.
end
()
i
=
m
.
end
()
m
=
re
.
search
(
end
,
html
[
n
+
i
:])
m
=
re
.
search
(
end
,
html
[
n
+
i
:
e
])
if
not
m
:
if
not
m
:
break
break
j
=
m
.
start
()
j
=
m
.
start
()
...
@@ -5945,7 +6026,7 @@ def data_from_html(file, outpath, issues, fulldetail=False):
...
@@ -5945,7 +6026,7 @@ def data_from_html(file, outpath, issues, fulldetail=False):
tstr
=
dt
.
strftime
(
'%Y/%m/%d %H:%M:%S'
)
tstr
=
dt
.
strftime
(
'%Y/%m/%d %H:%M:%S'
)
error
=
find_in_html
(
html
,
'<table class="testfail"><tr><td>'
,
'</td>'
)
error
=
find_in_html
(
html
,
'<table class="testfail"><tr><td>'
,
'</td>'
)
if
error
:
if
error
:
m
=
re
.
match
(
'[a-z
]* failed in (?P<p>[a-z0-9_]*) phase
'
,
error
)
m
=
re
.
match
(
'[a-z
0-9]* failed in (?P<p>
\
S*).*
'
, error)
if m:
if m:
result = '
fail
in
%
s
' % m.group('
p
')
result = '
fail
in
%
s
' % m.group('
p
')
else:
else:
...
@@ -5974,6 +6055,9 @@ def data_from_html(file, outpath, issues, fulldetail=False):
...
@@ -5974,6 +6055,9 @@ def data_from_html(file, outpath, issues, fulldetail=False):
elist[err[0]] += 1
elist[err[0]] += 1
for i in elist:
for i in elist:
ilist.append('
%
sx
%
d
' % (i, elist[i]) if elist[i] > 1 else i)
ilist.append('
%
sx
%
d
' % (i, elist[i]) if elist[i] > 1 else i)
wifi = find_in_html(html, '
Wifi
Resume
:
', '
</
td
>
')
if wifi:
extra['
wifi
'] = wifi
low = find_in_html(html, '
freeze
time
:
<
b
>
', '
ms
</
b
>
')
low = find_in_html(html, '
freeze
time
:
<
b
>
', '
ms
</
b
>
')
if low and '
|
' in low:
if low and '
|
' in low:
issue = '
FREEZEx
%
d
' % len(low.split('
|
'))
issue = '
FREEZEx
%
d
' % len(low.split('
|
'))
...
@@ -6048,13 +6132,15 @@ def genHtml(subdir, force=False):
...
@@ -6048,13 +6132,15 @@ def genHtml(subdir, force=False):
for dirname, dirnames, filenames in os.walk(subdir):
for dirname, dirnames, filenames in os.walk(subdir):
sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = ''
sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = ''
for filename in filenames:
for filename in filenames:
file = os.path.join(dirname, filename)
if sysvals.usable(file):
if(re.match('.*_dmesg.txt', filename)):
if(re.match('.*_dmesg.txt', filename)):
sysvals
.
dmesgfile
=
os
.
path
.
join
(
dirname
,
filename
)
sysvals.dmesgfile = file
elif(re.match('.*_ftrace.txt', filename)):
elif(re.match('.*_ftrace.txt', filename)):
sysvals
.
ftracefile
=
os
.
path
.
join
(
dirname
,
filename
)
sysvals.ftracefile = file
sysvals.setOutputFile()
sysvals.setOutputFile()
if
sysvals
.
ftracefile
and
sysvals
.
htmlfile
and
\
if
(sysvals.dmesgfile or sysvals.ftracefile)
and sysvals.htmlfile and
\
(
force
or
not
os
.
path
.
exists
(
sysvals
.
htmlfile
)):
(force or not
sysvals.usable
(sysvals.htmlfile)):
pprint('FTRACE: %s' % sysvals.ftracefile)
pprint('FTRACE: %s' % sysvals.ftracefile)
if sysvals.dmesgfile:
if sysvals.dmesgfile:
pprint('DMESG : %s' % sysvals.dmesgfile)
pprint('DMESG : %s' % sysvals.dmesgfile)
...
@@ -6169,9 +6255,9 @@ def configFromFile(file):
...
@@ -6169,9 +6255,9 @@ def configFromFile(file):
sysvals.cgtest = getArgInt('cgtest', value, 0, 1, False)
sysvals.cgtest = getArgInt('cgtest', value, 0, 1, False)
elif(option == 'cgphase'):
elif(option == 'cgphase'):
d = Data(0)
d = Data(0)
if
value
not
in
d
.
sortedPhases
()
:
if value not in d.
phasedef
:
doError('invalid phase --> (%s: %s), valid phases are %s'
\
doError('invalid phase --> (%s: %s), valid phases are %s'
\
%
(
option
,
value
,
d
.
sortedPhase
s
()),
True
)
% (option, value, d.
phasedef.key
s()), True)
sysvals.cgphase = value
sysvals.cgphase = value
elif(option == 'fadd'):
elif(option == 'fadd'):
file = sysvals.configFile(value)
file = sysvals.configFile(value)
...
@@ -6184,9 +6270,7 @@ def configFromFile(file):
...
@@ -6184,9 +6270,7 @@ def configFromFile(file):
nums = value.split()
nums = value.split()
if len(nums) != 2:
if len(nums) != 2:
doError('multi requires 2 integers (exec_count and delay)', True)
doError('multi requires 2 integers (exec_count and delay)', True)
sysvals
.
multitest
[
'run'
]
=
True
sysvals.multiinit(nums[0], nums[1])
sysvals
.
multitest
[
'count'
]
=
getArgInt
(
'multi: n d (exec count)'
,
nums
[
0
],
2
,
1000000
,
False
)
sysvals
.
multitest
[
'delay'
]
=
getArgInt
(
'multi: n d (delay between tests)'
,
nums
[
1
],
0
,
3600
,
False
)
elif(option == 'devicefilter'):
elif(option == 'devicefilter'):
sysvals.setDeviceFilter(value)
sysvals.setDeviceFilter(value)
elif(option == 'expandcg'):
elif(option == 'expandcg'):
...
@@ -6342,6 +6426,7 @@ def printHelp():
...
@@ -6342,6 +6426,7 @@ def printHelp():
' -srgap Add a visible gap in the timeline between sus/res (default: disabled)
\
n
'
\
' -srgap Add a visible gap in the timeline between sus/res (default: disabled)
\
n
'
\
' -skiphtml Run the test and capture the trace logs, but skip the timeline (default: disabled)
\
n
'
\
' -skiphtml Run the test and capture the trace logs, but skip the timeline (default: disabled)
\
n
'
\
' -result fn Export a results table to a text file for parsing.
\
n
'
\
' -result fn Export a results table to a text file for parsing.
\
n
'
\
' -wifi If a wifi connection is available, check that it reconnects after resume.
\
n
'
\
' [testprep]
\
n
'
\
' [testprep]
\
n
'
\
' -sync Sync the filesystems before starting the test
\
n
'
\
' -sync Sync the filesystems before starting the test
\
n
'
\
' -rs on/off Enable/disable runtime suspend for all devices, restore all after test
\
n
'
\
' -rs on/off Enable/disable runtime suspend for all devices, restore all after test
\
n
'
\
...
@@ -6356,8 +6441,10 @@ def printHelp():
...
@@ -6356,8 +6441,10 @@ def printHelp():
' -predelay t Include t ms delay before 1st suspend (default: 0 ms)
\
n
'
\
' -predelay t Include t ms delay before 1st suspend (default: 0 ms)
\
n
'
\
' -postdelay t Include t ms delay after last resume (default: 0 ms)
\
n
'
\
' -postdelay t Include t ms delay after last resume (default: 0 ms)
\
n
'
\
' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)
\
n
'
\
' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)
\
n
'
\
' -multi n d Execute <n> consecutive tests at <d> seconds intervals. The outputs will
\
n
'
\
' -multi n d Execute <n> consecutive tests at <d> seconds intervals. If <n> is followed
\
n
'
\
' be created in a new subdirectory with a summary page.
\
n
'
\
' by a "
d
", "
h
", or "
m
" execute for <n> days, hours, or mins instead.
\
n
'
\
' The outputs will be created in a new subdirectory with a summary page.
\
n
'
\
' -maxfail n Abort a -multi run after n consecutive fails (default is 0 = never abort)
\
n
'
\
' [debug]
\
n
'
\
' [debug]
\
n
'
\
' -f Use ftrace to create device callgraphs (default: disabled)
\
n
'
\
' -f Use ftrace to create device callgraphs (default: disabled)
\
n
'
\
' -ftop Use ftrace on the top level call: "
%
s
" (default: disabled)
\
n
'
\
' -ftop Use ftrace on the top level call: "
%
s
" (default: disabled)
\
n
'
\
...
@@ -6379,11 +6466,11 @@ def printHelp():
...
@@ -6379,11 +6466,11 @@ def printHelp():
' -modes List available suspend modes
\
n
'
\
' -modes List available suspend modes
\
n
'
\
' -status Test to see if the system is enabled to run this tool
\
n
'
\
' -status Test to see if the system is enabled to run this tool
\
n
'
\
' -fpdt Print out the contents of the ACPI Firmware Performance Data Table
\
n
'
\
' -fpdt Print out the contents of the ACPI Firmware Performance Data Table
\
n
'
\
' -battery Print out battery info (if available)
\
n
'
\
' -wificheck Print out wifi connection info
\
n
'
\
' -wifi Print out wifi connection info (if wireless-tools and device exists)
\
n
'
\
' -x<mode> Test xset by toggling the given mode (on/off/standby/suspend)
\
n
'
\
' -x<mode> Test xset by toggling the given mode (on/off/standby/suspend)
\
n
'
\
' -sysinfo Print out system info extracted from BIOS
\
n
'
\
' -sysinfo Print out system info extracted from BIOS
\
n
'
\
' -devinfo Print out the pm settings of all devices which support runtime suspend
\
n
'
\
' -devinfo Print out the pm settings of all devices which support runtime suspend
\
n
'
\
' -cmdinfo Print out all the platform info collected before and after suspend/resume
\
n
'
\
' -flist Print the list of functions currently being captured in ftrace
\
n
'
\
' -flist Print the list of functions currently being captured in ftrace
\
n
'
\
' -flistall Print all functions capable of being captured in ftrace
\
n
'
\
' -flistall Print all functions capable of being captured in ftrace
\
n
'
\
' -summary dir Create a summary of tests in this dir [-genhtml builds missing html]
\
n
'
\
' -summary dir Create a summary of tests in this dir [-genhtml builds missing html]
\
n
'
\
...
@@ -6399,8 +6486,8 @@ if __name__ == '__main__':
...
@@ -6399,8 +6486,8 @@ if __name__ == '__main__':
genhtml = False
genhtml = False
cmd = ''
cmd = ''
simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall',
simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall',
'-devinfo'
,
'-status'
,
'-
battery'
,
'-xon'
,
'-xoff'
,
'-xstandby
'
,
'-devinfo', '-status', '-
xon', '-xoff', '-xstandby', '-xsuspend
',
'-x
suspend'
,
'-xinit'
,
'-xreset'
,
'-xstat'
,
'-wifi
'
]
'-x
init', '-xreset', '-xstat', '-wificheck', '-cmdinfo
']
if '-f' in sys.argv:
if '-f' in sys.argv:
sysvals.cgskip = sysvals.configFile('cgskip.txt')
sysvals.cgskip = sysvals.configFile('cgskip.txt')
# loop through the command line arguments
# loop through the command line arguments
...
@@ -6462,8 +6549,15 @@ if __name__ == '__main__':
...
@@ -6462,8 +6549,15 @@ if __name__ == '__main__':
sysvals.usedevsrc = True
sysvals.usedevsrc = True
elif(arg == '-sync'):
elif(arg == '-sync'):
sysvals.sync = True
sysvals.sync = True
elif(arg == '-wifi'):
sysvals.wifi = True
elif(arg == '-gzip'):
elif(arg == '-gzip'):
sysvals.gzip = True
sysvals.gzip = True
elif(arg == '-info'):
try:
val = next(args)
except:
doError('-info requires one string argument', True)
elif(arg == '-rs'):
elif(arg == '-rs'):
try:
try:
val = next(args)
val = next(args)
...
@@ -6555,10 +6649,14 @@ if __name__ == '__main__':
...
@@ -6555,10 +6649,14 @@ if __name__ == '__main__':
sysvals.cgexp = True
sysvals.cgexp = True
elif(arg == '-srgap'):
elif(arg == '-srgap'):
sysvals.srgap = 5
sysvals.srgap = 5
elif(arg == '-maxfail'):
sysvals.maxfail = getArgInt('-maxfail', args, 0, 1000000)
elif(arg == '-multi'):
elif(arg == '-multi'):
sysvals
.
multitest
[
'run'
]
=
True
try:
sysvals
.
multitest
[
'count'
]
=
getArgInt
(
'-multi n d (exec count)'
,
args
,
2
,
1000000
)
c, d = next(args), next(args)
sysvals
.
multitest
[
'delay'
]
=
getArgInt
(
'-multi n d (delay between tests)'
,
args
,
0
,
3600
)
except:
doError('-multi requires two values', True)
sysvals.multiinit(c, d)
elif(arg == '-o'):
elif(arg == '-o'):
try:
try:
val = next(args)
val = next(args)
...
@@ -6655,13 +6753,6 @@ if __name__ == '__main__':
...
@@ -6655,13 +6753,6 @@ if __name__ == '__main__':
elif(cmd == 'fpdt'):
elif(cmd == 'fpdt'):
if not getFPDT(True):
if not getFPDT(True):
ret = 1
ret = 1
elif
(
cmd
==
'battery'
):
out
=
getBattery
()
if
out
:
pprint
(
'AC Connect : %s
\
n
Battery Charge: %d'
%
out
)
else
:
pprint
(
'no battery found'
)
ret
=
1
elif(cmd == 'sysinfo'):
elif(cmd == 'sysinfo'):
sysvals.printSystemInfo(True)
sysvals.printSystemInfo(True)
elif(cmd == 'devinfo'):
elif(cmd == 'devinfo'):
...
@@ -6679,13 +6770,15 @@ if __name__ == '__main__':
...
@@ -6679,13 +6770,15 @@ if __name__ == '__main__':
ret = displayControl(cmd[1:])
ret = displayControl(cmd[1:])
elif(cmd == 'xstat'):
elif(cmd == 'xstat'):
pprint('Display Status: %s' % displayControl('stat').upper())
pprint('Display Status: %s' % displayControl('stat').upper())
elif
(
cmd
==
'wifi'
):
elif(cmd == 'wifi
check
'):
out
=
sysvals
.
checkWifi
()
dev
= sysvals.checkWifi()
if
'device'
not
in
out
:
if
dev
:
p
print
(
'WIFI interface not found'
)
p
rint('%s is connected' % sysvals.wifiDetails(dev)
)
else:
else:
for
key
in
sorted
(
out
):
print('No wifi connection found')
pprint
(
'%6s: %s'
%
(
key
.
upper
(),
out
[
key
]))
elif(cmd == 'cmdinfo'):
for out in sysvals.cmdinfo(False, True):
print('[%s - %s]
\
n
%s
\
n
' % out)
sys.exit(ret)
sys.exit(ret)
# if instructed, re-analyze existing data files
# if instructed, re-analyze existing data files
...
@@ -6720,24 +6813,38 @@ if __name__ == '__main__':
...
@@ -6720,24 +6813,38 @@ if __name__ == '__main__':
setRuntimeSuspend(True)
setRuntimeSuspend(True)
if sysvals.display:
if sysvals.display:
displayControl('init')
displayControl('init')
ret
=
0
failcnt, ret = 0,
0
if sysvals.multitest['run']:
if sysvals.multitest['run']:
# run multiple tests in a separate subdirectory
# run multiple tests in a separate subdirectory
if not sysvals.outdir:
if not sysvals.outdir:
s
=
'suspend-x%d'
%
sysvals
.
multitest
[
'count'
]
if 'time' in sysvals.multitest:
sysvals
.
outdir
=
datetime
.
now
().
strftime
(
s
+
'-%y%m%d-%H%M%S'
)
s = '-%dm' % sysvals.multitest['time']
else:
s = '-x%d' % sysvals.multitest['count']
sysvals.outdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S'+s)
if not os.path.isdir(sysvals.outdir):
if not os.path.isdir(sysvals.outdir):
os.makedirs(sysvals.outdir)
os.makedirs(sysvals.outdir)
sysvals.sudoUserchown(sysvals.outdir)
finish = datetime.now()
if 'time' in sysvals.multitest:
finish += timedelta(minutes=sysvals.multitest['time'])
for i in range(sysvals.multitest['count']):
for i in range(sysvals.multitest['count']):
if
(
i
!=
0
):
sysvals.multistat(True, i, finish)
if i != 0 and sysvals.multitest['delay'] > 0:
pprint('Waiting %d seconds...' % (sysvals.multitest['delay']))
pprint('Waiting %d seconds...' % (sysvals.multitest['delay']))
time.sleep(sysvals.multitest['delay'])
time.sleep(sysvals.multitest['delay'])
pprint
(
'TEST (%d/%d) START'
%
(
i
+
1
,
sysvals
.
multitest
[
'count'
]))
fmt = 'suspend-%y%m%d-%H%M%S'
fmt = 'suspend-%y%m%d-%H%M%S'
sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt))
sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt))
ret
=
runTest
(
i
+
1
)
ret = runTest(i+1, True)
pprint
(
'TEST (%d/%d) COMPLETE'
%
(
i
+
1
,
sysvals
.
multitest
[
'count'
]))
failcnt = 0 if not ret else failcnt + 1
sysvals
.
logmsg
=
''
if sysvals.maxfail > 0 and failcnt >= sysvals.maxfail:
pprint('Maximum fail count of %d reached, aborting multitest' % (sysvals.maxfail))
break
time.sleep(5)
sysvals.resetlog()
sysvals.multistat(False, i, finish)
if 'time' in sysvals.multitest and datetime.now() >= finish:
break
if not sysvals.skiphtml:
if not sysvals.skiphtml:
runSummary(sysvals.outdir, False, False)
runSummary(sysvals.outdir, False, False)
sysvals.sudoUserchown(sysvals.outdir)
sysvals.sudoUserchown(sysvals.outdir)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment