1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-09-04 04:12:42 +01:00

962 Commits

Author SHA1 Message Date
Marc Bonnici
601202c2ec WA Revent: Updated to support vsync version of revent
WA has been updated to automatically install and run vsync service apk and use the vsync version of revent for recording and playback on android platforms.
2017-01-31 17:46:36 +00:00
Marc Bonnici
a81fe5555a Revent: Added support for Vsync timings.
Updated revent to use timing information provided from VSync service
running on android to try and improve timing accuracy.
Revent now takes `-V` parameter for both the record and replay command to indicate that the VSync service should be used.
2017-01-31 17:46:31 +00:00
Marc Bonnici
d6eb8b6faf HelloJNI: Added Initial version of VSync Service app.
This is an android application containing a service designed to run
in the background and provide VSync information to revent to help
improve accuracy,
2017-01-31 17:45:10 +00:00
Sergei Trofimov
490dd404ae AndroidDevice: write "dumpsys window" output on host
On Android targets, WA collects device display information by running
"dumpsys window" during run initialisation. Previously, this was
redirectied into on-device file (under the working directory) and then
pulled from the target.

It looks like on Android-on-ChromeOS devices the redirect leads to an
"Unknown Error" and the resulting file is empty. To get around that,
this commit modfies the dumpsys command so that the output is collected
directly from the shell's stdout and then writen on the host.
2017-01-24 17:52:51 +00:00
setrofim
60f52c2187 Merge pull request #265 from jimboatarm/multiapp-workload
Multiapp Workload: Workload to test how responsive a device is when…
2017-01-16 16:41:35 +00:00
setrofim
fbb9908298 Merge pull request #330 from jimboatarm/break_setup
Splits ApkWorkload setup() into short methods.
2017-01-13 15:39:11 +00:00
jummp01
01fa0a3571 Splits ApkWorkload setup() into short methods.
Apkworkload setup phase performs many functionalities in
a single method that is broken down into short methods.
The split short methods can be called individually when
relevant use cases arise.
2017-01-13 11:56:39 +00:00
setrofim
be2b14a575 Merge pull request #331 from jimboatarm/skype_fix
Create a function for launching skype application.
2017-01-13 05:28:00 +00:00
setrofim
dab2bbb1c7 Merge pull request #329 from jimboatarm/epochtime
Changes Action Logger to give epoch time
2017-01-13 05:26:28 +00:00
setrofim
340ae72ca2 Merge pull request #332 from siddhanathan/typo
Fix typo
2017-01-13 05:25:02 +00:00
Siddhanathan Shanmugam
e64dc8bc26 Fix typo
Instrumention -> Instrumentation
2017-01-12 12:13:05 -08:00
Sergei Trofimov
cb48ece77f daq: fixing energy metric calculation
The summary energy metric was being calculated incorrectly. Instead of
dividing power by the sampling rate, it was being multiplied by it and
divided by a million for some reason.
2017-01-12 11:29:44 +00:00
jummp01
8f67b7f94b Create a function for launching skype application.
Skype has a unique launch command which is called in the setup
phase of the workload. The launch command is split into a stand alone
method which can be called as a separate method if required.

This can be used as common method if more applications in future
require their own customized launch command.
2017-01-12 11:27:42 +00:00
jummp01
fa553ee430 Changes Action Logger to give epoch time
Log time changed to produce epoch time in milli seconds.
Nano to milli second conversion done in uxperf result
processor is removed.

Tested on Mate8 and time obtained is verified.
2017-01-12 10:30:07 +00:00
Sergei Trofimov
01c9c88e79 perf: do not force root on Android in stop()
perf instrument was forcing killall() to run as root on Android devices.
This constraint was preventing perf from being used on unrooted devices.
However, it appears that it is possible for killall() to succeed on at
least some devices as a regular user.

This commit removes the constraint. Since killall() will default to
running as root whenever possible, the instrument will still behave
correctly on rooted Android devices where root is required.
2017-01-11 13:44:55 +00:00
setrofim
0c32e39ce0 Merge pull request #317 from jimboatarm/minapkremoved
Removed min_apk_version from UXperf workloads
2017-01-09 15:13:04 +00:00
Marc Bonnici
1364ec05e8 Version bump 2016-12-23 14:14:43 +00:00
marcbonnici
d5c888cc90 Merge pull request #325 from marcbonnici/documentation
Documentation and get-assets Update
2016-12-23 14:13:30 +00:00
Marc Bonnici
d6ab68bffc Documentation: Updated change log for new version. 2016-12-23 10:39:51 +00:00
Marc Bonnici
30e9b553ff get_assets: Updated Remote Assets URL
Updated URL to new location of WA assets as previous URL was no longer found.
2016-12-23 10:39:51 +00:00
Marc Bonnici
6a3f441064 Documentation: Added command info to invocation page.
Added `create` and `get-assets` command information to invocation
page of documentation.

Corrected spelling.
2016-12-23 10:39:51 +00:00
Marc Bonnici
13cbe2f059 Renamed `get-assests.py to get_assests.py`
``get-assests.py`` is not a valid python module name therefore it has been
renamed to ``get_assests.py``, the command however remains with the same name.
2016-12-23 10:39:51 +00:00
Marc Bonnici
53b173c55f Documentation Update
Updated documentation to conform with pylint and sphinx.
2016-12-23 10:39:51 +00:00
marcbonnici
f598c60514 Merge pull request #324 from marcbonnici/spec2000
Spec2000
2016-12-23 10:38:43 +00:00
marcbonnici
ceda8e74bf Merge pull request #323 from marcbonnici/poller
Poller
2016-12-23 10:35:44 +00:00
Marc Bonnici
173c71b867 FilePoller: Updated 32 bit binary.
Recompiled the 32 bit binary as previous version would fail
due to missing applet.
2016-12-22 17:38:20 +00:00
Marc Bonnici
d88d35be26 FilePoller: Made files a mandatory parameter.
Changed the `files` parameter to be mandatory and added check to
ensure that at least one file is passed in configuration otherwise
the instrument crashes.
2016-12-22 17:34:50 +00:00
marcbonnici
599452d41f Merge pull request #320 from marcbonnici/perf
Perf: Recompiled 32bit binary as little endian.
2016-12-22 11:04:14 +00:00
marcbonnici
33dae51536 Merge pull request #322 from marcbonnici/big.Little
big.Little Sample Agenda: Fixed workload name and typo.
2016-12-21 17:10:33 +00:00
marcbonnici
f8950dea33 Merge pull request #318 from marcbonnici/googlephotos
GooglePhotos: Updated to work with the latest version (v2.6.0).
2016-12-21 17:09:20 +00:00
Marc Bonnici
136d1fef0f GooglePhotos: Updated to work with the latest version (v2.6.0).
Dismisses backup confirmation in newer versions.
Updated for new way of editing photo colours and lack of confirmation.
2016-12-21 17:05:09 +00:00
marcbonnici
5204383582 Merge pull request #321 from marcbonnici/netstat
NetStat: Updated Regex to match logcat format in android 6.0
2016-12-21 16:53:55 +00:00
marcbonnici
bfa1d8dd62 Merge pull request #319 from marcbonnici/dex2oat
Dex2oat: Now uses root if available.
2016-12-21 16:53:12 +00:00
Marc Bonnici
b75fdf85d0 big.Little Sample Agenda: Fixed workload name and typo.
One of the workloads was listed as sqlite which is an instrument,
corrected the workload name to sqlitebm.

Added missing word in description.
2016-12-21 12:08:51 +00:00
Marc Bonnici
fcbb83f5ac Spec2000 Workload: Spelling Corrected 2016-12-20 16:34:07 +00:00
Marc Bonnici
807003128e Spec2000 Workload: Updated to use busybox provided from WA.
Commands have been updated to use the busybox executable that
is installed via WA rather than relying on it already being in
PATH on the device as this would fail for devices that it was
not installed on.
2016-12-20 16:20:59 +00:00
Marc Bonnici
3e4d068eff NetStat: Updated Regex to match logcat format in android 6.0
Android marshmallow uses a different default view for logcat
therefore prevented output from being extracted. The regex
expression has been updated to include matching the new format.
2016-12-20 09:56:26 +00:00
Marc Bonnici
a3936afb4c Perf: Recompiled 32bit binary for little endian.
Compiled 32bit perf binary as little endian instead of big
endian to support more devices.
2016-12-16 18:13:43 +00:00
Marc Bonnici
24000a21df Dex2oat: Now uses root if available.
Command fails to execute with permission error on some devices therefore
now attempts to use root if available.
2016-12-16 11:20:37 +00:00
marcbonnici
e5c0ca85f0 Merge pull request #315 from jimboatarm/fix-adobereader
Fix adobereader
2016-12-15 17:07:12 +00:00
Michael McGeagh
51f07c4473 Multiapp Workload: Workload to test how responsive a device is when context switching between appplication tasks. It combines workflows from googlephotos, gmail and skype.
Added tagName to give unique logger name for multiple share attempts. Turn off markers_enabled for subclasses

Renamed multiapp to appshare. Description is now more accurate

Changed appshare to use class instances for each sub workload. This allows APKs to be setup correctly on the device

Photos changed function name
2016-12-15 16:19:19 +00:00
Michael McGeagh
ffde7401ef Removed min_apk_version from UXperf workloads. The known working version is now part of the description instead. 2016-12-15 16:13:58 +00:00
James Hartley
b4026ae390 Fix inverted swipe up/down gestures
Tested on Chromebook and Mate 8
2016-12-15 15:28:23 +00:00
James Hartley
f76c00dd99 Fix adobereader on S7
Tested on S7
2016-12-15 15:04:07 +00:00
setrofim
b1e375a676 Merge pull request #314 from marcbonnici/skype
SkypeWorkload: Workload Fixes
2016-12-15 11:18:24 +00:00
Marc Bonnici
1102ba1679 SkypeWorkload: Workload Fixes
Fixed contact not being found when mistakenly selecting search for
bots instead of contact.

Changed element used to determine when contact has been
selected from status indicator to search icon as with other other
contacts in view the element is never removed.

Now throws error if end call button is not found otherwise workload
could fail to start the call and incorrectly report overall success.
2016-12-15 10:30:34 +00:00
setrofim
6d999301f3 Merge pull request #313 from marcbonnici/glbenchmark
glbenchmark: Updated version numbers from X.X.X to X.X.
2016-12-14 16:42:52 +00:00
Marc Bonnici
e4fdf0bdb9 glbenchmark: Updated version numbers from X.X.X to X.X.
Apks contain version number in format X.X therefore when trying to
match for versions using X.X.X the apk is never found.
2016-12-14 15:37:07 +00:00
setrofim
d493b1e790 Merge pull request #307 from marcbonnici/exact_abi
Modified how apks containing native code are matched to a target devices supported abi(s).
2016-12-14 10:32:56 +00:00
setrofim
47e31765b4 Merge pull request #312 from marcbonnici/facebook
Facebook
2016-12-14 08:13:54 +00:00
setrofim
79faec120e Merge pull request #311 from marcbonnici/playbooks
GooglePlayWorkloads: Updated for new version.
2016-12-14 08:13:12 +00:00
Marc Bonnici
66dbe7a508 GooglePlayWorkloads: Updated for new version. 2016-12-13 16:33:50 +00:00
Marc Bonnici
80a780dcfe FacebookWorkload: Fixed UI automation and speificed maximum vesrion.
Fixed the workload UI automation and specified the version of
facebook that the workload is designed to work with.
2016-12-12 18:12:34 +00:00
Marc Bonnici
694d51ffb6 AndroidWorkload: Fixed validate version error messages.
Fixed typos in ``validate_version`` method which caused incorrect reporting
of maximum apk version.
2016-12-12 18:09:40 +00:00
setrofim
1befe63e45 Merge pull request #310 from marcbonnici/peacekeeper
PeacekeeperWorkload: Updated to work with new APK versions
2016-12-12 16:59:38 +00:00
Marc Bonnici
27b08bade0 PeacekeeperWorkload: Updated to work with new APK versions
Updated peacekeeper UI automation to work with newer version of
chrome and firefox.
2016-12-12 16:49:54 +00:00
Marc Bonnici
1477a89ee4 AndroidDevice: Renamed 'supported_eabis' property to 'supported_abis'
Renamed android device property from 'supported_eabis' to 'supported_abis' to be consistent with linux device.

Updated dex2oat workload to use new property name.
2016-12-09 15:23:58 +00:00
Marc Bonnici
0dfbbae7b6 Renamed 'check_abi' parameter to 'exact_abi' 2016-12-09 14:11:16 +00:00
Marc Bonnici
a8a8d21de6 AndroidWorkload: Modified workload to properly check for an apks abi
Previously when retrieving apks only it's name would be used to choose
an apk. Now the native code reported by the apk is used to determine
the correct version to run for the specific device. It tries to
match the primary abi of device with native code before falling back to
using a compatible apk.

When using the check_abi parameter it no longer relies on naming convention
and only allows apks with native code supporting a devices primary abi to be
used.

Updated the relevant documentation.
2016-12-09 14:11:16 +00:00
Marc Bonnici
f467f6f991 AndroidDevice: Added method to retrive primary abi of installed package
Tries to retireve the primary abi of a currently installed package on
device.
2016-12-09 14:11:16 +00:00
Marc Bonnici
4352e02806 APK Info: Added property to extract native code from an apk
Looks for any native code present in an apk and stores the
mapped abi(s) for use when selecting appropriate apks.
2016-12-09 14:11:16 +00:00
Marc Bonnici
693d0544a3 ABI_MAP: Added armeabi-v7a as armeabi 2016-12-09 14:11:16 +00:00
Marc Bonnici
eb239c65d0 LinuxDevice: Added supported eabi property.
Added property to linux device to return list of supported abis
to be consistent with android devices. Currently only returns a
list containing the primary abi.
2016-12-09 14:11:16 +00:00
setrofim
f7e4232eaa Merge pull request #309 from jimboatarm/skype-waitonsignin
skype: longer wait time for signin and search
2016-12-09 13:44:40 +00:00
Michael McGeagh
8cbf189029 skype: longer wait time for signin and search 2016-12-09 13:45:35 +00:00
setrofim
6e45e1a039 Merge pull request #308 from marcbonnici/adobereader
AdobeReader: Updated workload for new app version
2016-12-09 08:14:06 +00:00
Marc Bonnici
b6f770cfc5 AdobeReader: Updated workload for new app version
Updated the workload to work with the latest version (v16.4)
of Adobe Reader app.
2016-12-08 18:14:16 +00:00
setrofim
c7de8cabd6 Merge pull request #294 from jimboatarm/improve-geekbench-timeouts
geekbench: Improve UiAutomator timeouts for slower devices
2016-12-02 17:04:01 +00:00
setrofim
fd7df36a5a Merge pull request #301 from jimboatarm/skype-hangup
skype: now hangs up at the end. Better duration handling
2016-12-02 17:03:13 +00:00
setrofim
607187ad5b Merge pull request #306 from marcbonnici/revent_BC
Revent: Fixed backwards compatibility with v1
2016-12-02 17:02:06 +00:00
setrofim
b4036c5f15 Merge pull request #304 from jimboatarm/uxperf-fix
UXPERF: handle error when only one timestamp is logged
2016-12-02 16:58:33 +00:00
Marc Bonnici
b6e077c06b Revent: Fixed backwards compatibility with v1.
Fixed new gamemode not being set for compatibility mode.
Fixed input buffer not being flushed causing replay to fail.
Fixed infinte loop if revent recording did not end correctly.
Updated revent binaries.
2016-12-02 16:58:09 +00:00
setrofim
8e0b793f89 Merge pull request #305 from jimboatarm/utilfps-fix
util-fps: handle divide by zero possibility
2016-12-02 16:56:59 +00:00
Michael McGeagh
8b82451230 util-fps: handle divide by zero possibility 2016-12-02 16:34:32 +00:00
Michael McGeagh
64c352fab6 UXPERF: handle error when only one timestamp is logged 2016-12-02 16:31:45 +00:00
setrofim
68697a42a7 Merge pull request #303 from jimboatarm/photos-reliability
GooglePhotos: Navigate up only when needed.
2016-12-02 14:37:40 +00:00
Michael McGeagh
ae4ae3da5e skype: now hangs up at the end. Better duration handling 2016-12-02 11:30:30 +00:00
Michael McGeagh
393abc267f GooglePhotos: Navigate up only when needed. Use baseclass' selectGalleryFolder 2016-12-02 11:28:38 +00:00
setrofim
751970f991 Merge pull request #302 from marcbonnici/master
Revent: Added updated revent binaries.
2016-12-02 10:31:03 +00:00
Marc Bonnici
254e9fff38 Revent: Added updated revent binaries.
Added updated revent binaries for armabi and arm64 for the fixes
in commit 7a19046645
2016-12-02 09:55:19 +00:00
James Hartley
088709f290 geekbench: Improve UiAutomator timeouts for slow devices, fixes for rooted devices
Tested by running Mate 8 on the lowest cluster at the lowest available frequency

On rooted devices, skip attempting to pull log files from device.  This allows
the benchmark to run to completion without failure.

GB log files are stored in /data/data/com.primatelabs.geekbench/files and
not accessible without root.  On Chromebooks ( which have no adb root
rights) it is possible to copy from this folder manually after the test run.
2016-12-02 07:23:44 +00:00
Sergei Trofimov
850fcb24ab pylint/pep8 fixes 2016-12-01 15:01:45 +00:00
setrofim
ace41d10a5 Merge pull request #257 from jimboatarm/gmail-workload
Gmail: A workload to perform standard productivity tasks within Gmail
2016-12-01 14:46:12 +00:00
Michael McGeagh
cb53fe9ec8 Gmail: A workload to perform standard productivity tasks within Gmail. The workload carries out various tasks, such as creating new emails, attaching images and sending them.
Moved broadcast to super. Mandatory and Default are XOR

Added a longer wait for sync to finish. Increases reliability on certain phones

Changed recipient to not mandatory and a default set

Wait for sync when launching gmail from the sharing feature

Fix: cornercase where image viewer already points to working directory. Refactored code due to duplication

Added new function to BaseUiAutomation class to find a folder in the gallery
2016-12-01 13:21:49 +00:00
setrofim
4e161127e1 Merge pull request #300 from setrofim/master
A couple of fixes for trace CPU power state post-processing and energy model scripts
2016-11-30 09:38:05 +00:00
setrofim
bf43bf93bc Merge pull request #298 from marcbonnici/revent_fixes
Revent: Fixes
2016-11-29 17:34:17 +00:00
Marc Bonnici
7a19046645 Revent: Fixes
Changed termination signal to interrupt signal to prevent code exiting too early.
Added exit handler to ensure revent exits correctly as previously was
crashing and therefore not running final code.
Fixed error in writing input event where half of timestamp seconds was missing.
Fixed typo in documentation for revent file structure.
2016-11-29 17:29:33 +00:00
Sergei Trofimov
5db11462be utils/power: handle devlib frequency reporting
When collecting ftrace events, the instrument will insert frequencies
into the trace to make it possible reconstruct power states when there
were no frequency transitions during the measured period.

The format in which frequencies are inserted is different in devlib.
Since post-processing scripts may be run on traces collected by devlib
as well as WA, it needs to support both formats.
2016-11-29 10:23:32 +00:00
Sergei Trofimov
7bf0e3c344 energy_model: only set "ui" parameter for ChomeOS
Fixed a bug, where "ui" runtime parameter was being set regardless of
the underlying platforms for "freq" iterations, causing the to fail on
non-ChomeOS devices.
2016-11-29 10:23:32 +00:00
setrofim
d16d8bf62d Merge pull request #297 from marcbonnici/octaned
ResourceGetters: Updated executable discovery to use http_getter
2016-11-28 11:45:46 +00:00
Marc Bonnici
c93cc81aac ResourceGetters: Updated executable discovery to use http_getter
Executables were not previously automatically downloaded from a
provided remote_assets_url. The http_getter is now called to attempt to
find and download executable files.
2016-11-28 11:38:29 +00:00
setrofim
9491763aa7 Merge pull request #290 from jimboatarm/git_fix
Fixes gitignore to untrack files from uiauto
2016-11-28 11:05:24 +00:00
setrofim
a172c8f624 Merge pull request #295 from jimboatarm/fix-octaned8-log-appending
Fix octaned8 results capture
2016-11-28 11:04:42 +00:00
setrofim
33286ba982 Merge pull request #296 from jimboatarm/fix-exact-apk-version
Fix exact_apk_version check
2016-11-28 11:03:23 +00:00
James Hartley
f69e4c5b18 Fix octaned8 results capture
Ensure the device log file is deleted between runs and that the host file is not kept as an
artefact.  Both can lead to errors appending data from the next iteration/run.
2016-11-24 14:54:19 +00:00
James Hartley
5b543d2edf Fix exact_apk_version check 2016-11-24 12:47:57 +00:00
jummp01
17edb13eb9 Fixes gitignore to untrack files from uiauto
Gitignore was untracking a few files from wlauto/external/uiautomator whereas
the folder name is uiauto instead. Name changing done to fix the bug.
2016-11-15 11:45:50 +00:00
setrofim
40d281b336 Merge pull request #283 from jimboatarm/octaned8
Add Octane d8 workload
2016-11-11 17:32:53 +00:00
setrofim
74ea78aa42 Merge pull request #286 from jimboatarm/fps-fix
FPS percentiles: Ignore ValueError when NaN
2016-11-11 17:32:21 +00:00
Michael McGeagh
8edce40301 FPS percentiles: Ignore ValueError when NaN
Fixed: if index isnt zero based, drop(0) will fail
2016-11-11 17:21:47 +00:00
James Hartley
642d757066 Add Octane d8 workload
A workload to run the binary (non-browser) version of Octane
2016-11-11 17:04:25 +00:00
setrofim
969201968e Merge pull request #282 from jimboatarm/min-apk-version-fix
Support for Geekbench 4
2016-11-11 11:23:07 +00:00
setrofim
3f76920fa9 Merge pull request #285 from jimboatarm/testbranchplz
Change min apk ver for reader
2016-11-11 10:30:20 +00:00
James Hartley
46b78d35be Geekbench 4 is similar in terms of operation but runs significantly different tests and hence
produces a different results output.

- Add UiAutomator and results parsing support for GB4
- Remove the version checking in init.py and rely instead on the ApkWorkload version
  checking.  The required version in the agenda is checked against that on the host or target

Tested with GB3.4.1 and GB4.0.0 on a Galaxy S7.  Older variants of the APK were not available.
2016-11-10 18:56:22 +00:00
James Hartley
ba34b973ac ApkWorkload: add check for an exact APK version
Checks for an APK version on the host or target which matches a specified value
2016-11-10 18:46:31 +00:00
Michael McGeagh
6d173f2f3f Change min apk ver for reader 2016-11-10 15:48:50 +00:00
setrofim
8b1d2c9fe9 Merge pull request #284 from Leo-Yan/add_camera_user_case_1110
rt-app: add user case for camera
2016-11-10 08:54:45 +00:00
Leo Yan
d3c59e2f74 rt-app: add user case for camera
Add camera-long.json and camera-short.json files to simulate camera
 recorder.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
2016-11-10 12:08:02 +08:00
setrofim
fce04d2938 Merge pull request #281 from jimboatarm/uxperf-newfps
uxperf result_processor: updated for changes in FPS instrument
2016-11-08 13:20:31 +00:00
setrofim
27df426c0d Merge pull request #263 from jimboatarm/books-codetidy
GooglePlayBooks: Code tidy to conform.
2016-11-08 13:19:27 +00:00
Michael McGeagh
f8966bf324 GooglePlayBooks: Code tidy to conform. Additional parameter added for when the search name differs to the library name. Defaults changed due to Hamlet dissapearing from the store.
Added cornercase of accidentially triggering a card popup

New version includes a new dialogue and name for search. Added support for this

If device has more than one account associated, a new popup appears. Handle that with an optional parameter listing specific account to select, if ommitted the first account in the list is selected
2016-11-08 12:31:27 +00:00
Michael McGeagh
e076d47a7b uxperf result_processor: updated for changes in FPS instrument 2016-11-08 12:20:47 +00:00
setrofim
ea798aefb3 Merge pull request #280 from jimboatarm/fps-fix
FPS - fix regex and handle empty frames
2016-11-08 08:29:46 +00:00
Michael McGeagh
dcf13f8c2c FPS - fix regex and handle empty frames 2016-11-07 17:39:51 +00:00
setrofim
f99c6f5656 Merge pull request #279 from jimboatarm/min-apk-version-fix
Fix incorrect min_apk_version setting in adobereader and googleplaybooks
2016-11-07 15:53:31 +00:00
James Hartley
359d9d3e5f Fix incorrect min_apk_version setting in adobereader and googleplaybooks 2016-11-07 15:42:38 +00:00
setrofim
d56f581a0a Merge pull request #277 from jimboatarm/fps-gfxinfo
FPS. Added gfxinfo methods of obtaining fps stats.
2016-11-04 17:11:59 +00:00
Sergei Trofimov
f12cf6d557 statedetect: pylint and dependencies fixes
- Corrected the depency for opencv bindings. Even though the library is
  imported as "cv2", the package containing it is called
  "opencv-python".
- pylint: ignore no-member warnings; cv2 pulls it's memebers dynamically
  from the underlying libopencv, so pylint can't see them.
2016-11-04 17:05:39 +00:00
Michael McGeagh
311c4e419f FPS. Added gfxinfo methods of obtaining fps stats. Auto detects and uses appropriate method via android version of device
Output 90th, 95th and 99th percentile metrics. This happens for both SurfaceFlinger and Gfxinfo methods.
2016-11-04 17:05:00 +00:00
setrofim
2becd94381 Merge pull request #278 from marcbonnici/revent_statedetection
ReventWorkload: Modified statedection to vary scale of images
2016-11-04 15:39:23 +00:00
Marc Bonnici
1daa7f97c0 ReventWorkload: Modified statedection to vary scale of images
Due to inaccuracies in revent playback, the resultant state does not
always match the templates precisely causing state detection to fail.
To help this images are now scaled to different sizes before being
matched to the templates to compensate for slight variations in size.
2016-11-04 15:25:31 +00:00
setrofim
7af5868c22 Merge pull request #276 from marcbonnici/android_utils
android: Fixed issue using single quoted command with adb_shell
2016-11-02 15:34:55 +00:00
Marc Bonnici
2e1ce49170 android: Fixed issue using single quoted command with adb_shell
When using 'check_exit_code' and 'as_root' options for adb_shell with
a command containing single quotes, the provided command was escaped
twice which has now been avoided.
2016-11-02 14:52:47 +00:00
setrofim
23eb357e9e Merge pull request #273 from setrofim/master
revent: gamepad support and refactoring
2016-10-26 17:09:56 +01:00
Sergei Trofimov
71c5d23d97 revent: updated documentation to reflect recent changes
- Updated documentation for revent format to reflect the new
  format.
- Moved format documentation below state verification section, to the
  bottom of the document,as generally this will be the least-sought
  section.
- Updated usage to document -g option
2016-10-26 13:34:14 +01:00
Sergei Trofimov
edfef444fb revent: Updated WA to use the new revent
- Updated the revent parser to handle the new revent format.
- Updated the revent parser to expose device info and recording
  metatdata.
- The parser can now be used in streaming and non-streaming mode (stream
  events from the file as they are being accessed, or read them all in
  at once).
- -g option added to "record" command to expose the gamepad recording
  mode.
2016-10-26 13:33:54 +01:00
Sergei Trofimov
3a7a5276e4 revent: added gamepad recording + major refactor
- Added support for gamepad recording. This type of recording contains
  only the events from a gamepad device (which is automatically
  identified). The details of this devices are collected and stored as
  part of the recording. On playback, uinput is used to create a virtual
  gamepad and replay into it.
- A "mode" field has been added to the recording format to help
  distinguish between the normal and gamepad recording types.
- A field for the total number of input events has been added before the
  start of the event stream (after the device description).
- The structure of revent code has undergone a major overhaul to improve
  maintainability and robustness.
- More detailed "info" command output.
- Updated Makefile to support debug/production builds.
2016-10-26 13:17:07 +01:00
setrofim
f179b09978 Merge pull request #272 from marcbonnici/revent
ReventWorkload: Corrected mistake in screen capture argument
2016-10-26 12:00:50 +01:00
Marc Bonnici
620fbfdd2a ReventWorkload: Corrected mistake in screen capture argument 2016-10-26 11:56:03 +01:00
setrofim
4213e8e7d1 Merge pull request #271 from marcbonnici/revent
ReventWorkload fixes and enhancements
2016-10-26 11:25:46 +01:00
Marc Bonnici
9fffa7958a ReventWorkload: State detection fixes
- Corrected code highlighting and phase names in documentation
- Fixed check_states paremeter not being honoured
- Moved state dependencies check to happen earlier in execution
  and to be a user facing error
2016-10-26 11:16:49 +01:00
Marc Bonnici
0f2bc17eca ReventWorkload: Added argument to take screen capture with revent record command
In order to use state detection with revent, a screen capture
is required for comparison. Added an argument to revent record command to
automatically record a screen capture after the recording is
complete.
2016-10-26 11:16:49 +01:00
Sergei Trofimov
558e40698b AndroidDevice: fixing UI hierarchy capture
- renamed the capture method from "capture_view_hierachy" to
  "capture_ui_hierarchy" to fix typo and make more descriptive.
- Change the file extension of the cature file to ".uix" because this is
  the extension uiautomatorviewer looks for.
2016-10-17 13:49:19 +01:00
Sergei Trofimov
41b52178bb pylint fixes. 2016-10-17 11:02:41 +01:00
Sergei Trofimov
8aa1bdc63d AndroidDevice: correctly handle None output on get_pids_of
It is possible that the command executed by get_pids_of() will return
None (in cases where there are no running processes with the specified
name and the grep call didn't find anything). If that happens, then the
subsequent call to split() failed (as that is not a method of None). To
avoid this, substitute an empty string instead.
2016-10-17 10:54:10 +01:00
Sergei Trofimov
8355fcf886 adb_shell: handle zero stdout on error
It looks like on recent systems, adb has started to correctly forward
stderr from the target device to stderr on the host (wereas in the past,
it got output to stdout on the host). This commit makes sure that
stderr gets correctly forwarded to the coller in cases where return code
checking was not enabled.
2016-10-17 10:49:53 +01:00
setrofim
fa7d89d734 Merge pull request #270 from jimboatarm/adobereader-s7fix
AdobeReader: Fails on S7 due to search icons being a different class.
2016-10-11 16:32:16 +01:00
Michael McGeagh
4649fa13db AdobeReader: Fails on S7 due to search icons being a different class. Removed the class specifier 2016-10-11 13:25:35 +01:00
Sergei Trofimov
10dd2b304e ApkWorkload: ensure that the APK is always replaced and that a downgrade is allowed. 2016-10-10 13:15:24 +01:00
Sergei Trofimov
93fbb7282a AndroidDevice: added support for downgrade when installing an APK
Adds support for passing -d option to "pm install", which allows
installing an APK when a newer version of the package is already present
on the device.
2016-10-10 12:55:14 +01:00
Sergei Trofimov
edc26fe75c vellamo: fixing capitalization in automation
Capitalization for the "LET'S ROLL" button text was incorrect in the
automation code. This has not caused issues up to this point, but it
seems the button is no longer being found in the latest AOSP. This
commit corrects the capitalization.
2016-10-07 17:21:56 +01:00
setrofim
6aecf1b35e Merge pull request #264 from jimboatarm/reader-workload
Reader Workload: The Adobe Reader workflow carries out typical…
2016-10-05 08:30:57 +01:00
Michael McGeagh
4c5e008609 Reader Workload: The Adobe Reader workflow carries out typical productivity tasks.
Conform to code style of other workloads.

Changed search strings to be a list. Allows user the ability to search for 1 or more search terms.

Renamed Reader to AdobeReader. Removed sleep and now detect and wait for searchicon
2016-10-04 16:59:22 +01:00
setrofim
5bed658045 Merge pull request #262 from jimboatarm/youtube-codetidy
Youtube: Codetidy to conform with the other workloads
2016-10-03 14:33:08 +01:00
setrofim
8ac5657993 Merge pull request #260 from jimboatarm/slides-codetidy
GoogleSlides: Code tidy, to conform with the other workloads.
2016-10-03 14:09:42 +01:00
setrofim
fc26daecfc Merge pull request #261 from jimboatarm/skype-codetidy
Skype CodeTidy to conform with the other workloads
2016-10-03 13:44:02 +01:00
setrofim
0232341445 Merge pull request #252 from jimboatarm/googlephotos-cropspeedchange
GooglePhotos: Change step value for crop operation to speed up workload
2016-10-03 13:25:45 +01:00
setrofim
3b052cc619 Merge pull request #266 from marcbonnici/revent
revent: Removed redundant android code
2016-09-30 14:33:52 +01:00
Marc Bonnici
3a9505d54e revent: Removed redundant android code 2016-09-30 14:25:11 +01:00
Michael McGeagh
4e94ff9ed7 Skype CodeTidy to conform with the other workloads
Dont double click if the confirm icon appears
2016-09-29 17:29:21 +01:00
Michael McGeagh
c47ae5cfcf Youtube: Codetidy to conform with the other workloads 2016-09-28 14:39:53 +01:00
Michael McGeagh
ce11b94f28 GoogleSlides: Code tidy, to conform with the other workloads. 2016-09-28 13:02:49 +01:00
Michael McGeagh
765fdd7cbb GooglePhotos: Change step value for crop operation to speed up workload. 500 is too slow and not realistic of real user behaviour.
Image order not guaranteed. Changed workflow to use subfolders to guarantee ordering and have same action be performed on the same image. As a result, swipe gestures are no longer applicable

Colour change was using clicks. Now uses drags. This is more reliable across devices
2016-09-28 09:58:22 +01:00
setrofim
77d724efa3 Merge pull request #258 from ep1cman/install_fix
ApkWorkload: Fixed replacing apps on a device
2016-09-26 17:00:39 +01:00
Sebastian Goscik
acb9dd61e7 ApkWorkload: Fixed replacing apps on a device
Previously if trying to downgrade an app using the `-r` option of
`adb install` the `INSTALL_FAILED_VERSION_DOWNGRADE` error would occur.
The app is now uninstalled first to prevent this.
2016-09-26 16:53:03 +01:00
Sebastian Goscik
cc7684986a Merge pull request #256 from marcbonnici/master
Skype: Added check for update popup.
2016-09-23 11:42:43 +01:00
Marc Bonnici
e69aea4e69 Skype: Added check for update popup.
Since there has been an update to the skype app, there was now a
update prompt preventing test from running. Now checks for the
prompt on older versions of skype and dismisses it if present.
2016-09-23 11:18:40 +01:00
setrofim
2b6f036d9a Merge pull request #255 from jimboatarm/skype-codetidy
Skype: Codetidy, no functional changes
2016-09-22 17:28:25 +01:00
Michael McGeagh
5738d19114 Skype: Codetidy, no functional changes. Make voice action default in code, move private function to bottom. 2016-09-22 16:52:39 +01:00
setrofim
53ae47bff3 Merge pull request #254 from marcbonnici/master
ReventWorkload:Fixed revent workloads with multiple iterations
2016-09-22 11:29:19 +01:00
Marc Bonnici
1c8e18bf36 ReventWorkload:Fixed revent workloads with multiple iterations
Since initilize only runs once per workload, we can't set variables required
for each iteration in initilize. Revent workload was setting its file paths
in initilize, now moved to setup.
2016-09-22 11:26:25 +01:00
Sebastian Goscik
5dbf7e7d38 Merge pull request #251 from jimboatarm/googlephotos-codetidy
GooglePhotos: Reorder functions and relabel ActionLogger tags
2016-09-20 12:48:45 +01:00
Michael McGeagh
a2945d58cb Reorder functions and relabel ActionLogger tags. No functional changes made to actual workload run 2016-09-20 11:15:40 +01:00
Sebastian Goscik
8727fe514a Merge pull request #249 from jimboatarm/googleplaybooks-gesturefix
GooglePlayBooks: Reorder so that the gesture test happens after selec…
2016-09-20 10:55:57 +01:00
setrofim
6465e732fd Merge pull request #250 from ep1cman/apk_ver_fixes
Redone APK file resolution
2016-09-20 10:50:29 +01:00
Sebastian Goscik
f9ec869c7b Revert "Updated workload versions to match APK files"
This reverts commit b426e00f2f.
2016-09-20 10:47:57 +01:00
Sebastian Goscik
1bbd3ef87a Revert "workloads: Fixed versions to be backward compatible"
This reverts commit 8608c3b747.
2016-09-20 10:47:57 +01:00
Sebastian Goscik
486ade6499 ApkWorkload: Reworked APK Resolution.
APK Resolution is now handled a bit differently to try maximise the likelyhood
of a workload running.

Like before `force_install` will always try to install the host version, if it
is not present or is not a correct version, it will error.

`check_apk` has changed so that when it is `True` it will prefer to use the host
side APK. If it is not there, or not a suitable version and/or abi and the target
already has a correct version of the app, the target app will be used. When it is
to `False` WA will prefer the target version of the app so long as it is a valid
version, if it is not then it will fallback to the host side APK.
2016-09-20 10:47:57 +01:00
Sebastian Goscik
1a23bd03a2 runner: Some types of exceptions will no longer take screenshots or dump UI hiarchy
For resource or Host errors (error which are not caused by the target).
the runner will no longer take screenshots ect as these are meaningless.
2016-09-20 10:13:14 +01:00
Michael McGeagh
5018a1ec94 GooglePlayBooks: Reorder so that the gesture test happens after selecting a known chapter in the book. Previously the gestures could happen on any random page thus making the results not neccessarily comparable to another run. 2016-09-20 10:10:21 +01:00
Sebastian Goscik
fe58245843 Merge pull request #248 from jimboatarm/youtube-actionlogger-modified
Youtube: Changed actionlogger to measure different more relevant acti…
2016-09-19 17:36:39 +01:00
Sebastian Goscik
006bf6387f Merge pull request #247 from jimboatarm/googleplaybooks-actionlogger-renametags
GooglePlayBooks: Modified ActionLogger tags and capture points
2016-09-19 17:34:52 +01:00
Michael McGeagh
19569816d3 Youtube: Changed actionlogger to measure different more relevant actions. Also rearranged if statement for video_source so that the default is at the top. 2016-09-19 16:46:03 +01:00
Michael McGeagh
1dfbaf4ebe GooglePlayBooks: Modified ActionLogger tags and capture points 2016-09-19 14:21:03 +01:00
Sebastian Goscik
5b7d61b4b9 Merge pull request #246 from jimboatarm/googleslides-slidecount-fix
GoogleSlides workload did not do slide_count number of swipes in edit…
2016-09-19 13:40:08 +01:00
Michael McGeagh
b5dc5b8648 GoogleSlides workload did not do slide_count number of swipes in edit mode. This fixes that. 2016-09-19 13:26:21 +01:00
setrofim
2202326c02 Merge pull request #244 from ep1cman/glb_bug
workloads: Fixed versions to be backward compatible
2016-09-13 11:47:14 +01:00
Sebastian Goscik
8608c3b747 workloads: Fixed versions to be backward compatible
In a recent commit workload versions were changed to match their APK versions.
This commit adds the old versions to the allowed versions and automatically
maps them onto the new values.
2016-09-13 11:07:18 +01:00
Sebastian Goscik
9afe084f2c Merge pull request #243 from setrofim/master
Miscellaneous fixes
2016-09-13 10:26:51 +01:00
Sebastian Goscik
83ab1ac441 Merge pull request #242 from jimboatarm/upstream-slides
Add Google slides workload
2016-09-13 10:24:19 +01:00
Sergei Trofimov
ea1d13c37f common/android: pep8 fixes
- added missing space between global definitions and a class
- added missing space for inline comment
2016-09-13 10:22:47 +01:00
Sergei Trofimov
20996e9a58 core: changing the time of constraint validation for params
Constraints and allowed values of Extension Parameters will now be check
when the Parameter value is set, rather than when validating the
extension. Mandatory status of a Parameter is still checked during
valudation.
2016-09-13 10:20:52 +01:00
Sergei Trofimov
3711f7316d cpustates: fixing stand-alone script with timeline option
When running the stand-alone cpustates script and specifying a timeline
file (which causes the corresponding reporter to be enabled), a
timeline report is generated in addition to the usual cpustates and
parallelism reports.

Up to this point, the main() of the stand-alone script was expecting
exactly two reports and so it crashing when running with the timeline
option. This commit fixes this case.
2016-09-13 10:16:25 +01:00
muendelezaji
d279cc7453 Add Google Slides workload 2016-09-12 17:57:41 +01:00
muendelezaji
f6b8fd3f4b Ignore exception for non-fatal permission grant failure 2016-09-09 23:22:38 +01:00
Sebastian Goscik
ff2f88fbd7 Merge pull request #225 from jimboatarm/googlephotos_uxperf
Add googlephotos workload
2016-09-09 14:26:46 +01:00
John Richardson
96f4ade874 Add googlephotos workload 2016-09-09 09:56:15 +01:00
setrofim
ac0256e377 Merge pull request #239 from jimboatarm/googleplaybooks_fix
Updates and fixes for googleplaybooks workload
2016-09-08 15:50:17 +01:00
Sebastian Goscik
793af6253f Merge pull request #241 from jimboatarm/skype_uxperf
Add Skype workload
2016-09-08 13:34:57 +01:00
John Richardson
5ef7d2dd44 Remove skypevideo workload
The original skypevideo workload has now been replaced with the newer
skype workload.
2016-09-07 16:51:40 +01:00
John Richardson
cf8cb5bfab Add Skype workload 2016-09-07 16:45:11 +01:00
muendelezaji
9376c6875b ApkWorkload extension support
- Allow disabling main activity launch in setup (required for some apps)
- Parameterise clear data on reset (default behaviour unchanged)
2016-09-07 16:45:07 +01:00
setrofim
a6347f5833 Merge pull request #240 from ep1cman/master
Workloads: Fixed issues with calling super
2016-09-06 10:16:08 +01:00
Sebastian Goscik
38a7e01e83 Workloads: Fixed issues with calling super
Super works by having a iterator of parent classes to ensure each is called
once and only once. WA calls some parent methods in classes with multiple
inheritenceconditionally so calls them directly instread. This breaks super
which ends up calling some methods multiple times.

To work around this until workloads are reworked to use composition rather than
inheritance, all classes that that subclass `Workload` directly no longer use
`super`.
2016-09-06 10:11:09 +01:00
John Richardson
e18366b3f8 Add support for chrome books to googleplaybooks workload
Accommodate layout changes in googleplaybooks on chrome book devices
when accessing the action bar menu in the app.
2016-09-05 17:15:49 +01:00
Sebastian Goscik
b9701201a3 Merge pull request #227 from jimboatarm/upstream-youtube
Add Youtube workload
2016-09-05 15:37:47 +01:00
muendelezaji
441ba974b7 Youtube workload 2016-09-05 15:03:53 +01:00
John Richardson
a33df50ce8 Use new AndroidUxPerformance class in googleplaybooks
Utilise new convenience method for checking for an valid internet
connection and set the min_apk_version within the AndroidUxPerformance
class.
2016-09-05 14:56:14 +01:00
John Richardson
52d4635fe8 Improve logic for scrolling during book search 2016-09-02 15:29:28 +01:00
John Richardson
14924ec6f4 Remove hardcoded package name from googleplaybooks workload 2016-09-02 15:29:28 +01:00
setrofim
3d610788a3 Merge pull request #238 from jimboatarm/check_app_version_uxperf
Add check_app_version method to ApkWorkload
2016-09-02 11:59:08 +01:00
John Richardson
1986511ae8 Add check_app_version method to ApkWorkload
Implement new method to enforce that a valid apk version is used to run
the workload. Based on a min and max range of apk versions tested
during development.
2016-09-02 11:56:40 +01:00
Sebastian Goscik
175e7f3cc0 Merge pull request #237 from jimboatarm/workload-check-internet
Add network check methods to Device and Workload classes
2016-09-02 10:35:01 +01:00
muendelezaji
392a3f1600 Add network check methods to Device and Workload classes
- Device subclasses should provide their own implementation.
    Default behaviour is to raise a `NotImplementedError`
  - Workload subclasses can set `requires_network` to `True` and
    network connectivity check will be performed during `setup()`
2016-09-02 10:33:18 +01:00
Sebastian Goscik
b5c0bdb0eb Merge pull request #236 from jimboatarm/android_uxperf_workload
Android uxperf workload
2016-08-31 15:02:57 +01:00
John Richardson
502b0ed4b3 Add package name to uiautomator params in AndroidUxPerfWorkload
The package name is common to all workloads that inherit from this
class and is used when locating UI elements.
2016-08-31 14:44:21 +01:00
John Richardson
cab9d918ab Move uiautomator params in AndroidUxPerfWorkload
uiautomator parameters are set per instance of a workload and not per
iteration. Move uiautomator parameter assignment from setup() to
validate().
2016-08-31 14:43:33 +01:00
Sebastian Goscik
e686e89b39 Merge pull request #234 from jimboatarm/broadcast_media_mounted
Add broadcast_media_mounted method to android device
2016-08-31 11:43:42 +01:00
John Richardson
b510b31052 Add broadcast_media_mounted method to android device
New method to force a re-index of the mediaserver cache for the
specified directory. Used in workloads that require external media files
as dependencies.
2016-08-31 10:24:06 +01:00
setrofim
5b59d101ef Merge pull request #232 from ep1cman/cleanup
Cleanup
2016-08-26 17:32:50 +01:00
Sebastian Goscik
7713f02252 Execution: Added a clean_up global config to delete WA files from devices
Adds a WA configuration point `clean_up` that will delete the WA binaries
directory  and the WA working directory from a device at the end of a WA run.
2016-08-26 17:25:11 +01:00
Sebastian Goscik
0a2afdfd84 AndroidDevice: Added -rf to delete_files
This allows it to delete folders and makes it consistend with LinuxDevice.
2016-08-26 17:13:21 +01:00
Sebastian Goscik
530714c61c Merge pull request #228 from jimboatarm/uxperf_workload_class
Add new AndroidUxPerfWorkload class
2016-08-26 13:46:25 +01:00
John Richardson
67f418f79f Add new AndroidUxPerfWorkload class
Create a new workload class to encapsulate functionality common to all
uxperf workloads.
2016-08-26 12:22:39 +01:00
setrofim
64860a2d1a Merge pull request #229 from ep1cman/dependencies
pylint fixes
2016-08-25 14:25:42 +01:00
Sebastian Goscik
f57dd83d1a pylint fixes 2016-08-25 14:20:10 +01:00
setrofim
3782a33060 Merge pull request #226 from ep1cman/version_check_fixes
Version check fixes
2016-08-24 16:01:18 +01:00
Sebastian Goscik
8e27794124 Added a script to check APK/Workload versions for inconsistencies 2016-08-24 15:48:22 +01:00
Sebastian Goscik
9d4aa4983a antutu: Fixed setting permissions
It has been observed on some devices that the FINE_LOCATION premissions is required
for antutu to run without asking for permissions at run time but this was not listed
in the APK manifest. This caused issues on devices were only the permissions in the
manifest can be granted. This commit sliences any error when trying to set this permission
as well as only trying only on Android 6+
2016-08-24 14:36:00 +01:00
Sebastian Goscik
b426e00f2f Updated workload versions to match APK files
Some workloads presented a different version than what was in the APK file.
With the changes introduced in bb33123 several workloads broke.
2016-08-24 14:33:18 +01:00
Sebastian Goscik
07d34e5615 ApkWorkload: Moved APK resolution into setup
Previously if you had multiple versions of the same workload in one
agenda only the first one would work, the others would fail to find
their APK.
2016-08-24 14:28:53 +01:00
Sebastian Goscik
b1ae5a5465 Merge pull request #224 from setrofim/master
ssh: fixing rasing of CalledProcessErrorWithStderr
2016-08-23 17:26:07 +01:00
Sergei Trofimov
4ea4bc8631 ssh: fixing rasing of CalledProcessErrorWithStderr
CalledProcessErrorWithStderr is a subclass of CalledProcessError that
also takes stderr output. Both that and normal output must be passed as
keyword arguments. They were being passed as keyword arguments inside
_scp() of SshConnection, causing cryptic errors to appear.

Additionally, "output" was not being properly poped off before invoking
super's init.
2016-08-23 17:22:02 +01:00
Sebastian Goscik
fe259dca05 Merge pull request #216 from jimboatarm/googleplay_uxperf
Add UxPerfUiAutomation and googleplaybooks workload
2016-08-09 13:49:02 +01:00
John Richardson
86f3066f56 Add unsupported package check to AndroidUiAutoBenchmark
Add method to automatically check against a dictionary of known package
versions that don't work well with AndroidUiAutoBenchmark workloads.
Raises an exception if found.
2016-08-09 12:08:28 +01:00
John Richardson
0f579e18b3 Add googleplaybooks workload 2016-08-09 12:08:20 +01:00
John Richardson
25172fb027 Add UxPerfUiAutomation class
UxPerfUiAutomation contains methods specific to UX performance testing.
2016-08-09 09:56:04 +01:00
John Richardson
550a0db61a Rename dumpsys_enabled parameter to markers_enabled
Change parameter name for enabling markers to better reflect its
purpose. The old name was a misnomer.
2016-08-09 09:56:04 +01:00
John Richardson
73c2609a72 Fix message regex in uxperf result processor
The logcat output differs between devices. Modify the regex pattern to
accommodate different output formats when matching UX_PERF markers.
2016-08-09 09:56:04 +01:00
setrofim
1ec7961b0e Merge pull request #210 from drcef/master
Implemented visual state detection functionality for revent workloads
2016-08-05 11:57:59 +01:00
George Psimenos
01f2a5f412 Implemented visual state detection functionality for revent workloads
- Added statedetect.py in utils which is a standalone module that
    contains all the methods needed for state detection

  - Modified the setup() and run() methods of the GameWorkload class
    in common/android/workload.py to have a parameter that enables
    state checks and run the check after setup and run if requested.

State detection uses the template matching method available in
OpenCV to determine the state of the workload by detecting
predefined unique elements on a screenshot from the device.
2016-08-05 10:09:18 +01:00
setrofim
480a054860 Merge pull request #220 from ep1cman/master
RunConfiguration: Fixed disabling of instruments in workload specs
2016-08-04 16:18:52 +01:00
Sebastian Goscik
e9ba9352a6 RunConfiguration: Fixed disabling of instruments in workload specs 2016-08-04 16:16:53 +01:00
Sebastian Goscik
0a3ff099c0 Merge pull request #219 from jimboatarm/mdzj/upstream-get-assets
Add script to get external assets for workloads
2016-08-04 15:46:16 +01:00
muendelezaji
75cc5854bf Add script to get external assets for workloads 2016-08-04 13:59:12 +01:00
Sebastian Goscik
77aaa0b849 Merge pull request #217 from jimboatarm/dump_hierarchy_uxperf
Dump hierarchy view on error
2016-08-03 09:57:09 +01:00
John Richardson
0945dd6ba4 Dump hierarchy view on error
Dump window hierarchy view from uiautomator to a file when WA fails
during execution. Note: the xml file are pre-formatted after dump.
Implementation specific to android.device.
2016-08-02 16:47:24 +01:00
setrofim
4c94ba43ac Merge pull request #215 from jimboatarm/remove-old-apk-permissions
permission grant for API 23 and above
2016-07-29 16:33:59 +01:00
muendelezaji
efae2e8c32 Android permission grant for API 23 and above
Issue: On some devices, _grant_requested_permissions may throw an
error when trying to grant permissions that were already granted
at install time using 'adb install -g'.

Fix: Surround permission grant method for API 23+ with try/except

Issue: Currently, _grant_requested_permissions skips all lines after
the first line not starting with 'android.permission'. This causes
a problem for apps where some required permissions appear after a
non-matching line e.g. Google Slides.

Fix: Don't break on non-matching line until end of section is reached
2016-07-29 16:27:29 +01:00
Sebastian Goscik
59874b862d Merge pull request #212 from jimboatarm/fps_util_uxperf
Additional changes to FpsProcessor, fps instrument and uxperf result processor
2016-07-27 14:56:14 +01:00
John Richardson
da19859c25 Add logging and exception handling to uxperf result processor
The uxperf result processor now provides warnings for unmatched UX_PERF
markers when running the fps instrument. Previously unmatched markers
resulted in an exception being thrown. Includes additional logging for
debugging purposes.
2016-07-27 14:50:24 +01:00
Sebastian Goscik
d87e425c24 Merge pull request #214 from jimboatarm/network_check_uxperf
Add network connectivity check for devices
2016-07-27 11:59:57 +01:00
John Richardson
2872080d1a Add network connectivity check for devices
Add a general check that pings a IP address rather than checking the
status of dumpsys wifi due to the fact that not all devices are
connected via wifi. Intended for workloads that require an internet
connection to operate.
2016-07-26 16:30:06 +01:00
John Richardson
625a3a39a5 Add dumpsys_period parameter to fps instrument
Add a new parameter to fps instrument to specify the time period between
calls to ``dumpsys SurfaceFlinger --latency`` in seconds when collecting
frame data. A lower value improves the granularity of timings when
recording actions for UX Performance metrics.
2016-07-26 11:30:34 +01:00
John Richardson
aa2d187c4d Fix for FpsProcessor logic in utils module
- Add requirement on filtered_vsyncs_to_compose for total_vsync metric
- Remove misleading comment in class description
2016-07-26 11:29:51 +01:00
Sebastian Goscik
b80e5dc52e Merge pull request #213 from jimboatarm/baselib_uxperf
Extensions to baselib for UX Performance
2016-07-26 11:28:57 +01:00
John Richardson
2208d45bfb Add further convenience methods to BaseUiAutomation
Convenience methods to make it easier to get UiObjects and perform
UiDevice based gestures and operations.
2016-07-26 10:34:04 +01:00
John Richardson
51e4e71931 Upgrade Android API level from 17 to 18
Upgrade API level for BaseUiAutomation from 17 -> 18 and update
dependent workloads accordingly.
2016-07-26 10:30:15 +01:00
John Richardson
0388fa6f36 Minor code maintenance for base class BaseUiAutomation
- Rename inconsistently named variables
- Avoid long wrapped lines where possible
- Fix whitespace around operators
2016-07-26 08:59:17 +01:00
setrofim
ee7c04a568 Merge pull request #209 from ep1cman/revent_fixes
Pylint fixes
2016-07-21 16:47:14 +01:00
Sebastian Goscik
9707aa6237 Pylint fixes
Pylint now checks for trailing new lines, this commit fixes them.
2016-07-21 16:40:26 +01:00
setrofim
019ee34c0d Merge pull request #207 from ep1cman/revent_fixes
Revent fixes
2016-07-21 15:43:55 +01:00
Sebastian Goscik
873bdf0bc7 revent: replay and record fix + reorganisation
The two commands now always copy over revent.

Reoraganised the commands to use a common base class.
2016-07-21 15:42:12 +01:00
Sebastian Goscik
54c409ce6f revent: Fixed magic check
A null character was not being added to the end of the string.
2016-07-21 15:42:11 +01:00
setrofim
a2d0747b4c Merge pull request #200 from ep1cman/revent_fixes
revent: Fixed dump command segfault
2016-07-19 16:54:53 +01:00
Sebastian Goscik
25eac432c9 revent: Added revent file structure to documentation 2016-07-19 16:52:12 +01:00
Sebastian Goscik
dd61f99785 revent: Updated resource getters to check if a file is actually a recording 2016-07-19 16:48:13 +01:00
Sebastian Goscik
164f207084 revent: Timeout is now based on recording duration
The revent file is now parsed and the duration of the recording is calculated.
This duration + 30 seconds is now used for the timeout for revent.
2016-07-19 16:48:13 +01:00
Sebastian Goscik
cb01b0c9a9 utils/revent: Added revent recording parser
revent binary recordings can now be parsed and used within WA.
2016-07-19 16:48:13 +01:00
Sebastian Goscik
139a0698c9 revent: Added "magic" and file version to revent files.
revent files should now start with "REVENT" followed by the file format
version.
2016-07-19 16:48:13 +01:00
Sebastian Goscik
259b813a96 revent: Various fixes.
revent:
    - Fixed 32-bit/64-bit compatibility by no longer "long" for timestamps
    - Removed superfluous code
    - SIGTERM is now handled only while waiting for a file not while processing one
    - Added '-s' to docs
    - Fixed path_buff size

Record Command:

    - Removed timeout in command as -s is specified.
    - Previously the command would send SIGTERM to revent but not wait for it to terminate.
      This would result in the pulled recording missing its send. This has now been fixed.

Replay Command:
    - Added more logging
2016-07-19 16:11:42 +01:00
Sebastian Goscik
299b28b3c1 Merge pull request #203 from setrofim/master
resource getters: weaken File to also resove to directories
2016-07-15 16:07:49 +02:00
Sergei Trofimov
ece33c1d68 resource getters: weaken File to also resove to directories
Because UNIX tells us that "everything is a file".
2016-07-15 15:05:19 +01:00
Sebastian Goscik
f68cf4e317 Merge pull request #201 from jimboatarm/marker_api
Add per-action instrumentation for UX performance
2016-07-15 11:15:46 +02:00
John Richardson
c49c5c4121 Add per-action instrumentation for UX performance
- Implement a new Marker API in BaseUiAutomation so workload can
  generate start and end markers with string name. Outputs to logcat.

- Document the Marker output log format in the WA documentation

- Create a results processor to take existing instrument fps logs and
  parse them based on the workload markers. Produce per-action fps
  metrics.

- Add simple timing results based on the workload markers
2016-07-14 13:49:39 +01:00
John Richardson
b8d7956d4c Move processing logic in fps instrument to utility file
Processing logic for frame statistics can be moved out of fps instrument
to a new utility file. This will allow result processors to use the same
logic to produce frame statistics on a subsection of the data
produced by the fps instrument.
2016-07-14 13:49:39 +01:00
setrofim
fee872585f Merge pull request #202 from mdigiorgio/camerarecord-slowmo
camerarecord: add possibility to select slow_motion recording mode
2016-07-13 17:14:07 +01:00
Michele Di Giorgio
2dd3a2ba4d camerarecord: add possibility to select slow_motion recording mode
Signed-off-by: Michele Di Giorgio <michele.digiorgio@arm.com>
2016-07-13 16:40:39 +01:00
setrofim
662033399f Merge pull request #190 from jimboatarm/upstream-apk-check
Apk version check
2016-07-12 17:53:01 +01:00
muendelezaji
bb33123b17 Check APK version and ABI when installing
- Check the APK's versionName property against the workload's
  expected version if specified
- If workload specifies check_abi param, try to get APK from
  ABI-specific path on the host
- Add variant_name param to APK resource-getter for backwards
  compatibility of dex2oat and peacekeeper
2016-07-12 17:02:17 +01:00
muendelezaji
fab6a977aa Properly replace APK during adb install
Issue: For certain installation errors, it is possible for WA to
 incorrectly report that an APK was reinstalled while it actually
 wasn't, leading to bugs later on in the run.

Fix:
 - Add the '-r' flag to adb install when reinstalling, to make sure
   APK is replaced.
 - Add '-g' flag for API 23 and higher, to grant all permissions that
   would otherwise be requested at runtime (similar to pre-API 23)
2016-07-12 13:08:28 +01:00
setrofim
25dd6b71f3 Merge pull request #194 from mdigiorgio/camerarecord-framestats
camerarecord: add frame stats collection through dumpsys gfxinfo
2016-07-11 15:43:13 +01:00
Sebastian Goscik
246416d4d2 Merge pull request #197 from setrofim/master
file_poller fixes.
2016-07-11 14:56:01 +02:00
Sergei Trofimov
1fe037486f file_poller: added error checking and reporting
- Updated poller binary to propery check for errors (e.g. on attempting
  to open a file) and report them to stderr
- Updated the file_poller instrument to collect poller stderr output
  into a log file and to check the log for errors or warnings on
  completion of an iteration.
2016-07-11 13:55:11 +01:00
Michele Di Giorgio
f27b500028 camerarecord: add frame stats collection through dumpsys gfxinfo
Signed-off-by: Michele Di Giorgio <michele.digiorgio@arm.com>
2016-07-11 13:53:38 +01:00
Sergei Trofimov
5a780e8211 file_poller: fixed validation with Linux devices
- device.is_rooted check was being perfromed inside validate() which
  gets invoked before the device is connected. This worked for most
  Android devices, because connections is a no-op for them, however
  failed for Linux targets. The check is now performed inside
  initialize().
- Added _is_ready() check inside is_rooted to catch similar problems
  quicker in the future.
2016-07-11 13:23:15 +01:00
setrofim
60ca0649ab Merge pull request #196 from ep1cman/master
file-poller: Improved csv output
2016-07-11 11:21:45 +01:00
Sebastian Goscik
dbda128813 file-poller: Improved csv output
All ',' and '\n' will now be stripped from the files contents so it doesn't
effect csv formatting

Also fixed some whitespace
2016-07-11 11:06:57 +01:00
setrofim
ff7a0626ce Merge pull request #193 from per-mathisen-arm/master
Fix a frequently repeated typo
2016-07-11 09:09:13 +01:00
setrofim
9a94c59605 Merge pull request #195 from mdigiorgio/geekbench-output
geekbench: fix output files listing
2016-07-11 09:08:53 +01:00
Michele Di Giorgio
d3dd9c849a geekbench: fix output files listing
After running the benchmark, when collecting the output files the execution
fails because the split('\n') call, used for creating a list of output files,
returns an empty string as last element. The empty string makes the pull command
fail because file '' doesn't exist on the target device.

Signed-off-by: Michele Di Giorgio <michele.digiorgio@arm.com>
2016-07-08 11:59:51 +01:00
Per Inge Mathisen
12a78ce291 Fix a frequently repeated typo 2016-07-08 10:16:47 +02:00
Sergei Trofimov
c8a735e298 sysbench: adding arm64 binary 2016-07-01 17:35:19 +01:00
Sebastian Goscik
071bf9fba7 Merge pull request #189 from ranjeetkumar/master
Permission granted for generic browser
2016-06-29 13:40:46 +01:00
Sebastian Goscik
ef919a0fa9 Merge pull request #186 from setrofim/master
LinuxDevice: error output for pull/push_file
2016-06-29 13:39:02 +01:00
Ranjeet Kumar
88b18dda07 Permission granted for generic browser 2016-06-29 17:57:25 +05:30
Sergei Trofimov
242df842bc LinuxDevice: error output for pull/push_file
Standard string representation of a subprocess.CalledProcessError does
not include the output of the command, so it was not previsouly included
in the resulting DeviceError. This commit ensures that the output is
propagated, regardless of whether it came from stdout or stderr of the
underlying process.
2016-06-28 13:48:48 +01:00
setrofim
a6355885fc Merge pull request #185 from ep1cman/fixes
AndroidDevice & BaseLinuxDevice: minor parameter changes
2016-06-21 14:57:05 +01:00
Sebastian Goscik
77a44f11c6 AndroidDevice & BaseLinuxDevice: minor parameter changes
Moved ``working_directory`` parameter to BaseLinuxDevice.

Changed the default ``binaries_directory`` for AndroidDevice to allow
WA binaries to be easily separated.
2016-06-21 14:55:02 +01:00
Sergei Trofimov
afeb726d53 energy_model: only set "ui" runtime parameter for ChromeOS
energy_model instrument generates job specs during the run. One of the
things it does is set "ui" runtime parameter to "off". This parameter
only exists for ChromeOS devices. This commit ensure that the parameter
is not set when running on any other device.
2016-06-21 09:14:12 +01:00
setrofim
7904e6b562 Merge pull request #182 from ep1cman/fixes
sysfs_extractor & cpufreq: Fixed error when tar.gz file already existed
2016-06-20 10:13:38 +01:00
Sebastian Goscik
224b973ace sysfs_extractor & cpufreq: Fixed error when tar.gz file already existed
If the tar.gz already existed on the target device the instruments would
fail. This fix adds the "-f" option to gzip to force it to overwrite the
file.
2016-06-20 10:12:00 +01:00
Sergei Trofimov
8660d0f488 hwuitest: invoke executable via full path
Previously, the workload was invoking the executable via its name,
assuming that it will be in PATH. As WA's executables directory is not
in path, the invocation was failing. This commit saves the full path to
the installed executable and uses that instead.
2016-06-17 08:03:50 +01:00
Sergei Trofimov
be7aa3d379 recentfling: fixing uninstalling of binaries
Inconsistently, while install() for Android devices automatically
handles both APKs and executables appropriately, uninstall() only works
for packages. Changing to use uninstall_executable() for the scripts
deployed by recentfling.
2016-06-15 09:00:49 +01:00
setrofim
8503fea0ee Merge pull request #180 from ep1cman/release-notes
docs: Clarified documentation regarding binary dependencies
2016-06-14 11:18:25 +01:00
Sebastian Goscik
4a15a41cf8 docs: Clarified documentation regarding binary dependencies 2016-06-14 11:13:54 +01:00
Sebastian Goscik
3a90309383 Merge pull request #179 from setrofim/master
bbench and recentfling fixes
2016-06-14 10:22:20 +01:00
Sergei Trofimov
b48e5ce58a recentfling: script deployment and PID file fixes
- Scripts are now deployed during via install() ensuring that they are
  executable.
- Handle the case where the PID file is delted before getting to
  process_results.
- Exposed the option to not start any apps before flinging via a
  parameter.
2016-06-14 10:21:06 +01:00
Sergei Trofimov
f33d6f4729 bbench: handle lack of results in logcat
- make sure results_list is always instatiated even if no metrics found;
  this would previously cause a "used before declaration" error
- Detect that no metrics were extracted from the log and raise a
  WorkloadError
2016-06-14 10:20:51 +01:00
Sergei Trofimov
6f8989a8ba setup.py: Updated url to be a valid URI
New PyPI upload APIs were complaining.
2016-06-10 15:56:19 +01:00
Sebastian Goscik
a826b661f4 Version bump 2016-06-10 14:26:32 +01:00
setrofim
43f4e52995 Merge pull request #178 from ep1cman/release-notes
Documentation changes & Removing apk_version
2016-06-10 13:22:11 +01:00
Sebastian Goscik
23b3b165d5 docs: Change log & updates 2016-06-10 13:17:10 +01:00
Sebastian Goscik
2f87e126f0 apk_version: Removed instrument
APK versions are now added as result classifiers:
48259d872b
2016-06-09 13:55:27 +01:00
setrofim
59d74b6273 Merge pull request #177 from ep1cman/release-notes
servo_power: Added check for device platform.
2016-06-08 11:16:14 +01:00
Sebastian Goscik
7b92f355c8 netstat: Changed exception type & typo fix 2016-06-08 11:13:35 +01:00
Sebastian Goscik
982069be32 servo_power: Added check for device platform.
Now checks to see if the device is running chromeOS.
2016-06-08 11:10:53 +01:00
setrofim
63ff8987ea Merge pull request #176 from ep1cman/cpustates
cpustates
2016-06-06 17:12:12 +01:00
Sebastian Goscik
f276d4e39f cpustates: Added the ability to configure how a missing start marker is handled.
cpustates can now handle the lack of a start marker in three ways:

 - try: If the start marker is present only the correct section of the trace
        will be used, if its not the whole trace will be used.
 - error: An error will be raised if the start marker is missing
 - ignore: The markers are ignored and the whole trace is always used.
2016-06-06 17:09:48 +01:00
Sebastian Goscik
1811a8b733 PowerStateProcessor: Added a warning when no stop marker is encountered
PowerStateProcessor will now stop itrerating over events when it finds
a stop marker. If it does not find a stop marker it will log a warning.
2016-06-06 17:03:56 +01:00
Sebastian Goscik
0ae03e2c54 PowerStateProcessor: Exceptions no longer stop processing
If an exception is raised inside a generator it cannot be continued.
To get around this exceptions are now caught and later output via the
logger.

Also added logger setup when running cpustates as a standalone script
2016-06-06 16:28:07 +01:00
Sebastian Goscik
c423a8b4bc Utils.misc: Added memoised function decorator
This allows the return value of a function to be cached so that
when it is called in the future the function does not need to
run.

Borrowed from: https://github.com/ARM-software/devlib
2016-06-06 16:28:07 +01:00
Sebastian Goscik
c207a34872 cpustates: Now shows a warning when it fails to nudge a core.
Before WA would raise a error message that wasn't very clear.
Now when cpustates tries to nudge cores and and error occurs it
will only show a warning (which promts users to check if the cpu is
hot plugged out) and keep going with the reset of the run without
causing errors in other WA extensions.
2016-06-02 15:14:03 +01:00
setrofim
2cb40d3da6 Merge pull request #175 from ep1cman/master
Revent fixes
2016-06-01 17:04:46 +01:00
Sebastian Goscik
18d1f9f649 ReventWorkload: Now kills all revent instances on teardown
Previously revent would be left running if a run was aborted.
2016-06-01 16:47:01 +01:00
Sebastian Goscik
17ce8d0fe9 Revent: Device model name is now used when searching for revent files
Previously the WA device name was used when searching for revent files.
Since most were `generic_android` this made it difficult to keep revent
files for multiple android devices. Now it the device model is used instead.

If a file with the device model is not found it will fall back to the WA
device name.
2016-06-01 16:47:01 +01:00
setrofim
ac03c9bab4 Merge pull request #174 from ep1cman/master
LinuxDevice fixes
2016-06-01 14:14:13 +01:00
Sebastian Goscik
8bdffe6f9c LinuxDevice: Removed has_root method
Was not used anywhere and is_rooted should be used instead
2016-06-01 14:13:37 +01:00
Sebastian Goscik
2ff13089fd LinuxDevice: kick_off & killall will now run as root on rooted devices by default
kick_off has been changed to behave the same as AndroidDevice.

Said changes caused kill all to fail on rooted devices. Killall will now
behave in the same way as kick_off, if specifically told to (or not to)
run as root it will. Otherwise it will run as root if the device is rooted
2016-06-01 13:50:59 +01:00
setrofim
772346507c Merge pull request #144 from ep1cman/servo
servo_power: Added support for chromebook servo boards
2016-05-27 16:16:49 +01:00
Sebastian Goscik
0fc88a84be servo_power: Added support for chromebook servo boards
Servo is a debug board used for Chromium OS test and development. Among other uses, it allows
access to the built in power monitors (if present) of a Chrome OS device. More information on
Servo board can be found in the link bellow:

 https://www.chromium.org/chromium-os/servo

based on: 03ede10739
and: 9a0dc55b55
2016-05-27 16:09:08 +01:00
setrofim
6e4f6af942 Merge pull request #164 from ep1cman/poller
Poller: Added an instrument to poll files and output a csv of their v…
2016-05-26 16:33:59 +01:00
Sebastian Goscik
c87daa510e Poller: Added an instrument to poll files and output a csv of their values 2016-05-26 16:32:58 +01:00
Sebastian Goscik
5e1c9694e7 Merge pull request #171 from setrofim/master
list_or_string: ensure that elements of a list are always strings
2016-05-26 16:07:22 +01:00
Sergei Trofimov
a9a42164a3 list_or_string: ensure that elements of a list are always strings 2016-05-26 16:05:43 +01:00
Sebastian Goscik
0d50fe9b77 AndroidDevice: kick-off no longer requires root
kick off will now use root if the device is rooted or if manually
specified otherwise its run without root.
2016-05-26 10:29:21 +01:00
setrofim
e5c228bab2 Merge pull request #170 from ep1cman/camera_update
cameracapture & camerarecord: Fixed parameters
2016-05-25 09:49:58 +01:00
Sebastian Goscik
7ccac87b93 cameracapture & camerarecord: Fixed parameters
Parameters were not being passed to the UI automation properly
2016-05-25 09:49:21 +01:00
setrofim
24a2afb5b9 Merge pull request #168 from ep1cman/vellamo-update
Vellamo update
2016-05-24 13:01:31 +01:00
Sebastian Goscik
9652801cce vellamo: Fixed geting values from logcat
The previous method of getting results out of logcat does not work
if the format of logcat changes.
2016-05-24 13:00:10 +01:00
setrofim
881b7514e2 Merge pull request #169 from ep1cman/buildprop
AndroidDevice: Improved gathering of build props
2016-05-24 12:56:22 +01:00
Sebastian Goscik
17fe6c9a5b AndroidDevice: Improved gathering of build props
These are now gathered via `getprop` rather than trying to parse the
build.prop file directly.

This fixes issues with build.prop files that have imports.
2016-05-24 12:55:33 +01:00
Sebastian Goscik
f02b6d5fd9 vellamo: Added support for v3.2.4 2016-05-24 09:57:38 +01:00
Sebastian Goscik
eaf4d02aea Merge pull request #162 from chase-qi/add-blogbench-workload
workloads: add blogbench workload
2016-05-24 09:55:37 +01:00
Chase Qi
56a4d52995 workloads: add blogbench workload
Blogbench is a portable filesystem benchmark that tries to reproduce the
load of a real-world busy file server.

Signed-off-by: Chase Qi <chase.qi@linaro.org>
2016-05-24 16:49:19 +08:00
Sebastian Goscik
ec5c149df5 Merge pull request #165 from chase-qi/add-stress-ng-workload
workloads: add stress_ng workload
2016-05-24 09:45:35 +01:00
setrofim
c0f32237e3 Merge pull request #167 from ep1cman/camera_update
cameracapture & camerarecord: Updated workloads to work with Android M+
2016-05-16 17:28:39 +01:00
Sebastian Goscik
5a1c8c7a7e cameracapture & camerarecord: Updated workloads to work with Android M+
The stock camera app as of Android M has changed. This commit updates
the ui automation to work with this new app. As part of this change
it was required to bump the API level of the ui automation to 18.

Also made the teardown of the capture workload close the app like the
record workload.
2016-05-16 17:25:50 +01:00
Sebastian Goscik
46cd26e774 BaseUiAutomation: Added functions for checking version strings
Added splitVersion and compareVersions functions allow versions strings
like "3.2.045" to be compared.

Also fixed the build script to now copy to the correct folder
2016-05-16 17:22:09 +01:00
Sebastian Goscik
544c498eb6 UiAutomatorWorkload: Added quotes around uiautomator parameters
Some characters would be interpreted by the shell thus breaking the
command. Adding quotes around the parameters solved this.

N.B Space still needs to be replaced.
2016-05-16 16:19:57 +01:00
Chase Qi
5ad75dd0b8 workloads: add stress_ng workload
stress-ng will stress test a computer system in various selectable ways.
It was designed to exercise various physical subsystems of a computer as
well as the various operating system kernel interfaces.

Signed-off-by: Chase Qi <chase.qi@linaro.org>
2016-05-13 19:35:26 +08:00
setrofim
b2248413b7 Merge pull request #148 from ep1cman/master
cpustates: Fix for error when trying to use cpustates with hotplugged…
2016-05-13 11:35:45 +01:00
setrofim
9296bafbd9 Merge pull request #157 from ep1cman/juno-fixes
hwmon & adb fixes
2016-05-10 09:49:33 +01:00
Sebastian Goscik
8abf39762d hwmon: Fixed sensor naming
Previously the sensor name was just appeneded to the end of the
previous sensors name.

Now the hwmon name is added as a classifier of the metric.
If the hwmon sensor has a label, the metric will use this for its name,
if it does not then the sensors kind and ID will be used e.g. temp3
2016-05-10 09:27:42 +01:00
Sebastian Goscik
87cbce4244 hwmon: Added allowed values to sensors parameter
Previously the sensor name was just appeneded to the end of the
previous sensors name.
2016-05-10 09:27:42 +01:00
Sebastian Goscik
ef61f16896 AndroidDevice: Fixed screen lock disable
Due to the previous commits, this command no longer works properly.

It turns out there is an issue with using multiple levels of escaping.
It seems that bash handles the backslashes and single quotes separately
incorrectly processing our escaping. To get around this we are writing the
sqlite command to a shell script file and running that.

This seems to be the only case in WA at the moment that requires this,
if more show up/when WA moves to devlib it should use the devlib shutil
mechanism.
2016-05-10 09:27:42 +01:00
Sebastian Goscik
e96450d226 adb_shell: Fixed getting return codes
They way we were attempting to get return codes before always gave
us a return code of the previous echo, therefore always `0`.

This commit adds the newline into the last echo.
2016-05-10 09:12:54 +01:00
setrofim
2cf08cf448 Merge pull request #161 from ep1cman/fixes
Added sqlite3 binary & changed kick_off signature
2016-05-09 17:36:04 +01:00
Sebastian Goscik
59cfd7c757 AndroidDevice: WA now pushes its own sqlite3 binary
Some device have the sqlite3 binary removed. WA will now check for
this and push its own binary if necessary.
2016-05-09 17:31:09 +01:00
Sebastian Goscik
d3c7f11f2d AndroidDevice: Changed kick_off signature to match BaseLinuxExamples 2016-05-09 17:06:08 +01:00
Sebastian Goscik
187fd70077 Merge pull request #158 from setrofim/master
report_power_stats: number of entries returned always matches number of reporters
2016-05-09 10:23:05 +01:00
Sergei Trofimov
fe7f98a98b report_power_stats: number of entries returned always matches number of reporters
Previously, only reports that were generated were returned. With this
commit, there will be an entry for each active reporter in the returned
list. If a reporter did not produce a valid report, the entry will be
None.

This ensures consistent output, even if a run time issue causes a
reporter not to produce a report  (e.g. if cpufreq events were not
enabled).
2016-05-09 10:20:25 +01:00
Sebastian Goscik
66c18fcd31 cpustates: Fix for error when trying to use cpustates with hotplugged cores
It is not possible to read frequencies from a core that has been hotplugged.
The code will now set the current and max frequencies of hotplugged cores
to None.

This still doesn't work for devices that have dynamic hotplug enabled
2016-05-06 15:00:32 +01:00
Sebastian Goscik
5773da0d08 Merge pull request #156 from setrofim/master
sysfile_getter/cpufreq: fix taball name
2016-05-06 13:54:53 +01:00
Sergei Trofimov
d581f1f329 sysfile_getter/cpufreq: fix taball name
Commit 724f6e590e changed sysfile_getter
behavior to first tar up copied files and then gzip them. Tarball name
needs to be updated to not include '.gz' extension.
2016-05-06 13:51:09 +01:00
setrofim
f165969d61 Merge pull request #153 from ep1cman/juno-fixes
Juno fixes
2016-05-04 11:57:56 +01:00
Sebastian Goscik
8dc24bd327 uboot: Now detects the U-Boot version to use correct line endings
Previously Linaro U-Boot releases had a bug where they used \n\r
as the line ending. This has now been fixed which caused
issues with WA. WA now detects the U-Boot version and uses the
coresponding line ending.
2016-05-04 11:54:29 +01:00
Sebastian Goscik
59066cb46d juno: Removed default bootargs
The default boot args have been removed since these cause issues with
the latest Linaro builds, which boot correctly without any bootargs.

Also made a regex string a raw-string.
2016-05-03 15:24:35 +01:00
setrofim
6c4d88ff57 Merge pull request #147 from setrofim/master
create command: fix example parameter name in templates
2016-04-20 14:45:16 +01:00
Sergei Trofimov
a40542d57b create command: fix example parameter name in templates
Parameter name in workload templates updated to be a valid identifier.
2016-04-20 14:43:07 +01:00
Sergei Trofimov
697aefc7bb ApkWorkload: clear app data on failed uninstall.
If uninstall fails, "pm clear" should be called to make sure that the
next time the app is launched it starts from a known state (which would
normally be ensured by the uninstall).
2016-04-19 16:43:42 +01:00
Sergei Trofimov
8bc71bb810 ApkWorkload: report correct apk verison on failed install
It's possible that there is already a version of an app on target that
differs form the version of the apk on the host. In such cases, WA will
usually try to uninstall the target version and install the host
version.

It's possible that the uninstall may fail. If that happens, it will be
reported as a warning but workload exectuion will proceed with the
target version. In this case, apk_version would have already been set to
that of the host apk. This change ensures that the APK version is
correctly set to the target version (the one that actually ran).
2016-04-19 16:33:37 +01:00
Sebastian Goscik
91210f26e9 RunCommand: WA no longer runs with no workloads specs
Previously if no worklaod specs were loaded, WA would still start instruments
and then go immediately to the teardown stage. This no longer happens.
2016-04-19 16:32:53 +01:00
Sergei Trofimov
44a49db04d glbcorp: pep8 fix
Added a missing blank line between method declaration and class
attribute definitions.
2016-04-15 16:39:24 +01:00
setrofim
0bfa4bff3c Merge pull request #142 from ep1cman/master
glbench updates
2016-04-14 16:41:26 +01:00
Sebastian Goscik
73aa590056 glbench: renamed start_activity to launch_package
To match changes made in: ff5f48b7e7
2016-04-14 16:36:37 +01:00
Sebastian Goscik
985b249a24 glbench: Fixed ending regex
Updated the regex that detected the end of the benchmark to match the new
logcat format.
2016-04-14 16:36:37 +01:00
Sebastian Goscik
f5e138bed0 Merge pull request #141 from setrofim/master
boostrap: nicer error messages on config parasing.
2016-04-14 16:22:10 +01:00
Sergei Trofimov
b6c0e2e4fd boostrap: nicer error messages on config parasing.
- handle ValueError as well as SyntaxError from config parser
- Report source file in the error message
2016-04-14 16:18:31 +01:00
Sebastian Goscik
df8ef6be6b Merge pull request #133 from mcgeagh/uxperf
CpuUtilisationTimeline added. This now will generate cpu utilisation …
2016-04-14 14:05:58 +01:00
Michael McGeagh
8a3186e1c8 CpuUtilisationTimeline added. This now will generate cpu utilisation based on frequencies and a number of samples
Fixed error in percentage when frequency is 'None'. Now default to 0 in these cases

cpu_utilisation is now a separate parameter in cpustate. Now generates a floating point number representing the utilisation based on the maximum frequency of the capture. No longer performs averaging of values, this can be done as a post-processing step

cpu utilisation now based on the max cpu freq per core, not max captured freq overall
2016-04-14 14:03:28 +01:00
Sebastian Goscik
68043f2a52 Merge pull request #138 from mcgeagh/fps-allviews
fps: Can now process multiple 'view' attributes
2016-04-14 13:57:28 +01:00
Michael McGeagh
95bbce77a2 fps: Can now process multiple 'view' attributes 2016-04-14 13:12:39 +01:00
Sebastian Goscik
ec85f9f8a0 Merge pull request #140 from setrofim/master
ApkWorkload: add package verison to the result as a classifer.
2016-04-14 11:35:49 +01:00
Sergei Trofimov
82e4998092 Deprecating apk_version instrument. 2016-04-14 11:33:54 +01:00
Sergei Trofimov
48259d872b ApkWorkload: add package verison to the result as a classifer. 2016-04-14 11:23:39 +01:00
setrofim
8d13e1f341 Merge pull request #128 from ep1cman/glbench_logcat_fix
glbench: Fixed updated logcat format
2016-04-13 16:46:09 +01:00
Sebastian Goscik
33ef949507 Merge pull request #135 from mcgeagh/fps-fix
Only check for crashed content if crash_check is true.
2016-04-11 13:38:18 +01:00
Michael McGeagh
68714e0e55 fps: Only check for crashed content if crash_check is true. 2016-04-11 12:01:12 +01:00
setrofim
9ee1666a76 Merge pull request #131 from ep1cman/master
SysfsExtractor & Busybox fixes
2016-04-07 10:31:31 +01:00
Sebastian Goscik
8dcdc9afe1 busybox: Rebuilt busybox binaries to prefer applets over system binaries
Busybox will now prefer to use its own built in applets before it tries
using the system binaries so that we are always running commands as expected.
2016-04-07 10:29:13 +01:00
Sebastian Goscik
724f6e590e SysfsExtractor: Now performs tar and gzip separately
On some devices there were permissions issues when trying to tar and gzip
the temp-fs in one command. These two steps are now done separately.
2016-04-07 10:29:13 +01:00
Sebastian Goscik
507090515b Merge pull request #134 from jimboatarm/master
Fix to install APKs with whitespace in their path name
2016-04-06 10:56:58 +01:00
James Hartley
1dfbe9e44c Fix to install APKs with whitespace in their path name 2016-04-06 10:53:08 +01:00
setrofim
d303ab2b50 Merge pull request #132 from ep1cman/artem
ADB 1.0.35 support
2016-04-05 16:05:16 +01:00
Sebastian Goscik
b17ae78d6b adb_shell: Now handles return codes from ADB
As of ADB 1.0.35/Android N, it will return the exit code of the command that it runs
This code handles this scenario as before WA treated a return code from ADB as an
error with ADB.
2016-04-05 15:53:41 +01:00
Sergei Trofimov
391b0b01fc pylint/pep8 fixes
- android/workload: emoved an extra bank line between methods
- trace_cmd: define member attribute inside __init__
- adb_shell: ignore pylint warning about too many branches in this case
2016-04-05 11:36:39 +01:00
setrofim
20861f0ee4 Merge pull request #130 from jimboatarm/master
Fix for packages without launch activities
2016-04-05 11:00:50 +01:00
James Hartley
ff5f48b7e7 Fix for packages without launch activities
If the package has no defined launch activity you must call the
activity manager in a different way.
2016-04-05 10:24:42 +01:00
Sebastian Goscik
9a301175b0 glbench: Fixed updated logcat format
The old results looked like:
I/TfwActivity(30824):    "description": "",
I/TfwActivity(30824):    "elapsed_time": 62070,
I/TfwActivity(30824):    "error": "NOERROR",

The new format is:
04-04 11:38:04.144  1410  1410 I TfwActivity:    "description": "",
04-04 11:38:04.144  1410  1410 I TfwActivity:    "elapsed_time": 62009,
04-04 11:38:04.144  1410  1410 I TfwActivity:    "error": "NOERROR",
2016-04-04 17:33:48 +01:00
setrofim
712c79020d Merge pull request #126 from ep1cman/master
ResourceResolver: Show version number when resource wasn't found.
2016-03-30 11:05:21 +01:00
Sebastian Goscik
12dfbef76b ResourceResolver: Show version number when resource wasn't found.
If the ResourceResolver was looking for a specific version of a
resource and could not find it, this version number is now shown
in the error message.
2016-03-30 11:01:35 +01:00
Sebastian Goscik
b1f607ef70 Merge pull request #125 from setrofim/master
trace-cmd fixes
2016-03-24 18:13:16 +00:00
Sergei Trofimov
107e8414bb trace-cmd: set a minimum bound on trace pull timeout
The timeout for the pulling the trace file after the run is being set
based on the time for which the trace was collected. For workloads with
short execution time, but large number of events, the resulting timeout
might be too short. To deal with this, do not let the timout be shorter
than 1 minute.
2016-03-24 16:49:42 +00:00
Sergei Trofimov
4f8b7e9f59 trace-cmd: updating sched_switch parser to handle both formats.
Depending on the kernel, sched_switch events may be formatted one of two
different ways in the text output. Previously, we've only handled the
"old" format. This commit updates the parser to handle the new format as
well.
2016-03-24 16:33:29 +00:00
setrofim
a077e7df3c Merge pull request #124 from ep1cman/master
BaseLinuxDevice: gzipped property files are now zcat'ed
2016-03-24 16:30:32 +00:00
Sebastian Goscik
a2257fe1e2 BaseLinuxDevice: gzipped property files are now zcat'ed
Before they were cat'ed this gave garbage output for compressed files.
Cat-ing is necessary since not all properties are normal files (sysfs).
2016-03-24 16:28:19 +00:00
Sebastian Goscik
50353d0b8f Merge pull request #122 from Sticklyman1936/lmbench_update
lmbench: Tidied up the code and improved stability
2016-03-24 16:26:52 +00:00
setrofim
0f5621ff66 Merge pull request #123 from Sticklyman1936/sysbench_fix
sysbench: use device busybox binary
2016-03-24 16:24:38 +00:00
Sascha Bischoff
2eca77fb02 sysbench: use device busybox binary
Use the full path to busybox on the target device as opposed to
assuming it is found on the path.
2016-03-24 16:21:01 +00:00
Sascha Bischoff
3de5b5fe0b lmbench: Tidied up the code and improved stability
This patch tidies up the benchmark code to bring it in line with the
style used in Workload Automation in general. Additionally, the
results from sub-benchmarks are now directly written to a file on the
device as opposed to processing the standard output/error from the
benchmark, which was error prone.
2016-03-24 10:20:32 +00:00
Sebastian Goscik
499a9f4082 Merge pull request #120 from setrofim/master
applaunch: pass the location of busybox into the script
2016-03-23 16:32:50 +00:00
Sergei Trofimov
3043506d86 applaunch: pass the location of busybox into the script
applaunch creates and deploys an auxilary script in order to collect
precise timings. This script invoked busybox with the assumption that it
is in PATH.

Since recent changes mean that it is no longer deployed to /system/bin,
the busybox in not found. With this commit, the full path to busybox
will be passed into the script's template.
2016-03-23 16:28:18 +00:00
Sebastian Goscik
7db904b359 Merge pull request #119 from ep1cman/master
adb_shell: Fixed checking exit codes on Android N
2016-03-23 13:51:17 +00:00
Sebastian Goscik
5abeb7aac2 adb_shell: Fixed checking exit codes on Android N
As of android N '\n' is used as the new line separator not '\r\n'.
This fix makes the function detect which is being used by the device.
2016-03-23 13:43:07 +00:00
setrofim
e04691afb9 Merge pull request #118 from ep1cman/master
daq: Fixed channel merging
2016-03-21 11:22:10 +00:00
Sebastian Goscik
15ced50640 daq: Fixed channel merging
Fixed channel merging when setting merge to True.
Channel merges done by setting a mapping manually were not affected by this bug.
2016-03-21 11:15:30 +00:00
setrofim
1a2e1fdf75 Merge pull request #114 from ep1cman/master
dhyrstone: Fixed arm64 binary
2016-03-15 14:40:47 +00:00
Sebastian Goscik
3531dd6d07 dhyrstone: Fixed arm64 binary
It was dynamically linked, its is now statically linked
2016-03-15 14:38:18 +00:00
setrofim
cf55f317f8 Merge pull request #113 from ep1cman/master
freq_sweep: Improved documentation
2016-03-09 16:52:04 +00:00
Sebastian Goscik
79554a2dbc freq_sweep: Improved documentation
- Added explanation that this instrument does not taskset workloads
 - Fixed formatting issue with the agenda example
2016-03-09 16:37:15 +00:00
setrofim
06c232545a Merge pull request #112 from ep1cman/master
dhrystone: Updated executable resolution
2016-03-09 14:57:49 +00:00
Sebastian Goscik
11184750ec dhrystone: Updated executable resolution
Previously it was just using the binary in the dhrystone folder.
Now it uses WA's resource resolution to use the correct ABI.
2016-03-09 14:54:39 +00:00
setrofim
77b221fc5a Merge pull request #111 from ep1cman/master
daq: Added check for duplicate channel labels
2016-03-08 12:54:33 +00:00
Sebastian Goscik
20cd6a9c18 daq: Added check for duplicate channel labels
The daq instrument will no longer accept duplicate channel names.
This caused issues where files sent from the daq sever were being
overwritten.
2016-03-07 13:21:40 +00:00
Sebastian Goscik
34d7e7055a Merge pull request #110 from setrofim/master
run command: more usefull error message when specifying non-existing agenda path
2016-02-29 17:28:29 +00:00
Sergei Trofimov
0c1e01cad4 run command: more usefull error message when specifying non-existing agenda path
If the specified agenda argument is not found in the file system, WA
assumes it is the name of a workload and would then raise an "extension
not found error", which may be confusing if the user's intension was to
specify a path.

Now, WA will first check that neither path separator, nor a '.' are
present in the agenda argument before assuming it is a workload name, and
will provide a less confusing error in that case.
2016-02-29 17:26:29 +00:00
Sebastian Goscik
a68e46eb0a Merge pull request #106 from setrofim/master
LinuxDevice: fixed reboot.
2016-02-22 10:00:51 +00:00
Sergei Trofimov
203a3f7d07 LinuxDevice: fixed reboot.
- Deal with the dropped connection on issuing "reboot"
- Introduced a fixed initial delay before polling for connection to
  avoid re-connecting to adevice that is still in the process of
  shutting down.
2016-02-22 09:45:42 +00:00
Sebastian Goscik
de133cddb4 Merge pull request #105 from bjackman/check-config-exists
Add entry_point check for config file existence
2016-02-18 09:02:46 +00:00
Brendan Jackman
a5c9b94257 Add entry_point check for config file existence
This is just to provide a friendlier error message.
Before this commit you get an IOError from imp.load_source.
2016-02-17 17:24:14 +00:00
setrofim
c203ec8921 Merge pull request #103 from ep1cman/fixes
ApkWorkload: Fixed runtime permission granting
2016-02-15 11:50:36 +00:00
Sebastian Goscik
de021da300 ApkWorkload: Fixed runtime permission granting
"Normal" android permissions are automatically granted and cannot
be changed. Trying to "pm grant" these caused an error, this should
no longer occur.
2016-02-15 11:38:28 +00:00
setrofim
693afa3528 Merge pull request #102 from ep1cman/fixes
LinuxDevice: Added as_root to kick_off
2016-02-12 09:55:36 +00:00
Sebastian Goscik
5203188d9e LinuxDevice: Added as_root to kick_off 2016-02-12 09:54:14 +00:00
Steve Bannister
08663209d6 Fix up lmbench commandline 2016-02-11 17:40:31 +00:00
Sebastian Goscik
232e4b3e65 Merge pull request #101 from setrofim/master
Adding taskset capability to lmbench + minor fixes.
2016-02-11 09:35:58 +00:00
Sergei Trofimov
13ebc8ad55 pep8: removed trailling spaces 2016-02-11 08:22:53 +00:00
Sergei Trofimov
759f8db1bc lmbench: adding taskset support
lmbench can now be run pinned to specific CPUs.
2016-02-11 08:22:39 +00:00
setrofim
9a7cccacab Merge pull request #100 from setrofim/master
dhrystone: fix busybox reference.
2016-02-10 17:45:42 +00:00
Sergei Trofimov
288aa764b3 dhrystone: fix busybox reference. 2016-02-10 17:28:33 +00:00
Sebastian Goscik
a32cc0f213 Merge pull request #99 from setrofim/master
Minor fixes.
2016-02-10 16:50:17 +00:00
Sergei Trofimov
fdbc2ae372 pylint 2016-02-10 16:39:06 +00:00
Sergei Trofimov
9129a9d2d8 dhrystone: remove reference to sysbench from dhrystone doc. 2016-02-10 16:38:56 +00:00
Sebastian Goscik
cb46c57754 Merge pull request #98 from setrofim/master
ipython: switched to using LooseVersion for version checks.
2016-02-10 10:54:00 +00:00
Sebastian Goscik
536c0ffe4e Merge pull request #94 from ranjeetkumar/master
Added GoogleMap : Navigation app by Google Inc.
2016-02-10 09:37:00 +00:00
Sergei Trofimov
4f30e37f22 ipython: switched to using LooseVersion for version checks.
This is a fix for

https://github.com/ARM-software/workload-automation/issues/97

IPython can use rc tags in its version strings, which StrictVersion
can't handle.
2016-02-10 09:01:40 +00:00
ranjeet
0deb8fd7c6 Added GoogleMap : Navigation app by Google Inc. 2016-02-07 10:01:36 +05:30
Sebastian Goscik
85edc3084b Merge pull request #96 from setrofim/master
Fixes to cpufreq module and elimination of unknown state in cpustate result processor.
2016-02-04 16:25:00 +00:00
Sergei Trofimov
3a99a284c4 cpustate: ensure known initial state
cpustate result processor generates a view of the cpu subsystem power
state during execution of a workload from cpu_idle and cpu_frequency
ftraces. There exists a period before the first events in those
categories are seen where the state of the cpu subsystem is (partially)
unknown and it is reported as such by the result processor.

Unknown state usually exists for a relatively short period of time and
is generally not a big deal. For certain kinds of workloads, however, it
may constitude a significant protion of the trace.

Changes in this commit attempt to deal with this by a) reading starting
cpu frequencies and writing them into the trace, and b) nudging each
core to bring it out of idle; this happens before the start marker, so
that the system state between the markers should be completely known.
2016-02-04 16:08:22 +00:00
Sergei Trofimov
5e3cc8fcb5 cpufreq: minor fixes
- added a missing conversion from int to cpu name.
- fixed the invocation of the current cpu frequency function inside core
  and cluster versions.
2016-02-04 15:42:35 +00:00
setrofim
f92bd1bcdd Merge pull request #95 from ep1cman/fixes
Parameter: Fixed overriding of new parameters
2016-02-04 15:42:01 +00:00
Sebastian Goscik
519efaf22c Parameter: Fixed overriding of new parameters
Previously you could have `override` set to True on parameters that
only existed in the current scope.

Now if you try to override a parameter that doesn't exist higher up
in the hiarchy you will get a ValueError.
2016-02-04 15:36:47 +00:00
setrofim
28ef01505d Merge pull request #92 from ep1cman/fixes
AndroidDevice: Removed duplicate parameter
2016-02-03 15:07:32 +00:00
Sebastian Goscik
dec574e59e AndroidDevice: Removed duplicate parameter 2016-02-03 15:06:00 +00:00
Sebastian Goscik
7ad8b8522b AttributeCollection: No longer allows duplicate overriding attributes
Previously if parameters with the same names and override set to True
were added to an extension at the same level one would silently
override the other.

This is no longer the case and an error will be show instead.

Also added tests to check that this is handeled correctly
2016-02-03 15:05:14 +00:00
Sebastian Goscik
14a1bc8a5d Merge pull request #91 from setrofim/master
Some minor fixes for ABI resolution.
2016-02-02 09:41:08 +00:00
Sergei Trofimov
45a9c0a86d Removing hard-coded abi from generic_linux devices
ABI should be read from the target device as with other Device
interfaces. This must be a holdover from before this was being done.
2016-02-02 09:29:22 +00:00
Sergei Trofimov
7edb2c8919 Adding aarch64 to architecture list for arm64 ABI
This was observer being reported on a device.
2016-02-02 09:29:22 +00:00
setrofim
5fad83a50d Merge pull request #90 from ep1cman/fixes
manual: Fixed trying to logcat on non linux devices
2016-02-01 15:26:46 +00:00
Sebastian Goscik
68fefe8532 manual: Fixed trying to logcat on non linux devices 2016-02-01 15:24:32 +00:00
setrofim
c96590b713 Merge pull request #89 from ep1cman/fixes
sysbench: Fixed binary installation
2016-02-01 11:17:34 +00:00
Sebastian Goscik
dc22856431 sysbench: Fixed binary installation 2016-02-01 11:13:57 +00:00
Sebastian Goscik
2d1f0e99b9 Merge pull request #87 from setrofim/master
Added functions for manipulating kernel modules + pep8 fix.
2016-01-27 17:18:55 +00:00
Sergei Trofimov
da720c8613 pep8 2016-01-27 17:15:44 +00:00
Sergei Trofimov
eaabe01fa5 BaseLinuxDevice: added insmod() method.
Allows insting a kernel module on the target from a .ko located on the
host.
2016-01-27 17:15:41 +00:00
Sergei Trofimov
dc07c8d87e BaseLinuxDevice: added lsmod() method
Execute lsmod on the target device and parses the output into named
tuples.
2016-01-27 16:50:29 +00:00
setrofim
a402bfd7f9 Merge pull request #85 from ep1cman/fixes
Fixes
2016-01-26 15:14:09 +00:00
Sebastian Goscik
fe2d279eac RunInfo: Added default run name
The run name will now default to ``{output_folder}_{date}_{time}``
2016-01-26 15:00:39 +00:00
Sebastian Goscik
0ffbac1629 Merge pull request #84 from bjackman/pedantry
A couple of tweaks
2016-01-26 14:16:10 +00:00
Brendan Jackman
65cc22a305 core/agenda.py: Add check for empty values in agenda
This gives an error message when an agenda contains a key with no
value, so creating agendas is a little more user-friendly.
2016-01-25 13:43:38 +00:00
Brendan Jackman
2ae8c6073f doc: Apply it's/its grammar pedantry 2016-01-25 13:34:24 +00:00
Sebastian Goscik
dc5cf6d7b8 Merge pull request #83 from setrofim/master
Various fixes.
2016-01-22 14:29:13 +00:00
setrofim
e6ae9ecc51 Merge pull request #81 from ep1cman/bbench_fix
revent: Added record and replay commands
2016-01-22 12:55:16 +00:00
Sergei Trofimov
85fb5e3684 Pylint fixes
- apklaunch: ignore package (re-)assignment outside init.
- applaunch: factored out part of result processing into a separate
  method.
2016-01-22 12:19:39 +00:00
Sergei Trofimov
98b19328de Fixing assets discovery.
- Two different parameters may now have the same global alias as long as
  their types match
- `extension_asset` resource getter now picks up the path to the mouted
  filer from ``remote_assets_path`` global setting.
2016-01-22 12:19:31 +00:00
Sergei Trofimov
73ddc205fc geekbench: fixing root check
- negating the check (error if *not* rooted)
- do not check for version 2 (results are extracted differently and that
  does not require root).
2016-01-22 10:43:01 +00:00
Sebastian Goscik
1e6eaff702 revent: Added record and replay commands
Added two commands to WA to record and replay input events using revent.

As part of this also added the ability to get a device model from
android and linux device. This may need to be improved in the future.
2016-01-22 10:40:03 +00:00
setrofim
78d49ca8ae Merge pull request #82 from ep1cman/fixes
Fixes
2016-01-22 10:33:41 +00:00
Sebastian Goscik
f4c89644ff geekbench: Added check whether device is rooted 2016-01-22 09:39:49 +00:00
Sebastian Goscik
798a7befb8 pylint fixes 2016-01-22 09:39:29 +00:00
setrofim
6a388ffc71 Merge pull request #80 from ep1cman/bbench_fix
bbench fix
2016-01-20 16:57:10 +00:00
Sebastian Goscik
82df73278e recentfling: Fixed inequality 2016-01-20 16:31:27 +00:00
Sebastian Goscik
68a39d7fa1 bbench: Fix for web browser crash on latest Linaro release
Also fixes browser permissions issues on Android 6+
2016-01-20 16:29:38 +00:00
setrofim
120f0ff94f Merge pull request #78 from ep1cman/binary_install
BaseLinuxDevice: Tidied up the way binaries are handled
2016-01-19 10:52:54 +00:00
Sebastian Goscik
f47ba6fea6 ebizzy: changed os.path to device path 2016-01-19 10:45:09 +00:00
Sebastian Goscik
5f8da66322 antutu: Fixed runtime permissions
Antutu 6 lists corse_location as a requirement but also asks for
fine_location at runtime. So it is now manually beign granted.
2016-01-19 10:45:09 +00:00
Sebastian Goscik
67213d471b BaseLinuxDevice: documentation update
Added docs explaining how extension developers should deploy binaries.
2016-01-19 10:45:09 +00:00
Sebastian Goscik
7c35c604f4 BaseLinuxDevice: Tidied up the way binaries are handled
Added:
get_binary_path: Checks binary_directory for the wanted binary, if
                 if its not there, it will use which to find a
                 system one. returns the full path

install_if_needed: will install a binary only if it is not present.

Changes:
 - Busybox is now deployed to non-rooted devices
 - is_installed has now been removed as the new functions supersede it
 - binaries will now always be installed to `binaries_directory` and
   not system folders.
 - updated workloads to use these new functions
   - rt-app and sysbench might still need work
2016-01-19 10:45:09 +00:00
Sergei Trofimov
c11cc7d0d2 trace-cmd: do not error on missing host-side trace-cmd when report_on_target is set
When report_on_target option is set, binary trace will be "reported"
into a text version on the target device. This removes the need for
trace-cmd to be installed on the host, in which case that should not be
reported as an error.
2016-01-18 11:53:06 +00:00
setrofim
89f1e7b6e5 Merge pull request #79 from chase-qi/add-io-scheduler-test
applaunch: Added support for IO scheduler test
2016-01-15 10:29:07 +00:00
Chase Qi
bd826783cc applaunch: Added support for IO scheduler test
When IO is heavily loaded, the impact of IO schedulers on App launch
time varies. To measure the impact, added io_stress and io_scheduler two
parameters and related jinja2 blocks.

Signed-off-by: Chase Qi <chase.qi@linaro.org>
2016-01-15 02:16:35 -08:00
setrofim
0fb867e7c6 Merge pull request #77 from bjackman/apklaunch
workloads: Add apklaunch workload
2016-01-14 16:00:53 +00:00
Brendan Jackman
6b3187c2c9 workloads: Add apklaunch workload
This is a workload to install and run an arbitrary .apk
2016-01-14 15:58:26 +00:00
setrofim
75ce620e6b Merge pull request #76 from ep1cman/get_pid_fix
AndroidDevice: fixed get_pids_of
2016-01-13 17:15:12 +00:00
Sebastian Goscik
d9c4063307 AndroidDevice: fixed get_pids_of
As of Android M ps can no longer filter by process name. This is
now handled using grep from busybox
2016-01-13 17:07:30 +00:00
setrofim
5f2b25532b Merge pull request #75 from chase-qi/fix-applaunch-cleanup
applaunch: pass cleanup argument to the template
2016-01-13 08:20:53 +00:00
Chase Qi
0998c18efd applaunch: pass cleanup argument to the template
Since cleanup test block is defined in the device_script.template, the
value of cleanup is needed to render the template properly.

Signed-off-by: Chase Qi <chase.qi@linaro.org>
2016-01-12 18:20:22 -08:00
setrofim
9eeeaf02ad Merge pull request #74 from setrofim/master
juno: fixing a stupid error in u-boot boot path
2016-01-12 15:14:14 +00:00
Sergei Trofimov
df937dc847 juno: fixing a stupid error in u-boot boot path
Juno's bootargs parameter specifies the kernel boot arguments as a
sigle string. However, when it is passed into _boot_via_uboot, it was
expanded as a mapping, causing an error. This fixes that boneheaded
mistake...
2016-01-12 15:00:25 +00:00
setrofim
1ef7bb4e93 Merge pull request #73 from ep1cman/ipython4
ipython: Updated to work with the latest ipython version
2016-01-12 14:37:37 +00:00
Sebastian Goscik
41890589e1 ipython: Updated to work with the latest ipython version 2016-01-12 10:59:52 +00:00
Sebastian Goscik
a0cd66ed45 Merge pull request #71 from setrofim/master
trace_cmd: updated to handle empty CPUs.
2016-01-12 10:16:27 +00:00
Sergei Trofimov
b84f97a902 trace_cmd: updated to handle empty CPUs.
Updated trace-cmd parser to handle messages that the trace for a CPU is
empty.
2016-01-12 10:12:00 +00:00
setrofim
ffc3fcef67 Merge pull request #70 from ep1cman/antutu6
Antutu6
2016-01-11 16:12:40 +00:00
Sebastian Goscik
09563bc01e antutu: Updated to support Antutu v6 2016-01-11 14:37:32 +00:00
Sebastian Goscik
f1bb44b3e7 ApkWorkload: Added automatic granting of runtime permissions
As of Android 6.0, apps can request permissions at runtime. If the
target device is running Android 6.0+ these permissions are now automatically
granted.
2016-01-11 13:58:38 +00:00
Sebastian Goscik
1085c715c2 Merge pull request #69 from setrofim/master
juno_energy: add metrics to results and "strict" parameter
2016-01-07 11:11:58 +00:00
Sergei Trofimov
c105e8357c juno_energy: add metrics to results and "strict" parameter
- Summary metrics are now calculated from the contents of energy.csv and
  added to the overall results.
- Added a new "strict" parameter. If this is set to False, the device
  check during validation is omitted.
2016-01-07 11:09:00 +00:00
Sebastian Goscik
dc1b0e629e ipynb_exporter: default template no longer shows a blank plot for workloads without summary_metrics 2015-12-15 17:18:25 +00:00
Sergei Trofimov
62a0fd70de daq: fixed typo 2015-12-15 09:54:21 +00:00
Sergei Trofimov
438e18328d AndroidDevice: remove unnecessary escapes from update locksettings command
The single quotes will be escaped further down the command processing
chain.
2015-12-15 09:52:46 +00:00
setrofim
57b31149f1 Merge pull request #68 from ep1cman/daq_fix
daq: Fixed bug where an exception would be raised if merge_channles=False
2015-12-15 09:43:23 +00:00
Sebastian Goscik
09390e7ffb daq: Fixed bug where an exception would be raised if merge_channles=False 2015-12-15 09:39:28 +00:00
Sergei Trofimov
e83d021a5c utils/android: fixed use of variables in as_root=True commands.
In order to execute as root, the command string gets echo'd into so;
previusly, double quotes were used in echo, which caused any veriables
in the command string to be expanded _before_ it was echoed.
2015-12-15 08:34:18 +00:00
Sergei Trofimov
bca012fccb csv: handle zero-value classifiers correctly
If the value of a classifier was zero (or any other value that
interprets as boolean False), it used to be coverted to an empty entry.
This makes sure that the value gets correctly ropagated.
2015-12-15 08:30:53 +00:00
Sergei Trofimov
bb37c31fed perf: added support for per-cpu statistics
per-cpu statistics now get added as metrics to the results (with
a classifier used to identify the cpu).
2015-12-11 14:01:04 +00:00
Sergei Trofimov
0005f927e8 pep8 2015-12-11 14:01:04 +00:00
setrofim
9222257d79 Merge pull request #67 from ep1cman/recentfling
Recentfling
2015-12-11 11:06:45 +00:00
Sebastian Goscik
585d8b2d7d recentfling: Added workload 2015-12-11 11:02:25 +00:00
Sebastian Goscik
d3470dca73 AndroidDevice: Fixed swipe_to_unlock
Previously swipe_to_unlock was not used and conflicted with a method
of the same name.

 - swipe_to_unlock() renamed perform_unlock_swipe()
 - swipe_to_unlock parameter now takes a direction, this allows swipe unlocking on Android M devices
 - ensure_screen_is_on() will now also unlock the screen if swipe_to_unlock is set
2015-12-11 10:58:32 +00:00
Sergei Trofimov
0f60e9600f trace_cmd: parser for sched_switch events and fixes
- Compiled regular expressions in EVENT_PARSER_MAP now get handled
  correctly.
- regex_body_parser now attemts to convert field values to ints,
  bringing it inline with the default parser behavior.
- There is now a regex for sched_switch events.
2015-12-10 13:41:24 +00:00
Sergei Trofimov
6a85dff94f pylint: addtional fix
further to bef8fb40ef
2015-12-10 13:39:28 +00:00
setrofim
aae88b8be4 Merge pull request #65 from Sticklyman1936/gem5_fixes
gem5 fixes and one AndroidDevice fix
2015-12-10 13:31:57 +00:00
Sascha Bischoff
72a617c16d Gem5Device: Remove the rename in pull_file to align with gem5 2015-12-10 11:09:42 +00:00
Sascha Bischoff
d6355966bf Gem5Device: Removed unused methods 2015-12-10 11:09:42 +00:00
Sascha Bischoff
845d577482 Gem5LinuxDevice: Added login_prompt and login_password_prompt parameters
Added two parameters which allow the user to change the strings used
to match the login prompt and the following password prompt to match
their device configurations.
2015-12-10 11:09:42 +00:00
Sascha Bischoff
9ccf256ee8 AndroidDevice: Use content instead of settings to get ANDROID_ID
We move from using settings to using content to get the ANDROID_ID as
this works across a wider range of Android versions.
2015-12-10 11:09:42 +00:00
Sascha Bischoff
cc9b00673e Gem5AndroidDevice: No longer wait for disabled boot animation
Adjust the wait_for_boot method of Gem5AndroidDevice to no longer wait
for the boot animation to finish if the animation has been
disabled. The service.bootanim.exit property is only set (to 0) when
the animation starts, and is set to 1 when the animation finishes. If
the animation never starts, then the property is not set at
all. Hence, we assume the boot animation has finished, unless the
property has been set.
2015-12-10 11:09:42 +00:00
Sascha Bischoff
e7c75b2d3b Gem5: Add support for deploying the m5 binary 2015-12-10 11:09:41 +00:00
Sascha Bischoff
480155fd8c Gem5Device: Try to connect to the shell up to 10 times 2015-12-10 11:09:41 +00:00
Sascha Bischoff
d98bdac0be Gem5Device: Move resize shell commands to own method
Moved the commands to resize the shell to their own method. They are
now executed twice. Once as soon as the shell is connected, and a
second time as part of initialize. This latter call takes place after
the isntallation of busybox.
2015-12-10 11:09:41 +00:00
Sascha Bischoff
32cf5c0939 Gem5Device: Removed busybox dependency. 2015-12-10 11:09:41 +00:00
Sebastian Goscik
a330a64340 Merge pull request #66 from ep1cman/pylint_update
Major pylint fix
2015-12-09 16:54:13 +00:00
Sebastian Goscik
bef8fb40ef Updated pylint for v1.5.1
Fixed WA for the latest version of pylint (1.5.1)
2015-12-09 16:52:39 +00:00
Sergei Trofimov
344bc519c4 AndroidDevice: fixing get_properites to refer to self.device
This is a fix to the previous fix
(2510329cdf) that updated get_properties
to store "dumpsys window" output relative to the working_directory. That
commit constructed the path using self.device, which is wrong, as in
this case self itself is the device.
2015-12-08 11:26:56 +00:00
setrofim
3da58d9541 Merge pull request #64 from ep1cman/hwuitest
hwuitest: Added workload
2015-12-03 16:46:06 +00:00
Sebastian Goscik
065ebaac61 hwuitest: Added workload
This workload allow WA to use hwuitest from AOSP to test rendering
latency on Android devices.
2015-12-03 15:07:42 +00:00
Sergei Trofimov
f85ef61ce9 lmbench: add the output file as an artifiact 2015-12-03 10:54:32 +00:00
setrofim
e5c6ef5368 Merge pull request #62 from ep1cman/trace-cmd-target-extract
trace-cmd: Added ability to generate reports on target device
2015-12-02 09:58:44 +00:00
Sebastian Goscik
a697c47c49 trace-cmd: Added ability to generate reports on target device 2015-12-02 09:53:43 +00:00
Sascha Bischoff
c6e712d44c Gem5Device: simplfy if statement based on pylint recommendation 2015-12-01 18:23:26 +00:00
Sascha Bischoff
00c9bdc2a6 Gem5Device: Fix runtime error caused by lack of kwargs 2015-12-01 18:23:26 +00:00
setrofim
1b31d8ef6f Merge pull request #53 from ep1cman/systrace
Added systrace instrument
2015-11-27 09:54:57 +00:00
Sebastian Goscik
b3a9512f44 Added systrace instrument
Added an instrument to uses systrace.py from the android SDK.
 Generates a fancy HTML report (only works in Google chrome).
2015-11-27 09:53:59 +00:00
Sergei Trofimov
a06016a442 adb_shell: fixing handling of line breaks at the end of the output
- adb protcol uses "\r\n" for line breaks. This is not handled by
  Python's line break translation, as not a file. So spliting on '\n'
  when extracting the exit code resulted in stray '\r' in the output.
- adb_shell expects exit code to be echoed on the same line. This may
  not have been the case if latest output from executed command was not
  a complete line. An extra echo will now ensure that the exit code will
  be on its own line even in that case.
2015-11-24 15:50:38 +00:00
Sergei Trofimov
c02a1118d7 BaseLinuxDevice: list_file_systems() now handles blank lines
mount() may return an empty line at the end of the output; this update
handles that.
2015-11-24 15:50:38 +00:00
Sebastian Goscik
d9f1190e1f Version bump 2015-11-23 16:19:45 +00:00
setrofim
36c58ee76f Merge pull request #61 from setrofim/documentation-update
doc: updating installation instructions
2015-11-23 16:02:32 +00:00
Sergei Trofimov
b04d141680 doc: updating installation instructions
Re-writing some of the instructions for clarity plus updating with the
correct pip invocations.
2015-11-23 15:47:27 +00:00
setrofim
3453fe5fc1 Merge pull request #59 from ep1cman/changelog
Updated change log
2015-11-23 10:13:38 +00:00
Sebastian Goscik
016876e814 Updated change log
Initial update of change log, this will probably need a lot of tidy up.
2015-11-23 10:11:23 +00:00
setrofim
e8ba515075 Merge pull request #58 from Sticklyman1936/gem5_init_fix
Gem5Device: Fix issue with init arguments
2015-11-20 14:21:11 +00:00
Sascha Bischoff
c533da3f38 Gem5Device: Fix issue with init arguments
- This patch addresses an issue with the arguments passed the
  BaseGem5Device __init__. With this patch these are no longer passed
  in as they are not required in the base device implementation.
2015-11-20 13:10:35 +00:00
Sergei Trofimov
8261c1d5b5 freqsweap: fix: was erroneously merging runtime_params into workload_params 2015-11-19 14:11:23 +00:00
setrofim
1d12e6a8b0 Merge pull request #57 from ep1cman/freqsweep
Freqsweep: Added the ability to specify workload/runtime parameters
2015-11-18 11:29:39 +00:00
Sebastian Goscik
2957d63e2f Freqsweep: Added the ability to specify workload/runtime parameters
E.g:
  sweeps:
    - cluster: a15
      runtime_params:
        a15_cores: 1
2015-11-18 11:27:35 +00:00
setrofim
7b8d62d1ec Merge pull request #56 from ep1cman/streamline_improvements
Streamline improvements
2015-11-16 17:28:02 +00:00
Sebastian Goscik
2063f48cf0 streamline: cleaned up and added Linux support
- The streamline instrument can now run on linux clients
  because it no longer relies on adb port forwarding
- Updated description.
- Cleaned up code
- Now check for streamline not caiman
- Gatord is now only run once instead of restarted every
  job
2015-11-16 17:27:17 +00:00
Sergei Trofimov
2510329cdf AndroidDevice fix: create dympsys file relative to working directory on target.
Commit 95f17702d7 redirected output of
"dumpsys window" to a file (needed for Gem5 support). However, the file
was created in $PWD, which breaks on production devices, as that
location is not writable. This moves the file under the working
directory on the device.
2015-11-16 13:09:28 +00:00
Sergei Trofimov
9c8c81cc25 csv result processor: write results.csv after each iteration.
(partial) results.csv will now be written after each iteration rather
than at the end of the run.
2015-11-16 12:43:52 +00:00
Sergei Trofimov
2e5b3671e9 LinuxDevice fix: do not invoke super's hard_reset()
as it does not have one...
2015-11-16 12:43:52 +00:00
Sergei Trofimov
705ce9ae40 rt_app: added an option to force install.
Userful when the target device already has rt-app on it, but you want to
replace it with the version from your host.
2015-11-16 12:43:52 +00:00
setrofim
f43daacd41 Merge pull request #52 from ep1cman/freqsweep
Added freqsweep instrument
2015-11-13 15:19:52 +00:00
Sebastian Goscik
3b41f69762 Added freqsweep instrument
Added an instrument to sweep workloads across all available frequenices
2015-11-13 15:16:54 +00:00
setrofim
a722e594af Merge pull request #55 from Sticklyman1936/split_gem5device
Gem5Device: Refactor into BaseGem5Device, Gem5LinuxDevice and Gem5And…
2015-11-13 14:26:07 +00:00
Sascha Bischoff
a447689a86 Gem5Device: Refactor into BaseGem5Device, Gem5LinuxDevice and Gem5AndroidDevice
- Refactored the Gem5Device to avoid duplicated code. There is now a
  BaseGem5Device which includes all of the shared functionality. The
  Gem5LinuxDevice and the Gem5AndroidDevice both inherit from
  BaseGem5Device, and LinuxDevice or AndroidDevice, respectively.
2015-11-13 14:19:24 +00:00
setrofim
9fe4887626 Merge pull request #54 from ep1cman/daq_merge
Added ability to merge DAQ channels
2015-11-13 11:00:36 +00:00
Sebastian Goscik
6492b95edd Added ability to merge DAQ channels
If the parameter merge_channels is set to true (false by default).
 DAQ channels that have consecutive letters on the end of their names
 will be summed together. E.g: A7, A15a, A15b becomes A7, A15

 You can also  manually specify a channel mapping by setting
 merge_channels to a dict. .
2015-11-13 10:56:50 +00:00
setrofim
c5b4b70aae Merge pull request #50 from Sticklyman1936/master
Add Gem5Device to WA
2015-11-11 16:55:57 +00:00
Sascha Bischoff
55f6ef4a5e Gem5Device: Remove VirtIO device rebinding to align with gem5
- Remove the unbind and rebind for the VirtIO 9P mount method as gem5
  now checkpoints the basic state of the device. This allows us to
  just mount it assuming that checkpoint have been created correctly.
2015-11-11 16:45:01 +00:00
Sascha Bischoff
672c74c76c Gem5Device: Avoid duplicate get_properties code
- Remove the duplicated get_properties code by calling the internal
  _get_android_properties method directly.
2015-11-11 16:45:01 +00:00
Sascha Bischoff
95f17702d7 AndroidDevice: Move the processing of Android properties to an internal method
- Move the processing of Android properties to an internal
  method. This allows the Android properties to be extracted without
  extracting those of the Linux device.

- Redirect the output from 'dumpsys window' to a file and pull the
  file as opposed to extracting the output from the terminal. This is
  more reliable in the event that another process writes to the shell.
2015-11-11 16:45:01 +00:00
Sascha Bischoff
ee4764adc4 Gem5Device: Addressed review comments
- Replaced hard-coded pexpect expect string with UNIQUE_PROMPT.

- Changed the capture_screen debug to a warning to make sure that the
  user knows when it happens.

- Fixed the logic for checking when a file exists. Previously, if the
  output could not correctly be processed (ValueError) then we just
  assumed that the file existed if there was any output at all. This
  is clearly not a good default. Changed to default to False if it was
  not able to process the output as this seems to be the safest
  option.

- Changed ad hoc filename extraction to use os.path.basename.

- Removed the processing of some kwargs and defaults that are handled
  by the parent class.

- Stopped overriding some paramaters which were purely defined in the
  Gem5Device.
2015-11-11 16:45:00 +00:00
Sascha Bischoff
3a8eed1062 Gem5Device: Allowed the gem5 binary to be specified in the agenda
- Added the gem5_binary option to the agenda which allows a different
  gem5 binary to be specified. This allows WA to be used with
  different levels of gem5 debugging. as well as allowing non-standard
  gem5 binary names and locations.
2015-11-04 10:38:50 +00:00
Sascha Bischoff
29abd290f4 Gem5Device: Fix style issues
- Fix up style issues
2015-11-02 16:30:13 +00:00
Sascha Bischoff
3bf114cf48 Gem5Device: Improve shell command matching
- Replace ugly while True loop with a simple regex substitution
  achieving the same thing. This is required to match the command in
  the shell output when the command wraps around due to the length of
  the command.
2015-11-02 11:42:33 +00:00
Sascha Bischoff
96a6179355 Gem5Device: Add a gem5 device for Android
- Implementation of a gem5 device which allows simulated systems to be
  used in the place of a real device. Currently, only Android is
  supported.

- The gem5 simulation is started automatically based on a command line
  passed in via the agenda. The correct telnet port to connect on is
  extracted from the standard error from the gem5 process.

- Resuming from gem5 checkpoints is supported, and can be specified as
  part of the gem5 system description. Additionally, the agenda option
  checkpoint_post_boot can be used to create a checkpoint
  automatically once the system has booted. This can then by used for
  subsequent runs to avoid booting the system a second time.

- The Gem5Device waits for Android to finish booting, before sending
  commands to the simulated device. Additionally, the device supports
  a sleep option, which will sleep in the simulated system for a
  number of seconds, prior to running the workload. This ensures that
  the system can quieten down, prior to running the workload.

- The Gem5Device relies of VirtIO to pull files into the simulated
  environment, and therefire diod support is required on the host
  system. Additionally, VirtIO 9P support is required in the guest
  system kernel.

- The m5 writefile binary and gem5 pseudo instruction are used to
  extract files from the simulated environment.
2015-11-02 10:15:34 +00:00
Sascha Bischoff
a6382b730b TelnetConnection:
- Allowed telnet connections without a password.

This is required as part of the upcoming Gem5Device, which uses a
password-less telnet connection to communicate with the device.
2015-11-02 10:09:59 +00:00
setrofim
661371f6f0 Merge pull request #49 from ep1cman/master
Fixed telnet support
2015-10-21 11:58:06 +01:00
Sebastian Goscik
b9b4a7c65c Fixed telnet support
- Added port kwarg to telnet login function (default port=23)
2015-10-21 11:53:25 +01:00
Sergei Trofimov
20a5660ea1 android device: always deploy busybox on rooted devices. 2015-10-19 13:40:50 +01:00
Sergei Trofimov
691c380779 serial_port: updating to handle newer versions of pexpect
from version 4.0.0 onwards, fdpexpect is now namespaced under the main
pexpect libarary, rather than being stand-alone.
2015-10-16 17:38:19 +01:00
Sergei Trofimov
7546232c10 trace_cmd: fix parser to oportunistically convert parsed values to ints
This was done previosly but was broken by commit

1c146e3ce7
2015-10-16 17:08:09 +01:00
Sergei Trofimov
4fa3d9de6e Import pxssh via pexpect
Importing it directly causes issues in some environments.
2015-10-16 11:05:53 +01:00
Sergei Trofimov
90bfbf6022 Adding autotest workload wrapper. 2015-10-09 08:43:53 +01:00
setrofim
079d5b4ec5 Merge pull request #48 from lisatn/rtapp_use_cases
rt-app: Update use cases
2015-10-09 08:21:07 +01:00
Lisa Nguyen
2c5d51cb2a rt-app: Update use cases
Add video-long.json and video-short.json files and
update spreading-tasks.json. The originals can be
found in git.linaro.org/power/rt-app.git repo.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-10-08 17:46:20 -07:00
Sergei Trofimov
1c146e3ce7 trace_cmd: more robust event fields parsing
The default paraser can now handle spaces in field values (but not field
names).
2015-10-08 17:13:48 +01:00
Sergei Trofimov
6159711a05 iozone: ensure test 0 always runs
Test 0 (write) creates a file that is used by subsequent tests.
Therefore if this test is not specified withen selecting which tests to
run, izone will fail with an error.

To avoid this, check the tests list specified by the user andd add test
0 if necessary.
2015-10-08 09:16:32 +01:00
Sergei Trofimov
208fdf4210 iozone: pylint fixes 2015-10-08 09:10:08 +01:00
setrofim
0fc602ecdb Merge pull request #43 from lisatn/iozone
Add iozone workload
2015-10-08 08:59:36 +01:00
Sergei Trofimov
552ea2a1bb fix: moving is_file and is_directory into BaseLinuxDevice, as relied on by get_properties. 2015-10-05 16:30:33 +01:00
Lisa Nguyen
5f6247cf8b iozone: Modify comments
Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-10-01 14:57:35 -07:00
Lisa Nguyen
c96a50e081 iozone: Add description to enable classifiers
In order to show more detailed results for the iozone
workload, inform users to enable classifiers in their
agenda or config file.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-10-01 14:48:09 -07:00
Lisa Nguyen
812bbffab1 iozone: Rewrite parse_metrics() function
When users specify tests, the parse_metrics()
function doesn't capture the last report name and its
results during the parsing process. Fix the
parse_metrics() function to make sure the data for
all reports are captured.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-10-01 12:38:04 -07:00
Lisa Nguyen
361f1a0f0c iozone: Whitespace cleanup
Cleanup whitespace and reorganize code.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-10-01 11:52:51 -07:00
Lisa Nguyen
8e84e4a230 iozone: Add descriptions and refactor code
Add test descriptions, remove defaults, and
fix functions to parse non-thread related data.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-10-01 11:37:05 -07:00
Sergei Trofimov
fe4d49e334 android device: added swipe-to-unlock option 2015-10-01 12:06:02 +01:00
Sergei Trofimov
dc01dd79ee telemetry: report errors. 2015-10-01 12:06:02 +01:00
Sergei Trofimov
0003993173 daq: updated workload labeling in daq_power.csv
Workload labels, rather than names, are now used in the "workload"
column.
2015-10-01 12:05:53 +01:00
Sergei Trofimov
b6442acf80 device: more reliable get_properites
Pulling entries from procfs does not work on some platforms. This commit
updates get_properites() to cat the contents of a property_file and
write it to output file on the host, rather than pulling it (directories
are still pulled).
2015-09-30 12:39:49 +01:00
Sergei Trofimov
a6feb65b34 daq: adding gpio_sync option.
When enabled, this wil cause the instrument to insert a marker into
ftrace, while at the same time setting a GPIO pin high.

For this to work, GPIO sysfs interface must be be enabed in the kernel
and the specified pin must be exported.
2015-09-25 15:03:16 +01:00
Sergei Trofimov
f1d3ebc466 adding missing supported_platforms attributes.
Bbench only works on Android. It should advertise that fact by setting
supported_platforms to ['android'].
Telemetry is a Chrome browser workload that is only supported on
ChromeOS and Android.
2015-09-23 08:42:09 +01:00
Sergei Trofimov
0608356465 list command: adding --packaged-only option
With this option, only extensions packaged with WA itself will be
listed. Extensions discovered from other packages or from local paths
will not appear in the list.
2015-09-22 08:41:53 +01:00
Sergei Trofimov
d7ef6ff8ba netstats: added "period" parameter.
This parameter allows specifying polling period for the on-device
service.
2015-09-21 08:45:26 +01:00
Sergei Trofimov
2904246cb5 Adding netstats instrument.
This instrument allows monitoring data sent/received by applications on
an Android device.
2015-09-18 09:33:17 +01:00
Sergei Trofimov
5abb42eab9 Do not attempt to get_sysfile_value() as root on unrooted devices. 2015-09-18 09:33:17 +01:00
setrofim
ce91e34f9f Merge pull request #47 from lisatn/rtapp-binary-update
rt-app: Update binaries
2015-09-16 09:12:01 +01:00
Lisa Nguyen
18f4c3611c rt-app: Update binaries
A newer version of rt-app has been released. Built
binaries from git://git.linaro.org/power/rt-app.git.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-09-15 14:43:47 -07:00
Sergei Trofimov
6bdd6cf037 energy_model: preserve indecies during bs power table calculation. 2015-09-14 16:06:00 +01:00
Sergei Trofimov
e36c619fc2 vexperess flashing: added an option to keep UEFI entry 2015-09-14 15:31:21 +01:00
Sergei Trofimov
76253e1e26 Fixing turning off UI in ChromeOS + adding it energy_model. 2015-09-14 12:53:08 +01:00
Sergei Trofimov
bf8dc6642f energy_model: cleanner error reporting. 2015-09-14 11:05:26 +01:00
Sergei Trofimov
3d8c384bb7 cpufreq: handle non-integer output in get_available_frequencies 2015-09-14 11:03:54 +01:00
Sergei Trofimov
3247b63cb9 shh: handle backspaces in serial output 2015-09-14 10:58:14 +01:00
Lisa Nguyen
100c6c0ac9 iozone: Add functions and rewrite update_result()
Added functions to parse thread-mode results and
non-thread mode results accordingly, in addition
to rewriting the update_result() function.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-09-13 20:50:17 -07:00
Sergei Trofimov
f063726cc3 Further fixes for Juno flashing. 2015-09-10 08:40:09 +01:00
Sergei Trofimov
84f7adbfb2 uefi menu: updated prompt_regex to handle debug UEFI builds. 2015-09-09 17:40:02 +01:00
Sergei Trofimov
b6c497d32b Updated boolean to interpret 'off' as False 2015-09-09 14:32:27 +01:00
Sergei Trofimov
f430187b11 sysbench: fixed case where default timeout < max_time 2015-09-08 18:00:17 +01:00
Sergei Trofimov
37c49e22b3 chromeos_test_image: added a runtime parameter to disable ui 2015-09-08 17:43:10 +01:00
Sergei Trofimov
9e12930a43 dhrystone: kill any running instances during setup (also handle CTRL-C). 2015-09-08 17:42:18 +01:00
Sergei Trofimov
d5f4457701 cpufreq: refined availability check not to rely on the top-level cpu/cpufreq directory 2015-09-08 17:41:25 +01:00
Sergei Trofimov
c9f86b05dd flashing: fixing vexpress flashing 2015-09-07 17:56:05 +01:00
Sergei Trofimov
6e447aa8b2 docs: typo 2015-09-07 17:55:42 +01:00
Sergei Trofimov
5eb7ca07fe energy_model: fix cluster power estimation based on voltage. 2015-09-07 11:52:31 +01:00
Sergei Trofimov
6d6cddff58 Added 'negative_values' to daq instrument which can be used to specify how negative values in the samples should be handled. 2015-09-04 17:22:17 +01:00
Sergei Trofimov
94cc17271e sysfs_extractor: fixed pulled files verification.
When no files are listed for one the specified directoris, the
instrument checks whether there are any files in that directory on the
device. If that directory itself does not exist; that will result in an
error. This is now handled correctly.
2015-09-04 08:56:19 +01:00
Sergei Trofimov
9aadb9087a http_assets: fixing that which was broken 2015-09-04 08:56:15 +01:00
Sergei Trofimov
2e35d4003f nenamark: made duration configurable. 2015-09-03 17:29:42 +01:00
Sergei Trofimov
0d076fe8ba andebench: added parameter to only run native portion of the benchmark. 2015-09-03 17:21:45 +01:00
Sergei Trofimov
bfed59a7cf Adding an HTTP-based resource getter. 2015-09-03 13:55:44 +01:00
Sergei Trofimov
047308a904 ipython: pylint fixes 2015-09-03 12:07:41 +01:00
Sergei Trofimov
0179d45b5b energy_model: minor fix for previous adjustment. 2015-09-03 11:06:26 +01:00
Sergei Trofimov
c04b98c75a ipython: updated version check.
Version 4.0.0 changes API and breaks WA's usage of it. Updated version
check to only initialize ipython utils if version is < 4.0.0.
2015-09-02 17:39:11 +01:00
Sergei Trofimov
3501eccb8e energy_model: yet another adjustment to leakage compensation. 2015-09-02 15:31:13 +01:00
Sergei Trofimov
a80780b9ed energy_model: idle state fix 2015-09-01 16:19:53 +01:00
Sergei Trofimov
1b6b0907f9 energy_model: further fixes to idle measurement.
- Fix to core frequency to min
- Only disable idle states that are deeper than the measured state.
  Keep shallower states enabed.
2015-08-28 17:12:24 +01:00
setrofim
4389a7d350 Merge pull request #46 from JaviMerino/fix_trace_warning
trace: fix data file trace name in warning
2015-08-28 16:05:16 +01:00
Javi Merino
227c39d95d trace: fix data file trace name in warning
The warning refers to trace.bin, which is not the extension that we use
for it.  Instead, use the variable with the default trace
name (trace.dat) for the warning.
2015-08-28 15:52:43 +01:00
Sergei Trofimov
25b9350fea energy_model: fixing idle state handling to encompass all active cores on a cluster. 2015-08-26 12:48:22 +01:00
Sergei Trofimov
9b7b57a4d4 androbench: removed trailing spaces from metric names. 2015-08-21 13:58:00 +01:00
Sergei Trofimov
5aae705172 androbench: added early check for root on device; updated description with link to website. 2015-08-21 09:37:53 +01:00
setrofim
b653beacd3 Merge pull request #45 from bathepawan/master
Androbench Storage Benchmark
2015-08-21 09:16:28 +01:00
Sergei Trofimov
88f57e5251 Agenda: default config to dict 2015-08-21 08:34:49 +01:00
Pawan Bathe
f44fd9df7a Change device pull to handle root,and renamed local file as well history.db from results.db 2015-08-20 21:25:55 +05:30
Pawan Bathe
8513304aeb python sqlite3 to remove host/DUT dependencies + other changes 2015-08-19 21:53:50 +05:30
Pawan Bathe
e38c87f258 Fix pylint errors 2015-08-18 01:28:09 +05:30
Pawan Bathe
03a9470007 Fixed issue reported by pep8 checkers 2015-08-18 01:09:45 +05:30
Pawan Bathe
2d8b8ba799 moved UiAutomator code to java, and removed not required python code for device interfacing 2015-08-18 00:46:48 +05:30
Pawan Bathe
e4ee496bc9 Use sqllite3 instead of sqllite to remove host dependencies and result unit in proper format 2015-08-17 23:20:30 +05:30
Sergei Trofimov
205934d55b juno: use bootargs on hard_reset with u-boot 2015-08-17 14:36:28 +01:00
Sergei Trofimov
95c3f049fb trace_cmd: handle trace headers and thread names with spaces 2015-08-17 12:37:58 +01:00
Sergei Trofimov
25c0fd7b8b Allow setting classifiers via agenda. 2015-08-17 10:37:40 +01:00
Pawan Bathe
1cf60c2615 Results format 2015-08-15 02:39:45 +05:30
Pawan Bathe
c3d8128ff3 Androbench Storage Benchmark Workload Addition 2015-08-15 02:10:08 +05:30
Sergei Trofimov
aa2ae03ce6 daq: daq_power.csv now matches the order of labels (if specified). 2015-08-13 16:10:58 +01:00
Sergei Trofimov
6137d5650f delay: added fixed_before_start configuration; updated all to be very_slow
- fixed_before_start is a fixed time period equivalent to
  temperature_before_start
- Changed existing *_between_specs and *_between_iterations callbacks to
  be very_slow, as they should always run after everything else.
2015-08-12 16:12:38 +01:00
Sergei Trofimov
0703db05cf rt-app: relaxing timeouts. 2015-08-12 11:53:29 +01:00
Sergei Trofimov
0e1990a2bb ssh: fixed error reporting on failed exit code extraction. 2015-08-12 11:28:38 +01:00
Lisa Nguyen
25e53c2abc iozone: Add license information
Add license information for the iozone binaries.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-08-11 14:07:26 -07:00
Sergei Trofimov
14f5858e3d pep8 2015-08-11 17:02:38 +01:00
Sergei Trofimov
a6d374bcff wa create workload: better error reporting
Give more informative errors if Android SDK installed but no
platform has been downloaded.
2015-08-11 16:59:25 +01:00
Sergei Trofimov
85eba9c37a Better error reporting for subprocess.CalledProcessError 2015-08-11 16:51:34 +01:00
Lisa Nguyen
0acbcc9f95 Add iozone workload
Initial commit of the iozone workload.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-08-10 13:13:17 -07:00
Sergei Trofimov
1d67dd3b99 energy_model: adjusting to compensate for leakage when evaluating cluster power 2015-08-10 10:48:26 +01:00
Sergei Trofimov
ab45c4499f utils.misc.normalize: only normalize string keys. 2015-08-10 10:42:20 +01:00
Sergei Trofimov
75e4b7d2ae fps: filter out bogus actual-present times and ignore janks above PAUSE_LATENCY
The PAUSE_LATENCY thing is in line with what Google do inside
SurfaceFlingerHelper.
2015-08-06 11:20:58 +01:00
Sergei Trofimov
5e92728d77 pylint fixes 2015-07-27 10:11:59 +01:00
Sergei Trofimov
b5d879a90b APK workloads: added an option to skip host-side APK check entirely. 2015-07-27 09:55:23 +01:00
Sergei Trofimov
507efaec48 perf: reverting type change for optionstring 2015-07-24 16:20:14 +01:00
Sergei Trofimov
0db14e2466 Updating energy_model to mitigate cluster power issue
A quadratic is now fitted to single and two-core power measured across
frequencies. This quadratic is then used in projection of cluster power.
This mitigates issues with cluster powers going negative or "crossing
over".
2015-07-24 08:11:23 +01:00
Sergei Trofimov
6ced04daf0 Fix for the previous fix... 2015-07-23 10:25:13 +01:00
Sergei Trofimov
b6064fa348 perf: fix for Android: killall sleep as root. 2015-07-23 10:17:01 +01:00
setrofim
6207f79f01 Merge pull request #41 from rockyzhang/patch-2
passing 'video' command line to Juno kernel
2015-07-21 18:09:45 +01:00
Sergei Trofimov
295b04fb5a Updating jank calcluation to only count "large" janks. 2015-07-21 10:03:21 +01:00
Sergei Trofimov
19072530e4 daq: fix for the updated twisted support. 2015-07-21 08:35:36 +01:00
Sergei Trofimov
39ed42ccb9 daqpower: updating to work with new versions of twisted. 2015-07-20 17:40:02 +01:00
Sergei Trofimov
89da25c25e cpustates: added "Running (unknown Hz)" state to the timeline. 2015-07-20 17:04:09 +01:00
Sergei Trofimov
4debbb2a66 Updating ANROID_VERSION_MAP with recent versions. 2015-07-17 17:24:14 +01:00
Sergei Trofimov
e38bd942a8 bbench: fixed to work when binaries_directory is not in path. 2015-07-17 15:38:47 +01:00
Sergei Trofimov
47b2081ccb doc: fixing daq wiring screenshot diagram 2015-07-17 12:43:46 +01:00
Sergei Trofimov
298602768e doc: changing theme to "classic" to be compatible with new version of sphinx 2015-07-17 12:43:25 +01:00
Sergei Trofimov
d2dbc9d6dd Added the ability to override the timeout of deploying the assets tarball in GameWorkload 2015-07-16 16:53:35 +01:00
Rocky Zhang
d512029f10 Update __init__.py 2015-07-16 16:27:08 +08:00
Rocky Zhang
dc7dea1c3e passing 'video' command line to Juno kernel
There's a known issue that HDMI will lose sync with monitor, adding video kernel parameter will make the HDMI more stable for juno

> HDMI can lose sync with the monitor intermittently, particularly at higher resolutions. 
> If you are affected by this then try adding a kernel command line argument that forces 
> a video mode with reduced blanking, such as the following:
> video=DVI-D-1:1920x1080R@60
2015-07-16 15:45:26 +08:00
Sergei Trofimov
2d3be33bb0 Added target_config option to telemetry 2015-07-14 11:26:17 +01:00
Sergei Trofimov
65ab86221b Reduce starting priority of trace-cmd instrument. 2015-07-13 17:04:45 +01:00
Sergei Trofimov
b8e25efdd4 ssh: attempt to deal with dropped connections 2015-07-10 11:44:01 +01:00
setrofim
2e4bda71a8 Merge pull request #39 from JaviMerino/ipynb_convert_to_html
ipynb_exporter convert to html
2015-07-09 13:58:51 +01:00
Javi Merino
30d7ee52f4 ipynb_exporter: learn to convert the notebook to HTML 2015-07-09 12:50:02 +01:00
Javi Merino
539c3de7b8 ipython: rename IPYTHON_NBCONVERT to IPYTHON_NBCONVERT_PDF
This command is tailored for converting notebooks to pdf, but we also
want it to be able to generate html.
2015-07-09 12:49:31 +01:00
Sergei Trofimov
687e1ba6b8 daq server: report DAQError messages properly 2015-07-09 11:00:46 +01:00
Sergei Trofimov
a72ae92ece stream: pylint/pep8 fixes. 2015-07-09 08:23:20 +01:00
setrofim
1562f17d8c Merge pull request #38 from lisatn/stream
Add stream workload
2015-07-09 08:19:50 +01:00
Lisa Nguyen
255e6c1545 stream: Add initialize and finalize functions
Add initalize and finalize functions in the stream workload
in addition to simplifying code.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-07-08 11:16:13 -07:00
Lisa Nguyen
c733ecad98 Add stream workload
Initial commit of the stream workload to measure
memory bandwidth.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-07-07 11:12:28 -07:00
Sergei Trofimov
088d0f6981 fix: added remote_assets_mount_point to ingore list for cofig parsing 2015-07-07 16:20:24 +01:00
Sergei Trofimov
13e5e4d943 adb_connect: do not assume port 5555 2015-07-07 11:19:58 +01:00
Naresh Kamboju
6e72ad0cc3 hwmon: print both before/after and mean temperatures
Print both before/after and mean temperatures of DCC and MCC

Example:
mp_a7bc_w01,bbench_with_audio,1,"arm,vexpress-temp DCC",34.062,Celsius mp_a7bc_w01,bbench_with_audio,1,"arm,vexpress-temp DCC before",33.849,Celsius mp_a7bc_w01,bbench_with_audio,1,"arm,vexpress-temp DCC after",34.275,Celsius mp_a7bc_w01,bbench_with_audio,1,"arm,vexpress-temp MCC",45.432,Celsius mp_a7bc_w01,bbench_with_audio,1,"arm,vexpress-temp MCC before",45.432,Celsius mp_a7bc_w01,bbench_with_audio,1,"arm,vexpress-temp MCC after",45.432,Celsius

Signed-off-by: Naresh Kamboju <naresh.kamboju@linaro.org>
2015-07-06 14:09:50 +01:00
Sergei Trofimov
cb89bd5708 Fixing typo in config_example.py 2015-07-02 12:17:19 +01:00
Sergei Trofimov
30bb453747 gaming workloads: added an option to prevent clearing of package data before execution 2015-07-01 16:17:39 +01:00
Sergei Trofimov
a37e734cf1 fix: adding dependencies_directory to NO_ONE resource owner 2015-07-01 16:08:10 +01:00
Sergei Trofimov
a27768fe21 rt-app: do not unintall at then end by default
rt-app workload will no longer uninstall the executable at the
end of the run by default. A parameter can be used to re-enabed the
uninstall.
2015-06-30 15:54:58 +01:00
Sergei Trofimov
6affc484f4 resource getter: Change the order in which executable paths checked. 2015-06-30 15:54:40 +01:00
Sergei Trofimov
90ea2dd569 resource getter: look for executable resource in correct loction.
Look in the bin/ directory under resource owner's dependencies directory
as well as general dependencies bin.
2015-06-30 10:50:56 +01:00
Sergei Trofimov
df6d1f1c2b resorce resover: debug-print the path of found resource 2015-06-30 10:50:49 +01:00
Sergei Trofimov
34a604f4fc juno: do not auto-disconnect at the end of the run
Juno connection no persists at the end of the run. Boolean parameter
actually_disconnect has been added to allow restoring the old behavior.
2015-06-30 10:36:20 +01:00
Sergei Trofimov
f7941bbc25 More informative syntax error reporting. 2015-06-30 10:36:20 +01:00
setrofim
f6ecc25a4b Merge pull request #34 from bobbyb-arm/lmbench-submit2
Initial commit of lmbench workload
2015-06-30 09:55:30 +01:00
Bobby Batacharia
5c53f394cb Initial commit of lmbench workload
Remove unused includes
2015-06-29 22:55:56 +01:00
Sergei Trofimov
967f9570e2 manhattan: fixing syntax error introduced by previous commit 2015-06-29 17:57:41 +01:00
Sergei Trofimov
19d6ce5486 manhattan: chaning run_timemout into a parameter and upping default to 10mins 2015-06-29 17:55:43 +01:00
Sergei Trofimov
3b4dc137d2 cpustate: check if trace marker is present and disable marker filtering if it is not. 2015-06-29 17:33:28 +01:00
Sergei Trofimov
78314c1ef2 cpustates added an option to ignore trace markers. 2015-06-29 17:28:00 +01:00
setrofim
b3c9d43ccd Merge pull request #33 from vflouris/master
Energy model instruments: allows power adjustment for thermal effect
2015-06-29 14:19:20 +01:00
Vasilis Flouris
7f5952aa9c Energy model instruments: allows power adjustment for thermal effect 2015-06-29 13:04:41 +01:00
Sergei Trofimov
b018adac11 pylint fixes 2015-06-29 11:34:49 +01:00
Sergei Trofimov
4904c6cf71 listdir on Linux: return empty list for an empty directory
Previously, was returning a list with a single empty string element
2015-06-29 11:28:47 +01:00
Sergei Trofimov
26dee81164 Adding arm64-v8a to ABI map 2015-06-29 09:21:06 +01:00
setrofim
c09972e7a8 Merge pull request #30 from bobbyb-arm/fixes
Fixes
2015-06-28 11:42:54 +01:00
Bobby Batacharia
6069ccacdc ExtensionLoader should follow symlinks 2015-06-28 11:00:01 +01:00
Bobby Batacharia
22d72de969 Fix terminal size discovery in DescriptionListFormatter 2015-06-28 10:35:15 +01:00
Sergei Trofimov
b712dddfc0 android device: update android_prompt so that it works even if is not / 2015-06-26 16:25:44 +01:00
Sergei Trofimov
d6cebc46ce perf: updating binaries and adding option to force install 2015-06-26 14:19:15 +01:00
Sergei Trofimov
85c78e6566 sysfile_getter: fixed Exception when both device and host paths are empty. 2015-06-26 12:14:02 +01:00
Sergei Trofimov
fcb6504f1e Adding ID to overall cpustate reports. 2015-06-26 10:24:07 +01:00
Sergei Trofimov
b25f7ec4a3 Updated installation docs with warning about potential permission issues. 2015-06-26 10:23:39 +01:00
Sergei Trofimov
5401a59da0 Adding support for U-Boot booting in Juno. 2015-06-25 11:32:01 +01:00
Sergei Trofimov
00561e0973 Adding support for U-Boot booting in Juno. 2015-06-25 10:59:19 +01:00
Sergei Trofimov
642da319d4 linpack-cli: setting run timeout based on array size 2015-06-19 09:47:49 +01:00
Sergei Trofimov
a6e9525264 Adding command line version of linpack benchmark. 2015-06-19 09:42:16 +01:00
Sergei Trofimov
4d5413ac26 add agenda command: added options for iterations and runtime parameters 2015-06-18 17:38:51 +01:00
Sergei Trofimov
ccea63555c Added retries
Failed jobs will now be automatically retired. This is controlled by two
new settings:

retry_on_status - a list of statuses which will be consided failures and
                  result in a retry
max_retries - number of retries before giving up
2015-06-18 16:46:26 +01:00
Sergei Trofimov
51c5ef1520 create command: make sure "create agenda" can pick up loacal extensions 2015-06-18 16:18:27 +01:00
Sergei Trofimov
c6ede56942 rt-app: added taskset_mask parameter 2015-06-18 15:21:12 +01:00
Sergei Trofimov
e0ecc9aaf4 Added an invoke() method to devices.
This allows invoking an executable on the device under controlled
contions (e.g. within a particular directory, or taskset to specific
CPUs)
2015-06-18 15:07:44 +01:00
Sergei Trofimov
44c2f18f76 Adding "create agenda" sub-command
It is now possible to generate agendas for a set of extensions with

  wa create agenda ext1 ext2 ext3 -o output.yaml

Confiuration will include all parameters for those extensions with
default values.
2015-06-18 12:50:12 +01:00
Sergei Trofimov
53c669f906 streamline: do not instatiate resource getter directly 2015-06-18 12:33:56 +01:00
Sergei Trofimov
c076a87098 Added support for YAML configs
Config files (the default one in ~/.workload_automation plus ones
specified with -c) can now be written using YAML syntax as well as
Python.
2015-06-18 11:35:50 +01:00
Vasilis Flouris
90c0ed281d Documentation: punctuation error fix 2015-06-18 10:46:29 +01:00
Vasilis Flouris
aac69a9c14 Documentation update 2015-06-18 10:39:20 +01:00
Sergei Trofimov
08bfef961e run command: adding a command line option to diable instruments
Also, updating help messages for exising arguments to use multiline
strings.
2015-06-18 10:07:48 +01:00
Sergei Trofimov
d9f45db71e Implementing dynamic device modules
Dynamic modules may be loaded automatically on device initialization if
the device supports them. Dynamic modules implent probe() method to
determine whether they are supported by a particular deviced.

devcpufreq and cpuidle have been converted into dynamic modules
2015-06-18 09:42:40 +01:00
Sergei Trofimov
73d85c2b4e cleaning up initialize()
- standardisded on a single context argument
- removed Device.init() no longer necessary as initilize now
  automatically gets propagated up the hierarchy. Renamed the existing
  use of it to "initilize".
- related pylint cleanup.
2015-06-18 09:30:38 +01:00
Sergei Trofimov
55b38556fe cpufreq: splitting out cpufreq stuff into a device module 2015-06-18 09:30:38 +01:00
Sergei Trofimov
a71756acda pylint fixes 2015-06-18 09:30:14 +01:00
Sergei Trofimov
9470efe410 chromeos_test_image: only set default password if keyfile was not specified 2015-06-18 08:39:02 +01:00
Sergei Trofimov
0b29bda206 rt-app: removed ftrace check
trace-cmd seems to work fine with "ftrace: true" in the config, so
removing the check that prevented both from being enabled.
2015-06-17 10:14:08 +01:00
Sergei Trofimov
042da24e7d antutu: updating result parsing to handle Android M logcat output
Looks like M formats logcat output with some extra ":"'s which was
screwing up the old parsing logic.
2015-06-17 09:46:11 +01:00
Sergei Trofimov
a1e99e5591 Android device: correctly set busybox path 2015-06-16 17:23:22 +01:00
Sergei Trofimov
b98b31a427 sysfile_getter: use self.device.busybox rather than just "busybox"
Was breaking when location into which busybox was installed  was not in
PATH.
2015-06-16 17:02:23 +01:00
Sergei Trofimov
4eb0d9d750 Reverting to the old way of getting the abi on Android
uname is not available on all Android devices, and we cannot rely on
busybox for establishing the ABI, as we need to get the ABI before we
can depoly the right version of busybox.
2015-06-16 15:15:18 +01:00
Sergei Trofimov
4af93d94dd show command: adding supported platforms 2015-06-16 12:56:48 +01:00
Sergei Trofimov
e7fae25821 list command: can now filter results by supported platform
Added -p option to the list command. This alows filtering results by
supported platforms, e.g.

	wa list workloads -p linux

Also adding missing supported_platforms attribute to various extensions.
If an extension does not have this attribute, the assumption is that it
is supported by all available platforms.
2015-06-16 12:49:07 +01:00
Sergei Trofimov
53de517488 device: set core_clusters from core_names if not explicitly specified
if core_names are specified in the device config but core_clusters are
not, assume that all cores with the same name are on the same cluster.
2015-06-16 12:21:44 +01:00
Sergei Trofimov
15e854b8f1 telemetry: fix the doc so they no longer say it must be installed
WA will now fetch it automatically
2015-06-16 11:10:50 +01:00
Sergei Trofimov
a85e45c6b0 cpustate: now generates a timeline csv as well as stats 2015-06-16 11:04:25 +01:00
Sergei Trofimov
4d3feeba64 list_file_systems: fix for Android M and Linux devices
In previous versions of Android, "mount" returned output in the format
similar to fstab entries, which is what list_file_systems expected. This
fixes it to be able to handle the more traditional "mount" output in the
format

	<device> on <mount point> type <fs type> <options>

as well as continue to parse the Android output correctly.
2015-06-16 08:49:58 +01:00
setrofim
92ddcbb1e3 Merge pull request #27 from lisatn/master
perf: remove CCIPerfEvent class
2015-06-15 18:49:29 +01:00
Lisa Nguyen
7c7a5de988 perf: remove CCIPerfEvent class
Remove the CCIPerfEvent class since it's no longer used
in WA.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-06-15 10:34:59 -07:00
Sergei Trofimov
cbf7eadc6c sqlite: adding global aliases to params
Adding global aliases to parameters to fix old configs that still used
the deprecated "<ext name>_<param name>" format for specifying parameter
values.
2015-06-15 14:34:57 +01:00
Sergei Trofimov
d775be25f7 Removing total_tasks "metric" form rt-app, as reported as a classifier. 2015-06-15 13:07:49 +01:00
Sergei Trofimov
8dc4321deb Adding rt-app workload 2015-06-15 12:04:00 +01:00
Vasilis Flouris
0d3e6b8386 Fixes missing directories problem in DynamicFrequencyInstrument 2015-06-12 17:53:05 +01:00
Vasilis Flouris
7ee44fb0e4 Fix: for the chromeos test image device 2015-06-12 14:39:46 +01:00
Sergei Trofimov
ab76aa73f2 cpustate: fixing division by zero
total running time (in parallel stats) is zero when all cores on a
cluster are hotplugged. this caused a division by zero when calculating
percentage.
2015-06-12 13:02:05 +01:00
Sergei Trofimov
179baf030e Fixed typo. 2015-06-12 12:43:35 +01:00
Vasilis Flouris
2f214da8a2 fix: uname utility is unavailable in Android. It has to be invoked through busybox. 2015-06-11 18:58:34 +01:00
Sergei Trofimov
e357a46b62 Documenting the Workload initialize and finalize methods 2015-06-11 18:17:53 +01:00
Sergei Trofimov
6c8228a26c Invoking workload finalizers at the end of the run. 2015-06-11 18:04:55 +01:00
Sergei Trofimov
b3a0933221 Adding intialize and finalize methods to workloads that will only be invoked once per run
- added initialze and finalize methods to workloads, which were the only
  major extension types that did not have them
- Semanatics for initialize/finalize for *all* Extensions are changed so
  that now they will always run at most once per run. They will not be
  executed twice even if invoke via istances of different subclasses (if
  those subclasses defined their own verions, then their versions will
  be invoked once each, but the base version will only get invoked
  once).
2015-06-11 17:45:09 +01:00
Sergei Trofimov
557b792c77 Made abi property common between Android and Linux devices
In both cases, the ABI is now obtained by executing "uname -m" on the
device and perfroming a mapping from the returned machine architecture
a known ABI. If no known ABI is found the architecture string itself is
returned.
2015-06-11 17:45:09 +01:00
Sergei Trofimov
2ee9b40527 classifiers: usability updates
- add IterationResult-level classifiers that get merged into every
  added metric (saves having to pass the same classifiers to each
  metric added).
- Added a global alias to csv result processor's  use_all_classifiers
  attribute.
2015-06-11 17:45:09 +01:00
Sergei Trofimov
32f3dc21e4 Added job_status property to ExecutionContext 2015-06-11 17:45:09 +01:00
Vasilis Flouris
b31a9bd61a fixes a minor bug in energy model instrument 2015-06-11 13:09:04 +01:00
Sergei Trofimov
67896dfd86 energy_model: adding dhrystone support
- updated energy_model to accept dhrystone as well as sysbench as
  the workload
- added "threads" parameter to sysbench (basically, an alias for
  "num_threads") to be consistent with dhrystone
- added "taskset_mask" parameter to dhrystone to allow pinning
  it to specific cores.
2015-06-11 10:10:36 +01:00
Vasilis Flouris
88ba8e3ba7 Fixes result result processing bug in sysbench 2015-06-09 18:25:30 +01:00
Sergei Trofimov
771567365d daq instrument: updating default server_port to match daq server. 2015-06-09 15:22:57 +01:00
Sergei Trofimov
5fdb94d804 removing old tarball. 2015-06-09 13:17:28 +01:00
Sergei Trofimov
026e663155 daqpower: typo fix 2015-06-09 13:14:07 +01:00
Sergei Trofimov
4b7af1d2a6 Another update to daqpower
- server will now periodically clean up uncollected files
- fixed not being able to resolve IP address for hostname
  (report "localhost" in that case).
2015-06-09 13:08:50 +01:00
Sergei Trofimov
d9cd1d3282 Removing daqpower hack that got accidentally committed 2015-06-09 12:58:13 +01:00
Sergei Trofimov
c239322c4d Updated daqpower package
- Now works with earlier versions of the DAQmx driver. This is needed to
  be able to run the server on Linux systems, which support older
  verisions of the driver only.
- DAQ error messages are now properly propaged to the client (PyDAQmx
  uses "mess" rather than "message" attribute to store the message in
  the Exception obejects).
- pylint and pep8 fixes
2015-06-09 11:03:26 +01:00
Sergei Trofimov
0c19d75bf4 Adding daqpower package to static checkers. 2015-06-09 11:03:26 +01:00
Sergei Trofimov
084de2e58c Adding an illustration for DAQ wiring. 2015-06-09 11:03:26 +01:00
Vasilis Flouris
88c304292f comment correction 2015-06-05 13:00:59 +01:00
Sergei Trofimov
c40a7fd644 more robust exit_code handling for ssh interface
Background processes may produce output on STDOUT. This could get
captured when obtaining the result of "echo $?" to get previos command's
exit code. So it's not safe to assume that output will always be an int.
Attempt to strip out superflous output before doing the int conversion
and, on failure, log a warning but don't error out.
2015-06-05 12:47:01 +01:00
Sergei Trofimov
b976164ee9 Fixing typo in a cpustate parameter name. 2015-06-05 09:05:13 +01:00
setrofim
d102994214 Merge pull request #25 from zhizhouzh/master
get options in config_example.py reachable
2015-06-04 10:03:04 +01:00
zhizhou.zhang
7422a72a7b get options in config_example.py reachable
Some options in config_example.py are not reachable. It makes users
confused. So make the options in the file as gobal_alias.

Signed-off-by: zhizhou.zhang <zhizhou.zhang@spreadtrum.com>
2015-06-04 15:56:52 +08:00
setrofim
3044d192f9 Merge pull request #24 from vflouris/pull-request
Pull request: second batch of changes for energy_model
2015-06-03 18:12:19 +01:00
Vasilis Flouris
afa2b11975 Adds copyright header to energy model instrument 2015-06-03 18:07:40 +01:00
Vasilis Flouris
1a604ac2e3 Fixes a bug in energy model instrument 2015-06-03 18:04:51 +01:00
Vasilis Flouris
d60034f7d7 Allows running the energy instrument without hotplugging 2015-06-03 18:04:45 +01:00
Sergei Trofimov
8980304e56 Adding a note about cpuidle module to cpustates. 2015-06-03 16:33:45 +01:00
Sergei Trofimov
02af02f0cb Adding cpustates result processor (and script) 2015-06-03 16:20:48 +01:00
Sergei Trofimov
9971041e45 Updating copyrights in scripts. 2015-06-03 16:20:48 +01:00
Sergei Trofimov
e9b21e2ef3 Adding a generic trace-cmd paraser. 2015-06-03 16:20:48 +01:00
Sergei Trofimov
5cfecf8068 show command: minor fix to parameter rendering
Make sure default of 'False' is reported for boolean values.
2015-06-03 16:20:48 +01:00
Sergei Trofimov
bf189dbe6a mino doc tweak. 2015-06-03 16:20:48 +01:00
Sergei Trofimov
ecb1a9f1f9 Adding /proc/cmdline to pulled metadata 2015-06-02 15:05:52 +01:00
setrofim
22b3fe1ac8 Merge pull request #23 from vflouris/pull-request
Pull request: minor fixes for energy model generation and a device interace for Chrome OS test image devices.
2015-06-02 13:07:57 +01:00
Vasilis Flouris
953783dc2b Adds the generic_chromeos device. 2015-06-02 13:05:08 +01:00
Sergei Trofimov
8f972322a5 Updating documentation for generic device interfaces 2015-06-02 12:58:04 +01:00
Vasilis Flouris
1fa93c04d2 fixes a few minor bugs. 2015-06-02 10:53:20 +01:00
Sergei Trofimov
ebe6202e22 push/pull commands always raise DeviceError + handle error on pulling a property file.
Previosuly, they raised CalledProcessError/DeviceError based on
implementation. Making it consistent to facillitated handling in calling
code.
2015-06-01 17:25:59 +01:00
Sergei Trofimov
b4971d76d6 pull more stuff during run initialization
added more paths to pull by default when device.get_properties is
invoked during run initialization. Also moved the LinuxDevice
implementation into BaseLinuxDevice, so that AndroidDevice tires to pull
the same files (on top of the Android-specific stuff).
2015-06-01 16:41:33 +01:00
Sergei Trofimov
ead0be2763 Fixing merge_lists to work for list_or_* types 2015-06-01 16:18:13 +01:00
Sergei Trofimov
29aa81a694 Adding a couple of unit tests for some of the more interesting types. 2015-06-01 15:46:14 +01:00
Sergei Trofimov
f59da723fb list_or: chaniging how list_or_* functions work and adding a generic list_or
list_or_* functions (e.g. list_or_string) will now always return a list,
however will accept lists or indivitual values. Also added a list_or()
generator function, similar to what already exists for list_of().
2015-06-01 15:31:25 +01:00
Sergei Trofimov
a9ab67990a sysbench: updating to work on unrooted Android devices. 2015-06-01 12:21:51 +01:00
Sergei Trofimov
adefbb7b2c android devices: updating executable install/uninstall work on unrooted devices 2015-06-01 12:19:54 +01:00
Sergei Trofimov
c550657912 Updating contribution guidelines.
Clarifying style guidelines and refering "Writing Extensions" section.
2015-06-01 10:36:21 +01:00
Sergei Trofimov
578dfb3d99 telemetry: fixing "test" parameter description. 2015-06-01 10:08:26 +01:00
Sergei Trofimov
f49287cf09 Fixes for Emacs
- Do not try to use a pager if it explicitly disabled with PAGER='' in
  the environment.
- If terminal size is identified as (0, 0), fall back to default (80,
  25).
2015-06-01 10:05:23 +01:00
Sergei Trofimov
777003ed51 Adding instrument_is_enabled function
As instrumentation can be enabled/disabled for a specfic workload
execution, it is sometimes not enough to verify that an instrument has
been installed for the run; one might need to check whether it is
currently enabled.
2015-05-28 10:13:50 +01:00
Sergei Trofimov
a254a44f0e adding abi property to LinuxDevice 2015-05-28 09:08:46 +01:00
Sergei Trofimov
506ed57ca6 fix: telemetry: ignore all return codes
Telemetry seems to return random values as return code, so completely
ignore them and don't treat any values as errors.
2015-05-27 17:25:17 +01:00
Sergei Trofimov
c31d4ec8a3 ssh: fixing timeout behavior
Since a command would still be running on time out, it would prevent
issuing subsequent commands in the same SSH shell, make it look like
the device has become unresponsive.

If a timeout condition is his, send ^C to kill the current foreground
process and make the shell available for subsequent commands.
2015-05-27 09:13:03 +01:00
Sergei Trofimov
9e822c4b18 dvfs: fix active_cpus --> online_cpus rename 2015-05-26 12:30:15 +01:00
Sergei Trofimov
260616711f removing unused variable. 2015-05-26 09:29:59 +01:00
Sergei Trofimov
b9a8f6155c telemetry: remove obsolete metrics. 2015-05-15 14:09:53 +01:00
Sergei Trofimov
a450957b9a Fixing locally defined instruments erroneously propagating into global instrumentation 2015-05-15 10:01:26 +01:00
Sergei Trofimov
512bacc1be Adding classifiers to metrics and updating csv and telemetry to take advantage of them
- Adding "classifiers" field to Metric objects. This is a dict mapping
  classifier names (arbitrary strings) to corresponding values for that
  specific metrics. This is to allow extensions to add
  extension-specific annotations to metric that could be handled in a
  generic way (e.g. by result processors).
- Updating telemetry workload to add classifiers for the url and internal
  iteration (or "time") for a particular result.
- Updating csv result processor with the option to use classifiers to
  add columns to results.csv (either using all classifiers found, or
  only for the specific ones listed).
2015-05-14 15:15:32 +01:00
Sergei Trofimov
782d4501cd revent: fix resource resolution when dependency location does not exist. 2015-05-14 14:34:41 +01:00
Sergei Trofimov
26dfe97ffd ssh: fix: do not attempt to check mode of keyfile if it has not been specified. 2015-05-14 11:27:50 +01:00
Sergei Trofimov
48748797b7 setup.py: fix for OSX
On Unix, pip will change current working directory to whereever it has
extracted the downloaded package. On Mac OSX, it does not appear to do
that. To get around this difference, specify paths in setup.py relative
to the location of setup.py, rather than the current working directory.
2015-05-13 16:59:11 +01:00
Sergei Trofimov
ee63cbde62 telemetry: automatically download if necessary
If run_benchmark_path isn't specified, Telemetry zip archive will be
downloaded and extracted into dependencies.
2015-05-13 14:33:13 +01:00
Sergei Trofimov
e7b58c72ac telemetry: added fps extraction
Also fixed text that mistakenly referred to "run_benchmarks" (plural) as
the name of the script.
2015-05-13 14:05:15 +01:00
Sergei Trofimov
9b16e3f282 linux device: removing (keyfile or password) validation check
It may be possible to connect to a device without either, so it
should not be invalid to not specifiy either in the device config.
2015-05-13 08:46:10 +01:00
Sergei Trofimov
4e9601d905 config_example: disabled summary_csv and added status result processor
Made status result processor enabled by default on new WA installations
and disabled summary_csv by default.
2015-05-12 16:18:08 +01:00
Sergei Trofimov
48cced2ff9 antutu: robustness fixes for v5 multi-times executions
- added slight delays to ensure more precise navigation
- handle dialogs that occasionally pop up when re-running tests
2015-05-12 14:29:24 +01:00
Sergei Trofimov
57d3b80e85 power_loadtest: kill any already-running autotest instances during setup 2015-05-12 14:27:04 +01:00
Sergei Trofimov
cbd2c6727f Adding ChromeOS power_LoadTest 2015-05-12 11:34:30 +01:00
Sergei Trofimov
5daa9014a8 Adding "agruments" type
This type represents arguments that are passed on a command line to an
application. It has both string and list representations.
2015-05-12 11:34:30 +01:00
Sergei Trofimov
b2981a57bc ssh: ensure keyfile has the right permissions
The key file must only be readable by the owner. If the specified key
file has different access permissions, create a temporary copy with the
right permissions and use that.
2015-05-12 11:34:30 +01:00
Sergei Trofimov
98b259be33 energy_model: fix np.vectorize on ImportError
np.vectorize was being unconditionally invoked at top level. On an
ImportError, np as set to None, so this was resuling in an
AttributeError when loading the module if one of the dependent libraries
was not present on the host system. This moves the invocation into the
try block with the imports to avoid an error when energy_model module is
loaded by the extension is not used.
2015-05-12 11:34:30 +01:00
Sergei Trofimov
b30d702f22 minor fixes to cpufreq APIs
- adding missing cpu id conversion to set_cpu_min_freq
- adding "exact" parameter to set_cpu_frequency; only produce an error
  when the specified frequency is not supported by the cpu if "axact"
  is set; (otherwise let cpufreq decide what the actual frequency will
  be).
2015-05-12 11:34:30 +01:00
Sergei Trofimov
40bd32280a minor fixes to cpufreq APIs
- adding missing cpu id conversion to set_cpu_min_freq
- adding "exact" parameter to set_cpu_frequency; only produce an error
  when the specified frequency is not supported by the cpu if "axact"
  is set; (otherwise let cpufreq decide what the actual frequency will
  be).
2015-05-11 12:12:41 +01:00
Sergei Trofimov
fbde403f6f pep8 2015-05-11 12:12:41 +01:00
Sergei Trofimov
4b210e7aab energy_model: adjusting sysbench setup based on feed back from power team. 2015-05-11 12:12:41 +01:00
Vasilis Flouris
2929106049 Energy model: fixing sysbench taskset failure
Make sure when migrating sshd to root cgroup also migrate their
children, including the bash for the wa session. So the subsequent
processes kicked off from that shell can be taskset to any cluster.
2015-05-11 12:12:41 +01:00
Sergei Trofimov
485ba419b3 energy_model: set matplotlib backent to AGG
Matplotlib defautls to the GTK backend. This can cause problems when
running in a headless session (e.g. over SSH). Since energy_model
istrument generates PNG plots, rather than rendering directly to UI, it
doesn't actually need GTK; set backend to AGG so that energy_model works
in headless environments.
2015-05-11 12:12:41 +01:00
Sergei Trofimov
0e751bdd73 Handling duplicate prompt in pxssh in a slightly differnt way. 2015-05-11 12:12:41 +01:00
Sergei Trofimov
556bc84023 energy_model: fix for when running as a sudo user (rather than root) 2015-05-11 12:12:41 +01:00
Sergei Trofimov
715438e486 Adding missing documentation for module. 2015-05-11 12:12:41 +01:00
Sergei Trofimov
68ae8b9277 energy_model: added energy_metric
It is now possible to specify energy_metric instead of power_metric for
cases where continuous power is not available but energy can be
measured.
2015-05-11 12:12:41 +01:00
Sergei Trofimov
c5b884cf81 casless_string: added format() method 2015-05-11 12:12:41 +01:00
Sergei Trofimov
a4bff161aa idle: updated to work on Linux devices. 2015-05-11 12:12:41 +01:00
Sergei Trofimov
950f0851bf Fix: implementing get_pid_of() and ps() for linux devices.
Existing implementation relied on android version of ps.
2015-05-11 12:12:41 +01:00
Sergei Trofimov
49d7072440 Fix: cpuidle check directory name when numerating idle states
Do not assume that all directories under cpuidle/ represent states;
check that the directory name starts with "state" before trying to parse
it.
2015-05-11 12:12:41 +01:00
Sergei Trofimov
9d5e0cdc00 Fixing pylint false positives in energy_model
The new  version of pylint is throwing up a couple of new
false positives that the earlier versions did not seem to flag.
2015-05-11 12:12:41 +01:00
Sergei Trofimov
841bd784d9 Fix: correctly set measured/measuring cores. 2015-05-11 12:12:41 +01:00
Sergei Trofimov
47ce9db383 Updating energy model instrument to be able to accumulate multiple power rails for each cluster. 2015-05-11 12:12:40 +01:00
Sergei Trofimov
c52d562411 Adding energy_model instrument.
This instrument can be used to generate an energy model for a device
based on collected power and performance measurments. The instrument
produces a C file with an energy model and an accompanying HTML report.

This instrument is very different from other instrumentation, as it
actually generates the run queue on the fly based on the operating
frequencies and idle states it discovers on the device. The agenda needs
only to contain the single "base" spec that defines the workload to be
used for performance measurement.
2015-05-11 12:12:40 +01:00
Sergei Trofimov
6b041e6822 Added cgroups device module.
cgroups  modules allows query and manipulation of cgroups controllers on
a Linux device. Currently, only cpusets controller is implemented.
2015-05-11 12:12:40 +01:00
Sergei Trofimov
c82dd87830 Adding cpuidle modules and refactoring Device cpufreq APIs.
cpuidle module implements cpuidle state discovery, query and
manipulation for a Linux device. This replaces the more primitive
get_cpuidle_states method of LinuxDevice.

Renamed APIs (and added a couple of new ones) to be more consistent:

"core" APIs take a core name as the parameter (e.g. "a15") or whatever
is listed in core_names for that device.
"cluster" APIs take a numeric cluster ID (eg. 0) as the parameter. These
get mapped using core_clusters for that device.
"cpu" APIs take a cpufreq cpu ID as a parameter. These could be
integers, e.g. 0, or full string id, e.g. "cpu0".
2015-05-11 12:12:40 +01:00
Sergei Trofimov
b002505ac2 Updated Parameter to automatically convert int and boot kinds to integer and boolean respectively.
integer and boolen are defined in wlauto.utils.types; they perform more
intuitive conversions from other types, particularly strings, so are
more suitable than int and bool for parameters. If, for whatever reason,
native types are in fact desired for a Parameter, this behavior can be
supressed by specifying convert_types=False when defining the parameter.
2015-05-11 12:12:40 +01:00
Sergei Trofimov
09aa9e6792 Adding some conversion functions to misc utils.
- list_to_range and range_to_list convert between lists of integers
  and corresponding range strings, e.g. between [0,1,2,4] and '0-2,4'
- list_to_mask and mask_to_list convert between lists of integers and
  corresponding integer masks, e.g. between [0,1,2,4] and 0x17

Conflicts:
	wlauto/utils/misc.py
2015-05-11 12:12:40 +01:00
Sergei Trofimov
108928c6a5 Added copy() method to WorkloadRunSpec. 2015-05-11 12:12:40 +01:00
Sergei Trofimov
3112eb0a9b Adding new types and updating device parameters to use them.
- added caseless_string type. This behaves exactly like a string, except
  this ignores case in comparisons. It does, however, preserve case. E.g.

	>>> s = caseless_string('Test')
	>>> s == 'test'
	True
	>>> print s
	Test

- added list_of type generating function. This allows to dynamically
  generate type-safe list types based on an existing type. E.g.

	>>> list_of_bool = list_of(bool)
	>>> list_of_bool(['foo', 0, 1, '', True])
	[True, False, True, False, True]

- Update core_names Device Parameter to be of type caseless_string
2015-05-11 12:12:40 +01:00
Sergei Trofimov
070b2230c9 updated ExecutionContext to keep a reference to the runner.
This will enable Extenstions to do things like modify the job queue.
2015-05-11 12:12:40 +01:00
Sergei Trofimov
958a8a09da daq instrument updated to report energy. 2015-05-11 12:12:40 +01:00
Sergei Trofimov
62593987f4 sysbench workload updates.
- added the ability to run based on time, rather than number of
  requests.
- added a parameter to taskset to specific core(s).

Conflicts:
	wlauto/workloads/sysbench/__init__.py
2015-05-11 12:12:40 +01:00
Sergei Trofimov
e422ccc509 show command: remove duplicat output. 2015-05-07 12:18:59 +01:00
Sergei Trofimov
6ccca6d4c0 show command: handle bad PAGER
If show command finds a PAGER defined in the user's environment but is
unable to use it, fall back to dumping output directly to STDOUT.
2015-05-07 12:02:03 +01:00
Sergei Trofimov
57972a56af geekbench: upping run time out.
Run timeout was been hit on very slow systems.
2015-05-07 11:55:37 +01:00
Sergei Trofimov
67ad4a63e4 antutu: multi-times playback fix [part 2]
A "please rate me" dialog occasionally pops but when returning to the
initial screen (when re-running the test). The check to dismiss it
wasn't being done at the right time, so it was still preventing
mutli-times execution. This commit resolves that issue.
2015-05-07 10:48:26 +01:00
Sergei Trofimov
7a86a1b17f hwmon: move sensor discovery into initialize()
It only needs to be done once per run.
2015-05-07 09:39:33 +01:00
Vasilis Flouris
f504fc8791 A fix for spec2000 to align with device API changes 2015-05-06 17:02:48 +01:00
Sergei Trofimov
09d0736d3b antutu: fixing multi-times playback for v5
"times" parameter didn't work properly for version 5 because an extra
back button press was required due to UI changes from previous versions.
This commit adds the button press.
2015-05-06 12:56:58 +01:00
Sergei Trofimov
2f1c7300d4 doc: documenting remote_assets_path
Adding documentation explaining how to use remote_assets_path setting.
2015-05-05 14:52:39 +01:00
Sergei Trofimov
6824f045fd telemetry: adding support for Android devices
Also, adding missing copyright header.
2015-05-05 12:24:53 +01:00
Sergei Trofimov
e57c5fccb3 sysfile_extractor: ignore exit code when removing directory at the end of the run.
On some systems the temporary directory may still be "busy" after WA is
don't with it. Since it's just an empty dir and it will be reused on the
subsequent runs; do check if rm -rf succeeded.
2015-05-05 09:32:40 +01:00
Sergei Trofimov
a6ef53291b ssh: making execute() thread safe. 2015-05-05 09:09:57 +01:00
Sergei Trofimov
1993007d49 telemetry: relaxing the initial validation check
It seems valid install may return values other than 0xff00. Relaxing the
check to consider anything above 0xff to be valid.
2015-05-05 08:17:43 +01:00
Sergei Trofimov
8b606dd5f9 config: fixing an issue introduced by previous config fix...
When the merging logic was updated to preserve duplicates within the
same list, it inadvertently broke the logic that removed items marked
for removal with a '~'. This commit rectifies that.

Note to self: merging functions are doing *way* to much; they should be
refactored into several individual function and config should be
resolved in distinct stages.
2015-04-30 13:34:21 +01:00
Sergei Trofimov
799558d201 Fix: lists with duplicate entries in parameter values
If list parameter values contained duplicates, those got removed when
merging parameter values from different sources. This commit fixes that
behavor, so that duplcates that appear within the *same* list are
preserved.
2015-04-30 08:46:24 +01:00
Sergei Trofimov
bb5d5cba8e daq: make EnumEntry picklable to support multiprocessing invocation 2015-04-29 12:32:15 +01:00
Vasilis Flouris
82fed172d5 fix for leaked file descriptors in daq 2015-04-29 11:41:19 +01:00
Vasilis Flouris
cd6babeab1 adding device_entry parameter to energy probe instrument 2015-04-29 10:42:44 +01:00
Sergei Trofimov
e87e4c582c Fix: properly handle carriage return stripping in ssh. 2015-04-28 12:46:21 +01:00
Sergei Trofimov
97efd11b86 Fix: properly handle core_names and core_clusters in the agenda
Keep duplicates in lists when merging device_config dict from agenda
with the rest of the config; This will ensure that core_name sand
core_clusters aren't reduced to just unique elements.
2015-04-28 12:44:08 +01:00
Sergei Trofimov
bb6421b339 Fixing file_exists on linux devices. 2015-04-28 10:29:47 +01:00
Sergei Trofimov
50c8c4da34 pep8: minor fixes in hackbench and ebizzy 2015-04-28 08:30:43 +01:00
setrofim
dcea921907 Merge pull request #17 from lisatn/ebizzy-workload
Add ebizzy workload
2015-04-28 08:27:08 +01:00
setrofim
0beb3fc3a2 Merge pull request #18 from lisatn/hackbench_workload
Hackbench workload
2015-04-28 08:26:58 +01:00
Lisa Nguyen
1633d91331 hackbench: Clean regex code and add run_timeout parameter
Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-04-27 14:42:25 -07:00
Lisa Nguyen
d126d56e98 Add ebizzy workload
Add ebizzy to allow users to run a workload resembling common
web server application workloads.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-04-27 12:53:17 -07:00
Sergei Trofimov
06e5698d89 Added link to pre-built documentation. 2015-04-27 18:26:55 +01:00
Sergei Trofimov
5ceb093f3c Improving agenda validation
- raise an error if an agenda contains duplicate keys (by default PyYAML
  will silently ignore this)
- raise an error if config section in an agenda is not dict-like
  (before, this was allowed to propagate and relsulted an a traceback
  further down the line).
2015-04-27 16:36:30 +01:00
Sergei Trofimov
698240b6e0 telemetry: copy generated trace files into WA output
If trace files have been generated during a telemetry run (e.g.
--profiler=trace was enabled), copy them into wa_output and extract
them.
2015-04-27 15:50:59 +01:00
Sergei Trofimov
101d6a37ce Fix: correctly handle non-identifier alias names
Update ExtensionLoader to index aliases by their identifier'd name.
2015-04-27 11:57:34 +01:00
Lisa Nguyen
4cff2a52c0 Add hackbench workload
Add hackbench to run tests on the Linux scheduler.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-04-26 13:12:08 -07:00
Sergei Trofimov
f906cbd851 Sent INITIAL_BOOT signal in hard reset path during intial boot 2015-04-24 17:51:55 +01:00
Sergei Trofimov
0c0be69e42 pylint: temporarily diable checkers broken in latest version
A couple of checkers appear to be broken in latest version (report false
positives). Disabling them until fixed.
2015-04-24 17:45:27 +01:00
Sergei Trofimov
97a397d5c8 ipython utils: handle ancient versions of IPython
Very old versions of IPython do not have IPython.version_info attribute
that the ultls module relied on. This commit changes it to use the more
standard __version__ attriute that is present in all versions.
2015-04-24 10:56:23 +01:00
Sergei Trofimov
54e89a2118 Fix to initial ~/.workload_automation deployment when sudoing
Only attempt to chown ~/.workload_automation to SUDO_USER if the
effective user is root.
2015-04-24 10:05:13 +01:00
Sergei Trofimov
704324ca77 Adding missing descriptions for modules. 2015-04-22 17:02:27 +01:00
Sergei Trofimov
aef7f52f96 telemetry: ignore errors in dividuation subtests.
check_output will ignore error code 1 returned by telemetry execution,
as this happens when individiual sub-tests and partial results may, and
should, still be extracted.
2015-04-21 15:12:48 +01:00
Sergei Trofimov
5035fe6f44 Adding ignore parameter to check_output
Adding a parater to wlauto.utils.misc.check_output to specify that it
should ignore certain error codes when they are returned by the
subprocess and not raise them as errors.
2015-04-21 15:01:15 +01:00
Sergei Trofimov
399c9f82c3 telemetry: handle scalar values correctly.
The result regex in telemetry workload has been updated to capture lines
reproting single value results.
2015-04-21 13:19:21 +01:00
Sergei Trofimov
ff0d08cc8e All using idetifier version of non-identifier named instruments in configuration.
E.g. refering to "trace-cmd" as "trace_cmd" in the instrumentation list.
2015-04-20 09:18:49 +01:00
setrofim
7655007f8a Merge pull request #13 from JaviMerino/ipynb_exporter_with_ipython_3
Make the ipynb_exporter result processor work with ipython version 3
2015-04-20 09:11:07 +01:00
setrofim
1fc811e437 Merge pull request #12 from JaviMerino/fix_2276ae0
Fix trace-cmd after 2276ae0c5b
2015-04-20 09:07:45 +01:00
Javi Merino
8d3f9362fb Fix trace-cmd after 2276ae0c5b
Commit 2276ae0c5b ("Fixing config processing for extensions with
non-identifier names.") broke customizing the trace-cmd instrumentation
from the agenda.  With an agenda like:

config:
  instrumentation: [trace-cmd, delay]
  trace_events: ['thermal*']
  trace_buffer_size: 28000

trace_events and trace_buffer_size get added to the RunConfiguration's
_raw_config under the trace-cmd name, but then when it's looked up in
_finalize_config_list(), the dictionary is actually looked up using
identifier(extname), i.e. 'trace_cmd'.  Fix this by adding the user's
configuration using identifier(name) as well.
2015-04-17 20:10:25 +01:00
Javi Merino
e30386ce4a Add ipython version 3 support for the generic ipython support 2015-04-17 19:00:55 +01:00
Javi Merino
d12f5c65e1 Factor out the parsing of a valid cell run in the generic ipython implementation
run_cell() becomes more complicated when we add ipython version 3
support which upsets pylint because there are "too many
branches (15/12)".  Factor out part of the function to make pylint
happy.
2015-04-17 18:56:57 +01:00
Javi Merino
2b04cb38d9 Don't break prematurely when running a cell on an ipython kernel
The kernel may go idle before it processes the next input, which break
the while=True loop in run_cell() early.  Wait for an acknowledgement
of the input we've sent to the kernel before considering an idle
message to mean that the cell has been parsed.
2015-04-17 18:56:57 +01:00
setrofim
0faa5ae455 Merge pull request #11 from JaviMerino/ipynb_exp_improvs
Generic Ipynb_exporter improvements to ease ipython 3 support
2015-04-17 18:23:04 +01:00
Javi Merino
3bf04735c1 Factor out ipython nbconvert in ipynb_exporter results processor
ipython nbconvert CLI changes between ipython 2 and 3, so keep the
string separate so that we can update when we add ipython version 3 support.
2015-04-17 17:52:07 +01:00
Javi Merino
f54bb0981f Don't use shell_channel in ipynb_exporter result processor
It's not needed for IPython 2 and it breaks in IPython 3
2015-04-17 17:52:07 +01:00
Javi Merino
f41be396fa Use notebook format 3 for ipynb_exporter
The file assumes format 3 throughout the code, so explicitly import that
format instead of the generic "current" format.
2015-04-17 17:52:07 +01:00
Javi Merino
d31a5c3c48 Factor out the ipython implementation in ipynb_exporter
The internal ABI for ipython has changed between ipython version 2 and
3.  In its current state, the result processor only works with IPython
version 2, so fail if the user wants to use the result processor with
the wrong version.

Abstract the ipython interface to a file so that we can make it support
versions 2 and 3 at the same time.
2015-04-17 17:52:07 +01:00
Sergei Trofimov
314fecfcd4 Fixing get_meansd for numbers < 1 2015-04-17 17:27:47 +01:00
Sergei Trofimov
497b5febc3 Fixing buffer_size_file in trace-cmd for non-Android devices
The default value for buffer_size_file contained a path under "/d/",
which is an Android-specific alias for "/sys/kernel/debug". This commit
updates the default value to use the system-agnostic path.
2015-04-17 16:06:12 +01:00
Sergei Trofimov
2276ae0c5b Fixing config processing for extensions with non-identifier names.
Internally, WA expects extension names to be valid Python identifiers.
When this is not the case, conversion takes place when loading
configuration for the extension (e.g. "trace-cmd" gets converted to
"trace_cmd").

The conversion is intended to be transparent to the user, so
configuration stores values as they are provided by the user, however it
needs to perform the conversion internally, e.g. when querying
ExtensionLoader. This conversion was missing when performing a lookup of
one of the internal structures, which was causing earlier-collected
settings to not be propagated into the final config.
2015-04-17 15:56:28 +01:00
Sergei Trofimov
53f2eafd16 Fixing key-based authentication for SSH. 2015-04-17 11:59:46 +01:00
setrofim
a26a50941b Merge pull request #10 from JaviMerino/notify2
Use notify2 as it's available in pypi
2015-04-16 13:13:53 +01:00
Sergei Trofimov
075712d940 Fixing format string in ipynb_exporter 2015-04-16 13:06:00 +01:00
Sergei Trofimov
c0bb30e12d Fixing overall score generation in telemetry
Updating overall score generation function to handle zero values.
2015-04-16 13:00:59 +01:00
Javi Merino
99c129cb03 Add notify2 to the extra dependencies 2015-04-16 11:43:49 +01:00
Javi Merino
dd199a6893 Move the notify results processor to notify2
pynotify is not in pypi.
2015-04-16 11:43:49 +01:00
setrofim
d627c778e5 Merge pull request #9 from JaviMerino/add_notify
Add a notify result processor
2015-04-16 08:43:47 +01:00
Sergei Trofimov
ee626fd36e Adding telemetry workload.
This workload executes tests from Google's Telemetry browser test
framework. Currently, only ChromeOS devices are supported.
2015-04-15 18:40:30 +01:00
Sergei Trofimov
315fecdf71 Updating XE503C12 device adapter.
- Setting platfrom to "chromeos"
- Changing the default binaries_directory (/usr/bin is not writable).
2015-04-15 18:40:30 +01:00
Sergei Trofimov
b198e131ee SyfsExtractor: added use_tmpfs parameter
Updating SysfsExtractor with a parameter to explicitly enable/disable
tempfs caching. Previously, this was determined entirely by whether the
device is rooted.
2015-04-15 18:40:30 +01:00
Sergei Trofimov
3e6b927cde Updating screen on instrument to support periodic polling. 2015-04-15 17:54:07 +01:00
Sergei Trofimov
fcc970db3f Adding screenon instrument 2015-04-15 16:34:24 +01:00
Javi Merino
a96088de9c Add a notify result processor
This result processor displays a desktop notification when the run
finishes.  It's useful when you are running a long agenda in WA and want
to be notified when the results are available.
2015-04-15 15:14:23 +01:00
setrofim
4195ca591c Merge pull request #8 from JaviMerino/fix_pep8
Fix pep8 errors in ipynb_exporter
2015-04-15 14:50:26 +01:00
Javi Merino
86f543cb72 Fix pep8 errors in ipynb_exporter
I ran first pep8 and then pylint, so I missed the pep8 errors introduced
by me shutting up pylint 😇
2015-04-15 14:34:23 +01:00
setrofim
9aae0e7886 Merge pull request #7 from JaviMerino/add_ipynb_export
Add an ipython notebook exporter results_processor
2015-04-15 14:23:52 +01:00
Javi Merino
8e09795c95 Add an ipython notebook exporter results_processor 2015-04-15 14:21:54 +01:00
Sergei Trofimov
5bf9f05c4b Updating result object to track their output directories.
Also, context.result will no result in context.run_result when
not executing a job.
2015-04-14 14:38:59 +01:00
Sergei Trofimov
8e340e456d Added open_file to misc utils.
A function to open a file using an associated launcher in an OS-agnostic
way.
2015-04-14 14:18:10 +01:00
Sergei Trofimov
61b834e52c Removing unnecessary comment form sqlite result processor documentation. 2015-04-14 12:02:24 +01:00
setrofim
11b8001308 Merge pull request #6 from JaviMerino/fix_param_documentation
Fix Param documentation
2015-04-14 06:03:31 +01:00
Javi Merino
1807f3e3d7 Fix Param documentation
The param documentation states that for a boolean, "kind" should be
"as_bool" from wlauto.utils.misc, but there is no "as_bool".  Currently,
workload automation automatically converts native python types like bool
and int to workload automation specific ones.  Remove this bit from the
documentation as it's not true any more.

Change-Id: I0100708530bcf67556eda386c39bc444a3e0f2b2
2015-04-13 22:42:25 +01:00
Sergei Trofimov
e03686f961 Improve error repoting when loading extensions
The error message will now contain the offending extension (either
package name or full path to extension file) if a Python error occurs
when ExtensionLoader attempts to load it.
2015-04-13 08:25:56 +01:00
Sergei Trofimov
c5d3c2bd62 Fixing reboot on Linux devices [part 2]
- connect() to device before issuing the initial reboot, as soft reset
  requires a device connection.
- boot() has been implemented to wait properly for the device to reboot
  after reset.
- port now defaults to 22 rather than being left unset, as need
  something to connect to when polling for device after reboot.
- Only use -P option for scp when port is *not* 22; as that option
  appears to cause intermittent issues with default scp on Ubuntu 12.04
2015-04-10 17:04:22 +01:00
Sergei Trofimov
d838caadd5 Adding XE503C12 device.
Adding a device interface for Samsung XE503C12 Chromebooks.
2015-04-10 09:37:40 +01:00
Sergei Trofimov
086f03730b ssh: pep8 fix 2015-04-10 09:36:55 +01:00
Sergei Trofimov
fea32de3d3 Parameterizing password prompt for sudo in Ssh interface.
On some devices, sudo presents a different prompt when asking for a
password. All the prompt to be specified in device configruation to
handle such cases.
2015-04-10 09:03:48 +01:00
Lisa Nguyen
b41d316fd6 doc/source: Add details about running WA on Linux
Mention in the documentation that Android SDK is optional for
users who plan to run WA on Linux devices only, and how they
would only be able to start running a limited number of workloads.

Also included a few trivial fixes such as spelling errors and
moving sentences around to improve flow.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-04-10 08:22:01 +01:00
Lisa Nguyen
e37bf90da7 sysbench: Fix spelling, descriptions, and error message
Make the WorkloadError() message clearer if the sysbench
binary cannot be found on the device and host.

Also make trivial fixes to improve descriptions and fix
spelling errors.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-04-10 08:22:01 +01:00
Sergei Trofimov
544f5f0b92 Fixing terminalsize import error.
terminalsize was loaded from a location added to sys.path during
bootstrap. This appeared to be causing import issues. There is no longer
a good reason for terminalsize to be loaded that way, so just moved it
under wlauto.utils so that it can be loaded normally.
2015-04-09 08:32:02 +01:00
setrofim
73f889b45b Merge pull request #3 from freedomtan/master
typo: s/SKD/SDK/
2015-04-07 09:47:51 +01:00
Sergei Trofimov
7b5f5e2ed0 Fixing Linux device reset.
_is_ready was being set to False before invoking execute("reboot")
causing a device not ready error.
2015-04-07 09:09:13 +01:00
Koan-Sin Tan
cd4790dd4b s/SKD/SDK/ 2015-04-07 09:23:24 +08:00
Lisa Nguyen
0421b58c55 doc/source: Add uninstall and upgrade sections
Add the uninstall and upgrade commands for users to remove or
upgrade Workload Automation for future reference.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-04-01 17:19:02 +01:00
Lisa Nguyen
a7895a17bf common/linux/device.py: Create binaries_directory path if it doesn't exist
Some Linux devices may run on minimal root file systems
(e.g. buildroot) where /usr/local/bin path doesn't exist. Create
the binaries_directory if it doesn't exist instead of letting WA
quit and return errors such as:

INFO     Runner: Skipping the rest of the iterations for this spec.
ERROR    Runner: Error while running memcpy
ERROR    Runner: CalledProcessError("Command 'sshpass
                  -p '<password>' /usr/bin/scp -r
                  /usr/local/lib/python2.7/dist-packages/
                  wlauto-2.3.0-py2.7.egg/wlauto/workloads/memcpy
                  /memcpy root@192.168.x.x:/usr/local/bin/memcpy'
                  returned non-zero exit status 1")
ERROR    Runner: Got:
ERROR    Runner:
ERROR    Runner: scp: /usr/local/bin/memcpy:
                  No such file or directory

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-04-01 08:05:11 +01:00
Sergei Trofimov
925c354551 Fix hotplugging all cores on a cluster.
When attempting to set number of cores on a cluster to 0, make
sure at least one core is enabled on the other cluster beforehand.
2015-03-27 12:54:26 +00:00
Lisa Nguyen
58ab762131 doc/source: Update quickstart
Update the quickstart guide to include steps for setting
up WA to run on Linux devices.

Signed-off-by: Lisa Nguyen <lisa.nguyen@linaro.org>
2015-03-26 17:51:51 +00:00
Sergei Trofimov
adb5ea9a30 Fixing UEFI entry creation for Juno
- UEFI config can be specified as a device_config parameter
- The same config is used to create a missing UEFI entry, and
  to re-create the entry when flashing. UEFI config now wholy
  resides within the device and is not specified for vexpress
  flasher.
2015-03-26 10:42:55 +00:00
Vasilis Flouris
5c48b75375 Adding dumpsys window output to __meta 2015-03-25 17:56:58 +00:00
Sergei Trofimov
678efa72e1 Fixing sysbench workload
- Updated sysbench binary to a statically linked verison
- Added missing LICENSE file for the sysbench binary
- Removed Android browser launch and shutdown from workload (now runs on both
  Linux and Android)
- Updated update_result to work with the new binary
- Added missing descriptions for parameters
- Added file_test_mode parameter -- this is a mandatory argumet if test is
  fileio
- Added cmd_params parameter to pass options directily to sysbench invocation
2015-03-25 10:31:02 +00:00
Vasilis Flouris
01d4126cc8 Fix for 64 bit revent [part 2]
The struct used to read events is being padded when built for 64
bit platforms. The padding has been made explicit in the struct, and
matching padding was added when writing the events during recording.
2015-03-23 18:59:54 +00:00
Kevin Hilman
bf12d18457 common/linux/device.py: don't require sudo if already root user
On generic_linux devices, one might ssh as the root user, in which
case there is no need to use sudo.

In addition, some root filesystems may not have sudo (e.g. minimal
buildroot/busybox).

This patch attempts to detect the root user using 'id -u' and, if it
detects the root user, avoids the use of sudo for running commands as
well.

Cc: Lisa Nguyen <lisa.nguyen@linaro.org>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
(setrofim: modified to only test once)
2015-03-23 10:18:32 +00:00
Kevin Hilman
d4ee737e50 doc: device_setup: fix generic_linux device_config example
A copy/paste of the documentation example results in a python
backtrace because the dict keys cannot be quoted:

    wlauto.exceptions.ConfigError: Sytax error in config: keyword can't be an expression (config.py, line XYZ)

Fix by removing the quotes from the keys in the example.

Signed-off-by: Kevin Hilman <khilman@linaro.org>
2015-03-23 09:24:40 +00:00
Sergei Trofimov
ee7f22e902 Fixing 64bit revent
Then number of input event files was being written as a size_t but read
as an int by revent. These types have different sizes with 64bit GCC,
causing revent not being able to replay recorded files. This comint
updates revent to use size_t when both reading and writing.
2015-03-20 09:25:57 +00:00
Sergei Trofimov
6a77ac656f Updated fps instrumentat to generate detailed FPS traces as well as report average FPS. 2015-03-19 17:15:36 +00:00
Sergei Trofimov
2f7acfd87a Added "post install" section to installation docs.
This section lists workloads that require additional external
dependencies.
2015-03-18 10:51:39 +00:00
Sergei Trofimov
cce287a1e7 Fixed dev_scripts/get_apk_versions.
It was relying on a distmanagement module that no longer exists. The
required functionality from that module is now part of the script.
2015-03-18 10:50:02 +00:00
Sergei Trofimov
aa74e1e8f5 Minor fix to rst table generation.
Updated format_simple_table to take headers into account when
calculating column widths. Also updated docs where it currently used.
2015-03-18 10:47:07 +00:00
Sergei Trofimov
3e0c8aa83b glb_corporate: clear logcat in Monitor's __init__ to prevent getting results from previous run. 2015-03-16 09:36:32 +00:00
setrofim
6d9b49d4bb Merge pull request #1 from rockyzhang/patch-1
Update __init__.py
2015-03-16 09:24:48 +00:00
Rocky Zhang
aca08cf74d Update __init__.py
The boot monitor seems to have some buffer overrun issue while loading the latest Linaro android images.
The behavior is after loading the initrd, the kernel loading will fail, very likely to due command line buffer overrun.
the new initrd in the Linaro image is 3 times larger than the previous version, which could cause the issue.
putting a dummy enter between loading initrd and the kernel could resolve the issue.
2015-03-16 11:26:58 +08:00
Sergei Trofimov
529a1d3b95 Fixing initialization of ~/.workload_automation. 2015-03-13 10:25:31 +00:00
Sergei Trofimov
db7a525bc7 Fixing broken label in documentation. 2015-03-11 16:05:17 +00:00
774 changed files with 54956 additions and 2953 deletions

6
.gitignore vendored
View File

@@ -14,9 +14,9 @@ wa_output/
doc/source/api/
doc/source/extensions/
MANIFEST
wlauto/external/uiautomator/bin/
wlauto/external/uiautomator/*.properties
wlauto/external/uiautomator/build.xml
wlauto/external/uiauto/bin/
wlauto/external/uiauto/*.properties
wlauto/external/uiauto/build.xml
*.orig
local.properties
wlauto/external/revent/libs/

View File

@@ -46,6 +46,8 @@ documentation.
Documentation
=============
You can view pre-built HTML documentation `here <http://pythonhosted.org/wlauto/>`_.
Documentation in reStructuredText format may be found under ``doc/source``. To
compile it into cross-linked HTML, make sure you have `Sphinx
<http://sphinx-doc.org/install.html>`_ installed, and then ::

View File

@@ -6,6 +6,11 @@ distributed as part of WA releases.
Scripts
-------
:check_apk_versions: Compares WA workload versions with the versions listed in APK
if there are any incistency it will highlight these. This
requires all APK files to be present for workloads with
versions.
:clean_install: Performs a clean install of WA from source. This will remove any
existing WA install (regardless of whether it was made from
source or through a tarball with pip).

View File

@@ -0,0 +1,66 @@
#!/usr/bin/env python
import os
from distutils.version import StrictVersion
from wlauto.core.extension_loader import ExtensionLoader
from wlauto.common.android.workload import ApkWorkload
from wlauto.utils.android import ApkInfo
el = ExtensionLoader()
class fake_config(object):
def __init__(self, ext_loader):
self.ext_loader = ext_loader
self.get_extension = ext_loader.get_extension
class fake_device(object):
platform = "android"
config = fake_config(el)
device = fake_device()
if "WA_USER_DIRECTORY" in os.environ:
base_path = os.environ["WA_USER_DIRECTORY"]
else:
base_path = "~/.workload_automation/dependencies/"
apk_workloads = [e for e in el.list_workloads()
if issubclass(el.get_extension_class(e.name), ApkWorkload)]
for wl in apk_workloads:
# Get versions from workloads
workload_versions = []
for p in wl.parameters:
if p.name == "version" and p.allowed_values:
workload_versions = p.allowed_values
break
else:
continue
dep_path = os.path.join(os.path.expanduser(base_path), wl.name)
apks = [apk for apk in os.listdir(dep_path) if apk.endswith(".apk")]
# Get versions from APK files
apk_versions = []
for apk in apks:
# skip antutu 3d benchmark apk
if apk == "com.antutu.benchmark.full-1.apk":
continue
apk_versions.append(ApkInfo(os.path.join(dep_path, apk)).version_name)
# Output workload info
print "Workload: {}".format(wl.name)
print "Workload Versions: {}".format(sorted(workload_versions, key=StrictVersion))
print "APK versions: {}".format(sorted(apk_versions, key=StrictVersion))
# Check for bad/missing versions
error = False
for v in apk_versions:
if v not in workload_versions:
msg = "APK version '{}' not present in workload list of versions"
print msg.format(v)
error = True
if not error:
print "OK"

View File

@@ -1,13 +1,82 @@
#!/usr/bin/env python
import os
import sys
import re
import logging
import subprocess
import argparse
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from wlauto.exceptions import WAError
from wlauto.utils.misc import write_table
from distmanagement.apk import get_aapt_path, get_apk_versions
from wlauto.exceptions import WAError, ToolError
from wlauto.utils.doc import format_simple_table
def get_aapt_path():
"""Return the full path to aapt tool."""
sdk_path = os.getenv('ANDROID_HOME')
if not sdk_path:
raise ToolError('Please make sure you have Android SDK installed and have ANDROID_HOME set.')
build_tools_directory = os.path.join(sdk_path, 'build-tools')
versions = os.listdir(build_tools_directory)
for version in reversed(sorted(versions)):
aapt_path = os.path.join(build_tools_directory, version, 'aapt')
if os.path.isfile(aapt_path):
logging.debug('Found aapt for version {}'.format(version))
return aapt_path
else:
raise ToolError('aapt not found. Please make sure at least one Android platform is installed.')
def get_apks(path):
"""Return a list of paths to all APK files found under the specified directory."""
apks = []
for root, dirs, files in os.walk(path):
for file in files:
_, ext = os.path.splitext(file)
if ext.lower() == '.apk':
apks.append(os.path.join(root, file))
return apks
class ApkVersionInfo(object):
def __init__(self, workload=None, package=None, label=None, version_name=None, version_code=None):
self.workload = workload
self.package = package
self.label = label
self.version_name = version_name
self.version_code = version_code
def to_tuple(self):
return (self.workload, self.package, self.label, self.version_name, self.version_code)
version_regex = re.compile(r"name='(?P<name>[^']+)' versionCode='(?P<vcode>[^']+)' versionName='(?P<vname>[^']+)'")
def extract_version_info(apk_path, aapt):
command = [aapt, 'dump', 'badging', apk_path]
output = subprocess.check_output(command)
version_info = ApkVersionInfo(workload=apk_path.split(os.sep)[-2])
for line in output.split('\n'):
if line.startswith('application-label:'):
version_info.label = line.split(':')[1].strip().replace('\'', '')
elif line.startswith('package:'):
match = version_regex.search(line)
if match:
version_info.package = match.group('name')
version_info.version_code = match.group('vcode')
version_info.version_name = match.group('vname')
else:
pass # not interested
return version_info
def get_apk_versions(path, aapt):
apks = get_apks(path)
versions = [extract_version_info(apk, aapt) for apk in apks]
return versions
if __name__ == '__main__':
@@ -18,8 +87,10 @@ if __name__ == '__main__':
args = parser.parse_args()
versions = get_apk_versions(args.path, aapt)
write_table([v.to_tuple() for v in versions], sys.stdout,
align='<<<>>', headers=['path', 'package', 'name', 'version code', 'version name'])
table = format_simple_table([v.to_tuple() for v in versions],
align='<<<>>',
headers=['workload', 'package', 'name', 'version code', 'version name'])
print table
except WAError, e:
logging.error(e)
sys.exit(1)

View File

@@ -1,8 +1,13 @@
#!/bin/bash
DEFAULT_DIRS=(
wlauto
wlauto/external/daq_server/src/daqpower
)
EXCLUDE=wlauto/external/,wlauto/tests
EXCLUDE_COMMA=wlauto/core/bootstrap.py,wlauto/workloads/geekbench/__init__.py
IGNORE=E501,E265,E266,W391
IGNORE=E501,E265,E266,W391,E401,E402,E731
if ! hash pep8 2>/dev/null; then
echo "pep8 not found in PATH"
@@ -13,7 +18,9 @@ fi
if [[ "$1" == "" ]]; then
THIS_DIR="`dirname \"$0\"`"
pushd $THIS_DIR/.. > /dev/null
pep8 --exclude=$EXCLUDE,$EXCLUDE_COMMA --ignore=$IGNORE wlauto
for dir in "${DEFAULT_DIRS[@]}"; do
pep8 --exclude=$EXCLUDE,$EXCLUDE_COMMA --ignore=$IGNORE $dir
done
pep8 --exclude=$EXCLUDE --ignore=$IGNORE,E241 $(echo "$EXCLUDE_COMMA" | sed 's/,/ /g')
popd > /dev/null
else

View File

@@ -1,5 +1,10 @@
#!/bin/bash
DEFAULT_DIRS=(
wlauto
wlauto/external/daq_server/src/daqpower
)
target=$1
compare_versions() {
@@ -30,17 +35,19 @@ compare_versions() {
}
pylint_version=$(python -c 'from pylint.__pkginfo__ import version; print version')
compare_versions $pylint_version "1.3.0"
compare_versions $pylint_version "1.5.1"
result=$?
if [ "$result" == "2" ]; then
echo "ERROR: pylint version must be at least 1.3.0; found $pylint_version"
echo "ERROR: pylint version must be at least 1.5.1; found $pylint_version"
exit 1
fi
THIS_DIR="`dirname \"$0\"`"
if [[ "$target" == "" ]]; then
pushd $THIS_DIR/.. > /dev/null
pylint --rcfile extras/pylintrc wlauto
for dir in "${DEFAULT_DIRS[@]}"; do
pylint --rcfile extras/pylintrc $dir
done
popd > /dev/null
else
pylint --rcfile $THIS_DIR/../extras/pylintrc $target

View File

@@ -6,10 +6,10 @@ Modules
Modules are essentially plug-ins for Extensions. They provide a way of defining
common and reusable functionality. An Extension can load zero or more modules
during it's creation. Loaded modules will then add their capabilities (see
during its creation. Loaded modules will then add their capabilities (see
Capabilities_) to those of the Extension. When calling code tries to access an
attribute of an Extension the Extension doesn't have, it will try to find the
attribute among it's loaded modules and will return that instead.
attribute among its loaded modules and will return that instead.
.. note:: Modules are themselves extensions, and can therefore load their own
modules. *Do not* abuse this.

View File

@@ -0,0 +1,57 @@
.. _apk_workload_settings:
APK Workloads
=============
APK resolution
--------------
WA has various resource getters that can be configured to locate APK files but for most people APK files
should be kept in the ``$WA_HOME/dependencies/SOME_WORKLOAD/`` directory. (by default
``~/.workload_automation/dependencies/SOME_WORKLOAD/``). The ``WA_HOME`` enviroment variable can be used
to chnage the location of this folder. The APK files need to be put into the corresponding directories
for the workload they belong to. The name of the file can be anything but as explained below may need
to contain certain peices of information.
All ApkWorkloads have parameters that affect the way in which APK files are resolved, ``exact_abi``,
``force_install`` and ``check_apk``. Their exact behaviours are outlined below.
.. confval:: exact_abi
If this setting is enabled WA's resource resolvers will look for the devices ABI with any native
code present in the apk. By default this setting is disabled since most apks will work across all
devices. You may wish to enable this feature when working with devices that support multiple ABI's (like
64-bit devices that can run 32-bit APK files) and are specifically trying to test one or the other.
.. confval:: force_install
If this setting is enabled WA will *always* use the APK file on the host, and re-install it on every
iteration. If there is no APK on the host that is a suitable version and/or ABI for the workload WA
will error when ``force_install`` is enabled.
.. confval:: check_apk
This parameter is used to specify a preference over host or target versions of the app. When set to
``True`` WA will prefer the host side version of the APK. It will check if the host has the APK and
if the host APK meets the version requirements of the workload. If does and the target already has
same version nothing will be done, other wise it will overwrite the targets app with the host version.
If the hosts is missing the APK or it does not meet version requirements WA will fall back to the app
on the target if it has the app and it is of a suitable version. When this parameter is set to
``false`` WA will prefer to use the version already on the target if it meets the workloads version
requirements. If it does not it will fall back to search the host for the correct version. In both modes
if neither the host nor target have a suitable version, WA will error and not run the workload.
Some workloads will also feature the follow parameters which will alter the way their APK files are resolved.
.. confval:: version
This parameter is used to specify which version of uiautomation for the workload is used. In some workloads
e.g. ``geekbench`` multiple versions with drastically different UI's are supported. When a workload uses a
version it is required for the APK file to contain the uiautomation version in the file name. In the case
of antutu the file names could be: ``geekbench_2.apk`` or ``geekbench_3.apk``.
.. confval:: variant_name
Some workloads use variants of APK files, this is usually the case with web browser APK files, these work
in exactly the same way as the version, the variant of the apk

View File

@@ -1,6 +1,846 @@
=================================
What's New in Workload Automation
=================================
-------------
Version 2.6.0
-------------
.. note:: Users who are currently using the GitHub master version of WA should
uninstall the existing version before upgrading to avoid potential issues.
Additions:
##########
Workloads
~~~~~~~~~
- ``AdobeReader``: A workload that carries out following typical productivity
tasks. These include opening a file, performing various gestures and
zooms on screen and searching for a predefined set of strings.
- ``octaned8``: A workload to run the binary (non-browser) version of the JS
benchmark Octane.
- ``GooglePlayBooks``: A workload to perform standard productivity tasks with
Google Play Books. This workload performs various tasks, such as searching
for a book title online, browsing through a book, adding and removing notes,
word searching, and querying information about the book.
- ``GooglePhotos``: A workload to perform standard productivity tasks with
Google Photos. Carries out various tasks, such as browsing images,
performing zooms, and post-processing the image.
- ``GoogleSlides``: Carries out various tasks, such as creating a new
presentation, adding text, images, and shapes, as well as basic editing and
playing a slideshow.
- ``Youtube``: The workload plays a video, determined by the ``video_source``
parameter. While the video is playing, some common actions such as video
seeking, pausing playback and navigating the comments section are performed.
- ``Skype``: Replacement for the ``skypevideo`` workload. Logs into Skype
and initiates a voice or video call with a contact.
Framework
~~~~~~~~~
- ``AndroidUxPerfWorkload``: Added a new workload class to encapsulate
functionality common to all uxperf workloads.
- ``UxPerfUiAutomation``: Added class which contains methods specific to
UX performance
testing.
- ``get-assets``: Added new script and command to retrieve external assets
for workloads
Results Processors
~~~~~~~~~~~~~~~~~~~
- ``uxperf``: Parses device logcat for `UX_PERF` markers to produce performance
metrics for workload actions using specified instrumentation.
Other
~~~~~
- ``State Detection``: Added feature to use visual state detection to
verify the state of a workload after setup and run.
Fixes/Improvements:
###################
Documentation
~~~~~~~~~~~~~~
- ``Revent``: Added file structure to the documentation.
- Clarified documentation regarding binary dependencies.
- Updated documentation with ``create`` and ``get-assets`` commands.
Instruments
~~~~~~~~~~~~
- ``sysfs_extractor``: Fixed error when `tar.gz` file already existed on device,
now overwrites.
- ``cpufreq``: Fixed error when `tar.gz` file already existed on device, now
overwrites.
- ``file-poller``:
- Improved csv output.
- Added error checking and reporting.
- Changed ``files`` to be a mandatory parameter.
- ``fps``:
- Added a new parameter to fps instrument to specify the time period between
calls to ``dumpsys SurfaceFlinger --latency`` when collecting frame data.
- Added gfxinfo methods to obtain fps stats. Auto detects and uses appropriate
method via android version of device.
- Fixed issue with regex.
- Now handles empty frames correctly.
- ``energy_model``: Ensures that the ``ui`` runtime parameter is only set for
ChromeOS devices.
- ``ftrace``: Added support to handle traces collected by both WA and devlib.
- ``Perf``: Updated 32bit binary file for little endian devices.
Resource Getters
~~~~~~~~~~~~~~~~
- ``http_getter``: Now used to try and find executables files from a
provided ``remove_assets_url``.
Result Processors
~~~~~~~~~~~~~~~~~
- ``cpu_states``: Fixes using stand-alone script with timeline option.
Workloads
~~~~~~~~~
- ``antutu``: Fixed setting permissions of ``FINE_LOCATION`` on some devices.
- ``bbench`` Fixed handling of missing results.
- ``camerarecord``:
- Added frame stats collection through dumpsys gfxinfo.
- Added possibility to select slow_motion recording mode.
- ``Geekbench``:
- Fixed output file listing causing pull failure.
- Added support for Geekbench 4.
- ``recentfling``:
- Fixed issue when binaries were not uninstalled correctly.
- Scripts are now deployed via ``install()`` to ensure they are executable.
- Fixed handling of when a PID file is deleted before reaching processing
results stage.
- Added parameter to not start any apps before flinging.
- ``rt-app``: Added camera recorder simulation.
- ``sysbench``: Added arm64 binary.
- ``Vellamo``: Fixed capitalization in part of UIAutomation to prevent
potential issues.
- ``Spec2000``: Now uses WA deployed version of busybox.
- ``NetStat``: Updated to support new default logcat format in Android 6.
- ``Dex2oat``: Now uses root if available.
Framework
~~~~~~~~~
- ``adb_shell``:
- Fixed issue when using single quoted command with ``adb_shell``.
- Correctly forward stderror to the caller for newer version of adb.
- ``revent``
- Added ``-S`` argument to "record" command to automatically record a
screen capture after a recording is completed.
- Fixed issue with multiple iterations of a revent workload.
- Added ``-s`` option to executable to allow waiting on stdin.
- Removed timeout in command as ``-s`` is specified.
- Revent recordings can now be parsed and used within WA.
- Fixed issue when some recordings wouldn't be retrieved correctly.
- Timeout is now based on recording duration.
- Added `magic` and file version to revent files. Revent files should now
start with ``REVENT`` followed by the file format version.
- Added support for gamepad recording. This type of recording contains
only the events from a gamepad device (which is automatically
identified).
- A ``mode`` field has been added to the recording format to help
distinguish between the normal and gamepad recording types.
- Added ``-g`` option to ``record`` command to expose the gamepad recording
mode.
- The structure of revent code has undergone a major overhaul to improve
maintainability and robustness.
- More detailed ``info`` command output.
- Updated Makefile to support debug/production builds.
- ``Android API``: Upgraded Android API level from 17 to 18.
- ``uiautomator``: The window hierarchy is now dumped to a file when WA fails
on android devices.
- ``AndroidDevice``:
- Added support for downgrading when installing an APK.
- Added a ``broadcast_media_mounted`` method to force a re-index of the
mediaserver cache for a specified directory.
- Now correctly handles ``None`` output for ``get_pids_of()`` when there are no
running processes with the specified name.
- Renamed the capture method from ``capture_view_hierachy`` to
``capture_ui_hierarchy``.
- Changed the file extension of the capture file to ``.uix``
- Added ``-rf`` to delete_files to be consistent with ``LinuxDevice``.
- ``LinuxDevice``: Now ensures output from both stdout and etderr is propagated in
the event of a DeviceError.
- ``APKWorkload``:
- Now ensure APKs are replaced properly when reinstalling.
- Now checks APK version and ABI when installing.
- Fixed error on some devices when trying to grant permissions that were
already granted.
- Fixed some permissions not being granted.
- Now allows disabling the main activity launch in setup (required for some
apps).
- Added parameter to clear data on reset (default behaviour unchanged).
- Ignores exception for non-fatal permission grant failure.
- Fixed issue of multiple versions of the same workload failing to find their APK.
- Added method to ensure a valid apk version is used within a workload.
- Updated how APK resolution is performed to maximise likelihood of
a workload running.
- When ``check_apk`` is ``True`` will prefer host APK and if no suitable APK
is found, will use target APK if the correct version is present. When ``False``
will prefer target apk if it is a valid version otherwise will fallback to
host APK.
- ``RunConfiguration``: Fixed disabling of instruments in workload specs.
- ``Devices``:
- Added network connectivity check for devices.
- Subclasses can now set ``requires_network`` to ``True`` and network
connectivity check will be performed during ``setup()``.
- ``Workloads``:
- Added network check methods.
- Fixed versions to be backwards compatible.
- Updated workload versions to match APK files.
- Fixed issues with calling super.
- ``Assets``: Added script to retrieve external assets for workloads.
- ``Execution``: Added a ``clean_up`` global config option to delete WA files from
devices.
- ``Runner``: No longer takes a screenshot or dump of UI hierarchy for some errors when
unnecessary, e.g. host errors.
- ``core``: Constraints and allowed values are now checked when set instead of
when validating.
- ``FpsProcessor``:
- Added requirement on ``filtered_vsyncs_to_compose`` for ``total_vsync metric``.
- Removed misleading comment in class description.
- ``BaseUiAutomation``: Added new Marker API so workloads generate start and end
markers with a string name.
- ``AndroidUiAutoBenchmark``: Automatically checks for known package versions
that don't work well with AndroidUiAutoBenchmark workloads.
Other
~~~~~
- Updated setup.py url to be a valid URI.
- Fixed workload name in big.Little sample agenda.
Incompatible changes
####################
Framework
~~~~~~~~~
- ``check_abi``: Now renamed to ``exact_abi``, is used to ensure that if enabled,
only an apk containing no native code or code designed for the devices primary
abi is use.
- ``AndroidDevice``: Renamed ``supported_eabis`` property to ``supported_abis``
to be consistent with linux devices.
Workloads
~~~~~~~~~~
- ``skypevideo``: Workload removed and replaced with ``skype`` workload.
-------------
Version 2.5.0
-------------
Additions:
##########
Instruments
~~~~~~~~~~~
- ``servo_power``: Added support for chromebook servo boards.
- ``file_poller``: polls files and outputs a CSV of their values over time.
- ``systrace``: The Systrace tool helps analyze the performance of your
application by capturing and displaying execution times of your applications
processes and other Android system processes.
Workloads
~~~~~~~~~
- ``blogbench``: Blogbench is a portable filesystem benchmark that tries to
reproduce the load of a real-world busy file server.
- ``stress-ng``: Designed to exercise various physical subsystems of a computer
as well as the various operating system kernel interfaces.
- ``hwuitest``: Uses hwuitest from AOSP to test rendering latency on Android
devices.
- ``recentfling``: Tests UI jank on android devices.
- ``apklaunch``: installs and runs an arbitrary apk file.
- ``googlemap``: Launches Google Maps and replays previously recorded
interactions.
Framework
~~~~~~~~~
- ``wlauto.utils.misc``: Added ``memoised`` function decorator that allows
caching of previous function/method call results.
- Added new ``Device`` APIs:
- ``lsmod``: lists kernel modules
- ``insmod``: inserts a kernel module from a ``.ko`` file on the host.
- ``get_binary_path``: Checks ``binary_directory`` for the wanted binary,
if it is not found there it will try to use ``which``
- ``install_if_needed``: Will only install a binary if it is not already
on the target.
- ``get_device_model``: Gets the model of the device.
- ``wlauto.core.execution.ExecutionContext``:
- ``add_classfiers``: Allows adding a classfier to all metrics for the
current result.
Other
~~~~~
- Commands:
- ``record``: Simplifies recording revent files.
- ``replay``: Plays back revent files.
Fixes/Improvements:
###################
Devices
~~~~~~~
- ``juno``:
- Fixed ``bootargs`` parameter not being passed to ``_boot_via_uboot``.
- Removed default ``bootargs``
- ``gem5_linux``:
- Added ``login_prompt`` and ``login_password_prompt`` parameters.
- ``generic_linux``: ABI is now read from the target device.
Instruments
~~~~~~~~~~~
- ``trace-cmd``:
- Added the ability to report the binary trace on the target device,
removing the need for ``trace-cmd`` binary to be present on the host.
- Updated to handle messages that the trace for a CPU is empty.
- Made timeout for pulling trace 1 minute at minimum.
- ``perf``: per-cpu statistics now get added as metrics to the results (with a
classifier used to identify the cpu).
- ``daq``:
- Fixed bug where an exception would be raised if ``merge_channels=False``
- No longer allows duplicate channel labels
- ``juno_energy``:
- Summary metrics are now calculated from the contents of ``energy.csv`` and
added to the overall results.
- Added a ``strict`` parameter. When this is set to ``False`` the device
check during validation is omitted.
- ``sysfs_extractor``: tar and gzip are now performed separately to solve
permission issues.
- ``fps``:
- Now only checks for crashed content if ``crash_check`` is ``True``.
- Can now process multiple ``view`` attributes.
- ``hwmon``: Sensor naming fixed, they are also now added as result classifiers
Resource Getters
~~~~~~~~~~~~~~~~
- ``extension_asset``: Now picks up the path to the mounted filer from the
``remote_assets_path`` global setting.
Result Processors
~~~~~~~~~~~~~~~~~
- ``cpustates``:
- Added the ability to configure how a missing ``START`` marker in the trace
is handled.
- Now raises a warning when there is a ``START`` marker in the trace but no
``STOP`` marker.
- Exceptions in PowerStateProcessor no longer stop the processing of the
rest of the trace.
- Now ensures a known initial state by nudging each CPU to bring it out of
idle and writing starting CPU frequencies to the trace.
- Added the ability to create a CPU utilisation timeline.
- Fixed issues with getting frequencies of hotplugged CPUs
- ``csv``: Zero-value classifieres are no longer converted to an empty entry.
- ``ipynb_exporter``: Default template no longer shows a blank plot for
workloads without ``summary_metrics``
Workloads
~~~~~~~~~
- ``vellamo``:
- Added support for v3.2.4.
- Fixed getting values from logcat.
- ``cameracapture``: Updated to work with Android M+.
- ``camerarecord``: Updated to work with Android M+.
- ``lmbench``:
- Added the output file as an artifact.
- Added taskset support
- ``antutu`` - Added support for v6.0.1
- ``ebizzy``: Fixed use of ``os.path`` to ``self.device.path``.
- ``bbench``: Fixed browser crashes & permissions issues on android M+.
- ``geekbench``:
- Added check whether device is rooted.
- ``manual``: Now only uses logcat on Android devices.
- ``applaunch``:
- Fixed ``cleanup`` not getting forwarded to script.
- Added the ability to stress IO during app launch.
- ``dhrystone``: Now uses WA's resource resolution to find it's binary so it
uses the correct ABI.
- ``glbench``: Updated for new logcat formatting.
Framework
~~~~~~~~~
- ``ReventWorkload``:
- Now kills all revent instances on teardown.
- Device model name is now used when searching for revent files, falling back
to WA device name.
- ``BaseLinuxDevice``:
- ``killall`` will now run as root by default if the device
is rooted.
- ``list_file_systems`` now handles blank lines.
- All binaries are now installed into ``binaries_directory`` this allows..
- Busybox is now deployed on non-root devices.
- gzipped property files are no zcat'ed
- ``LinuxDevice``:
- ``kick_off`` no longer requires root.
- ``kick_off`` will now run as root by default if the device is rooted.
- No longer raises an exception if a connection was dropped during a reboot.
- Added a delay before polling for a connection to avoid re-connecting to a
device that is still in the process of rebooting.
- ``wlauto.utils.types``: ``list_or_string`` now ensures that elements of a list
are strings.
- ``AndroidDevice``:
- ``kick_off`` no longer requires root.
- Build props are now gathered via ``getprop`` rather than trying to parse
build.prop directly.
- WA now pushes its own ``sqlite3`` binary.
- Now uses ``content`` instead of ``settings`` to get ``ANDROID_ID``
- ``swipe_to_unlock`` parameter is now actually used. It has been changed to
take a direction to accomodate various devices.
- ``ensure_screen_is_on`` will now also unlock the screen if swipe_to_unlock
is set.
- Fixed use of variables in as_root=True commands.
- ``get_pids_of`` now used ``busybox grep`` since as of Android M+ ps cannot
filter by process name anymore.
- Fixed installing APK files with whitespace in their path/name.
- ``adb_shell``:
- Fixed handling of line breaks at the end of command output.
- Newline separator is now detected from the target.
- As of ADB v1.0.35, ADB returns the return code of the command run. WA now
handles this correctly.
- ``ApkWorkload``:
- Now attempts to grant all runtime permissions for devices on Android M+.
- Can now launch packages that don't have a launch activity defined.
- Package version is now added to results as a classifier.
- Now clears app data if an uninstall failed to ensure it starts from a known
state.
- ``wlauto.utils.ipython``: Updated to work with ipython v5.
- ``Gem5Device``:
- Added support for deploying the ``m5`` binary.
- No longer waits for the boot animation to finish if it has been disabled.
- Fixed runtime error caused by lack of kwargs.
- No longer depends on ``busybox``.
- Split out commands to resize shell to ``resize_shell``.
- Now tries to connect to the shell up to 10 times.
- No longer renames gzipped files.
- Agendas:
- Now errors when an agenda key is empty.
- ``wlauto.core.execution.RunInfo``: ``run_name`` will now default to
``{output_folder}_{date}_{time}``.
- Extensions:
- Two different parameters can now have the same global alias as long as they
their types match.
- You can no longer ``override`` parameters that are defined at the same
level.
- ``wlauto.core.entry_point``: Now gives a better error when a config file
doesn't exist.
- ``wlauto.utils.misc``: Added ``aarch64`` to list for arm64 ABI.
- ``wlauto.core.resolver``: Now shows what version was being search for when a
resource is not found.
- Will no longer start instruments ect. if a run has no workload specs.
- ``wlauto.utils.uboot``: Now detects uboot version to use correct line endings.
- ``wlauto.utils.trace_cmd``: Added a parser for sched_switch events.
Other
~~~~~
- Updated to pylint v1.5.1
- Rebuilt ``busybox`` binaries to prefer built-in applets over system binaries.
- ``BaseUiAutomation``: Added functions for checking version strings.
Incompatible changes
####################
Instruments
~~~~~~~~~~~
- ``apk_version``: Removed, use result classifiers instead.
Framework
~~~~~~~~~
- ``BaseLinuxDevice``: Removed ``is_installed`` use ``install_if_needed`` and
``get_binary_path`` instead.
- ``LinuxDevice``: Removed ``has_root`` method, use ``is_rooted`` instead.
- ``AndroidDevice``: ``swipe_to_unlock`` method replaced with
``perform_unlock_swipe``.
-------------
Version 2.4.0
-------------
Additions:
##########
Devices
~~~~~~~~
- ``gem5_linux`` and ``gem5_android``: Interfaces for Gem5 simulation
environment running Linux and Android respectively.
- ``XE503C1211``: Interface for Samsung XE503C12 Chromebooks.
- ``chromeos_test_image``: Chrome OS test image device. An off the shelf
device will not work with this device interface.
Instruments
~~~~~~~~~~~~
- ``freq_sweep``: Allows "sweeping" workloads across multiple CPU frequencies.
- ``screenon``: Ensures screen is on, before each iteration, or periodically
on Android devices.
- ``energy_model``: This instrument can be used to generate an energy model
for a device based on collected power and performance measurments.
- ``netstats``: Allows monitoring data sent/received by applications on an
Android device.
Modules
~~~~~~~
- ``cgroups``: Allows query and manipulation of cgroups controllers on a Linux
device. Currently, only cpusets controller is implemented.
- ``cpuidle``: Implements cpuidle state discovery, query and manipulation for
a Linux device. This replaces the more primitive get_cpuidle_states method
of LinuxDevice.
- ``cpufreq`` has now been split out into a device module
Reasource Getters
~~~~~~~~~~~~~~~~~
- ``http_assets``: Downloads resources from a web server.
Results Processors
~~~~~~~~~~~~~~~~~~~
- ``ipynb_exporter``: Generates an IPython notebook from a template with the
results and runs it.
- ``notify``: Displays a desktop notification when a run finishes
(Linux only).
- ``cpustates``: Processes power ftrace to produce CPU state and parallelism
stats. There is also a script to invoke this outside of WA.
Workloads
~~~~~~~~~
- ``telemetry``: Executes Google's Telemetery benchmarking framework
- ``hackbench``: Hackbench runs tests on the Linux scheduler
- ``ebizzy``: This workload resembles common web server application workloads.
- ``power_loadtest``: Continuously cycles through a set of browser-based
activities and monitors battery drain on a device (part of ChromeOS autotest
suite).
- ``rt-app``: Simulates configurable real-time periodic load.
- ``linpack-cli``: Command line version of linpack benchmark.
- ``lmbench``: A suite of portable ANSI/C microbenchmarks for UNIX/POSIX.
- ``stream``: Measures memory bandwidth.
- ``iozone``: Runs a series of disk I/O performance tests.
- ``androbench``: Measures the storage performance of device.
- ``autotest``: Executes tests from ChromeOS autotest suite.
Framework
~~~~~~~~~
- ``wlauto.utils``:
- Added ``trace_cmd``, a generic trace-cmd paraser.
- Added ``UbootMenu``, allows navigating Das U-boot menu over serial.
- ``wlauto.utils.types``:
- ``caseless_string``: Behaves exactly like a string, except this ignores
case in comparisons. It does, however, preserve case.
- ``list_of``: allows dynamic generation of type-safe list types based on
an existing type.
- ``arguments``: represents arguments that are passed on a command line to
an application.
- ``list-or``: allows dynamic generation of types that accept either a base
type or a list of base type. Using this ``list_or_integer``,
``list_or_number`` and ``list_or_bool`` were also added.
- ``wlauto.core.configuration.WorkloadRunSpec``:
- ``copy``: Allows making duplicates of ``WorkloadRunSpec``'s
- ``wlatuo.utils.misc``:
- ``list_to_ranges`` and ``ranges_to_list``: convert between lists of
integers and corresponding range strings, e.g. between [0,1,2,4] and
'0-2,4'
- ``list_to_mask`` and ``mask_to_list``: convert between lists of integers
and corresponding integer masks, e.g. between [0,1,2,4] and 0x17
- ``wlauto.instrumentation``:
- ``instrument_is_enabled``: Returns whether or not an instrument is
enabled for the current job.
- ``wlauto.core.result``:
- Added "classifiers" field to Metric objects. This is a dict mapping
classifier names (arbitrary strings) to corresponding values for that
specific metrics. This is to allow extensions to add extension-specific
annotations to metric that could be handled in a generic way (e.g. by
result processors). They can also be set in agendas.
- Failed jobs will now be automatically retired
- Implemented dynamic device modules that may be loaded automatically on
device initialization if the device supports them.
- Added support for YAML configs.
- Added ``initialze`` and ``finalize`` methods to workloads.
- ``wlauto.core.ExecutionContext``:
- Added ``job_status`` property that returns the status of the currently
running job.
Fixes/Improvements
##################
Devices
~~~~~~~~
- ``tc2``: Workaround for buffer overrun when loading large initrd blob.
- ``juno``:
- UEFI config can now be specified as a parameter.
- Adding support for U-Boot booting.
- No longer auto-disconnects ADB at the end of a run.
- Added ``actually_disconnect`` to restore old disconnect behaviour
- Now passes ``video`` command line to Juno kernel to work around a known
issue where HDMI loses sync with monitors.
- Fixed flashing.
Instruments
~~~~~~~~~~~
- ``trace_cmd``:
- Fixed ``buffer_size_file`` for non-Android devices
- Reduce starting priority.
- Now handles trace headers and thread names with spaces
- ``energy_probe``: Added ``device_entry`` parameter.
- ``hwmon``:
- Sensor discovery is now done only at the start of a run.
- Now prints both before/after and mean temperatures.
- ``daq``:
- Now reports energy
- Fixed file descriptor leak
- ``daq_power.csv`` now matches the order of labels (if specified).
- Added ``gpio_sync``. When enabled, this wil cause the instrument to
insert a marker into ftrace, while at the same time setting a GPIO pin
high.
- Added ``negative_values`` parameter. which can be used to specify how
negative values in the samples should be handled.
- Added ``merge_channels`` parameter. When set DAQ channel will be summed
together.
- Workload labels, rather than names, are now used in the "workload"
column.
- ``cpufreq``:
- Fixes missing directories problem.
- Refined the availability check not to rely on the top-level cpu/cpufreq
directory
- Now handles non-integer output in ``get_available_frequencies``.
- ``sysfs_extractor``:
- No longer raises an error when both device and host paths are empty.
- Fixed pulled files verification.
- ``perf``:
- Updated binaries.
- Added option to force install.
- ``killall`` is now run as root on rooted Android devices.
- ``fps``:
- now generates detailed FPS traces as well as report average FPS.
- Updated jank calcluation to only count "large" janks.
- Now filters out bogus ``actual-present`` times and ignore janks above
``PAUSE_LATENCY``
- ``delay``:
- Added ``fixed_before_start`` parameter.
- Changed existing ``*_between_specs`` and ``*_between_iterations``
callbacks to be ``very_slow``
- ``streamline``:
- Added Linux support
- ``gatord`` is now only started once at the start of the run.
modules
~~~~~~~
- ``flashing``:
- Fixed vexpress flashing
- Added an option to keep UEFI entry
Result Processors
~~~~~~~~~~~~~~~~~
- ``cpustate``:
- Now generates a timeline csv as well as stats.
- Adding ID to overall cpustate reports.
- ``csv``: (partial) ``results.csv`` will now be written after each iteration
rather than at the end of the run.
Workloads
~~~~~~~~~
- ``glb_corporate``: clears logcat to prevent getting results from previous
run.
- ``sysbench``:
- Updated sysbench binary to a statically linked verison
- Added ``file_test_mode parameter`` - this is a mandatory argumet if
``test`` is ``"fileio"``.
- Added ``cmd_params`` parameter to pass options directily to sysbench
invocation.
- Removed Android browser launch and shutdown from workload (now runs on
both Linux and Android).
- Now works with unrooted devices.
- Added the ability to run based on time.
- Added a parameter to taskset to specific core(s).
- Added ``threads`` parameter to be consistent with dhrystone.
- Fixed case where default ``timeout`` < ``max_time``.
- ``Dhrystone``:
- added ``taskset_mask`` parameter to allow pinning to specific cores.
- Now kills any running instances during setup (also handles CTRL-C).
- ``sysfs_extractor``: Added parameter to explicitly enable/disable tempfs
caching.
- ``antutu``:
- Fixed multi-``times`` playback for v5.
- Updated result parsing to handle Android M logcat output.
- ``geekbench``: Increased timout to cater for slower devices.
- ``idle``: Now works on Linux devices.
- ``manhattan``: Added ``run_timemout`` parameter.
- ``bbench``: Now works when binaries_directory is not in path.
- ``nemamark``: Made duration configurable.
Framework
~~~~~~~~~~
- ``BaseLinuxDevice``:
- Now checks that at least one core is enabled on another cluster before
attempting to set number of cores on a cluster to ``0``.
- No longer uses ``sudo`` if already logged in as ``root``.
- Now saves ``dumpsys window`` output to the ``__meta`` directory.
- Now takes ``password_prompt`` as a parameter for devices with a non
standard ``sudo`` password prompt.
- No longer raises an error if ``keyfile`` or ``password`` are not
provided when they are not necessary.
- Added new cpufreq APIs:
- ``core`` APIs take a core name as the parameter (e.g. "a15")
- ``cluster`` APIs take a numeric cluster ID (eg. 0)
- ``cpu`` APIs take a cpufreq cpu ID as a parameter.
- ``set_cpu_frequency`` now has a ``exact`` parameter. When true (the
default) it will produce an error when the specified frequency is not
supported by the cpu, otherwise cpufreq will decide what to do.
- Added ``{core}_frequency`` runtime parameter to set cluster frequency.
- Added ``abi`` property.
- ``get_properties`` moved from ``LinuxDevice``, meaning ``AndroidDevice``
will try to pull the same files. Added more paths to pull by default
too.
- fixed ``list_file_systems`` for Android M and Linux devices.
- Now sets ``core_clusters`` from ``core_names`` if not explicitly
specified.
- Added ``invoke`` method that allows invoking an executable on the device
under controlled contions (e.g. within a particular directory, or
taskset to specific CPUs).
- No longer attempts to ``get_sysfile_value()`` as root on unrooted
devices.
- ``LinuxDevice``:
- Now creates ``binaries_directory`` path if it doesn't exist.
- Fixed device reset
- Fixed ``file_exists``
- implemented ``get_pid_of()`` and ``ps()``. Existing implementation
relied on Android version of ps.
- ``listdir`` will now return an empty list for an empty directory
instead of a list containing a single empty string.
- ``AndroidDevice``:
- Executable (un)installation now works on unrooted devices.
- Now takes into account ``binar_directory`` when setting up busybox path.
- update ``android_prompt`` so that it works even if is not ``"/"``
- ``adb_connect``: do not assume port 5555 anymore.
- Now always deploys busybox on rooted devices.
- Added ``swipe_to_unlock`` method.
- Fixed initialization of ``~/.workload_automation.``.
- Fixed replaying events using revent on 64 bit platforms.
- Improved error repoting when loading extensions.
- ``result`` objects now track their output directories.
- ``context.result`` will not result in ``context.run_result`` when not
executing a job.
- ``wlauto.utils.ssh``:
- Fixed key-based authentication.
- Fixed carriage return stripping in ssh.
- Now takes ``password_prompt`` as a parameter for non standard ``sudo``
password prompts.
- Now with 100% more thread safety!
- If a timeout condition is hit, ^C is now sent to kill the current
foreground process and make the shell available for subsequent commands.
- More robust ``exit_code`` handling for ssh interface
- Now attempts to deal with dropped connections
- Fixed error reporting on failed exit code extraction.
- Now handles backspaces in serial output
- Added ``port`` argument for telnet connections.
- Now allows telnet connections without a password.
- Fixed config processing for extensions with non-identifier names.
- Fixed ``get_meansd`` for numbers < 1
- ``wlatuo.utils.ipython``:
- Now supports old versions of IPython
- Updated version check to only initialize ipython utils if version is
< 4.0.0. Version 4.0.0 changes API and breaks WA's usage of it.
- Added ``ignore`` parameter to ``check_output``
- Agendas:
- Now raise an error if an agenda contains duplicate keys
- Now raise an error if config section in an agenda is not dict-like
- Now properly handles ``core_names`` and ``core_clusters``
- When merging list parameters from different sources, duplicates are no
longer removed.
- The ``INITIAL_BOOT`` signal is now sent went performing a hard reset during
intial boot
- updated ``ExecutionContext`` to keep a reference to the ``runner``. This
will enable Extenstions to do things like modify the job queue.
- Parameter now automatically convert int and boot kinds to integer and
boolean respectively, this behavior can be supressed by specifying
``convert_types``=``False`` when defining the parameter.
- Fixed resource resolution when dependency location does not exist.
- All device ``push`` and ``pull`` commands now raise ``DeviceError`` if they
didn't succeed.
- Fixed showing Parameter default of ``False`` for boolean values.
- Updated csv result processor with the option to use classifiers to
add columns to ``results.csv``.
- ``wlauto.utils.formatter``: Fix terminal size discovery.
- The extension loader will now follow symlinks.
- Added arm64-v8a to ABI map
- WA now reports syntax errors in a more informative way.
- Resource resolver: now prints the path of the found resource to the log.
- Resource getter: look for executable in the bin/ directory under resource
owner's dependencies directory as well as general dependencies bin.
- ``GamingWorkload``:
- Added an option to prevent clearing of package data before execution.
- Added the ability to override the timeout of deploying the assets
tarball.
- ``ApkWorkload``: Added an option to skip host-side APK check entirely.
- ``utils.misc.normalize``: only normalize string keys.
- Better error reporting for subprocess.CalledProcessError
- ``boolean`` now interprets ``'off'`` as ``False``
- ``wlauto.utils.uefi``: Added support for debug builds.
- ``wlauto.utils.serial_port``: Now supports fdexpect versions > 4.0.0
- Semanatics for ``initialize``/``finalize`` for *all* Extensions are changed
so that now they will always run at most once per run. They will not be
executed twice even if invoked via instances of different subclasses (if
those subclasses defined their own verions, then their versions will be
invoked once each, but the base version will only get invoked once).
- Pulling entries from procfs does not work on some platforms. WA now tries
to cat the contents of a property_file and write it to a output file on the
host.
Documentation
~~~~~~~~~~~~~
- ``installation``:
- Added ``post install`` section which lists workloads that require
additional external dependencies.
- Added the ``uninstall`` and ``upgrade`` commands for users to remove or
upgrade Workload Automation.
- Added documentation explaining how to use ``remote_assets_path``
setting.
- Added warning about potential permission issues with pip.
- ``quickstart``: Added steps for setting up WA to run on Linux devices.
- ``device_setup``: fixed ``generic_linux`` ``device_config`` example.
- ``contributing``: Clarified style guidelines
- ``daq_device_setup``: Added an illustration for DAQ wiring.
- ``writing_extensions``: Documented the Workload initialize and finalize
methods.
- Added descriptions to extension that didn't have one.
Other
~~~~~
- ``daq_server``:
- Fixed showing available devices.
- Now works with earlier versions of the DAQmx driver.thus you can now run
the server on Linux systems.
- DAQ error messages are now properly propaged to the client.
- Server will now periodically clean up uncollected files.
- fixed not being able to resolve IP address for hostname
(report "localhost" in that case).
- Works with latest version of twisted.
- ``setup.py``: Fixed paths to work with Mac OS X.
- ``summary_csv`` is no longer enabled by default.
- ``status`` result processor is now enabled by default.
- Commands:
- ``show``:
- Now shows what platform extensions support.
- Will no longer try to use a pager if ``PAGER=''`` in the environment.
- ``list``:
- Added ``"-p"`` option to filter results by supported platforms.
- Added ``"--packaged-only"`` option to only list extensions packaged
with WA.
- ``run``: Added ``"--disable"`` option to diable instruments.
- ``create``:
- Added ``agenda`` sub-command to generate agendas for a set of
extensions.
- ``create workload`` now gives more informative errors if Android SDK
installed but no platform has been downloaded.
Incompatible changes
####################
Framework
~~~~~~~~~
- ``BaseLinuxDevice``:
- Renamed ``active_cpus`` to ``online_cpus``
- Renamed ``get_cluster_cpu`` to ``get_cluster_active_cpu``
- Renamed ``get_core_cpu`` to ``get_core_online_cpu``
- All extension's ``initialize`` function now takes one (and only one)
parameter, ``context``.
- ``wlauto.core.device``: Removed ``init`` function. Replaced with
``initialize``
-------------
Version 2.3.0
-------------

View File

@@ -113,7 +113,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
html_theme = 'classic'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the

View File

@@ -97,6 +97,32 @@ Available Settings
Added in version 2.1.5.
.. confval:: retry_on_status
This is list of statuses on which a job will be cosidered to have failed and
will be automatically retried up to ``max_retries`` times. This defaults to
``["FAILED", "PARTIAL"]`` if not set. Possible values are:
``"OK"``
This iteration has completed and no errors have been detected
``"PARTIAL"``
One or more instruments have failed (the iteration may still be running).
``"FAILED"``
The workload itself has failed.
``"ABORTED"``
The user interupted the workload
.. confval:: max_retries
The maximum number of times failed jobs will be retried before giving up. If
not set, this will default to ``3``.
.. note:: this number does not include the original attempt
.. confval:: instrumentation
This should be a list of instruments to be enabled during run execution.
@@ -136,6 +162,12 @@ Available Settings
All three values should be Python `old-style format strings`_ specifying which
`log record attributes`_ should be displayed.
.. confval:: remote_assets_path
Path to the local mount of a network assets repository. See
:ref:`assets_repository`.
There are also a couple of settings are used to provide additional metadata
for a run. These may get picked up by instruments or result processors to
attach context to results.

View File

@@ -2,12 +2,23 @@
Contributing Code
=================
We welcome code contributions via GitHub pull requests to the official WA
repository. To help with maintainability of the code line we ask that the code
uses a coding style consistent with the rest of WA code, which is basically
`PEP8 <https://www.python.org/dev/peps/pep-0008/>`_ with line length and block
comment rules relaxed (the wrapper for PEP8 checker inside ``dev_scripts`` will
run it with appropriate configuration).
We welcome code contributions via GitHub pull requests.To help with
maintainability of the code line we ask that the code uses a coding style
consistent with the rest of WA code. Briefly, it is
- `PEP8 <https://www.python.org/dev/peps/pep-0008/>`_ with line length and block
comment rules relaxed (the wrapper for PEP8 checker inside ``dev_scripts``
will run it with appropriate configuration).
- Four-space indentation (*no tabs!*).
- Title-case for class names, underscore-delimited lower case for functions,
methods, and variables.
- Use descriptive variable names. Delimit words with ``'_'`` for readability.
Avoid shortening words, skipping vowels, etc (common abbreviations such as
"stats" for "statistics", "config" for "configuration", etc are OK). Do
*not* use Hungarian notation (so prefer ``birth_date`` over ``dtBirth``).
New extensions should also follow implementation guidelines specified in
:ref:`writing_extensions` section of the documentation.
We ask that the following checks are performed on the modified code prior to
submitting a pull request:

BIN
doc/source/daq-wiring.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

View File

@@ -68,6 +68,12 @@ varies between models.
possible to use any other configuration (e.g. ports 1, 2 and 5).
As an example, the following illustration shows the wiring of PORT0 (using AI/0
and AI/1 channels) on a DAQ USB-6210
.. image:: daq-wiring.png
:scale: 70 %
Setting up NI-DAQmx driver on a Windows Machine
-----------------------------------------------

View File

@@ -64,7 +64,7 @@ you might want to change are outlined below.
advanced WA functionality (like setting of core-related runtime parameters
such as governors, frequencies, etc). ``core_names`` should be a list of
core names matching the order in which they are exposed in sysfs. For
example, ARM TC2 SoC is a 2x3 big.LITTLE system; it's core_names would be
example, ARM TC2 SoC is a 2x3 big.LITTLE system; its core_names would be
``['a7', 'a7', 'a7', 'a15', 'a15']``, indicating that cpu0-cpu2 in cpufreq
sysfs structure are A7's and cpu3 and cpu4 are A15's.
@@ -363,11 +363,11 @@ A typical ``device_config`` inside ``config.py`` may look something like
.. code-block:: python
device_config = dict(
'host'='192.168.0.7',
'username'='guest',
'password'='guest',
'core_names'=['a7', 'a7', 'a7', 'a15', 'a15'],
'core_clusters'=[0, 0, 0, 1, 1],
host='192.168.0.7',
username='guest',
password='guest',
core_names=['a7', 'a7', 'a7', 'a15', 'a15'],
core_clusters=[0, 0, 0, 1, 1],
# ...
)

View File

@@ -118,6 +118,7 @@ and detailed descriptions of how WA functions under the hood.
additional_topics
daq_device_setup
revent
apk_workloads
contributing
API Reference

View File

@@ -15,16 +15,23 @@ Operating System
WA runs on a native Linux install. It was tested with Ubuntu 12.04,
but any recent Linux distribution should work. It should run on either
32bit or 64bit OS, provided the correct version of Android (see below)
32-bit or 64-bit OS, provided the correct version of Android (see below)
was installed. Officially, **other environments are not supported**. WA
has been known to run on Linux Virtual machines and in Cygwin environments,
though additional configuration maybe required in both cases (known issues
though additional configuration may be required in both cases (known issues
include makings sure USB/serial connections are passed to the VM, and wrong
python/pip binaries being picked up in Cygwin). WA *should* work on other
Unix-based systems such as BSD or Mac OS X, but it has not been tested
in those environments. WA *does not* run on Windows (though it should be
possible to get limited functionality with minimal porting effort).
.. Note:: If you plan to run Workload Automation on Linux devices only,
SSH is required, and Android SDK is optional if you wish
to run WA on Android devices at a later time. Then follow the
steps to install the necessary python packages to set up WA.
However, you would be starting off with a limited number of
workloads that will run on Linux devices.
Android SDK
-----------
@@ -32,12 +39,11 @@ Android SDK
You need to have the Android SDK with at least one platform installed.
To install it, download the ADT Bundle from here_. Extract it
and add ``<path_to_android_sdk>/sdk/platform-tools`` and ``<path_to_android_sdk>/sdk/tools``
to your ``PATH``. To test that you've installed it properly run ``adb
version``, the output should be similar to this::
to your ``PATH``. To test that you've installed it properly, run ``adb
version``. The output should be similar to this::
$$ adb version
adb version
Android Debug Bridge version 1.0.31
$$
.. _here: https://developer.android.com/sdk/index.html
@@ -53,11 +59,16 @@ usually the best bet.
Optionally (but recommended), you should also set ``ANDROID_HOME`` to point to
the install location of the SDK (i.e. ``<path_to_android_sdk>/sdk``).
.. note:: You may need to install 32-bit compatibility libararies for the SDK
to work properly. On Ubuntu you need to run::
sudo apt-get install lib32stdc++6 lib32z1
Python
------
Workload Automation 2 requires Python 2.7 (Python 3 is not supported, at the moment).
Workload Automation 2 requires Python 2.7 (Python 3 is not supported at the moment).
pip
@@ -69,6 +80,23 @@ similar distributions, this may be done with APT::
sudo apt-get install python-pip
.. note:: Some versions of pip (in particluar v1.5.4 which comes with Ubuntu
14.04) are know to set the wrong permissions when installing
packages, resulting in WA failing to import them. To avoid this it
is recommended that you update pip and setuptools before proceeding
with installation::
sudo -H pip install --upgrade pip
sudo -H pip install --upgrade setuptools
If you do run into this issue after already installing some packages,
you can resolve it by running ::
sudo chmod -R a+r /usr/local/lib/python2.7/dist-packagessudo
find /usr/local/lib/python2.7/dist-packages -type d -exec chmod a+x {} \;
(The paths above will work for Ubuntu; they may need to be adjusted
for other distros).
Python Packages
---------------
@@ -86,11 +114,11 @@ Workload Automation 2 depends on the following additional libraries:
You can install these with pip::
sudo pip install pexpect
sudo pip install pyserial
sudo pip install pyyaml
sudo pip install docutils
sudo pip install python-dateutil
sudo -H pip install pexpect
sudo -H pip install pyserial
sudo -H pip install pyyaml
sudo -H pip install docutils
sudo -H pip install python-dateutil
Some of these may also be available in your distro's repositories, e.g. ::
@@ -129,12 +157,26 @@ may not always have Internet access).
headers to install. You can get those by installing ``python-dev``
package in apt on Ubuntu (or the equivalent for your distribution).
Installing
==========
Download the tarball and run pip::
Installing the latest released version from PyPI (Python Package Index)::
sudo -H pip install wlauto
This will install WA along with its mandatory dependencies. If you would like to
install all optional dependencies at the same time, do the following instead::
sudo -H pip install wlauto[all]
Alternatively, you can also install the latest development version from GitHub
(you will need git installed for this to work)::
git clone git@github.com:ARM-software/workload-automation.git workload-automation
sudo -H pip install ./workload-automation
sudo pip install wlauto-$version.tar.gz
If the above succeeds, try ::
@@ -142,3 +184,161 @@ If the above succeeds, try ::
Hopefully, this should output something along the lines of "Workload Automation
version $version".
(Optional) Post Installation
============================
Some WA extensions have additional dependencies that need to be
statisfied before they can be used. Not all of these can be provided with WA and
so will need to be supplied by the user. They should be placed into
``~/.workload_automation/dependencies/<extenion name>`` so that WA can find
them (you may need to create the directory if it doesn't already exist). You
only need to provide the dependencies for workloads you want to use.
Binary Files
------------
Some workloads require native binaries to work. Different binaries will be required
for different ABIs. WA may not include the required binary for a workload due to
licensing/distribution issues, or may not have a binary compiled for your device's
ABI. In such cases, you will have to supply the missing binaries.
Executable binaries for a workload should be placed inside
``~/.workload_automation/dependencies/<extension name>/bin/<ABI>`` directory.
This directory may not already exist, in which case you would have to create it.
Binaries placed in that location will take precidence over any already inclueded with
WA. For example, if you have your own ``drystone`` binary compiled for ``arm64``,
and you want WA to pick it up, you can do the following on WA host machine ::
mkdir -p ~/.workload_automation/dependencies/dhrystone/bin/arm64/
cp /path/to/your/dhrystone ~/.workload_automation/dependencies/dhrystone/bin/arm64/
APK Files
---------
APKs are applicaton packages used by Android. These are necessary to install an
application onto devices that do not have Google Play (e.g. devboards running
AOSP). The following is a list of workloads that will need one, including the
version(s) for which UI automation has been tested. Automation may also work
with other versions (especially if it's only a minor or revision difference --
major version differens are more likely to contain incompatible UI changes) but
this has not been tested.
================ ============================================ ========================= ============ ============
workload package name version code version name
================ ============================================ ========================= ============ ============
andebench com.eembc.coremark AndEBench v1383a 1383
angrybirds com.rovio.angrybirds Angry Birds 2.1.1 2110
angrybirds_rio com.rovio.angrybirdsrio Angry Birds 1.3.2 1320
anomaly2 com.elevenbitstudios.anomaly2Benchmark A2 Benchmark 1.1 50
antutu com.antutu.ABenchMark AnTuTu Benchmark 5.3 5030000
antutu com.antutu.ABenchMark AnTuTu Benchmark 3.3.2 3322
antutu com.antutu.ABenchMark AnTuTu Benchmark 4.0.3 4000300
benchmarkpi gr.androiddev.BenchmarkPi BenchmarkPi 1.11 5
caffeinemark com.flexycore.caffeinemark CaffeineMark 1.2.4 9
castlebuilder com.ettinentertainment.castlebuilder Castle Builder 1.0 1
castlemaster com.alphacloud.castlemaster Castle Master 1.09 109
cfbench eu.chainfire.cfbench CF-Bench 1.2 7
citadel com.epicgames.EpicCitadel Epic Citadel 1.07 901107
dungeondefenders com.trendy.ddapp Dungeon Defenders 5.34 34
facebook com.facebook.katana Facebook 3.4 258880
geekbench ca.primatelabs.geekbench2 Geekbench 2 2.2.7 202007
geekbench com.primatelabs.geekbench3 Geekbench 3 3.0.0 135
glb_corporate net.kishonti.gfxbench GFXBench 3.0.0 1
glbenchmark com.glbenchmark.glbenchmark25 GLBenchmark 2.5 2.5 4
glbenchmark com.glbenchmark.glbenchmark27 GLBenchmark 2.7 2.7 1
gunbros2 com.glu.gunbros2 GunBros2 1.2.2 122
ironman com.gameloft.android.ANMP.GloftIMHM Iron Man 3 1.3.1 1310
krazykart com.polarbit.sg2.krazyracers Krazy Kart Racing 1.2.7 127
linpack com.greenecomputing.linpackpro Linpack Pro for Android 1.2.9 31
nenamark se.nena.nenamark2 NenaMark2 2.4 5
peacekeeper com.android.chrome Chrome 18.0.1025469 1025469
peacekeeper org.mozilla.firefox Firefox 23.0 2013073011
quadrant com.aurorasoftworks.quadrant.ui.professional Quadrant Professional 2.0 2000000
realracing3 com.ea.games.r3_row Real Racing 3 1.3.5 1305
smartbench com.smartbench.twelve Smartbench 2012 1.0.0 5
sqlite com.redlicense.benchmark.sqlite RL Benchmark 1.3 5
templerun com.imangi.templerun Temple Run 1.0.8 11
thechase com.unity3d.TheChase The Chase 1.0 1
truckerparking3d com.tapinator.truck.parking.bus3d Truck Parking 3D 2.5 7
vellamo com.quicinc.vellamo Vellamo 3.0 3001
vellamo com.quicinc.vellamo Vellamo 2.0.3 2003
videostreaming tw.com.freedi.youtube.player FREEdi YT Player 2.1.13 79
================ ============================================ ========================= ============ ============
Gaming Workloads
----------------
Some workloads (games, demos, etc) cannot be automated using Android's
UIAutomator framework because they render the entire UI inside a single OpenGL
surface. For these, an interaction session needs to be recorded so that it can
be played back by WA. These recordings are device-specific, so they would need
to be done for each device you're planning to use. The tool for doing is
``revent`` and it is packaged with WA. You can find instructions on how to use
it :ref:`here <revent_files_creation>`.
This is the list of workloads that rely on such recordings:
+------------------+
| angrybirds |
+------------------+
| angrybirds_rio |
+------------------+
| anomaly2 |
+------------------+
| castlebuilder |
+------------------+
| castlemastera |
+------------------+
| citadel |
+------------------+
| dungeondefenders |
+------------------+
| gunbros2 |
+------------------+
| ironman |
+------------------+
| krazykart |
+------------------+
| realracing3 |
+------------------+
| templerun |
+------------------+
| truckerparking3d |
+------------------+
.. _assets_repository:
Maintaining Centralized Assets Repository
-----------------------------------------
If there are multiple users within an organization that may need to deploy
assets for WA extensions, that organization may wish to maintain a centralized
repository of assets that individual WA installs will be able to automatically
retrieve asset files from as they are needed. This repository can be any
directory on a network filer that mirrors the structure of
``~/.workload_automation/dependencies``, i.e. has a subdirectories named after
the extensions which assets they contain. Individual WA installs can then set
``remote_assets_path`` setting in their config to point to the local mount of
that location.
(Optional) Uninstalling
=======================
If you have installed Workload Automation via ``pip`` and wish to remove it, run this command to
uninstall it::
sudo -H pip uninstall wlauto
.. Note:: This will *not* remove any user configuration (e.g. the ~/.workload_automation directory)
(Optional) Upgrading
====================
To upgrade Workload Automation to the latest version via ``pip``, run::
sudo -H pip install --upgrade --no-deps wlauto

View File

@@ -61,13 +61,13 @@ Instrument method realive to other callbacks registered for the signal (within t
level, callbacks are invoked in the order they were registered). The table below shows the mapping
of the prifix to the corresponding priority:
=========== ===
=========== ========
prefix priority
=========== ===
very_fast\_ 20
fast\_ 10
normal\_ 0
slow\_ -10
very_slow\_ -20
=========== ===
=========== ========
very_fast\_ 20
fast\_ 10
normal\_ 0
slow\_ -10
very_slow\_ -20
=========== ========

View File

@@ -1,11 +1,12 @@
.. _invocation:
.. highlight:: none
========
Commands
========
Installing the wlauto package will add ``wa`` command to your system,
which you can run from anywhere. This has a number of sub-commands, which can
which you can run from anywhere. This has a number of sub-commands, which can
be viewed by executing ::
wa -h
@@ -15,7 +16,7 @@ Individual sub-commands are discussed in detail below.
run
---
The most common sub-command you will use is ``run``. This will run specfied
The most common sub-command you will use is ``run``. This will run specified
workload(s) and process resulting output. This takes a single mandatory
argument that specifies what you want WA to run. This could be either a
workload name, or a path to an "agenda" file that allows to specify multiple
@@ -24,7 +25,7 @@ section for details). Executing ::
wa run -h
Will display help for this subcommand that will look somehtign like this::
Will display help for this subcommand that will look something like this::
usage: run [-d DIR] [-f] AGENDA
@@ -47,13 +48,13 @@ Will display help for this subcommand that will look somehtign like this::
--debug Enable debug mode. Note: this implies --verbose.
-d DIR, --output-directory DIR
Specify a directory where the output will be
generated. If the directoryalready exists, the script
generated. If the directory already exists, the script
will abort unless -f option (see below) is used,in
which case the contents of the directory will be
overwritten. If this optionis not specified, then
overwritten. If this option is not specified, then
wa_output will be used instead.
-f, --force Overwrite output directory if it exists. By default,
the script will abort in thissituation to prevent
the script will abort in this situation to prevent
accidental data loss.
-i ID, --id ID Specify a workload spec ID from an agenda to run. If
this is specified, only that particular spec will be
@@ -81,10 +82,74 @@ agenda file used to run the workloads along with any other device-specific
configuration files used during execution.
create
------
This can be used to create various WA-related objects, currently workloads, packages and agendas.
The full set of options for this command are::
usage: wa create [-h] [-c CONFIG] [-v] [--debug] [--version]
{workload,package,agenda} ...
positional arguments:
{workload,package,agenda}
workload Create a new workload. By default, a basic workload
template will be used but you can use options to
specify a different template.
package Create a new empty Python package for WA extensions.
On installation, this package will "advertise" itself
to WA so that Extensions with in it will be loaded by
WA when it runs.
agenda Create an agenda whit the specified extensions
enabled. And parameters set to their default values.
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
specify an additional config.py
-v, --verbose The scripts will produce verbose output.
--debug Enable debug mode. Note: this implies --verbose.
--version show program's version number and exit
Use "wa create <object> -h" to see all the object-specific arguments. For example::
wa create agenda -h
will display the relevant options that can be used to create an agenda.
get-assets
----------
This command can download external extension dependencies used by Workload Automation.
It can be used to download assets for all available extensions or those specificity listed.
The full set of options for this command are::
usage: wa get-assets [-h] [-c CONFIG] [-v] [--debug] [--version] [-f]
[--url URL] (-a | -e EXT [EXT ...])
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
specify an additional config.py
-v, --verbose The scripts will produce verbose output.
--debug Enable debug mode. Note: this implies --verbose.
--version show program's version number and exit
-f, --force Always fetch the assets, even if matching versions
exist in local cache.
--url URL The location from which to download the files. If not
provided, config setting ``remote_assets_url`` will be
used if available, else uses the default
REMOTE_ASSETS_URL parameter in the script.
-a, --all Download assets for all extensions found in the index.
Cannot be used with -e.
-e EXT [EXT ...] One or more extensions whose assets to download.
Cannot be used with --all.
list
----
This lists all extensions of a particular type. For example ::
This lists all extensions of a particular type. For example::
wa list workloads
@@ -97,11 +162,11 @@ show
This will show detailed information about an extension, including more in-depth
description and any parameters/configuration that are available. For example
executing ::
executing::
wa show andebench
will produce something like ::
will produce something like::
andebench
@@ -131,5 +196,64 @@ will produce something like ::
- Results displayed in Iterations per second
- Detailed log file for comprehensive engineering analysis
.. _record-command:
record
------
This command simplifies the process of recording an revent file. It
will automatically deploy revent and even has the option of automatically
opening apps. WA uses two parts to the names of revent recordings in the
format, {device_name}.{suffix}.revent. - device_name can either be specified
manually with the ``-d`` argument or it can be automatically determined. On
Android device it will be obtained from ``build.prop``, on Linux devices it is
obtained from ``/proc/device-tree/model``. - suffix is used by WA to determine
which part of the app execution the recording is for, currently these are
either ``setup`` or ``run``. This should be specified with the ``-s``
argument. The full set of options for this command are::
usage: wa record [-h] [-c CONFIG] [-v] [--debug] [--version] [-d DEVICE]
[-s SUFFIX] [-o OUTPUT] [-p PACKAGE] [-g] [-C]
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
specify an additional config.py
-v, --verbose The scripts will produce verbose output.
--debug Enable debug mode. Note: this implies --verbose.
--version show program's version number and exit
-d DEVICE, --device DEVICE
The name of the device
-s SUFFIX, --suffix SUFFIX
The suffix of the revent file, e.g. ``setup``
-o OUTPUT, --output OUTPUT
Directory to save the recording in
-p PACKAGE, --package PACKAGE
Package to launch before recording
-g, --gamepad Record from a gamepad rather than all devices.
-C, --clear Clear app cache before launching it
.. _replay-command:
replay
------
Along side ``record`` wa also has a command to playback recorded revent files.
It behaves very similar to the ``record`` command taking many of the same options::
usage: wa replay [-h] [-c CONFIG] [-v] [--debug] [--version] [-p PACKAGE] [-C]
revent
positional arguments:
revent The name of the file to replay
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
specify an additional config.py
-v, --verbose The scripts will produce verbose output.
--debug Enable debug mode. Note: this implies --verbose.
--version show program's version number and exit
-p PACKAGE, --package PACKAGE
Package to launch before recording
-C, --clear Clear app cache before launching it

View File

@@ -2,7 +2,7 @@
Quickstart
==========
This sections will show you how to quickly start running workloads using
This guide will show you how to quickly start running workloads using
Workload Automation 2.
@@ -13,22 +13,26 @@ Install
the :doc:`installation` section.
Make sure you have Python 2.7 and a recent Android SDK with API level 18 or above
installed on your system. For the SDK, make sure that either ``ANDROID_HOME``
environment variable is set, or that ``adb`` is in your ``PATH``.
installed on your system. A complete install of the Android SDK is required, as
WA uses a number of its utilities, not just adb. For the SDK, make sure that either
``ANDROID_HOME`` environment variable is set, or that ``adb`` is in your ``PATH``.
.. note:: A complete install of the Android SDK is required, as WA uses a
number of its utilities, not just adb.
.. Note:: If you plan to run Workload Automation on Linux devices only, SSH is required,
and Android SDK is optional if you wish to run WA on Android devices at a
later time.
However, you would be starting off with a limited number of workloads that
will run on Linux devices.
In addition to the base Python 2.7 install, you will also need to have ``pip``
(Python's package manager) installed as well. This is usually a separate package.
Once you have the pre-requisites and a tarball with the workload automation package,
you can install it with pip::
Once you have those, you can install WA with::
sudo pip install wlauto-2.2.0dev.tar.gz
sudo -H pip install wlauto
This will install Workload Automation on your system, along with the Python
packages it depends on.
This will install Workload Automation on your system, along with its mandatory
dependencies.
(Optional) Verify installation
-------------------------------
@@ -52,15 +56,23 @@ For more details, please see the :doc:`installation` section.
Configure Your Device
=====================
Out of the box, WA is configured to work with a generic Android device through
``adb``. If you only have one device listed when you execute ``adb devices``,
and your device has a standard Android configuration, then no extra configuration
is required (if your device is connected via network, you will have to manually execute
``adb connect <device ip>`` so that it appears in the device listing).
Locate the device configuration file, config.py, under the
~/.workload_automation directory. Then adjust the device
configuration settings accordingly to the device you are using.
If you have multiple devices connected, you will need to tell WA which one you
want it to use. You can do that by setting ``adb_name`` in device configuration inside
``~/.workload_automation/config.py``\ , e.g.
Android
-------
By default, the device is set to 'generic_android'. WA is configured to work
with a generic Android device through ``adb``. If you only have one device listed
when you execute ``adb devices``, and your device has a standard Android
configuration, then no extra configuration is required.
However, if your device is connected via network, you will have to manually execute
``adb connect <device ip>`` so that it appears in the device listing.
If you have multiple devices connected, you will need to tell WA which one you
want it to use. You can do that by setting ``adb_name`` in device_config section.
.. code-block:: python
@@ -73,10 +85,73 @@ want it to use. You can do that by setting ``adb_name`` in device configuration
# ...
This should give you basic functionality. If your device has non-standard
Android configuration (e.g. it's a development board) or your need some advanced
functionality (e.g. big.LITTLE tuning parameters), additional configuration may
be required. Please see the :doc:`device_setup` section for more details.
Linux
-----
First, set the device to 'generic_linux'
.. code-block:: python
# ...
device = 'generic_linux'
# ...
Find the device_config section and add these parameters
.. code-block:: python
# ...
device_config = dict(
host = '192.168.0.100',
username = 'root',
password = 'password'
# ...
)
# ...
Parameters:
- Host is the IP of your target Linux device
- Username is the user for the device
- Password is the password for the device
Enabling and Disabling Instrumentation
---------------------------------------
Some instrumentation tools are enabled after your initial install of WA.
.. note:: Some Linux devices may not be able to run certain instruments
provided by WA (e.g. cpufreq is disabled or unsupported by the
device).
As a start, keep the 'execution_time' instrument enabled while commenting out
the rest to disable them.
.. code-block:: python
# ...
Instrumentation = [
# Records the time it took to run the workload
'execution_time',
# Collects /proc/interrupts before and after execution and does a diff.
# 'interrupts',
# Collects the contents of/sys/devices/system/cpu before and after execution and does a diff.
# 'cpufreq',
# ...
)
This should give you basic functionality. If you are working with a development
board or you need some advanced functionality (e.g. big.LITTLE tuning parameters),
additional configuration may be required. Please see the :doc:`device_setup`
section for more details.
Running Your First Workload
@@ -155,8 +230,55 @@ This agenda
the config.py.
- Disables execution_time instrument, if it is enabled in the config.py
There is a lot more that could be done with an agenda. Please see :doc:`agenda`
section for details.
An agenda can be created in a text editor and saved as a YAML file. Please make note of
where you have saved the agenda.
Please see :doc:`agenda` section for more options.
.. _YAML: http://en.wikipedia.org/wiki/YAML
Examples
========
These examples show some useful options with the ``wa run`` command.
To run your own agenda::
wa run <path/to/agenda> (e.g. wa run ~/myagenda.yaml)
To redirect the output to a different directory other than wa_output::
wa run dhrystone -d my_output_directory
To use a different config.py file::
wa run -c myconfig.py dhrystone
To use the same output directory but override existing contents to
store new dhrystone results::
wa run -f dhrystone
To display verbose output while running memcpy::
wa run --verbose memcpy
Uninstall
=========
If you have installed Workload Automation via ``pip``, then run this command to
uninstall it::
sudo pip uninstall wlauto
.. Note:: It will *not* remove any user configuration (e.g. the ~/.workload_automation
directory).
Upgrade
=======
To upgrade Workload Automation to the latest version via ``pip``, run::
sudo pip install --upgrade --no-deps wlauto

View File

@@ -1,3 +1,5 @@
.. _resources:
Dynamic Resource Resolution
===========================
@@ -7,10 +9,10 @@ The idea is to decouple resource identification from resource discovery.
Workloads/instruments/devices/etc state *what* resources they need, and not
*where* to look for them -- this instead is left to the resource resolver that
is now part of the execution context. The actual discovery of resources is
performed by resource getters that are registered with the resolver.
performed by resource getters that are registered with the resolver.
A resource type is defined by a subclass of
:class:`wlauto.core.resource.Resource`. An instance of this class describes a
:class:`wlauto.core.resource.Resource`. An instance of this class describes a
resource that is to be obtained. At minimum, a ``Resource`` instance has an
owner (which is typically the object that is looking for the resource), but
specific resource types may define other parameters that describe an instance of

View File

@@ -1,7 +1,10 @@
.. _revent_files_creation:
revent
======
++++++
Overview and Usage
==================
revent utility can be used to record and later play back a sequence of user
input events, such as key presses and touch screen taps. This is an alternative
@@ -20,28 +23,44 @@ to Android UI Automator for providing automation for workloads. ::
Recording
---------
To record, transfer the revent binary to the device, then invoke ``revent
record``, giving it the time (in seconds) you want to record for, and the
file you want to record to (WA expects these files to have .revent
extension)::
WA features a ``record`` command that will automatically deploy and start
revent on the target device::
host$ adb push revent /data/local/revent
host$ adb shell
device# cd /data/local
device# ./revent record 1000 my_recording.revent
wa record
INFO Connecting to device...
INFO Press Enter when you are ready to record...
[Pressed Enter]
INFO Press Enter when you have finished recording...
[Pressed Enter]
INFO Pulling files from device
Once started, you will need to get the target device ready to record (e.g.
unlock screen, navigate menus and launch an app) then press ``ENTER``.
The recording has now started and button presses, taps, etc you perform on
the device will go into the .revent file. To stop the recording simply press
``ENTER`` again.
Once you have finished recording the revent file will be pulled from the device
to the current directory. It will be named ``{device_model}.revent``. When
recording revent files for a ``GameWorkload`` you can use the ``-s`` option to
add ``run`` or ``setup`` suffixes.
From version 2.6 of WA onwards, a "gamepad" recording mode is also supported.
This mode requires a gamepad to be connected to the device when recoridng, but
the recordings produced in this mode should be portable across devices.
For more information run please read :ref:`record-command`
The recording has now started and button presses, taps, etc you perform on the
device will go into the .revent file. The recording will stop after the
specified time period, and you can also stop it by hitting return in the adb
shell.
Replaying
---------
To replay a recorded file, run ``revent replay`` on the device, giving it the
file you want to replay::
To replay a recorded file, run ``wa replay``, giving it the file you want to
replay::
device# ./revent replay my_recording.revent
wa replay my_recording.revent
For more information run please read :ref:`replay-command`
Using revent With Workloads
@@ -95,3 +114,359 @@ where as UI Automator only works for Android UI elements (such as text boxes or
radio buttons), which makes the latter useless for things like games. Recording
revent sequence is also faster than writing automation code (on the other hand,
one would need maintain a different revent log for each screen resolution).
Using state detection with revent
=================================
State detection can be used to verify that a workload is executing as expected.
This utility, if enabled, and if state definitions are available for the
particular workload, takes a screenshot after the setup and the run revent
sequence, matches the screenshot to a state and compares with the expected
state. A WorkloadError is raised if an unexpected state is encountered.
To enable state detection, make sure a valid state definition file and
templates exist for your workload and set the check_states parameter to True.
State definition directory
--------------------------
State and phase definitions should be placed in a directory of the following
structure inside the dependencies directory of each workload (along with
revent files etc):
::
dependencies/
<workload_name>/
state_definitions/
definition.yaml
templates/
<oneTemplate>.png
<anotherTemplate>.png
...
definition.yaml file
--------------------
This defines each state of the workload and lists which templates are expected
to be found and how many are required to be detected for a conclusive match. It
also defines the expected state in each workload phase where a state detection
is run (currently those are setup_complete and run_complete).
Templates are picture elements to be matched in a screenshot. Each template
mentioned in the definition file should be placed as a file with the same name
and a .png extension inside the templates folder. Creating template png files
is as simple as taking a screenshot of the workload in a given state, cropping
out the relevant templates (eg. a button, label or other unique element that is
present in that state) and storing them in PNG format.
Please see the definition file for Angry Birds below as an example to
understand the format. Note that more than just two states (for the afterSetup
and afterRun phase) can be defined and this helps track the cause of errors in
case an unexpected state is encountered.
.. code-block:: yaml
workload_name: angrybirds
workload_states:
- state_name: titleScreen
templates:
- play_button
- logo
matches: 2
- state_name: worldSelection
templates:
- first_world_thumb
- second_world_thumb
- third_world_thumb
- fourth_world_thumb
matches: 3
- state_name: level_selection
templates:
- locked_level
- first_level
matches: 2
- state_name: gameplay
templates:
- pause_button
- score_label_text
matches: 2
- state_name: pause_screen
templates:
- replay_button
- menu_button
- resume_button
- help_button
matches: 4
- state_name: level_cleared_screen
templates:
- level_cleared_text
- menu_button
- replay_button
- fast_forward_button
matches: 4
workload_phases:
- phase_name: setup_complete
expected_state: gameplay
- phase_name: run_complete
expected_state: level_cleared_screen
File format of revent recordings
================================
You do not need to understand recording format in order to use revent. This
section is intended for those looking to extend revent in some way, or to
utilize revent recordings for other purposes.
Format Overview
---------------
Recordings are stored in a binary format. A recording consists of three
sections::
+-+-+-+-+-+-+-+-+-+-+-+
| Header |
+-+-+-+-+-+-+-+-+-+-+-+
| |
| Device Description |
| |
+-+-+-+-+-+-+-+-+-+-+-+
| |
| |
| Event Stream |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+
The header contains metadata describing the recording. The device description
contains information about input devices involved in this recording. Finally,
the event stream contains the recorded input events.
All fields are either fixed size or prefixed with their length or the number of
(fixed-sized) elements.
.. note:: All values below are little endian
Recording Header
----------------
An revent recoding header has the following structure
* It starts with the "magic" string ``REVENT`` to indicate that this is an
revent recording.
* The magic is followed by a 16 bit version number. This indicates the format
version of the recording that follows. Current version is ``2``.
* The next 16 bits indicate the type of the recording. This dictates the
structure of the Device Description section. Valid values are:
``0``
This is a general input event recording. The device description
contains a list of paths from which the events where recorded.
``1``
This a gamepad recording. The device description contains the
description of the gamepad used to create the recording.
* The header is zero-padded to 128 bits.
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 'R' | 'E' | 'V' | 'E' |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 'N' | 'T' | Version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Mode | PADDING |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PADDING |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Device Description
------------------
This section describes the input devices used in the recording. Its structure is
determined by the value of ``Mode`` field in the header.
general recording
~~~~~~~~~~~~~~~~~
.. note:: This is the only format supported prior to version ``2``.
The recording has been made from all available input devices. This section
contains the list of ``/dev/input`` paths for the devices, prefixed with total
number of the devices recorded.
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Number of devices |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Device paths +-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Similarly, each device path is a length-prefixed string. Unlike C strings, the
path is *not* NULL-terminated.
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length of device path |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Device path |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
gamepad recording
~~~~~~~~~~~~~~~~~
The recording has been made from a specific gamepad. All events in the stream
will be for that device only. The section describes the device properties that
will be used to create a virtual input device using ``/dev/uinput``. Please
see ``linux/input.h`` header in the Linux kernel source for more information
about the fields in this section.
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| bustype | vendor |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| product | version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| name_length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| name |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ev_bits |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| |
| key_bits (96 bytes) |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| |
| rel_bits (96 bytes) |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| |
| abs_bits (96 bytes) |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| num_absinfo |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| |
| |
| |
| absinfo entries |
| |
| |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Each ``absinfo`` entry consists of six 32 bit values. The number of entries is
determined by the ``abs_bits`` field.
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| value |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| minimum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| maximum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| fuzz |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| flat |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| resolution |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Event structure
---------------
The majority of an revent recording will be made up of the input events that were
recorded. The event stream is prefixed with the number of events in the stream.
Each event entry structured as follows:
* An unsigned integer representing which device from the list of device paths
this event is for (zero indexed). E.g. Device ID = 3 would be the 4th
device in the list of device paths.
* A signed integer representing the number of seconds since "epoch" when the
event was recorded.
* A signed integer representing the microseconds part of the timestamp.
* An unsigned integer representing the event type
* An unsigned integer representing the event code
* An unsigned integer representing the event value
For more information about the event type, code and value please read:
https://www.kernel.org/doc/Documentation/input/event-codes.txt
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Device ID | Timestamp Seconds |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp Seconds (cont.) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp Seconds (cont.) | stamp Micoseconds |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp Micoseconds (cont.) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp Micoseconds (cont.) | Event Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Event Code | Event Value |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Event Value (cont.) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Parser
------
WA has a parser for revent recordings. This can be used to work with revent
recordings in scripts. Here is an example:
.. code:: python
from wlauto.utils.revent import ReventRecording
with ReventRecording('/path/to/recording.revent') as recording:
print "Recording: {}".format(recording.filepath)
print "There are {} input events".format(recording.num_events)
print "Over a total of {} seconds".format(recording.duration)

View File

@@ -1,3 +1,5 @@
.. _writing_extensions:
==================
Writing Extensions
==================
@@ -9,7 +11,7 @@ interesting of these are
can be benchmarks, high-level use cases, or pretty much anything else.
:devices: These are interfaces to the physical devices (development boards or end-user
devices, such as smartphones) that use cases run on. Typically each model of a
physical device would require it's own interface class (though some functionality
physical device would require its own interface class (though some functionality
may be reused by subclassing from an existing base).
:instruments: Instruments allow collecting additional data from workload execution (e.g.
system traces). Instruments are not specific to a particular Workload. Instruments
@@ -29,7 +31,7 @@ Extension Basics
================
This sub-section covers things common to implementing extensions of all types.
It is recommended you familiarize yourself with the information here before
It is recommended you familiarize yourself with the information here before
proceeding onto guidance for specific extension types.
To create an extension, you basically subclass an appropriate base class and them
@@ -39,22 +41,22 @@ The Context
-----------
The majority of methods in extensions accept a context argument. This is an
instance of :class:`wlauto.core.execution.ExecutionContext`. If contains
instance of :class:`wlauto.core.execution.ExecutionContext`. If contains
of information about current state of execution of WA and keeps track of things
like which workload is currently running and the current iteration.
Notable attributes of the context are
context.spec
context.spec
the current workload specification being executed. This is an
instance of :class:`wlauto.core.configuration.WorkloadRunSpec`
and defines the workload and the parameters under which it is
being executed.
being executed.
context.workload
context.workload
``Workload`` object that is currently being executed.
context.current_iteration
context.current_iteration
The current iteration of the spec that is being executed. Note that this
is the iteration for that spec, i.e. the number of times that spec has
been run, *not* the total number of all iterations have been executed so
@@ -77,9 +79,9 @@ In addition to these, context also defines a few useful paths (see below).
Paths
-----
You should avoid using hard-coded absolute paths in your extensions whenever
You should avoid using hard-coded absolute paths in your extensions whenever
possible, as they make your code too dependent on a particular environment and
may mean having to make adjustments when moving to new (host and/or device)
may mean having to make adjustments when moving to new (host and/or device)
platforms. To help avoid hard-coded absolute paths, WA automation defines
a number of standard locations. You should strive to define your paths relative
to one of those.
@@ -93,7 +95,7 @@ extension methods.
context.run_output_directory
This is the top-level output directory for all WA results (by default,
this will be "wa_output" in the directory in which WA was invoked.
context.output_directory
This is the output directory for the current iteration. This will an
iteration-specific subdirectory under the main results location. If
@@ -102,7 +104,7 @@ context.output_directory
context.host_working_directory
This an addition location that may be used by extensions to store
non-iteration specific intermediate files (e.g. configuration).
non-iteration specific intermediate files (e.g. configuration).
Additionally, the global ``wlauto.settings`` object exposes on other location:
@@ -130,12 +132,63 @@ device, the ``os.path`` modules should *not* be used for on-device path
manipulation. Instead device has an equipment module exposed through
``device.path`` attribute. This has all the same attributes and behaves the
same way as ``os.path``, but is guaranteed to produce valid paths for the device,
irrespective of the host's path notation.
irrespective of the host's path notation. For example:
.. code:: python
result_file = self.device.path.join(self.device.working_directory, "result.txt")
self.command = "{} -a -b -c {}".format(target_binary, result_file)
.. note:: result processors, unlike workloads and instruments, do not have their
own device attribute; however they can access the device through the
context.
Deploying executables to a device
---------------------------------
Some devices may have certain restrictions on where executable binaries may be
placed and how they should be invoked. To ensure your extension works with as
wide a range of devices as possible, you should use WA APIs for deploying and
invoking executables on a device, as outlined below.
As with other resources (see :ref:`resources`) , host-side paths to the exectuable
binary to be deployed should be obtained via the resource resolver. A special
resource type, ``Executable`` is used to identify a binary to be deployed.
This is simiar to the regular ``File`` resource, however it takes an additional
parameter that specifies the ABI for which executable was compiled.
In order for the binary to be obtained in this way, it must be stored in one of
the locations scanned by the resource resolver in a directry structure
``<root>/bin/<abi>/<binary>`` (where ``root`` is the base resource location to
be searched, e.g. ``~/.workload_automation/depencencies/<extension name>``, and
``<abi>`` is the ABI for which the exectuable has been compiled, as returned by
``self.device.abi``).
Once the path to the host-side binary has been obtained, it may be deployed using
one of two methods of a ``Device`` instace -- ``install`` or ``install_if_needed``.
The latter will check a version of that binary has been perviously deployed by
WA and will not try to re-install.
.. code:: python
from wlauto import Executable
host_binary = context.resolver.get(Executable(self, self.device.abi, 'some_binary'))
target_binary = self.device.install_if_needed(host_binary)
.. note:: Please also note that the check is done based solely on the binary name.
For more information please see: :func:`wlauto.common.linux.BaseLinuxDevice.install_if_needed`
Both of the above methods will return the path to the installed binary on the
device. The executable should be invoked *only* via that path; do **not** assume
that it will be in ``PATH`` on the target (or that the executable with the same
name in ``PATH`` is the version deployed by WA.
.. code:: python
self.command = "{} -a -b -c".format(target_binary)
self.device.execute(self.command)
Parameters
----------
@@ -186,11 +239,11 @@ mandatory
and there really is no sensible default that could be given
(e.g. something like login credentials), should you consider
making it mandatory.
constraint
This is an additional constraint to be enforced on the parameter beyond
its type or fixed allowed values set. This should be a predicate (a function
that takes a single argument -- the user-supplied value -- and returns
its type or fixed allowed values set. This should be a predicate (a function
that takes a single argument -- the user-supplied value -- and returns
a ``bool`` indicating whether the constraint has been satisfied).
override
@@ -199,7 +252,7 @@ override
with the same name as already exists, you will get an error. If you do
want to override a parameter from further up in the inheritance
hierarchy, you can indicate that by setting ``override`` attribute to
``True``.
``True``.
When overriding, you do not need to specify every other attribute of the
parameter, just the ones you what to override. Values for the rest will
@@ -220,7 +273,7 @@ surrounding environment (e.g. that the device has been initialized).
The contract for ``validate`` method is that it should raise an exception
(either ``wlauto.exceptions.ConfigError`` or extension-specific exception type -- see
further on this page) if some validation condition has not, and cannot, been met.
further on this page) if some validation condition has not, and cannot, been met.
If the method returns without raising an exception, then the extension is in a
valid internal state.
@@ -240,7 +293,7 @@ everything it is doing, so you shouldn't need to add much additional logging in
your expansion's. But you might what to log additional information, e.g.
what settings your extension is using, what it is doing on the host, etc.
Operations on the host will not normally be logged, so your extension should
definitely log what it is doing on the host. One situation in particular where
definitely log what it is doing on the host. One situation in particular where
you should add logging is before doing something that might take a significant amount
of time, such as downloading a file.
@@ -257,7 +310,7 @@ Subsequent paragraphs (separated by blank lines) can then provide a more
detailed description, including any limitations and setup instructions.
For parameters, the description is passed as an argument on creation. Please
note that if ``default``, ``allowed_values``, or ``constraint``, are set in the
note that if ``default``, ``allowed_values``, or ``constraint``, are set in the
parameter, they do not need to be explicitly mentioned in the description (wa
documentation utilities will automatically pull those). If the ``default`` is set
in ``validate`` or additional cross-parameter constraints exist, this *should*
@@ -302,7 +355,7 @@ Utils
Workload Automation defines a number of utilities collected under
:mod:`wlauto.utils` subpackage. These utilities were created to help with the
implementation of the framework itself, but may be also be useful when
implementing extensions.
implementing extensions.
Adding a Workload
@@ -324,22 +377,31 @@ The Workload class defines the following interface::
def init_resources(self, context):
pass
def setup(self, context):
raise NotImplementedError()
def run(self, context):
raise NotImplementedError()
def update_result(self, context):
raise NotImplementedError()
def teardown(self, context):
raise NotImplementedError()
def validate(self):
pass
def initialize(self, context):
pass
def setup(self, context):
pass
def setup(self, context):
pass
def run(self, context):
pass
def update_result(self, context):
pass
def teardown(self, context):
pass
def finalize(self, context):
pass
.. note:: Please see :doc:`conventions` section for notes on how to interpret
this.
@@ -348,8 +410,23 @@ The interface should be implemented as follows
:name: This identifies the workload (e.g. it used to specify it in the
agenda_.
:init_resources: This method may be optionally override to implement dynamic
resource discovery for the workload.
**Added in version 2.1.3**
resource discovery for the workload. This method executes
early on, before the device has been initialized, so it
should only be used to initialize resources that do not
depend on the device to resolve. This method is executed
once per run for each workload instance.
:validate: This method can be used to validate any assumptions your workload
makes about the environment (e.g. that required files are
present, environment variables are set, etc) and should raise
a :class:`wlauto.exceptions.WorkloadError` if that is not the
case. The base class implementation only makes sure sure that
the name attribute has been set.
:initialize: This method will be executed exactly once per run (no matter
how many instances of the workload there are). It will run
after the device has been initialized, so it may be used to
perform device-dependent initialization that does not need to
be repeated on each iteration (e.g. as installing executables
required by the workload on the device).
:setup: Everything that needs to be in place for workload execution should
be done in this method. This includes copying files to the device,
starting up an application, configuring communications channels,
@@ -371,13 +448,11 @@ The interface should be implemented as follows
to the result (see below).
:teardown: This could be used to perform any cleanup you may wish to do,
e.g. Uninstalling applications, deleting file on the device, etc.
:finalize: This is the complement to ``initialize``. This will be executed
exactly once at the end of the run. This should be used to
perform any final clean up (e.g. uninstalling binaries installed
in the ``initialize``).
:validate: This method can be used to validate any assumptions your workload
makes about the environment (e.g. that required files are
present, environment variables are set, etc) and should raise
a :class:`wlauto.exceptions.WorkloadError` if that is not the
case. The base class implementation only makes sure sure that
the name attribute has been set.
.. _agenda: agenda.html
@@ -512,17 +587,17 @@ device name(case sensitive) then followed by a dot '.' then the stage name
then '.revent'. All your custom revent files should reside at
'~/.workload_automation/dependencies/WORKLOAD NAME/'. These are the current
supported stages:
:setup: This stage is where the game is loaded. It is a good place to
record revent here to modify the game settings and get it ready
to start.
:run: This stage is where the game actually starts. This will allow for
more accurate results if the revent file for this stage only
records the game being played.
For instance, to add a custom revent files for a device named mydevice and
a workload name mygame, you create a new directory called mygame in
'~/.workload_automation/dependencies/'. Then you add the revent files for
a workload name mygame, you create a new directory called mygame in
'~/.workload_automation/dependencies/'. Then you add the revent files for
the stages you want in ~/.workload_automation/dependencies/mygame/::
mydevice.setup.revent
@@ -531,7 +606,7 @@ the stages you want in ~/.workload_automation/dependencies/mygame/::
Any revent file in the dependencies will always overwrite the revent file in the
workload directory. So it is possible for example to just provide one revent for
setup in the dependencies and use the run.revent that is in the workload directory.
Adding an Instrument
====================
@@ -576,7 +651,7 @@ which is perhaps ``initialize`` that gets invoked after the device has been
initialised for the first time, and can be used to perform one-time setup (e.g.
copying files to the device -- there is no point in doing that for each
iteration). The full list of available methods can be found in
:ref:`Signals Documentation <instrument_name_mapping>`.
:ref:`Signals Documentation <instrumentation_method_map>`.
Prioritization
@@ -727,19 +802,19 @@ table::
with open(outfile, 'w') as wfh:
write_table(rows, wfh)
Adding a Resource Getter
========================
A resource getter is a new extension type added in version 2.1.3. A resource
getter implement a method of acquiring resources of a particular type (such as
APK files or additional workload assets). Resource getters are invoked in
priority order until one returns the desired resource.
priority order until one returns the desired resource.
If you want WA to look for resources somewhere it doesn't by default (e.g. you
have a repository of APK files), you can implement a getter for the resource and
register it with a higher priority than the standard WA getters, so that it gets
invoked first.
invoked first.
Instances of a resource getter should implement the following interface::
@@ -751,7 +826,7 @@ Instances of a resource getter should implement the following interface::
def get(self, resource, **kwargs):
raise NotImplementedError()
The getter should define a name (as with all extensions), a resource
type, which should be a string, e.g. ``'jar'``, and a priority (see `Getter
Prioritization`_ below). In addition, ``get`` method should be implemented. The
@@ -823,7 +898,7 @@ looks for the file under
elif not found_files:
return None
else:
raise ResourceError('More than one .apk found in {} for {}.'.format(resource_dir,
raise ResourceError('More than one .apk found in {} for {}.'.format(resource_dir,
resource.owner.name))
.. _adding_a_device:
@@ -923,7 +998,7 @@ top-level package directory is created by default, and it is OK to have
everything in there.
.. note:: When discovering extensions thorugh this mechanism, WA traveries the
Python module/submodule tree, not the directory strucuter, therefore,
Python module/submodule tree, not the directory strucuter, therefore,
if you are going to create subdirectories under the top level dictory
created for you, it is important that your make sure they are valid
Python packages; i.e. each subdirectory must contain a __init__.py
@@ -934,7 +1009,7 @@ At this stage, you may want to edit ``params`` structure near the bottom of
the ``setup.py`` to add correct author, license and contact information (see
"Writing the Setup Script" section in standard Python documentation for
details). You may also want to add a README and/or a COPYING file at the same
level as the setup.py. Once you have the contents of your package sorted,
level as the setup.py. Once you have the contents of your package sorted,
you can generate the package by running ::
cd my_wa_exts

View File

@@ -16,7 +16,7 @@
#
[MASTER]
profile=no
#profile=no
ignore=external
@@ -41,7 +41,9 @@ ignore=external
# https://bitbucket.org/logilab/pylint/issue/272/anomalous-backslash-in-string-for-raw
# C0330: bad continuation, due to:
# https://bitbucket.org/logilab/pylint/issue/232/wrong-hanging-indentation-false-positive
disable=C0301,C0103,C0111,W0142,R0903,R0904,R0922,W0511,W0141,I0011,R0921,W1401,C0330
# TODO: disabling no-value-for-parameter and logging-format-interpolation, as they appear to be broken
# in version 1.4.1 and return a lot of false postives; should be re-enabled once fixed.
disable=C0301,C0103,C0111,W0142,R0903,R0904,R0922,W0511,W0141,I0011,R0921,W1401,C0330,no-value-for-parameter,logging-format-interpolation
[FORMAT]
max-module-lines=4000

17
scripts/cpustates Normal file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env python
# Copyright 2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from wlauto.utils.power import main
main()

View File

@@ -1,17 +1,17 @@
#!/bin/bash
# $Copyright:
# ----------------------------------------------------------------
# This confidential and proprietary software may be used only as
# authorised by a licensing agreement from ARM Limited
# (C) COPYRIGHT 2013 ARM Limited
# ALL RIGHTS RESERVED
# The entire notice above must be reproduced on all authorised
# copies and copies may only be made to the extent permitted
# by a licensing agreement from ARM Limited.
# ----------------------------------------------------------------
# File: create_workload
# ----------------------------------------------------------------
# $
# Copyright 2013-2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
wa create workload $@

View File

@@ -1,16 +1,16 @@
#!/bin/bash
# $Copyright:
# ----------------------------------------------------------------
# This confidential and proprietary software may be used only as
# authorised by a licensing agreement from ARM Limited
# (C) COPYRIGHT 2013 ARM Limited
# ALL RIGHTS RESERVED
# The entire notice above must be reproduced on all authorised
# copies and copies may only be made to the extent permitted
# by a licensing agreement from ARM Limited.
# ----------------------------------------------------------------
# File: list_extensions
# ----------------------------------------------------------------
# $
# Copyright 2013-2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
wa list $@

View File

@@ -1,17 +1,17 @@
#!/bin/bash
# $Copyright:
# ----------------------------------------------------------------
# This confidential and proprietary software may be used only as
# authorised by a licensing agreement from ARM Limited
# (C) COPYRIGHT 2013 ARM Limited
# ALL RIGHTS RESERVED
# The entire notice above must be reproduced on all authorised
# copies and copies may only be made to the extent permitted
# by a licensing agreement from ARM Limited.
# ----------------------------------------------------------------
# File: run_workloads
# ----------------------------------------------------------------
# $
# Copyright 2013-2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
wa run $@

View File

@@ -1,17 +1,17 @@
#!/usr/bin/env python
# $Copyright:
# ----------------------------------------------------------------
# This confidential and proprietary software may be used only as
# authorised by a licensing agreement from ARM Limited
# (C) COPYRIGHT 2013 ARM Limited
# ALL RIGHTS RESERVED
# The entire notice above must be reproduced on all authorised
# copies and copies may only be made to the extent permitted
# by a licensing agreement from ARM Limited.
# ----------------------------------------------------------------
# File: run_workloads
# ----------------------------------------------------------------
# $
# Copyright 2013-2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from wlauto.core.entry_point import main
main()

View File

@@ -23,7 +23,10 @@ try:
except ImportError:
from distutils.core import setup
sys.path.insert(0, './wlauto/core/')
wlauto_dir = os.path.join(os.path.dirname(__file__), 'wlauto')
sys.path.insert(0, os.path.join(wlauto_dir, 'core'))
from version import get_wa_version
# happends if falling back to distutils
@@ -38,7 +41,7 @@ except OSError:
packages = []
data_files = {}
source_dir = os.path.dirname(__file__)
for root, dirs, files in os.walk('wlauto'):
for root, dirs, files in os.walk(wlauto_dir):
rel_dir = os.path.relpath(root, source_dir)
data = []
if '__init__.py' in files:
@@ -63,7 +66,7 @@ params = dict(
packages=packages,
package_data=data_files,
scripts=scripts,
url='N/A',
url='http://github.com/arm-sowftware/workload-automation',
license='Apache v2',
maintainer='ARM Architecture & Technology Device Lab',
maintainer_email='workload-automation@arm.com',
@@ -73,11 +76,14 @@ params = dict(
'pyserial', # Serial port interface
'colorama', # Printing with colors
'pyYAML', # YAML-formatted agenda parsing
'requests', # Fetch assets over HTTP
],
extras_require={
'other': ['jinja2', 'pandas>=0.13.1'],
'statedetect': ['numpy', 'imutils', 'opencv-python'],
'test': ['nose'],
'mongodb': ['pymongo'],
'notify': ['notify2'],
'doc': ['sphinx'],
},
# https://pypi.python.org/pypi?%3Aaction=list_classifiers

View File

@@ -29,7 +29,7 @@ from wlauto.common.linux.device import LinuxDevice # NOQA
from wlauto.common.android.device import AndroidDevice, BigLittleDevice # NOQA
from wlauto.common.android.resources import ApkFile, JarFile
from wlauto.common.android.workload import (UiAutomatorWorkload, ApkWorkload, AndroidBenchmark, # NOQA
AndroidUiAutoBenchmark, GameWorkload) # NOQA
AndroidUiAutoBenchmark, AndroidUxPerfWorkload, GameWorkload) # NOQA
from wlauto.core.version import get_wa_version

View File

@@ -1,6 +1,6 @@
# This agenda specifies configuration that may be used for regression runs
# on big.LITTLE systems. This agenda will with a TC2 device configured as
# described in the documentation.
# on big.LITTLE systems. This agenda will work with a TC2 device configured
# as described in the documentation.
config:
device: tc2
run_name: big.LITTLE_regression
@@ -69,7 +69,7 @@ workloads:
- id: b10
name: smartbench
- id: b11
name: sqlite
name: sqlitebm
- id: b12
name: vellamo

View File

@@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

View File

@@ -15,15 +15,20 @@
import os
import sys
import stat
import string
import textwrap
import argparse
import shutil
import getpass
import subprocess
from collections import OrderedDict
import yaml
from wlauto import ExtensionLoader, Command, settings
from wlauto.exceptions import CommandError
from wlauto.exceptions import CommandError, ConfigError
from wlauto.utils.cli import init_argument_parser
from wlauto.utils.misc import (capitalize, check_output,
ensure_file_directory_exists as _f, ensure_directory_exists as _d)
@@ -169,15 +174,105 @@ class CreatePackageSubcommand(CreateSubcommand):
touch(os.path.join(actual_package_path, '__init__.py'))
class CreateAgendaSubcommand(CreateSubcommand):
name = 'agenda'
description = """
Create an agenda whith the specified extensions enabled. And parameters set to their
default values.
"""
def initialize(self):
self.parser.add_argument('extensions', nargs='+',
help='Extensions to be added')
self.parser.add_argument('-i', '--iterations', type=int, default=1,
help='Sets the number of iterations for all workloads')
self.parser.add_argument('-r', '--include-runtime-params', action='store_true',
help="""
Adds runtime parameters to the global section of the generated
agenda. Note: these do not have default values, so only name
will be added. Also, runtime parameters are devices-specific, so
a device must be specified (either in the list of extensions,
or in the existing config).
""")
self.parser.add_argument('-o', '--output', metavar='FILE',
help='Output file. If not specfied, STDOUT will be used instead.')
def execute(self, args): # pylint: disable=no-self-use,too-many-branches,too-many-statements
loader = ExtensionLoader(packages=settings.extension_packages,
paths=settings.extension_paths)
agenda = OrderedDict()
agenda['config'] = OrderedDict(instrumentation=[], result_processors=[])
agenda['global'] = OrderedDict(iterations=args.iterations)
agenda['workloads'] = []
device = None
device_config = None
for name in args.extensions:
extcls = loader.get_extension_class(name)
config = loader.get_default_config(name)
del config['modules']
if extcls.kind == 'workload':
entry = OrderedDict()
entry['name'] = extcls.name
if name != extcls.name:
entry['label'] = name
entry['params'] = config
agenda['workloads'].append(entry)
elif extcls.kind == 'device':
if device is not None:
raise ConfigError('Specifying multiple devices: {} and {}'.format(device.name, name))
device = extcls
device_config = config
agenda['config']['device'] = name
agenda['config']['device_config'] = config
else:
if extcls.kind == 'instrument':
agenda['config']['instrumentation'].append(name)
if extcls.kind == 'result_processor':
agenda['config']['result_processors'].append(name)
agenda['config'][name] = config
if args.include_runtime_params:
if not device:
if settings.device:
device = loader.get_extension_class(settings.device)
device_config = loader.get_default_config(settings.device)
else:
raise ConfigError('-r option requires for a device to be in the list of extensions')
rps = OrderedDict()
for rp in device.runtime_parameters:
if hasattr(rp, 'get_runtime_parameters'):
# a core parameter needs to be expanded for each of the
# device's cores, if they're avialable
for crp in rp.get_runtime_parameters(device_config.get('core_names', [])):
rps[crp.name] = None
else:
rps[rp.name] = None
agenda['global']['runtime_params'] = rps
if args.output:
wfh = open(args.output, 'w')
else:
wfh = sys.stdout
yaml.dump(agenda, wfh, indent=4, default_flow_style=False)
if args.output:
wfh.close()
class CreateCommand(Command):
name = 'create'
description = '''Used to create various WA-related objects (see positional arguments list for what
objects may be created).\n\nUse "wa create <object> -h" for object-specific arguments.'''
formatter_class = argparse.RawDescriptionHelpFormatter
subcmd_classes = [CreateWorkloadSubcommand, CreatePackageSubcommand]
subcmd_classes = [
CreateWorkloadSubcommand,
CreatePackageSubcommand,
CreateAgendaSubcommand,
]
def initialize(self):
def initialize(self, context):
subparsers = self.parser.add_subparsers(dest='what')
self.subcommands = [] # pylint: disable=W0201
for subcmd_cls in self.subcmd_classes:
@@ -257,7 +352,12 @@ def create_uiauto_project(path, name, target='1'):
package_name,
target,
path)
check_output(command, shell=True)
try:
check_output(command, shell=True)
except subprocess.CalledProcessError as e:
if 'is is not valid' in e.output:
message = 'No Android SDK target found; have you run "{} update sdk" and download a platform?'
raise CommandError(message.format(android_path))
build_script = os.path.join(path, 'build.sh')
with open(build_script, 'w') as wfh:
@@ -296,5 +396,5 @@ def render_template(name, params):
def touch(path):
with open(path, 'w') as wfh: # pylint: disable=unused-variable
with open(path, 'w') as _:
pass

View File

@@ -0,0 +1,122 @@
# Copyright 2014-2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import sys
import argparse
from requests import ConnectionError, RequestException
from wlauto import File, ExtensionLoader, Command, settings
from wlauto.core.extension import Extension
REMOTE_ASSETS_URL = 'https://github.com/ARM-software/workload-automation-assets/raw/master/dependencies'
class GetAssetsCommand(Command):
name = 'get-assets'
description = '''
This command downloads external extension dependencies used by Workload Automation.
Works by first downloading a directory index of the assets, then iterating through
it to get assets for the specified extensions.
'''
# Uses config setting if available otherwise defaults to ARM-software repo
# Can be overriden with the --url argument
assets_url = settings.remote_assets_url or REMOTE_ASSETS_URL
def initialize(self, context):
self.parser.add_argument('-f', '--force', action='store_true',
help='Always fetch the assets, even if matching versions exist in local cache.')
self.parser.add_argument('--url', metavar='URL', type=not_empty, default=self.assets_url,
help='''The location from which to download the files. If not provided,
config setting ``remote_assets_url`` will be used if available, else
uses the default REMOTE_ASSETS_URL parameter in the script.''')
group = self.parser.add_mutually_exclusive_group(required=True)
group.add_argument('-a', '--all', action='store_true',
help='Download assets for all extensions found in the index. Cannot be used with -e.')
group.add_argument('-e', dest='exts', metavar='EXT', nargs='+', type=not_empty,
help='One or more extensions whose assets to download. Cannot be used with --all.')
def execute(self, args):
self.logger.debug('Program arguments: {}'.format(vars(args)))
if args.force:
self.logger.info('Force-download of assets requested')
if not args.url:
self.logger.debug('URL not provided, falling back to default setting in config')
self.logger.info('Downloading external assets from {}'.format(args.url))
# Get file index of assets
ext_loader = ExtensionLoader(packages=settings.extension_packages, paths=settings.extension_paths)
getter = ext_loader.get_resource_getter('http_assets', None, url=args.url, always_fetch=args.force)
try:
getter.index = getter.fetch_index()
except (ConnectionError, RequestException) as e:
self.exit_with_error(str(e))
all_assets = dict()
for k, v in getter.index.iteritems():
all_assets[str(k)] = [str(asset['path']) for asset in v]
# Here we get a list of all extensions present in the current WA installation,
# and cross-check that against the list of extensions whose assets are requested.
# The aim is to avoid downloading assets for extensions that do not exist, since
# WA extensions and asset index can be updated independently and go out of sync.
all_extensions = [ext.name for ext in ext_loader.list_extensions()]
assets_to_get = set(all_assets).intersection(all_extensions)
if args.exts:
assets_to_get = assets_to_get.intersection(args.exts)
# Check list is not empty
if not assets_to_get:
if args.all:
self.exit_with_error('Could not find extensions: {}'.format(', '.join(all_assets.keys())))
else: # args.exts
self.exit_with_error('Asset index has no entries for: {}'.format(', '.join(args.exts)))
# Check out of sync extensions i.e. do not exist in both WA and assets index
missing = set(all_assets).difference(all_extensions) | set(args.exts or []).difference(all_assets)
if missing:
self.logger.warning('Not getting assets for missing extensions: {}'.format(', '.join(missing)))
# Ideally the extension loader would be used to instantiate, but it does full
# validation of the extension, like checking connected devices or supported
# platform(s). This info might be unavailable and is not required to download
# assets, since they are classified by extension name alone. So instead we use
# a simple subclass of ``Extension`` providing a valid ``name`` attribute.
for ext_name in assets_to_get:
owner = _instantiate(NamedExtension, ext_name)
self.logger.info('Getting assets for: {}'.format(ext_name))
for asset in all_assets[ext_name]:
getter.get(File(owner, asset)) # Download the files
def exit_with_error(self, message, code=1):
self.logger.error(message)
sys.exit(code)
class NamedExtension(Extension):
def __init__(self, name, **kwargs):
super(NamedExtension, self).__init__(**kwargs)
self.name = name
def not_empty(val):
if val:
return val
else:
raise argparse.ArgumentTypeError('Extension name cannot be blank')
def _instantiate(cls, *args, **kwargs):
return cls(*args, **kwargs)

View File

@@ -24,22 +24,33 @@ class ListCommand(Command):
name = 'list'
description = 'List available WA extensions with a short description of each.'
def initialize(self):
def initialize(self, context):
extension_types = ['{}s'.format(ext.name) for ext in settings.extensions]
self.parser.add_argument('kind', metavar='KIND',
help=('Specify the kind of extension to list. Must be '
'one of: {}'.format(', '.join(extension_types))),
choices=extension_types)
self.parser.add_argument('-n', '--name', help='Filter results by the name specified')
self.parser.add_argument('-o', '--packaged-only', action='store_true',
help='''
Only list extensions packaged with WA itself. Do not list extensions
installed locally or from other packages.
''')
self.parser.add_argument('-p', '--platform', help='Only list results that are supported by '
'the specified platform')
def execute(self, args):
filters = {}
if args.name:
filters['name'] = args.name
ext_loader = ExtensionLoader(packages=settings.extension_packages, paths=settings.extension_paths)
if args.packaged_only:
ext_loader = ExtensionLoader()
else:
ext_loader = ExtensionLoader(packages=settings.extension_packages,
paths=settings.extension_paths)
results = ext_loader.list_extensions(args.kind[:-1])
if filters:
if filters or args.platform:
filtered_results = []
for result in results:
passed = True
@@ -47,6 +58,8 @@ class ListCommand(Command):
if getattr(result, k) != v:
passed = False
break
if passed and args.platform:
passed = check_platform(result, args.platform)
if passed:
filtered_results.append(result)
else: # no filters specified
@@ -57,3 +70,10 @@ class ListCommand(Command):
for result in sorted(filtered_results, key=lambda x: x.name):
output.add_item(get_summary(result), result.name)
print output.format_data()
def check_platform(extension, platform):
supported_platforms = getattr(extension, 'supported_platforms', [])
if supported_platforms:
return platform in supported_platforms
return True

223
wlauto/commands/record.py Normal file
View File

@@ -0,0 +1,223 @@
# Copyright 2014-2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import os
import sys
import signal
from math import ceil
from wlauto import ExtensionLoader, Command, settings
from wlauto.common.resources import Executable
from wlauto.core.resource import NO_ONE
from wlauto.core.resolver import ResourceResolver
from wlauto.core.configuration import RunConfiguration
from wlauto.core.agenda import Agenda
from wlauto.utils.revent import ReventRecording, GAMEPAD_MODE
class ReventCommand(Command):
# Validate command options
def validate_args(self, args):
if args.clear and not args.package:
print "Package must be specified if you want to clear cache\n"
self.parser.print_help()
sys.exit()
# pylint: disable=W0201
def execute(self, args):
self.validate_args(args)
self.logger.info("Connecting to device...")
ext_loader = ExtensionLoader(packages=settings.extension_packages,
paths=settings.extension_paths)
# Setup config
self.config = RunConfiguration(ext_loader)
for filepath in settings.get_config_paths():
self.config.load_config(filepath)
self.config.set_agenda(Agenda())
self.config.finalize()
context = LightContext(self.config)
# Setup device
self.device = ext_loader.get_device(settings.device, **settings.device_config)
self.device.validate()
self.device.dynamic_modules = []
self.device.connect()
self.device.initialize(context)
# Only install vsync service on android
if self.device.platform is 'android':
self.logger.debug("Installing HelloJni for vsync service")
host_HelloJni_apk = context.resolver.get(Executable(NO_ONE, self.device.abi, 'HelloJni.apk'))
self.target_HelloJni = self.device.install_if_needed(host_HelloJni_apk)
result = self.device.execute('dumpsys activity services | grep "ChoreoService"', check_exit_code=False)
if not result or 'com.example.hellojni/.ChoreoService' not in result:
self.device.execute('am startservice com.example.hellojni/.ChoreoService')
# Install revent
host_binary = context.resolver.get(Executable(NO_ONE, self.device.abi, 'revent'))
self.target_binary = self.device.install_executable(host_binary)
self.run(args)
def run(self, args):
raise NotImplementedError()
class RecordCommand(ReventCommand):
name = 'record'
description = '''Performs a revent recording
This command helps making revent recordings. It will automatically
deploy revent and even has the option of automatically opening apps.
Revent allows you to record raw inputs such as screen swipes or button presses.
This can be useful for recording inputs for workloads such as games that don't
have XML UI layouts that can be used with UIAutomator. As a drawback from this,
revent recordings are specific to the device type they were recorded on.
WA uses two parts to the names of revent recordings in the format,
{device_name}.{suffix}.revent.
- device_name can either be specified manually with the ``-d`` argument or
it can be automatically determined. On Android device it will be obtained
from ``build.prop``, on Linux devices it is obtained from ``/proc/device-tree/model``.
- suffix is used by WA to determine which part of the app execution the
recording is for, currently these are either ``setup`` or ``run``. This
should be specified with the ``-s`` argument.
**gamepad recording**
revent supports an alternative recording mode, where it will record events
from a single gamepad device. In this mode, revent will store the
description of this device as a part of the recording. When replaying such
a recording, revent will first create a virtual gamepad using the
description, and will replay the events into it, so a physical controller
does not need to be connected on replay. Unlike standard revent recordings,
recordings generated in this mode should be (to an extent) portable across
different devices.
note:
- The device on which a recording is being made in gamepad mode, must have
exactly one gamepad connected to it.
- The device on which a gamepad recording is being replayed must have
/dev/uinput enabled in the kernel (this interface is necessary to create
virtual gamepad).
'''
def initialize(self, context):
self.context = context
self.parser.add_argument('-d', '--device', help='The name of the device')
self.parser.add_argument('-s', '--suffix', help='The suffix of the revent file, e.g. ``setup``')
self.parser.add_argument('-o', '--output', help='Directory to save the recording in')
self.parser.add_argument('-p', '--package', help='Package to launch before recording')
self.parser.add_argument('-g', '--gamepad', help='Record from a gamepad rather than all devices.',
action="store_true")
self.parser.add_argument('-C', '--clear', help='Clear app cache before launching it',
action="store_true")
self.parser.add_argument('-S', '--capture-screen', help='Record a screen capture after recording',
action="store_true")
def run(self, args):
if args.device:
device_name = args.device
else:
device_name = self.device.get_device_model()
if args.suffix:
args.suffix += "."
revent_file = self.device.path.join(self.device.working_directory,
'{}.{}revent'.format(device_name, args.suffix or ""))
if args.clear:
self.device.execute("pm clear {}".format(args.package))
if args.package:
self.logger.info("Starting {}".format(args.package))
self.device.execute('monkey -p {} -c android.intent.category.LAUNCHER 1'.format(args.package))
self.logger.info("Press Enter when you are ready to record...")
raw_input("")
gamepad_flag = '-g ' if args.gamepad else ''
vsync_flag = '-V ' if self.device.platform is 'android' else ''
command = "{} record {}{}-s {}".format(self.target_binary, gamepad_flag, vsync_flag, revent_file)
self.device.kick_off(command)
self.logger.info("Press Enter when you have finished recording...")
raw_input("")
if args.capture_screen:
self.logger.info("Recording screen capture")
self.device.capture_screen(args.output or os.getcwdu())
self.device.killall("revent", signal.SIGINT)
self.logger.info("Waiting for revent to finish")
while self.device.get_pids_of("revent"):
pass
self.logger.info("Pulling files from device")
self.device.pull_file(revent_file, args.output or os.getcwdu())
class ReplayCommand(ReventCommand):
name = 'replay'
description = '''Replay a revent recording
Revent allows you to record raw inputs such as screen swipes or button presses.
See ``wa show record`` to see how to make an revent recording.
'''
def initialize(self, context):
self.context = context
self.parser.add_argument('revent', help='The name of the file to replay')
self.parser.add_argument('-p', '--package', help='Package to launch before recording')
self.parser.add_argument('-C', '--clear', help='Clear app cache before launching it',
action="store_true")
# pylint: disable=W0201
def run(self, args):
self.logger.info("Pushing file to device")
self.device.push_file(args.revent, self.device.working_directory)
revent_file = self.device.path.join(self.device.working_directory, os.path.split(args.revent)[1])
if args.clear:
self.device.execute("pm clear {}".format(args.package))
if args.package:
self.logger.info("Starting {}".format(args.package))
self.device.execute('monkey -p {} -c android.intent.category.LAUNCHER 1'.format(args.package))
self.logger.info("Replaying recording")
vsync_flag = '-V ' if self.device.platform is 'android' else ''
command = "{} replay {}{}".format(self.target_binary, vsync_flag, revent_file)
recording = ReventRecording(args.revent)
timeout = ceil(recording.duration) + 30
recording.close()
self.device.execute(command, timeout=timeout,
as_root=(recording.mode == GAMEPAD_MODE))
self.logger.info("Finished replay")
# Used to satisfy the API
class LightContext(object):
def __init__(self, config):
self.resolver = ResourceResolver(config)
self.resolver.load()

View File

@@ -20,6 +20,7 @@ import shutil
import wlauto
from wlauto import Command, settings
from wlauto.exceptions import ConfigError
from wlauto.core.agenda import Agenda
from wlauto.core.execution import Executor
from wlauto.utils.log import add_log_file
@@ -30,24 +31,43 @@ class RunCommand(Command):
name = 'run'
description = 'Execute automated workloads on a remote device and process the resulting output.'
def initialize(self):
def initialize(self, context):
self.parser.add_argument('agenda', metavar='AGENDA',
help='Agenda for this workload automation run. This defines which workloads will ' +
'be executed, how many times, with which tunables, etc. ' +
'See example agendas in {} '.format(os.path.dirname(wlauto.__file__)) +
'for an example of how this file should be structured.')
help="""
Agenda for this workload automation run. This defines which
workloads will be executed, how many times, with which
tunables, etc. See example agendas in {} for an example of
how this file should be structured.
""".format(os.path.dirname(wlauto.__file__)))
self.parser.add_argument('-d', '--output-directory', metavar='DIR', default=None,
help='Specify a directory where the output will be generated. If the directory' +
'already exists, the script will abort unless -f option (see below) is used,' +
'in which case the contents of the directory will be overwritten. If this option' +
'is not specified, then {} will be used instead.'.format(settings.output_directory))
help="""
Specify a directory where the output will be generated. If
the directory already exists, the script will abort unless -f
option (see below) is used, in which case the contents of the
directory will be overwritten. If this option is not specified,
then {} will be used instead.
""".format(settings.output_directory))
self.parser.add_argument('-f', '--force', action='store_true',
help='Overwrite output directory if it exists. By default, the script will abort in this' +
'situation to prevent accidental data loss.')
help="""
Overwrite output directory if it exists. By default, the script
will abort in this situation to prevent accidental data loss.
""")
self.parser.add_argument('-i', '--id', action='append', dest='only_run_ids', metavar='ID',
help='Specify a workload spec ID from an agenda to run. If this is specified, only that particular ' +
'spec will be run, and other workloads in the agenda will be ignored. This option may be used to ' +
'specify multiple IDs.')
help="""
Specify a workload spec ID from an agenda to run. If this is
specified, only that particular spec will be run, and other
workloads in the agenda will be ignored. This option may be
used to specify multiple IDs.
""")
self.parser.add_argument('--disable', action='append', dest='instruments_to_disable',
metavar='INSTRUMENT', help="""
Specify an instrument to disable from the command line. This
equivalent to adding "~{metavar}" to the instrumentation list in
the agenda. This can be used to temporarily disable a troublesome
instrument for a particular run without introducing permanent
change to the config (which one might then forget to revert).
This option may be specified multiple times.
""")
def execute(self, args): # NOQA
self.set_up_output_directory(args)
@@ -57,14 +77,28 @@ class RunCommand(Command):
agenda = Agenda(args.agenda)
settings.agenda = args.agenda
shutil.copy(args.agenda, settings.meta_directory)
if len(agenda.workloads) == 0:
raise ConfigError("No workloads specified")
elif '.' in args.agenda or os.sep in args.agenda:
raise ConfigError('Agenda "{}" does not exist.'.format(args.agenda))
else:
self.logger.debug('{} is not a file; assuming workload name.'.format(args.agenda))
agenda = Agenda()
agenda.add_workload_entry(args.agenda)
file_name = 'config_{}.py'
if args.instruments_to_disable:
if 'instrumentation' not in agenda.config:
agenda.config['instrumentation'] = []
for itd in args.instruments_to_disable:
self.logger.debug('Updating agenda to disable {}'.format(itd))
agenda.config['instrumentation'].append('~{}'.format(itd))
basename = 'config_'
for file_number, path in enumerate(settings.get_config_paths(), 1):
shutil.copy(path, os.path.join(settings.meta_directory, file_name.format(file_number)))
file_ext = os.path.splitext(path)[1]
shutil.copy(path, os.path.join(settings.meta_directory,
basename + str(file_number) + file_ext))
executor = Executor()
executor.execute(agenda, selectors={'ids': args.only_run_ids})

View File

@@ -18,11 +18,11 @@ import sys
import subprocess
from cStringIO import StringIO
from terminalsize import get_terminal_size # pylint: disable=import-error
from wlauto import Command, ExtensionLoader, settings
from wlauto.utils.doc import (get_summary, get_description, get_type_name, format_column, format_body,
format_paragraph, indent, strip_inlined_text)
from wlauto.utils.misc import get_pager
from wlauto.utils.terminalsize import get_terminal_size
class ShowCommand(Command):
@@ -33,12 +33,13 @@ class ShowCommand(Command):
Display documentation for the specified extension (workload, instrument, etc.).
"""
def initialize(self):
def initialize(self, context):
self.parser.add_argument('name', metavar='EXTENSION',
help='''The name of the extension for which information will
be shown.''')
def execute(self, args):
# pylint: disable=unpacking-non-sequence
ext_loader = ExtensionLoader(packages=settings.extension_packages, paths=settings.extension_paths)
extension = ext_loader.get_extension_class(args.name)
out = StringIO()
@@ -47,8 +48,12 @@ class ShowCommand(Command):
text = out.getvalue()
pager = get_pager()
if len(text.split('\n')) > term_height and pager:
sp = subprocess.Popen(pager, stdin=subprocess.PIPE)
sp.communicate(text)
try:
sp = subprocess.Popen(pager, stdin=subprocess.PIPE)
sp.communicate(text)
except OSError:
self.logger.warning('Could not use PAGER "{}"'.format(pager))
sys.stdout.write(text)
else:
sys.stdout.write(text)
@@ -58,6 +63,9 @@ def format_extension(extension, out, width):
out.write('\n')
format_extension_summary(extension, out, width)
out.write('\n')
if hasattr(extension, 'supported_platforms'):
format_supported_platforms(extension, out, width)
out.write('\n')
if extension.parameters:
format_extension_parameters(extension, out, width)
out.write('\n')
@@ -72,6 +80,11 @@ def format_extension_summary(extension, out, width):
out.write('{}\n'.format(format_body(strip_inlined_text(get_summary(extension)), width)))
def format_supported_platforms(extension, out, width):
text = 'supported on: {}'.format(', '.join(extension.supported_platforms))
out.write('{}\n'.format(format_body(text, width)))
def format_extension_description(extension, out, width):
# skip the initial paragraph of multi-paragraph description, as already
# listed above.
@@ -93,9 +106,8 @@ def format_extension_parameters(extension, out, width, shift=4):
param_text += indent('allowed values: {}\n'.format(', '.join(map(str, param.allowed_values))))
elif param.constraint:
param_text += indent('constraint: {}\n'.format(get_type_name(param.constraint)))
if param.default:
if param.default is not None:
param_text += indent('default: {}\n'.format(param.default))
param_texts.append(indent(param_text, shift))
out.write(format_column('\n'.join(param_texts), width))

View File

@@ -14,7 +14,7 @@ class ${class_name}(AndroidBenchmark):
parameters = [
# Workload parameters go here e.g.
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
Parameter('example_parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
description='This is an example parameter')
]

View File

@@ -14,7 +14,7 @@ class ${class_name}(AndroidUiAutoBenchmark):
parameters = [
# Workload parameters go here e.g.
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
Parameter('example_parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
description='This is an example parameter')
]

View File

@@ -8,7 +8,7 @@ class ${class_name}(Workload):
parameters = [
# Workload parameters go here e.g.
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
Parameter('example_parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
description='This is an example parameter')
]

View File

@@ -8,7 +8,7 @@ class ${class_name}(UiAutomatorWorkload):
parameters = [
# Workload parameters go here e.g.
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
Parameter('example_parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
description='This is an example parameter')
]

View File

@@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

View File

@@ -21,18 +21,23 @@ import time
import tempfile
import shutil
import threading
import json
import xml.dom.minidom
from subprocess import CalledProcessError
from wlauto.core.extension import Parameter
from wlauto.common.linux.device import BaseLinuxDevice
from wlauto.common.resources import Executable
from wlauto.core.resource import NO_ONE
from wlauto.common.linux.device import BaseLinuxDevice, PsEntry
from wlauto.exceptions import DeviceError, WorkerThreadError, TimeoutError, DeviceNotRespondingError
from wlauto.utils.misc import convert_new_lines
from wlauto.utils.misc import convert_new_lines, ABI_MAP
from wlauto.utils.types import boolean, regex
from wlauto.utils.android import (adb_shell, adb_background_shell, adb_list_devices,
adb_command, AndroidProperties, ANDROID_VERSION_MAP)
SCREEN_STATE_REGEX = re.compile('(?:mPowerState|mScreenOn)=([0-9]+|true|false)', re.I)
SCREEN_STATE_REGEX = re.compile('(?:mPowerState|mScreenOn|Display Power: state)=([0-9]+|true|false|ON|OFF)', re.I)
SCREEN_SIZE_REGEX = re.compile(r'mUnrestrictedScreen=\(\d+,\d+\)\s+(?P<width>\d+)x(?P<height>\d+)')
class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
@@ -46,11 +51,10 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
parameters = [
Parameter('adb_name',
description='The unique ID of the device as output by "adb devices".'),
Parameter('android_prompt', kind=regex, default=re.compile('^.*(shell|root)@.*:/ [#$] ', re.MULTILINE),
Parameter('android_prompt', kind=regex, default=re.compile('^.*(shell|root)@.*:/\S* [#$] ', re.MULTILINE),
description='The format of matching the shell prompt in Android.'),
Parameter('working_directory', default='/sdcard/wa-working',
description='Directory that will be used WA on the device for output files etc.'),
Parameter('binaries_directory', default='/system/bin',
Parameter('working_directory', default='/sdcard/wa-working', override=True),
Parameter('binaries_directory', default='/data/local/tmp/wa-bin', override=True,
description='Location of binaries on the device.'),
Parameter('package_data_directory', default='/data/data',
description='Location of of data for an installed package (APK).'),
@@ -71,6 +75,12 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
Specified whether the device should make sure that the screen is on
during initialization.
"""),
Parameter('swipe_to_unlock', kind=str, default=None,
allowed_values=[None, "horizontal", "vertical"],
description="""
If set a swipe of the specified direction will be performed.
This should unlock the screen.
"""),
]
default_timeout = 30
@@ -98,19 +108,34 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
@property
def abi(self):
return self.getprop()['ro.product.cpu.abi'].split('-')[0]
val = self.getprop()['ro.product.cpu.abi'].split('-')[0]
for abi, architectures in ABI_MAP.iteritems():
if val in architectures:
return abi
return val
@property
def supported_eabi(self):
def supported_abi(self):
props = self.getprop()
result = [props['ro.product.cpu.abi']]
if 'ro.product.cpu.abi2' in props:
result.append(props['ro.product.cpu.abi2'])
if 'ro.product.cpu.abilist' in props:
for eabi in props['ro.product.cpu.abilist'].split(','):
if eabi not in result:
result.append(eabi)
return result
for abi in props['ro.product.cpu.abilist'].split(','):
if abi not in result:
result.append(abi)
mapped_result = []
for supported_abi in result:
for abi, architectures in ABI_MAP.iteritems():
found = False
if supported_abi in architectures and abi not in mapped_result:
mapped_result.append(abi)
found = True
break
if not found and supported_abi not in mapped_result:
mapped_result.append(supported_abi)
return mapped_result
def __init__(self, **kwargs):
super(AndroidDevice, self).__init__(**kwargs)
@@ -126,8 +151,11 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
self._is_ready = False
self._just_rebooted = True
def boot(self, **kwargs):
self.reset()
def boot(self, hard=False, **kwargs):
if hard:
self.hard_reset()
else:
self.reset()
def connect(self): # NOQA pylint: disable=R0912
iteration_number = 0
@@ -155,7 +183,7 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
raise DeviceError('Could not boot {} ({}).'.format(self.name, self.adb_name))
while iteration_number < max_iterations:
available = (1 == int('0' + adb_shell(self.adb_name, 'getprop sys.boot_completed', timeout=self.default_timeout)))
available = (int('0' + (adb_shell(self.adb_name, 'getprop sys.boot_completed', timeout=self.default_timeout))) == 1)
if available:
break
else:
@@ -182,18 +210,13 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
self._just_rebooted = False
self._is_ready = True
def initialize(self, context, *args, **kwargs):
self.execute('mkdir -p {}'.format(self.working_directory))
def initialize(self, context):
self.sqlite = self.deploy_sqlite3(context) # pylint: disable=attribute-defined-outside-init
if self.is_rooted:
if not self.executable_is_installed('busybox'):
self.busybox = self.deploy_busybox(context)
else:
self.busybox = 'busybox'
self.disable_screen_lock()
self.disable_selinux()
if self.enable_screen_check:
self.ensure_screen_is_on()
self.init(context, *args, **kwargs)
def disconnect(self):
if self._logcat_poller:
@@ -231,7 +254,8 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
.. note:: This will get reset on userdata erasure.
"""
return self.execute('settings get secure android_id').strip()
output = self.execute('content query --uri content://settings/secure --projection value --where "name=\'android_id\'"').strip()
return output.split('value=')[-1]
def get_sdk_version(self):
try:
@@ -253,6 +277,24 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
return line.split('=', 1)[1]
return None
def get_installed_package_abi(self, package):
"""
Returns the primary abi of the specified package if it is installed
on the device, or ``None`` otherwise.
"""
output = self.execute('dumpsys package {}'.format(package))
val = None
for line in convert_new_lines(output).split('\n'):
if 'primaryCpuAbi' in line:
val = line.split('=', 1)[1]
break
if val == 'null':
return None
for abi, architectures in ABI_MAP.iteritems():
if val in architectures:
return abi
return val
def list_packages(self):
"""
List packages installed on the device.
@@ -274,11 +316,24 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
"""
return package_name in self.list_packages()
def executable_is_installed(self, executable_name):
return executable_name in self.listdir(self.binaries_directory)
def executable_is_installed(self, executable_name): # pylint: disable=unused-argument,no-self-use
raise AttributeError("""Instead of using is_installed, please use
``get_binary_path`` or ``install_if_needed`` instead. You should
use the path returned by these functions to then invoke the binary
please see: https://pythonhosted.org/wlauto/writing_extensions.html""")
def is_installed(self, name):
return self.executable_is_installed(name) or self.package_is_installed(name)
if self.package_is_installed(name):
return True
elif "." in name: # assumes android packages have a . in their name and binaries documentation
return False
else:
raise AttributeError("""Instead of using is_installed, please use
``get_binary_path`` or ``install_if_needed`` instead. You should
use the path returned by these functions to then invoke the binary
please see: https://pythonhosted.org/wlauto/writing_extensions.html""")
def listdir(self, path, as_root=False, **kwargs):
contents = self.execute('ls {}'.format(path), as_root=as_root)
@@ -290,13 +345,16 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
"""
self._check_ready()
if not as_root:
adb_command(self.adb_name, "push '{}' '{}'".format(source, dest), timeout=timeout)
else:
device_tempfile = self.path.join(self.file_transfer_cache, source.lstrip(self.path.sep))
self.execute('mkdir -p {}'.format(self.path.dirname(device_tempfile)))
adb_command(self.adb_name, "push '{}' '{}'".format(source, device_tempfile), timeout=timeout)
self.execute('cp {} {}'.format(device_tempfile, dest), as_root=True)
try:
if not as_root:
adb_command(self.adb_name, "push '{}' '{}'".format(source, dest), timeout=timeout)
else:
device_tempfile = self.path.join(self.file_transfer_cache, source.lstrip(self.path.sep))
self.execute('mkdir -p {}'.format(self.path.dirname(device_tempfile)))
adb_command(self.adb_name, "push '{}' '{}'".format(source, device_tempfile), timeout=timeout)
self.execute('cp {} {}'.format(device_tempfile, dest), as_root=True)
except CalledProcessError as e:
raise DeviceError(e)
def pull_file(self, source, dest, as_root=False, timeout=default_timeout): # pylint: disable=W0221
"""
@@ -304,45 +362,53 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
"""
self._check_ready()
if not as_root:
adb_command(self.adb_name, "pull '{}' '{}'".format(source, dest), timeout=timeout)
else:
device_tempfile = self.path.join(self.file_transfer_cache, source.lstrip(self.path.sep))
self.execute('mkdir -p {}'.format(self.path.dirname(device_tempfile)))
self.execute('cp {} {}'.format(source, device_tempfile), as_root=True)
adb_command(self.adb_name, "pull '{}' '{}'".format(device_tempfile, dest), timeout=timeout)
try:
if not as_root:
adb_command(self.adb_name, "pull '{}' '{}'".format(source, dest), timeout=timeout)
else:
device_tempfile = self.path.join(self.file_transfer_cache, source.lstrip(self.path.sep))
self.execute('mkdir -p {}'.format(self.path.dirname(device_tempfile)))
self.execute('cp {} {}'.format(source, device_tempfile), as_root=True)
adb_command(self.adb_name, "pull '{}' '{}'".format(device_tempfile, dest), timeout=timeout)
except CalledProcessError as e:
raise DeviceError(e)
def delete_file(self, filepath, as_root=False): # pylint: disable=W0221
self._check_ready()
adb_shell(self.adb_name, "rm '{}'".format(filepath), as_root=as_root, timeout=self.default_timeout)
adb_shell(self.adb_name, "rm -rf '{}'".format(filepath), as_root=as_root, timeout=self.default_timeout)
def file_exists(self, filepath):
self._check_ready()
output = adb_shell(self.adb_name, 'if [ -e \'{}\' ]; then echo 1; else echo 0; fi'.format(filepath),
timeout=self.default_timeout)
if int(output):
return True
else:
return False
return bool(int(output))
def install(self, filepath, timeout=default_timeout, with_name=None): # pylint: disable=W0221
def install(self, filepath, timeout=default_timeout, with_name=None, replace=False): # pylint: disable=W0221
ext = os.path.splitext(filepath)[1].lower()
if ext == '.apk':
return self.install_apk(filepath, timeout)
return self.install_apk(filepath, timeout, replace)
else:
return self.install_executable(filepath, with_name)
def install_apk(self, filepath, timeout=default_timeout): # pylint: disable=W0221
def install_apk(self, filepath, timeout=default_timeout, replace=False, allow_downgrade=False): # pylint: disable=W0221
self._check_ready()
ext = os.path.splitext(filepath)[1].lower()
if ext == '.apk':
return adb_command(self.adb_name, "install {}".format(filepath), timeout=timeout)
flags = []
if replace:
flags.append('-r') # Replace existing APK
if allow_downgrade:
flags.append('-d') # Install the APK even if a newer version is already installed
if self.get_sdk_version() >= 23:
flags.append('-g') # Grant all runtime permissions
self.logger.debug("Replace APK = {}, ADB flags = '{}'".format(replace, ' '.join(flags)))
return adb_command(self.adb_name, "install {} '{}'".format(' '.join(flags), filepath), timeout=timeout)
else:
raise DeviceError('Can\'t install {}: unsupported format.'.format(filepath))
def install_executable(self, filepath, with_name=None):
"""
Installs a binary executable on device. Requires root access. Returns
Installs a binary executable on device. Returns
the path to the installed binary, or ``None`` if the installation has failed.
Optionally, ``with_name`` parameter may be used to specify a different name under
which the executable will be installed.
@@ -351,24 +417,14 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
Updated in version 2.1.5 with ``with_name`` parameter.
"""
self._ensure_binaries_directory_is_writable()
executable_name = with_name or os.path.basename(filepath)
on_device_file = self.path.join(self.working_directory, executable_name)
on_device_executable = self.path.join(self.binaries_directory, executable_name)
self.push_file(filepath, on_device_file)
matched = []
for entry in self.list_file_systems():
if self.binaries_directory.rstrip('/').startswith(entry.mount_point):
matched.append(entry)
if matched:
entry = sorted(matched, key=lambda x: len(x.mount_point))[-1]
if 'rw' not in entry.options:
self.execute('mount -o rw,remount {} {}'.format(entry.device, entry.mount_point), as_root=True)
self.execute('cp {} {}'.format(on_device_file, on_device_executable), as_root=True)
self.execute('chmod 0777 {}'.format(on_device_executable), as_root=True)
return on_device_executable
else:
raise DeviceError('Could not find mount point for binaries directory {}'.format(self.binaries_directory))
self.execute('cp {} {}'.format(on_device_file, on_device_executable), as_root=self.is_rooted)
self.execute('chmod 0777 {}'.format(on_device_executable), as_root=self.is_rooted)
return on_device_executable
def uninstall(self, package):
self._check_ready()
@@ -376,17 +432,15 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
def uninstall_executable(self, executable_name):
"""
Requires root access.
Added in version 2.1.3.
"""
on_device_executable = self.path.join(self.binaries_directory, executable_name)
for entry in self.list_file_systems():
if entry.mount_point == '/system':
if 'rw' not in entry.options:
self.execute('mount -o rw,remount {} /system'.format(entry.device), as_root=True)
self.delete_file(on_device_executable)
on_device_executable = self.get_binary_path(executable_name, search_system_binaries=False)
if not on_device_executable:
raise DeviceError("Could not uninstall {}, binary not found".format(on_device_executable))
self._ensure_binaries_directory_is_writable()
self.delete_file(on_device_executable, as_root=self.is_rooted)
def execute(self, command, timeout=default_timeout, check_exit_code=True, background=False,
as_root=False, busybox=False, **kwargs):
@@ -408,7 +462,7 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
Added in version 2.1.3
.. note:: The device must be rooted to be able to use busybox.
.. note:: The device must be rooted to be able to use some busybox features.
:param as_root: If ``True``, will attempt to execute command in privileged mode. The device
must be rooted, otherwise an error will be raised. Defaults to ``False``.
@@ -427,51 +481,84 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
if as_root and not self.is_rooted:
raise DeviceError('Attempting to execute "{}" as root on unrooted device.'.format(command))
if busybox:
if not self.is_rooted:
DeviceError('Attempting to execute "{}" with busybox. '.format(command) +
'Busybox can only be deployed to rooted devices.')
command = ' '.join([self.busybox, command])
if background:
return adb_background_shell(self.adb_name, command, as_root=as_root)
else:
return adb_shell(self.adb_name, command, timeout, check_exit_code, as_root)
def kick_off(self, command):
def kick_off(self, command, as_root=None):
"""
Like execute but closes adb session and returns immediately, leaving the command running on the
device (this is different from execute(background=True) which keeps adb connection open and returns
a subprocess object).
.. note:: This relies on busybox's nohup applet and so won't work on unrooted devices.
Added in version 2.1.4
"""
if not self.is_rooted:
raise DeviceError('kick_off uses busybox\'s nohup applet and so can only be run a rooted device.')
if as_root is None:
as_root = self.is_rooted
try:
command = 'cd {} && busybox nohup {}'.format(self.working_directory, command)
output = self.execute(command, timeout=1, as_root=True)
command = 'cd {} && {} nohup {}'.format(self.working_directory, self.busybox, command)
output = self.execute(command, timeout=1, as_root=as_root)
except TimeoutError:
pass
else:
raise ValueError('Background command exited before timeout; got "{}"'.format(output))
def get_pids_of(self, process_name):
"""Returns a list of PIDs of all processes with the specified name."""
result = (self.execute('ps | {} grep {}'.format(self.busybox, process_name),
check_exit_code=False) or '').strip()
if result and 'not found' not in result:
return [int(x.split()[1]) for x in result.split('\n')]
else:
return []
def ps(self, **kwargs):
"""
Returns the list of running processes on the device. Keyword arguments may
be used to specify simple filters for columns.
Added in version 2.1.4
"""
lines = iter(convert_new_lines(self.execute('ps')).split('\n'))
lines.next() # header
result = []
for line in lines:
parts = line.split()
if parts:
result.append(PsEntry(*(parts[0:1] + map(int, parts[1:5]) + parts[5:])))
if not kwargs:
return result
else:
filtered_result = []
for entry in result:
if all(getattr(entry, k) == v for k, v in kwargs.iteritems()):
filtered_result.append(entry)
return filtered_result
def get_properties(self, context):
"""Captures and saves the information from /system/build.prop and /proc/version"""
props = super(AndroidDevice, self).get_properties(context)
props.update(self._get_android_properties(context))
return props
def _get_android_properties(self, context):
props = {}
props['android_id'] = self.get_android_id()
buildprop_file = os.path.join(context.host_working_directory, 'build.prop')
if not os.path.isfile(buildprop_file):
self.pull_file('/system/build.prop', context.host_working_directory)
self._update_build_properties(buildprop_file, props)
context.add_run_artifact('build_properties', buildprop_file, 'export')
self._update_build_properties(props)
version_file = os.path.join(context.host_working_directory, 'version')
if not os.path.isfile(version_file):
self.pull_file('/proc/version', context.host_working_directory)
self._update_versions(version_file, props)
context.add_run_artifact('device_version', version_file, 'export')
dumpsys_host_file = os.path.join(context.host_working_directory, 'window.dumpsys')
with open(dumpsys_host_file, 'w') as wfh:
wfh.write(self.execute('dumpsys window'))
context.add_run_artifact('dumpsys_window', dumpsys_host_file, 'meta')
prop_file = os.path.join(context.host_working_directory, 'android-props.json')
with open(prop_file, 'w') as wfh:
json.dump(props, wfh)
context.add_run_artifact('android_properties', prop_file, 'export')
return props
def getprop(self, prop=None):
@@ -485,6 +572,11 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
return props[prop]
return props
def deploy_sqlite3(self, context):
host_file = context.resolver.get(Executable(NO_ONE, self.abi, 'sqlite3'))
target_file = self.install_if_needed(host_file)
return target_file
# Android-specific methods. These either rely on specifics of adb or other
# Android-only concepts in their interface and/or implementation.
@@ -528,6 +620,30 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
else:
return adb_shell(self.adb_name, 'logcat -c', timeout=self.default_timeout)
def get_screen_size(self):
output = self.execute('dumpsys window')
match = SCREEN_SIZE_REGEX.search(output)
if match:
return (int(match.group('width')),
int(match.group('height')))
else:
return (0, 0)
def perform_unlock_swipe(self):
width, height = self.get_screen_size()
command = 'input swipe {} {} {} {}'
if self.swipe_to_unlock == "horizontal":
swipe_heigh = height * 2 // 3
start = 100
stop = width - start
self.execute(command.format(start, swipe_heigh, stop, swipe_heigh))
if self.swipe_to_unlock == "vertical":
swipe_middle = height / 2
swipe_heigh = height * 2 // 3
self.execute(command.format(swipe_middle, swipe_heigh, swipe_middle, 0))
else: # Should never reach here
raise DeviceError("Invalid swipe direction: {}".format(self.swipe_to_unlock))
def capture_screen(self, filepath):
"""Caputers the current device screen into the specified file in a PNG format."""
on_device_file = self.path.join(self.working_directory, 'screen_capture.png')
@@ -535,6 +651,17 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
self.pull_file(on_device_file, filepath)
self.delete_file(on_device_file)
def capture_ui_hierarchy(self, filepath):
"""Captures the current view hierarchy into the specified file in a XML format."""
on_device_file = self.path.join(self.working_directory, 'screen_capture.xml')
self.execute('uiautomator dump {}'.format(on_device_file))
self.pull_file(on_device_file, filepath)
self.delete_file(on_device_file)
parsed_xml = xml.dom.minidom.parse(filepath)
with open(filepath, 'w') as f:
f.write(parsed_xml.toprettyxml())
def is_screen_on(self):
"""Returns ``True`` if the device screen is currently on, ``False`` otherwise."""
output = self.execute('dumpsys power')
@@ -547,6 +674,8 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
def ensure_screen_is_on(self):
if not self.is_screen_on():
self.execute('input keyevent 26')
if self.swipe_to_unlock:
self.perform_unlock_swipe()
def disable_screen_lock(self):
"""
@@ -558,8 +687,16 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
"""
lockdb = '/data/system/locksettings.db'
sqlcommand = "update locksettings set value=\\'0\\' where name=\\'screenlock.disabled\\';"
self.execute('sqlite3 {} "{}"'.format(lockdb, sqlcommand), as_root=True)
sqlcommand = "update locksettings set value='0' where name='screenlock.disabled';"
f = tempfile.NamedTemporaryFile()
try:
f.write('{} {} "{}"'.format(self.sqlite, lockdb, sqlcommand))
f.flush()
on_device_executable = self.install_executable(f.name,
with_name="disable_screen_lock")
finally:
f.close()
self.execute(on_device_executable, as_root=True)
def disable_selinux(self):
# This may be invoked from intialize() so we can't use execute() or the
@@ -573,17 +710,30 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
if se_status == 'Enforcing':
self.execute('setenforce 0', as_root=True)
def get_device_model(self):
try:
return self.getprop(prop='ro.product.device')
except KeyError:
return None
def broadcast_media_mounted(self, dirpath):
"""
Force a re-index of the mediaserver cache for the specified directory.
"""
command = 'am broadcast -a android.intent.action.MEDIA_MOUNTED -d file://'
self.execute(command + dirpath)
# Internal methods: do not use outside of the class.
def _update_build_properties(self, filepath, props):
def _update_build_properties(self, props):
try:
with open(filepath) as fh:
for line in fh:
line = re.sub(r'#.*', '', line).strip()
if not line:
continue
key, value = line.split('=', 1)
props[key] = value
def strip(somestring):
return somestring.strip().replace('[', '').replace(']', '')
for line in self.execute("getprop").splitlines():
key, value = line.split(':', 1)
key = strip(key)
value = strip(value)
props[key] = value
except ValueError:
self.logger.warning('Could not parse build.prop.')
@@ -599,6 +749,18 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
else:
self.logger.warning('Could not parse version string.')
def _ensure_binaries_directory_is_writable(self):
matched = []
for entry in self.list_file_systems():
if self.binaries_directory.rstrip('/').startswith(entry.mount_point):
matched.append(entry)
if matched:
entry = sorted(matched, key=lambda x: len(x.mount_point))[-1]
if 'rw' not in entry.options:
self.execute('mount -o rw,remount {} {}'.format(entry.device, entry.mount_point), as_root=True)
else:
raise DeviceError('Could not find mount point for binaries directory {}'.format(self.binaries_directory))
class _LogcatPoller(threading.Thread):
@@ -675,4 +837,3 @@ class BigLittleDevice(AndroidDevice): # pylint: disable=W0223
parameters = [
Parameter('scheduler', default='hmp', override=True),
]

View File

@@ -34,3 +34,10 @@ class JarFile(FileResource):
class ApkFile(FileResource):
name = 'apk'
def __init__(self, owner, platform=None):
super(ApkFile, self).__init__(owner)
self.platform = platform
def __str__(self):
return '<{}\'s {} APK>'.format(self.owner, self.platform)

539
wlauto/common/android/workload.py Normal file → Executable file
View File

@@ -16,19 +16,30 @@
import os
import sys
import time
from math import ceil
from wlauto.core.extension import Parameter
from distutils.version import LooseVersion
from wlauto.core.extension import Parameter, ExtensionMeta, ListCollection
from wlauto.core.workload import Workload
from wlauto.core.resource import NO_ONE
from wlauto.common.resources import ExtensionAsset, Executable
from wlauto.exceptions import WorkloadError, ResourceError
from wlauto.utils.android import ApkInfo
from wlauto.common.android.resources import ApkFile, ReventFile
from wlauto.common.resources import ExtensionAsset, Executable, File
from wlauto.exceptions import WorkloadError, ResourceError, DeviceError
from wlauto.utils.android import ApkInfo, ANDROID_NORMAL_PERMISSIONS, UNSUPPORTED_PACKAGES
from wlauto.utils.types import boolean
from wlauto.utils.revent import ReventRecording
import wlauto.utils.statedetect as state_detector
import wlauto.common.android.resources
DELAY = 5
# Due to the way `super` works you have to call it at every level but WA executes some
# methods conditionally and so has to call them directly via the class, this breaks super
# and causes it to run things mutiple times ect. As a work around for this untill workloads
# are reworked everything that subclasses workload calls parent methods explicitly
class UiAutomatorWorkload(Workload):
"""
@@ -66,7 +77,7 @@ class UiAutomatorWorkload(Workload):
def __init__(self, device, _call_super=True, **kwargs): # pylint: disable=W0613
if _call_super:
super(UiAutomatorWorkload, self).__init__(device, **kwargs)
Workload.__init__(self, device, **kwargs)
self.uiauto_file = None
self.device_uiauto_file = None
self.command = None
@@ -82,12 +93,13 @@ class UiAutomatorWorkload(Workload):
self.uiauto_package = os.path.splitext(os.path.basename(self.uiauto_file))[0]
def setup(self, context):
Workload.setup(self, context)
method_string = '{}.{}#{}'.format(self.uiauto_package, self.uiauto_class, self.uiauto_method)
params_dict = self.uiauto_params
params_dict['workdir'] = self.device.working_directory
params = ''
for k, v in self.uiauto_params.iteritems():
params += ' -e {} {}'.format(k, v)
params += ' -e {} "{}"'.format(k, v)
self.command = 'uiautomator runtest {}{} -c {}'.format(self.device_uiauto_file, params, method_string)
self.device.push_file(self.uiauto_file, self.device_uiauto_file)
self.device.killall('uiautomator')
@@ -122,10 +134,16 @@ class ApkWorkload(Workload):
:package: The package name of the app. This is usually a Java-style name of the form
``com.companyname.appname``.
:activity: This is the initial activity of the app. This will be used to launch the
app during the setup.
app during the setup. Many applications do not specify a launch activity so
this may be left blank if necessary.
:view: The class of the main view pane of the app. This needs to be defined in order
to collect SurfaceFlinger-derived statistics (such as FPS) for the app, but
may otherwise be left as ``None``.
:launch_main: If ``False``, the default activity will not be launched (during setup),
allowing workloads to start the app with an intent of their choice in
the run step. This is useful for apps without a launchable default/main
activity or those where it cannot be launched without intent data (which
is provided at the run phase).
:install_timeout: Timeout for the installation of the APK. This may vary wildly based on
the size and nature of a specific APK, and so should be defined on
per-workload basis.
@@ -135,6 +153,9 @@ class ApkWorkload(Workload):
so, as with all timeouts, so leeway must be included in
the specified value.
:min_apk_version: The minimum supported apk version for this workload. May be ``None``.
:max_apk_version: The maximum supported apk version for this workload. May be ``None``.
.. note:: Both package and activity for a workload may be obtained from the APK using
the ``aapt`` tool that comes with the ADT (Android Developemnt Tools) bundle.
@@ -142,57 +163,230 @@ class ApkWorkload(Workload):
package = None
activity = None
view = None
install_timeout = None
default_install_timeout = 300
min_apk_version = None
max_apk_version = None
supported_platforms = ['android']
launch_main = True
parameters = [
Parameter('install_timeout', kind=int, default=300,
description='Timeout for the installation of the apk.'),
Parameter('check_apk', kind=boolean, default=True,
description='''
When set to True the APK file on the host will be prefered if
it is a valid version and ABI, if not it will fall back to the
version on the targer. When set to False the target version is
prefered.
'''),
Parameter('force_install', kind=boolean, default=False,
description='''
Always re-install the APK, even if matching version is found already installed
on the device. Runs ``adb install -r`` to ensure existing APK is replaced. When
this is set, check_apk is ignored.
'''),
Parameter('uninstall_apk', kind=boolean, default=False,
description="If ``True``, will uninstall workload's APK as part of teardown."),
description='If ``True``, will uninstall workload\'s APK as part of teardown.'),
Parameter('exact_abi', kind=bool, default=False,
description='''
If ``True``, workload will check that the APK matches the target
device ABI, otherwise any APK found will be used.
'''),
]
def __init__(self, device, _call_super=True, **kwargs):
if _call_super:
super(ApkWorkload, self).__init__(device, **kwargs)
Workload.__init__(self, device, **kwargs)
self.apk_file = None
self.apk_version = None
self.logcat_log = None
self.force_reinstall = kwargs.get('force_reinstall', False)
if not self.install_timeout:
self.install_timeout = self.default_install_timeout
self.exact_apk_version = None
self.exact_abi = kwargs.get('exact_abi')
def init_resources(self, context):
self.apk_file = context.resolver.get(wlauto.common.android.resources.ApkFile(self), version=getattr(self, 'version', None))
def setup(self, context):
self.initialize_package(context)
self.start_activity()
self.device.execute('am kill-all') # kill all *background* activities
def setup(self, context): # pylint: disable=too-many-branches
Workload.setup(self, context)
self.setup_workload_apk(context)
self.launch_application()
self.kill_background()
self.device.clear_logcat()
def initialize_package(self, context):
installed_version = self.device.get_installed_package_version(self.package)
host_version = ApkInfo(self.apk_file).version_name
if installed_version != host_version:
if installed_version:
message = '{} host version: {}, device version: {}; re-installing...'
self.logger.debug(message.format(os.path.basename(self.apk_file), host_version, installed_version))
else:
message = '{} host version: {}, not found on device; installing...'
self.logger.debug(message.format(os.path.basename(self.apk_file), host_version))
self.force_reinstall = True
else:
message = '{} version {} found on both device and host.'
self.logger.debug(message.format(os.path.basename(self.apk_file), host_version))
if self.force_reinstall:
if installed_version:
self.device.uninstall(self.package)
self.install_apk(context)
else:
self.reset(context)
self.apk_version = host_version
def setup_workload_apk(self, context):
# Get target version
target_version = self.device.get_installed_package_version(self.package)
if target_version:
target_version = LooseVersion(target_version)
self.logger.debug("Found version '{}' on target device".format(target_version))
def start_activity(self):
output = self.device.execute('am start -W -n {}/{}'.format(self.package, self.activity))
# Get host version
self.apk_file = context.resolver.get(ApkFile(self, self.device.abi),
version=getattr(self, 'version', None),
variant_name=getattr(self, 'variant_name', None),
strict=False)
# Get target abi
target_abi = self.device.get_installed_package_abi(self.package)
if target_abi:
self.logger.debug("Found apk with primary abi '{}' on target device".format(target_abi))
# Get host version, primary abi is first, and then try to find supported.
for abi in self.device.supported_abi:
self.apk_file = context.resolver.get(ApkFile(self, abi),
version=getattr(self, 'version', None),
variant_name=getattr(self, 'variant_name', None),
strict=False)
# Stop if apk found, or if exact_abi is set only look for primary abi.
if self.apk_file or self.exact_abi:
break
host_version = None
if self.apk_file is not None:
host_version = ApkInfo(self.apk_file).version_name
if host_version:
host_version = LooseVersion(host_version)
self.logger.debug("Found version '{}' on host".format(host_version))
# Error if apk was not found anywhere
if target_version is None and host_version is None:
msg = "Could not find APK for '{}' on the host or target device"
raise ResourceError(msg.format(self.name))
if self.exact_apk_version is not None:
if self.exact_apk_version != target_version and self.exact_apk_version != host_version:
msg = "APK version '{}' not found on the host '{}' or target '{}'"
raise ResourceError(msg.format(self.exact_apk_version, host_version, target_version))
# Error if exact_abi and suitable apk not found on host and incorrect version on device
if self.exact_abi and host_version is None:
if target_abi != self.device.abi:
msg = "APK abi '{}' not found on the host and target is '{}'"
raise ResourceError(msg.format(self.device.abi, target_abi))
# Ensure the apk is setup on the device
if self.force_install:
self.force_install_apk(context, host_version)
elif self.check_apk:
self.prefer_host_apk(context, host_version, target_version)
else:
self.prefer_target_apk(context, host_version, target_version)
self.reset(context)
self.apk_version = self.device.get_installed_package_version(self.package)
context.add_classifiers(apk_version=self.apk_version)
def launch_application(self):
if self.launch_main:
self.launch_package() # launch default activity without intent data
def kill_background(self):
self.device.execute('am kill-all') # kill all *background* activities
def force_install_apk(self, context, host_version):
if host_version is None:
raise ResourceError("force_install is 'True' but could not find APK on the host")
try:
self.validate_version(host_version)
except ResourceError as e:
msg = "force_install is 'True' but the host version is invalid:\n\t{}"
raise ResourceError(msg.format(str(e)))
self.install_apk(context, replace=True)
def prefer_host_apk(self, context, host_version, target_version):
msg = "check_apk is 'True' "
if host_version is None:
try:
self.validate_version(target_version)
except ResourceError as e:
msg += "but the APK was not found on the host and the target version is invalid:\n\t{}"
raise ResourceError(msg.format(str(e)))
else:
msg += "but the APK was not found on the host, using target version"
self.logger.debug(msg)
return
try:
self.validate_version(host_version)
except ResourceError as e1:
msg += "but the host APK version is invalid:\n\t{}\n"
if target_version is None:
msg += "The target does not have the app either"
raise ResourceError(msg.format(str(e1)))
try:
self.validate_version(target_version)
except ResourceError as e2:
msg += "The target version is also invalid:\n\t{}"
raise ResourceError(msg.format(str(e1), str(e2)))
else:
msg += "using the target version instead"
self.logger.debug(msg.format(str(e1)))
else: # Host version is valid
if target_version is not None and target_version == host_version:
msg += " and a matching version is alread on the device, doing nothing"
self.logger.debug(msg)
return
msg += " and the host version is not on the target, installing APK"
self.logger.debug(msg)
self.install_apk(context, replace=True)
def prefer_target_apk(self, context, host_version, target_version):
msg = "check_apk is 'False' "
if target_version is None:
try:
self.validate_version(host_version)
except ResourceError as e:
msg += "but the app was not found on the target and the host version is invalid:\n\t{}"
raise ResourceError(msg.format(str(e)))
else:
msg += "and the app was not found on the target, using host version"
self.logger.debug(msg)
self.install_apk(context)
return
try:
self.validate_version(target_version)
except ResourceError as e1:
msg += "but the target app version is invalid:\n\t{}\n"
if host_version is None:
msg += "The host does not have the APK either"
raise ResourceError(msg.format(str(e1)))
try:
self.validate_version(host_version)
except ResourceError as e2:
msg += "The host version is also invalid:\n\t{}"
raise ResourceError(msg.format(str(e1), str(e2)))
else:
msg += "Using the host APK instead"
self.logger.debug(msg.format(str(e1)))
self.install_apk(context, replace=True)
else:
msg += "and a valid version of the app is already on the target, using target app"
self.logger.debug(msg)
def validate_version(self, version):
min_apk_version = getattr(self, 'min_apk_version', None)
max_apk_version = getattr(self, 'max_apk_version', None)
if min_apk_version is not None and max_apk_version is not None:
if version < LooseVersion(min_apk_version) or \
version > LooseVersion(max_apk_version):
msg = "version '{}' not supported. " \
"Minimum version required: '{}', Maximum version known to work: '{}'"
raise ResourceError(msg.format(version, min_apk_version, max_apk_version))
elif min_apk_version is not None:
if version < LooseVersion(min_apk_version):
msg = "version '{}' not supported. " \
"Minimum version required: '{}'"
raise ResourceError(msg.format(version, min_apk_version))
elif max_apk_version is not None:
if version > LooseVersion(max_apk_version):
msg = "version '{}' not supported. " \
"Maximum version known to work: '{}'"
raise ResourceError(msg.format(version, max_apk_version))
def launch_package(self):
if not self.activity:
output = self.device.execute('am start -W {}'.format(self.package))
else:
output = self.device.execute('am start -W -n {}/{}'.format(self.package, self.activity))
if 'Error:' in output:
self.device.execute('am force-stop {}'.format(self.package)) # this will dismiss any erro dialogs
raise WorkloadError(output)
@@ -202,19 +396,62 @@ class ApkWorkload(Workload):
self.device.execute('am force-stop {}'.format(self.package))
self.device.execute('pm clear {}'.format(self.package))
def install_apk(self, context):
output = self.device.install(self.apk_file, self.install_timeout)
# As of android API level 23, apps can request permissions at runtime,
# this will grant all of them so requests do not pop up when running the app
# This can also be done less "manually" during adb install using the -g flag
if self.device.get_sdk_version() >= 23:
self._grant_requested_permissions()
def install_apk(self, context, replace=False):
success = False
if replace:
self.device.uninstall(self.package)
output = self.device.install_apk(self.apk_file, timeout=self.install_timeout,
replace=replace, allow_downgrade=True)
if 'Failure' in output:
if 'ALREADY_EXISTS' in output:
self.logger.warn('Using already installed APK (did not unistall properly?)')
self.reset(context)
else:
raise WorkloadError(output)
else:
self.logger.debug(output)
success = True
self.do_post_install(context)
return success
def _grant_requested_permissions(self):
dumpsys_output = self.device.execute(command="dumpsys package {}".format(self.package))
permissions = []
lines = iter(dumpsys_output.splitlines())
for line in lines:
if "requested permissions:" in line:
break
for line in lines:
if "android.permission." in line:
permissions.append(line.split(":")[0].strip())
# Matching either of these means the end of requested permissions section
elif "install permissions:" in line or "runtime permissions:" in line:
break
for permission in set(permissions):
# "Normal" Permisions are automatically granted and cannot be changed
permission_name = permission.rsplit('.', 1)[1]
if permission_name not in ANDROID_NORMAL_PERMISSIONS:
# On some API 23+ devices, this may fail with a SecurityException
# on previously granted permissions. In that case, just skip as it
# is not fatal to the workload execution
try:
self.device.execute("pm grant {} {}".format(self.package, permission))
except DeviceError as e:
if "changeable permission" in e.message or "Unknown permission" in e.message:
self.logger.debug(e)
else:
raise e
def do_post_install(self, context):
""" May be overwritten by dervied classes."""
""" May be overwritten by derived classes."""
pass
def run(self, context):
@@ -233,44 +470,64 @@ class ApkWorkload(Workload):
if self.uninstall_apk:
self.device.uninstall(self.package)
def validate(self):
if not self.apk_file:
raise WorkloadError('No APK file found for workload {}.'.format(self.name))
AndroidBenchmark = ApkWorkload # backward compatibility
class ReventWorkload(Workload):
default_setup_timeout = 5 * 60 # in seconds
default_run_timeout = 10 * 60 # in seconds
# pylint: disable=attribute-defined-outside-init
def __init__(self, device, _call_super=True, **kwargs):
if _call_super:
super(ReventWorkload, self).__init__(device, **kwargs)
Workload.__init__(self, device, **kwargs)
devpath = self.device.path
self.on_device_revent_binary = devpath.join(self.device.working_directory, 'revent')
self.on_device_setup_revent = devpath.join(self.device.working_directory, '{}.setup.revent'.format(self.device.name))
self.on_device_run_revent = devpath.join(self.device.working_directory, '{}.run.revent'.format(self.device.name))
self.setup_timeout = kwargs.get('setup_timeout', self.default_setup_timeout)
self.run_timeout = kwargs.get('run_timeout', self.default_run_timeout)
self.on_device_revent_binary = devpath.join(self.device.binaries_directory, 'revent')
self.on_device_HelloJni_apk = devpath.join(self.device.binaries_directory, 'HelloJni.apk')
self.setup_timeout = kwargs.get('setup_timeout', None)
self.run_timeout = kwargs.get('run_timeout', None)
self.revent_setup_file = None
self.revent_run_file = None
self.on_device_setup_revent = None
self.on_device_run_revent = None
self.statedefs_dir = None
def init_resources(self, context):
self.revent_setup_file = context.resolver.get(wlauto.common.android.resources.ReventFile(self, 'setup'))
self.revent_run_file = context.resolver.get(wlauto.common.android.resources.ReventFile(self, 'run'))
if self.check_states:
state_detector.check_match_state_dependencies()
def setup(self, context):
self.device.killall('revent', signal='SIGKILL')
self.revent_setup_file = context.resolver.get(ReventFile(self, 'setup'))
self.revent_run_file = context.resolver.get(ReventFile(self, 'run'))
devpath = self.device.path
self.on_device_setup_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_setup_file)[-1])
self.on_device_run_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_run_file)[-1])
self._check_revent_files(context)
self.device.killall('revent')
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_setup_revent)
default_setup_timeout = ceil(ReventRecording(self.revent_setup_file).duration) + 30
default_run_timeout = ceil(ReventRecording(self.revent_run_file).duration) + 30
self.setup_timeout = self.setup_timeout or default_setup_timeout
self.run_timeout = self.run_timeout or default_run_timeout
Workload.setup(self, context)
if self.device.platform is 'android':
result = self.device.execute('dumpsys activity services | grep "ChoreoService"',
check_exit_code=False)
if not result or 'com.example.hellojni/.ChoreoService' not in result:
self.logger.debug('Starting VSync Service')
self.device.execute('am startservice com.example.hellojni/.ChoreoService')
time.sleep(5) # Allow time for service to start
vsync_flag = '-V ' if self.device.platform is 'android' else ''
command = '{} replay {}{}'.format(self.on_device_revent_binary, vsync_flag, self.on_device_setup_revent)
self.device.execute(command, timeout=self.setup_timeout)
def run(self, context):
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_run_revent)
if self.device.platform is 'android':
self.device.execute('am startservice com.example.hellojni/.ChoreoService')
time.sleep(5) # Allow time for service to start
self.logger.debug('Replaying {}'.format(os.path.basename(self.on_device_run_revent)))
vsync_flag = '-V ' if self.device.platform is 'android' else ''
command = '{} replay {}{}'.format(self.on_device_revent_binary, vsync_flag, self.on_device_run_revent)
self.device.execute(command, timeout=self.run_timeout)
self.logger.debug('Replay completed.')
@@ -278,6 +535,8 @@ class ReventWorkload(Workload):
pass
def teardown(self, context):
self.device.killall('revent')
self.device.killall("com.example.hellojni")
self.device.delete_file(self.on_device_setup_revent)
self.device.delete_file(self.on_device_run_revent)
@@ -288,6 +547,10 @@ class ReventWorkload(Workload):
message = '{} does not exist. '.format(revent_binary)
message += 'Please build revent for your system and place it in that location'
raise WorkloadError(message)
if self.device.platform is 'android':
HelloJni_APK = context.resolver.get(Executable(NO_ONE, self.device.abi, 'HelloJni.apk'))
if not os.path.isfile(HelloJni_APK):
message = '{} does not exist. '.format(HelloJni_APK)
if not self.revent_setup_file:
# pylint: disable=too-few-format-args
message = '{0}.setup.revent file does not exist, Please provide one for your device, {0}'.format(self.device.name)
@@ -298,16 +561,44 @@ class ReventWorkload(Workload):
raise WorkloadError(message)
self.on_device_revent_binary = self.device.install_executable(revent_binary)
if self.device.platform is 'android':
self.on_device_HelloJni_apk = self.device.install_if_needed(HelloJni_APK)
self.device.push_file(self.revent_run_file, self.on_device_run_revent)
self.device.push_file(self.revent_setup_file, self.on_device_setup_revent)
def _check_statedetection_files(self, context):
try:
self.statedefs_dir = context.resolver.get(File(self, 'state_definitions'))
except ResourceError:
self.logger.warning("State definitions directory not found. Disabling state detection.")
self.check_states = False
def check_state(self, context, phase):
try:
self.logger.info("\tChecking workload state...")
screenshotPath = os.path.join(context.output_directory, "screen.png")
self.device.capture_screen(screenshotPath)
stateCheck = state_detector.verify_state(screenshotPath, self.statedefs_dir, phase)
if not stateCheck:
raise WorkloadError("Unexpected state after setup")
except state_detector.StateDefinitionError as e:
msg = "State definitions or template files missing or invalid ({}). Skipping state detection."
self.logger.warning(msg.format(e.message))
class AndroidUiAutoBenchmark(UiAutomatorWorkload, AndroidBenchmark):
supported_platforms = ['android']
def __init__(self, device, **kwargs):
UiAutomatorWorkload.__init__(self, device, **kwargs)
AndroidBenchmark.__init__(self, device, _call_super=False, **kwargs)
def initialize(self, context):
UiAutomatorWorkload.initialize(self, context)
AndroidBenchmark.initialize(self, context)
self._check_unsupported_packages()
def init_resources(self, context):
UiAutomatorWorkload.init_resources(self, context)
AndroidBenchmark.init_resources(self, context)
@@ -324,6 +615,88 @@ class AndroidUiAutoBenchmark(UiAutomatorWorkload, AndroidBenchmark):
UiAutomatorWorkload.teardown(self, context)
AndroidBenchmark.teardown(self, context)
def _check_unsupported_packages(self):
"""
Check for any unsupported package versions and raise an
exception if detected.
"""
for package in UNSUPPORTED_PACKAGES:
version = self.device.get_installed_package_version(package)
if version is None:
continue
if '-' in version:
version = version.split('-')[0] # ignore abi version
if version in UNSUPPORTED_PACKAGES[package]:
message = 'This workload does not support version "{}" of package "{}"'
raise WorkloadError(message.format(version, package))
class AndroidUxPerfWorkloadMeta(ExtensionMeta):
to_propagate = ExtensionMeta.to_propagate + [('deployable_assets', str, ListCollection)]
class AndroidUxPerfWorkload(AndroidUiAutoBenchmark):
__metaclass__ = AndroidUxPerfWorkloadMeta
deployable_assets = []
parameters = [
Parameter('markers_enabled', kind=bool, default=False,
description="""
If ``True``, UX_PERF action markers will be emitted to logcat during
the test run.
"""),
Parameter('clean_assets', kind=bool, default=False,
description="""
If ``True`` pushed assets will be deleted at the end of each iteration
"""),
Parameter('force_push_assets', kind=bool, default=False,
description="""
If ``True`` always push assets on each iteration, even if the
assets already exists in the device path
"""),
]
def _path_on_device(self, fpath, dirname=None):
if dirname is None:
dirname = self.device.working_directory
fname = os.path.basename(fpath)
return self.device.path.join(dirname, fname)
def push_assets(self, context):
for f in self.deployable_assets:
fpath = context.resolver.get(File(self, f))
device_path = self._path_on_device(fpath)
if self.force_push_assets or not self.device.file_exists(device_path):
self.device.push_file(fpath, device_path, timeout=300)
self.device.broadcast_media_mounted(self.device.working_directory)
def delete_assets(self):
for f in self.deployable_assets:
self.device.delete_file(self._path_on_device(f))
self.device.broadcast_media_mounted(self.device.working_directory)
def __init__(self, device, **kwargs):
super(AndroidUxPerfWorkload, self).__init__(device, **kwargs)
# Turn class attribute into instance attribute
self.deployable_assets = list(self.deployable_assets)
def validate(self):
super(AndroidUxPerfWorkload, self).validate()
self.uiauto_params['package'] = self.package
self.uiauto_params['markers_enabled'] = self.markers_enabled
def setup(self, context):
super(AndroidUxPerfWorkload, self).setup(context)
self.push_assets(context)
def teardown(self, context):
super(AndroidUxPerfWorkload, self).teardown(context)
if self.clean_assets:
self.delete_assets()
class GameWorkload(ApkWorkload, ReventWorkload):
"""
@@ -355,8 +728,22 @@ class GameWorkload(ApkWorkload, ReventWorkload):
asset_file = None
saved_state_file = None
view = 'SurfaceView'
install_timeout = 500
loading_time = 10
supported_platforms = ['android']
parameters = [
Parameter('install_timeout', default=500, override=True),
Parameter('check_states', kind=bool, default=False, global_alias='check_game_states',
description="""Use visual state detection to verify the state of the workload
after setup and run"""),
Parameter('assets_push_timeout', kind=int, default=500,
description='Timeout used during deployment of the assets package (if there is one).'),
Parameter('clear_data_on_reset', kind=bool, default=True,
description="""
If set to ``False``, this will prevent WA from clearing package
data for this workload prior to running it.
"""),
]
def __init__(self, device, **kwargs): # pylint: disable=W0613
ApkWorkload.__init__(self, device, **kwargs)
@@ -368,6 +755,8 @@ class GameWorkload(ApkWorkload, ReventWorkload):
def init_resources(self, context):
ApkWorkload.init_resources(self, context)
ReventWorkload.init_resources(self, context)
if self.check_states:
self._check_statedetection_files(context)
def setup(self, context):
ApkWorkload.setup(self, context)
@@ -375,23 +764,33 @@ class GameWorkload(ApkWorkload, ReventWorkload):
time.sleep(self.loading_time)
ReventWorkload.setup(self, context)
# state detection check if it's enabled in the config
if self.check_states:
self.check_state(context, "setup_complete")
def do_post_install(self, context):
ApkWorkload.do_post_install(self, context)
self._deploy_assets(context)
self._deploy_assets(context, self.assets_push_timeout)
def reset(self, context):
# If saved state exists, restore it; if not, do full
# uninstall/install cycle.
self.device.execute('am force-stop {}'.format(self.package))
if self.saved_state_file:
self._deploy_resource_tarball(context, self.saved_state_file)
else:
ApkWorkload.reset(self, context)
if self.clear_data_on_reset:
self.device.execute('pm clear {}'.format(self.package))
self._deploy_assets(context)
def run(self, context):
ReventWorkload.run(self, context)
def teardown(self, context):
# state detection check if it's enabled in the config
if self.check_states:
self.check_state(context, "run_complete")
if not self.saved_state_file:
ApkWorkload.teardown(self, context)
else:
@@ -416,7 +815,7 @@ class GameWorkload(ApkWorkload, ReventWorkload):
raise WorkloadError(message.format(resource_file, self.name))
# adb push will create intermediate directories if they don't
# exist.
self.device.push_file(asset_tarball, ondevice_cache)
self.device.push_file(asset_tarball, ondevice_cache, timeout=timeout)
device_asset_directory = self.device.path.join(self.device.external_storage_directory, 'Android', kind)
deploy_command = 'cd {} && {} tar -xzf {}'.format(device_asset_directory,

Binary file not shown.

Binary file not shown.

BIN
wlauto/common/bin/arm64/m5 Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
wlauto/common/bin/armeabi/m5 Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,6 @@
The gem5 simulator can be obtained from http://repo.gem5.org/gem5/ and the
corresponding documentation can be found at http://www.gem5.org.
The source for the m5 binaries bundled with Workload Automation (found at
wlauto/common/bin/arm64/m5 and wlauto/common/bin/armeabi/m5) can be found at
util/m5 in the gem5 source at http://repo.gem5.org/gem5/.

View File

@@ -0,0 +1,14 @@
# Copyright 2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

View File

@@ -0,0 +1,684 @@
# Copyright 2014-2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Original implementation by Rene de Jong. Updated by Sascha Bischoff.
# pylint: disable=E1101
import logging
import os
import re
import shutil
import socket
import subprocess
import sys
import tarfile
import time
from pexpect import EOF, TIMEOUT, pxssh
from wlauto import settings, Parameter
from wlauto.core.resource import NO_ONE
from wlauto.common.resources import Executable
from wlauto.core import signal as sig
from wlauto.exceptions import DeviceError
from wlauto.utils import ssh, types
class BaseGem5Device(object):
"""
Base implementation for a gem5-based device
This class is used as the base class for OS-specific devices such as the
G3m5LinuxDevice and the Gem5AndroidDevice. The majority of the gem5-specific
functionality is included here.
Note: When inheriting from this class, make sure to inherit from this class
prior to inheriting from the OS-specific class, i.e. LinuxDevice, to ensure
that the methods are correctly overridden.
"""
# gem5 can be very slow. Hence, we use some very long timeouts!
delay = 3600
long_delay = 3 * delay
ready_timeout = long_delay
default_timeout = delay
platform = None
path_module = 'posixpath'
parameters = [
Parameter('gem5_binary', kind=str, default='./build/ARM/gem5.fast',
mandatory=False, description="Command used to execute gem5. "
"Adjust according to needs."),
Parameter('gem5_args', kind=types.arguments, mandatory=True,
description="Command line passed to the gem5 simulation. This"
" command line is used to set up the simulated system, and "
"should be the same as used for a standard gem5 simulation "
"without workload automation. Note that this is simulation "
"script specific and will hence need to be tailored to each "
"particular use case."),
Parameter('gem5_vio_args', kind=types.arguments, mandatory=True,
constraint=lambda x: "{}" in str(x),
description="gem5 VirtIO command line used to enable the "
"VirtIO device in the simulated system. At the very least, "
"the root parameter of the VirtIO9PDiod device must be "
"exposed on the command line. Please set this root mount to "
"{}, as it will be replaced with the directory used by "
"Workload Automation at runtime."),
Parameter('temp_dir', kind=str, default='/tmp',
description="Temporary directory used to pass files into the "
"gem5 simulation. Workload Automation will automatically "
"create a directory in this folder, and will remove it again "
"once the simulation completes."),
Parameter('checkpoint', kind=bool, default=False,
mandatory=False, description="This parameter "
"tells Workload Automation to create a checkpoint of the "
"simulated system once the guest system has finished booting."
" This checkpoint can then be used at a later stage by other "
"WA runs to avoid booting the guest system a second time. Set"
" to True to take a checkpoint of the simulated system post "
"boot."),
Parameter('run_delay', kind=int, default=0, mandatory=False,
constraint=lambda x: x >= 0,
description="This sets the time that the "
"system should sleep in the simulated system prior to "
"running and workloads or taking checkpoints. This allows "
"the system to quieten down prior to running the workloads. "
"When this is combined with the checkpoint_post_boot"
" option, it allows the checkpoint to be created post-sleep,"
" and therefore the set of workloads resuming from this "
"checkpoint will not be required to sleep.")
]
@property
def is_rooted(self): # pylint: disable=R0201
# gem5 is always rooted
return True
# pylint: disable=E0203
def __init__(self):
self.logger = logging.getLogger('gem5Device')
# The gem5 subprocess
self.gem5 = None
self.gem5_port = -1
self.gem5outdir = os.path.join(settings.output_directory, "gem5")
self.m5_path = 'm5'
self.stdout_file = None
self.stderr_file = None
self.stderr_filename = None
self.sckt = None
# Find the first one that does not exist. Ensures that we do not re-use
# the directory used by someone else.
for i in xrange(sys.maxint):
directory = os.path.join(self.temp_dir, "wa_{}".format(i))
try:
os.stat(directory)
continue
except OSError:
break
self.temp_dir = directory
self.logger.debug("Using {} as the temporary directory.".format(self.temp_dir))
# Start the gem5 simulation when WA starts a run using a signal.
sig.connect(self.init_gem5, sig.RUN_START)
def validate(self):
# Assemble the virtio args
self.gem5_vio_args = str(self.gem5_vio_args).format(self.temp_dir) # pylint: disable=W0201
self.logger.debug("gem5 VirtIO command: {}".format(self.gem5_vio_args))
def init_gem5(self, _):
"""
Start gem5, find out the telnet port and connect to the simulation.
We first create the temporary directory used by VirtIO to pass files
into the simulation, as well as the gem5 output directory.We then create
files for the standard output and error for the gem5 process. The gem5
process then is started.
"""
self.logger.info("Creating temporary directory: {}".format(self.temp_dir))
os.mkdir(self.temp_dir)
os.mkdir(self.gem5outdir)
# We need to redirect the standard output and standard error for the
# gem5 process to a file so that we can debug when things go wrong.
f = os.path.join(self.gem5outdir, 'stdout')
self.stdout_file = open(f, 'w')
f = os.path.join(self.gem5outdir, 'stderr')
self.stderr_file = open(f, 'w')
# We need to keep this so we can check which port to use for the telnet
# connection.
self.stderr_filename = f
self.start_gem5()
def start_gem5(self):
"""
Starts the gem5 simulator, and parses the output to get the telnet port.
"""
self.logger.info("Starting the gem5 simulator")
command_line = "{} --outdir={}/gem5 {} {}".format(self.gem5_binary,
settings.output_directory,
self.gem5_args,
self.gem5_vio_args)
self.logger.debug("gem5 command line: {}".format(command_line))
self.gem5 = subprocess.Popen(command_line.split(),
stdout=self.stdout_file,
stderr=self.stderr_file)
while self.gem5_port == -1:
# Check that gem5 is running!
if self.gem5.poll():
raise DeviceError("The gem5 process has crashed with error code {}!".format(self.gem5.poll()))
# Open the stderr file
f = open(self.stderr_filename, 'r')
for line in f:
m = re.search(r"Listening\ for\ system\ connection\ on\ port\ (?P<port>\d+)", line)
if m:
port = int(m.group('port'))
if port >= 3456 and port < 5900:
self.gem5_port = port
f.close()
break
else:
time.sleep(1)
f.close()
def connect(self): # pylint: disable=R0912,W0201
"""
Connect to the gem5 simulation and wait for Android to boot. Then,
create checkpoints, and mount the VirtIO device.
"""
self.connect_gem5()
self.wait_for_boot()
if self.run_delay:
self.logger.info("Sleeping for {} seconds in the guest".format(self.run_delay))
self.gem5_shell("sleep {}".format(self.run_delay))
if self.checkpoint:
self.checkpoint_gem5()
self.mount_virtio()
self.logger.info("Creating the working directory in the simulated system")
self.gem5_shell('mkdir -p {}'.format(self.working_directory))
self._is_ready = True # pylint: disable=W0201
def wait_for_boot(self):
pass
def connect_gem5(self): # pylint: disable=R0912
"""
Connect to the telnet port of the gem5 simulation.
We connect, and wait for the prompt to be found. We do not use a timeout
for this, and wait for the prompt in a while loop as the gem5 simulation
can take many hours to reach a prompt when booting the system. We also
inject some newlines periodically to try and force gem5 to show a
prompt. Once the prompt has been found, we replace it with a unique
prompt to ensure that we are able to match it properly. We also disable
the echo as this simplifies parsing the output when executing commands
on the device.
"""
self.logger.info("Connecting to the gem5 simulation on port {}".format(self.gem5_port))
host = socket.gethostname()
port = self.gem5_port
# Connect to the gem5 telnet port. Use a short timeout here.
attempts = 0
while attempts < 10:
attempts += 1
try:
self.sckt = ssh.TelnetConnection()
self.sckt.login(host, 'None', port=port, auto_prompt_reset=False,
login_timeout=10)
break
except pxssh.ExceptionPxssh:
pass
else:
self.gem5.kill()
raise DeviceError("Failed to connect to the gem5 telnet session.")
self.logger.info("Connected! Waiting for prompt...")
# We need to find the prompt. It might be different if we are resuming
# from a checkpoint. Therefore, we test multiple options here.
prompt_found = False
while not prompt_found:
try:
self.login_to_device()
except TIMEOUT:
pass
try:
# Try and force a prompt to be shown
self.sckt.send('\n')
self.sckt.expect([r'# ', self.sckt.UNIQUE_PROMPT, r'\[PEXPECT\][\\\$\#]+ '], timeout=60)
prompt_found = True
except TIMEOUT:
pass
self.logger.info("Setting unique prompt...")
self.sckt.set_unique_prompt()
self.sckt.prompt()
self.logger.info("Prompt found and replaced with a unique string")
# We check that the prompt is what we think it should be. If not, we
# need to update the regex we use to match.
self.find_prompt()
self.sckt.setecho(False)
self.sync_gem5_shell()
self.resize_shell()
def get_properties(self, context): # pylint: disable=R0801
""" Get the property files from the device """
for propfile in self.property_files:
try:
normname = propfile.lstrip(self.path.sep).replace(self.path.sep, '.')
outfile = os.path.join(context.host_working_directory, normname)
if self.is_file(propfile):
self.execute('cat {} > {}'.format(propfile, normname))
self.pull_file(normname, outfile)
elif self.is_directory(propfile):
self.get_directory(context, propfile)
continue
else:
continue
except DeviceError:
# We pull these files "opportunistically", so if a pull fails
# (e.g. we don't have permissions to read the file), just note
# it quietly (not as an error/warning) and move on.
self.logger.debug('Could not pull property file "{}"'.format(propfile))
return {}
def get_directory(self, context, directory):
""" Pull a directory from the device """
normname = directory.lstrip(self.path.sep).replace(self.path.sep, '.')
outdir = os.path.join(context.host_working_directory, normname)
temp_file = os.path.join(context.host_working_directory, "{}.tar".format(normname))
# Check that the folder exists
self.gem5_shell("ls -la {}".format(directory))
# Compress the folder
try:
self.gem5_shell("{} tar -cvf {}.tar {}".format(self.busybox, normname, directory))
except DeviceError:
self.logger.debug("Failed to run tar command on device! Not pulling {}".format(directory))
return
self.pull_file(normname, temp_file)
f = tarfile.open(temp_file, 'r')
os.mkdir(outdir)
f.extractall(outdir)
os.remove(temp_file)
def get_pids_of(self, process_name):
""" Returns a list of PIDs of all processes with the specified name. """
result = self.gem5_shell('ps | {} grep {}'.format(self.busybox, process_name),
check_exit_code=False).strip()
if result and 'not found' not in result and len(result.split('\n')) > 2:
return [int(x.split()[1]) for x in result.split('\n')]
else:
return []
def find_prompt(self):
prompt = r'\[PEXPECT\][\\\$\#]+ '
synced = False
while not synced:
self.sckt.send('\n')
i = self.sckt.expect([prompt, self.sckt.UNIQUE_PROMPT, r'[\$\#] '], timeout=self.delay)
if i == 0:
synced = True
elif i == 1:
prompt = self.sckt.UNIQUE_PROMPT
synced = True
else:
prompt = re.sub(r'\$', r'\\\$', self.sckt.before.strip() + self.sckt.after.strip())
prompt = re.sub(r'\#', r'\\\#', prompt)
prompt = re.sub(r'\[', r'\[', prompt)
prompt = re.sub(r'\]', r'\]', prompt)
self.sckt.PROMPT = prompt
def close(self):
if self._logcat_poller:
self._logcat_poller.stop()
def reset(self):
self.logger.warn("Attempt to restart the gem5 device. This is not "
"supported!")
# pylint: disable=unused-argument
def push_file(self, source, dest, **kwargs):
"""
Push a file to the gem5 device using VirtIO
The file to push to the device is copied to the temporary directory on
the host, before being copied within the simulation to the destination.
Checks, in the form of 'ls' with error code checking, are performed to
ensure that the file is copied to the destination.
"""
filename = os.path.basename(source)
self.logger.debug("Pushing {} to device.".format(source))
self.logger.debug("temp_dir: {}".format(self.temp_dir))
self.logger.debug("dest: {}".format(dest))
self.logger.debug("filename: {}".format(filename))
# We need to copy the file to copy to the temporary directory
self.move_to_temp_dir(source)
# Back to the gem5 world
self.gem5_shell("ls -al /mnt/obb/{}".format(filename))
if self.busybox:
self.gem5_shell("{} cp /mnt/obb/{} {}".format(self.busybox, filename, dest))
else:
self.gem5_shell("cat /mnt/obb/{} > {}".format(filename, dest))
self.gem5_shell("sync")
self.gem5_shell("ls -al {}".format(dest))
self.gem5_shell("ls -al /mnt/obb/")
self.logger.debug("Push complete.")
# pylint: disable=unused-argument
def pull_file(self, source, dest, **kwargs):
"""
Pull a file from the gem5 device using m5 writefile
The file is copied to the local directory within the guest as the m5
writefile command assumes that the file is local. The file is then
written out to the host system using writefile, prior to being moved to
the destination on the host.
"""
filename = os.path.basename(source)
self.logger.debug("pull_file {} {}".format(source, filename))
# We don't check the exit code here because it is non-zero if the source
# and destination are the same. The ls below will cause an error if the
# file was not where we expected it to be.
self.gem5_shell("{} cp {} {}".format(self.busybox, source, filename),
check_exit_code=False)
self.gem5_shell("sync")
self.gem5_shell("ls -la {}".format(filename))
self.logger.debug('Finished the copy in the simulator')
self.gem5_util("writefile {}".format(filename))
if 'cpu' not in filename:
while not os.path.exists(os.path.join(self.gem5outdir, filename)):
time.sleep(1)
# Perform the local move
shutil.move(os.path.join(self.gem5outdir, filename), dest)
self.logger.debug("Pull complete.")
# pylint: disable=unused-argument
def delete_file(self, filepath, **kwargs):
""" Delete a file on the device """
self._check_ready()
self.gem5_shell("rm '{}'".format(filepath))
def file_exists(self, filepath):
""" Check if a file exists """
self._check_ready()
output = self.gem5_shell('if [ -e \'{}\' ]; then echo 1; else echo 0; fi'.format(filepath))
try:
if int(output):
return True
except ValueError:
# If we cannot process the output, assume that there is no file
pass
return False
def disconnect(self):
"""
Close and disconnect from the gem5 simulation. Additionally, we remove
the temporary directory used to pass files into the simulation.
"""
self.logger.info("Gracefully terminating the gem5 simulation.")
try:
self.gem5_util("exit")
self.gem5.wait()
except EOF:
pass
self.logger.info("Removing the temporary directory")
try:
shutil.rmtree(self.temp_dir)
except OSError:
self.logger.warn("Failed to remove the temporary directory!")
# gem5 might be slow. Hence, we need to make the ping timeout very long.
def ping(self):
self.logger.debug("Pinging gem5 to see if it is still alive")
self.gem5_shell('ls /', timeout=self.longdelay)
# Additional Android-specific methods.
def forward_port(self, _): # pylint: disable=R0201
raise DeviceError('we do not need forwarding')
# gem5 should dump out a framebuffer. We can use this if it exists. Failing
# that, fall back to the parent class implementation.
def capture_screen(self, filepath):
file_list = os.listdir(self.gem5outdir)
screen_caps = []
for f in file_list:
if '.bmp' in f:
screen_caps.append(f)
if len(screen_caps) == 1:
# Bail out if we do not have image, and resort to the slower, built
# in method.
try:
import Image
gem5_image = os.path.join(self.gem5outdir, screen_caps[0])
temp_image = os.path.join(self.gem5outdir, "file.png")
im = Image.open(gem5_image)
im.save(temp_image, "PNG")
shutil.copy(temp_image, filepath)
os.remove(temp_image)
self.logger.debug("capture_screen: using gem5 screencap")
return True
except (shutil.Error, ImportError, IOError):
pass
return False
# pylint: disable=W0613
def execute(self, command, timeout=1000, check_exit_code=True, background=False,
as_root=False, busybox=False, **kwargs):
self._check_ready()
if as_root and not self.is_rooted:
raise DeviceError('Attempting to execute "{}" as root on unrooted device.'.format(command))
if busybox:
if not self.is_rooted:
raise DeviceError('Attempting to execute "{}" with busybox. '.format(command) +
'Busybox can only be deployed to rooted devices.')
command = ' '.join([self.busybox, command])
if background:
self.logger.debug("Attempt to execute in background. Not supported "
"in gem5, hence ignored.")
return self.gem5_shell(command, as_root=as_root)
# Internal methods: do not use outside of the class.
def _check_ready(self):
"""
Check if the device is ready.
As this is gem5, we just assume that the device is ready once we have
connected to the gem5 simulation, and updated the prompt.
"""
if not self._is_ready:
raise DeviceError('Device not ready.')
def gem5_shell(self, command, as_root=False, timeout=None, check_exit_code=True, sync=True): # pylint: disable=R0912
"""
Execute a command in the gem5 shell
This wraps the telnet connection to gem5 and processes the raw output.
This method waits for the shell to return, and then will try and
separate the output from the command from the command itself. If this
fails, warn, but continue with the potentially wrong output.
The exit code is also checked by default, and non-zero exit codes will
raise a DeviceError.
"""
conn = self.sckt
if sync:
self.sync_gem5_shell()
self.logger.debug("gem5_shell command: {}".format(command))
# Send the actual command
conn.send("{}\n".format(command))
# Wait for the response. We just sit here and wait for the prompt to
# appear, as gem5 might take a long time to provide the output. This
# avoids timeout issues.
command_index = -1
while command_index == -1:
if conn.prompt():
output = re.sub(r' \r([^\n])', r'\1', conn.before)
output = re.sub(r'[\b]', r'', output)
# Deal with line wrapping
output = re.sub(r'[\r].+?<', r'', output)
command_index = output.find(command)
# If we have -1, then we cannot match the command, but the
# prompt has returned. Hence, we have a bit of an issue. We
# warn, and return the whole output.
if command_index == -1:
self.logger.warn("gem5_shell: Unable to match command in "
"command output. Expect parsing errors!")
command_index = 0
output = output[command_index + len(command):].strip()
# It is possible that gem5 will echo the command. Therefore, we need to
# remove that too!
command_index = output.find(command)
if command_index != -1:
output = output[command_index + len(command):].strip()
self.logger.debug("gem5_shell output: {}".format(output))
# We get a second prompt. Hence, we need to eat one to make sure that we
# stay in sync. If we do not do this, we risk getting out of sync for
# slower simulations.
self.sckt.expect([self.sckt.UNIQUE_PROMPT, self.sckt.PROMPT], timeout=self.delay)
if check_exit_code:
exit_code_text = self.gem5_shell('echo $?', as_root=as_root,
timeout=timeout, check_exit_code=False,
sync=False)
try:
exit_code = int(exit_code_text.split()[0])
if exit_code:
message = 'Got exit code {}\nfrom: {}\nOUTPUT: {}'
raise DeviceError(message.format(exit_code, command, output))
except (ValueError, IndexError):
self.logger.warning('Could not get exit code for "{}",\ngot: "{}"'.format(command, exit_code_text))
return output
def gem5_util(self, command):
""" Execute a gem5 utility command using the m5 binary on the device """
self.gem5_shell('{} {}'.format(self.m5_path, command))
def sync_gem5_shell(self):
"""
Synchronise with the gem5 shell.
Write some unique text to the gem5 device to allow us to synchronise
with the shell output. We actually get two prompts so we need to match
both of these.
"""
self.logger.debug("Sending Sync")
self.sckt.send("echo \*\*sync\*\*\n")
self.sckt.expect(r"\*\*sync\*\*", timeout=self.delay)
self.sckt.expect([self.sckt.UNIQUE_PROMPT, self.sckt.PROMPT], timeout=self.delay)
self.sckt.expect([self.sckt.UNIQUE_PROMPT, self.sckt.PROMPT], timeout=self.delay)
def resize_shell(self):
"""
Resize the shell to avoid line wrapping issues.
"""
# Try and avoid line wrapping as much as possible. Don't check the error
# codes from these command because some of them WILL fail.
self.gem5_shell('stty columns 1024', check_exit_code=False)
self.gem5_shell('{} stty columns 1024'.format(self.busybox), check_exit_code=False)
self.gem5_shell('stty cols 1024', check_exit_code=False)
self.gem5_shell('{} stty cols 1024'.format(self.busybox), check_exit_code=False)
self.gem5_shell('reset', check_exit_code=False)
def move_to_temp_dir(self, source):
"""
Move a file to the temporary directory on the host for copying to the
gem5 device
"""
command = "cp {} {}".format(source, self.temp_dir)
self.logger.debug("Local copy command: {}".format(command))
subprocess.call(command.split())
subprocess.call("sync".split())
def checkpoint_gem5(self, end_simulation=False):
""" Checkpoint the gem5 simulation, storing all system state """
self.logger.info("Taking a post-boot checkpoint")
self.gem5_util("checkpoint")
if end_simulation:
self.disconnect()
def mount_virtio(self):
"""
Mount the VirtIO device in the simulated system.
"""
self.logger.info("Mounting VirtIO device in simulated system")
self.gem5_shell('mkdir -p /mnt/obb')
mount_command = "mount -t 9p -o trans=virtio,version=9p2000.L,aname={} gem5 /mnt/obb".format(self.temp_dir)
self.gem5_shell(mount_command)
def deploy_m5(self, context, force=False):
"""
Deploys the m5 binary to the device and returns the path to the binary
on the device.
:param force: by default, if the binary is already present on the
device, it will not be deployed again. Setting force to
``True`` overrides that behaviour and ensures that the
binary is always copied. Defaults to ``False``.
:returns: The on-device path to the m5 binary.
"""
on_device_executable = self.path.join(self.binaries_directory, 'm5')
if not force and self.file_exists(on_device_executable):
# We want to check the version of the binary. We cannot directly
# check this because the m5 binary itself is unversioned. We also
# need to make sure not to check the error code as "m5 --help"
# returns a non-zero error code.
output = self.gem5_shell('m5 --help', check_exit_code=False)
if "writefile" in output:
self.logger.debug("Using the m5 binary on the device...")
self.m5_path = on_device_executable
return on_device_executable
else:
self.logger.debug("m5 on device does not support writefile!")
host_file = context.resolver.get(Executable(NO_ONE, self.abi, 'm5'))
self.logger.info("Installing the m5 binary to the device...")
self.m5_path = self.install(host_file)
return self.m5_path

View File

@@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,23 @@ reboot_policy = 'as_needed'
# random: Randomisizes the order in which specs run. #
execution_order = 'by_iteration'
# This indicates when a job will be re-run.
# Possible values:
# OK: This iteration has completed and no errors have been detected
# PARTIAL: One or more instruments have failed (the iteration may still be running).
# FAILED: The workload itself has failed.
# ABORTED: The user interupted the workload
#
# If set to an empty list, a job will not be re-run ever.
retry_on_status = ['FAILED', 'PARTIAL']
# How many times a job will be re-run before giving up
max_retries = 3
# If WA should delete its files from the device after the run is completed
clean_up = False
####################################################################################################
######################################### Device Settings ##########################################
####################################################################################################
@@ -70,7 +87,7 @@ device_config = dict(
####################################################################################################
################################### Instrumention Configuration ####################################
################################### Instrumentation Configuration ####################################
####################################################################################################
# This defines the additionnal instrumentation that will be enabled during workload execution, #
# which in turn determines what additional data (such as /proc/interrupts content or Streamline #
@@ -120,6 +137,9 @@ instrumentation = [
# Specifies how results will be processed and presented. #
# #
result_processors = [
# Creates a status.txt that provides a summary status for the run
'status',
# Creates a results.txt file for each iteration that lists all collected metrics
# in "name = value (units)" format
'standard',
@@ -132,7 +152,7 @@ result_processors = [
# all in the .csv format. Summary metrics are defined on per-worklod basis
# are typically things like overall scores. The contents of summary.csv are
# always a subset of the contents of results.csv (if it is generated).
'summary_csv',
#'summary_csv',
# Creates a results.csv that contains metrics for all iterations of all workloads
# in the JSON format
@@ -172,7 +192,7 @@ logging = {
####################################################################################################
#################################### Instruments Configuration #####################################
####################################################################################################
# Instrumention Configuration is related to specific insturment's settings. Some of the #
# Instrumentation Configuration is related to specific instrument's settings. Some of the #
# instrumentations require specific settings in order for them to work. These settings are #
# specified here. #
# Note that these settings only take effect if the corresponding instrument is
@@ -195,18 +215,6 @@ logging = {
# The kinds of sensors hwmon instrument will look for
#hwmon_sensors = ['energy', 'temp']
####################################################################################################
##################################### streamline configuration #####################################
# The port number on which gatord will listen
#port = 8080
# Enabling/disabling the run of 'streamline -analyze' on the captured data.
#streamline_analyze = True
# Enabling/disabling the generation of a CSV report
#streamline_report_csv = True
####################################################################################################
###################################### trace-cmd configuration #####################################
@@ -217,10 +225,10 @@ logging = {
####################################################################################################
######################################### DAQ configuration ########################################
# The host address of the machine that runs the daq Server which the insturment communicates with
# The host address of the machine that runs the daq Server which the instrument communicates with
#daq_server_host = '10.1.17.56'
# The port number for daq Server in which daq insturment communicates with
# The port number for daq Server in which daq instrument communicates with
#daq_server_port = 56788
# The values of resistors 1 and 2 (in Ohms) across which the voltages are measured

View File

@@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

View File

@@ -16,13 +16,12 @@
import os
from copy import copy
from collections import OrderedDict, defaultdict
import yaml
from wlauto.exceptions import ConfigError
from wlauto.utils.misc import load_struct_from_yaml, LoadSyntaxError
from wlauto.utils.types import counter, reset_counter
import yaml
def get_aliased_param(d, aliases, default=None, pop=True):
alias_map = [i for i, a in enumerate(aliases) if a in d]
@@ -70,6 +69,7 @@ class AgendaWorkloadEntry(AgendaEntry):
default=OrderedDict())
self.instrumentation = kwargs.pop('instrumentation', [])
self.flash = kwargs.pop('flash', OrderedDict())
self.classifiers = kwargs.pop('classifiers', OrderedDict())
if kwargs:
raise ConfigError('Invalid entry(ies) in workload {}: {}'.format(self.id, ', '.join(kwargs.keys())))
@@ -96,6 +96,7 @@ class AgendaSectionEntry(AgendaEntry):
default=OrderedDict())
self.instrumentation = kwargs.pop('instrumentation', [])
self.flash = kwargs.pop('flash', OrderedDict())
self.classifiers = kwargs.pop('classifiers', OrderedDict())
self.workloads = []
for w in kwargs.pop('workloads', []):
self.workloads.append(agenda.get_workload_entry(w))
@@ -128,6 +129,7 @@ class AgendaGlobalEntry(AgendaEntry):
default=OrderedDict())
self.instrumentation = kwargs.pop('instrumentation', [])
self.flash = kwargs.pop('flash', OrderedDict())
self.classifiers = kwargs.pop('classifiers', OrderedDict())
if kwargs:
raise ConfigError('Invalid entries in global section: {}'.format(kwargs))
@@ -136,7 +138,7 @@ class Agenda(object):
def __init__(self, source=None):
self.filepath = None
self.config = None
self.config = {}
self.global_ = None
self.sections = []
self.workloads = []
@@ -161,13 +163,22 @@ class Agenda(object):
self._assign_id_if_needed(w, 'workload')
return AgendaWorkloadEntry(**w)
def _load(self, source):
raw = self._load_raw_from_source(source)
def _load(self, source): # pylint: disable=too-many-branches
try:
raw = self._load_raw_from_source(source)
except ValueError as e:
name = getattr(source, 'name', '')
raise ConfigError('Error parsing agenda {}: {}'.format(name, e))
if not isinstance(raw, dict):
message = '{} does not contain a valid agenda structure; top level must be a dict.'
raise ConfigError(message.format(self.filepath))
for k, v in raw.iteritems():
if v is None:
raise ConfigError('Empty "{}" entry in {}'.format(k, self.filepath))
if k == 'config':
if not isinstance(v, dict):
raise ConfigError('Invalid agenda: "config" entry must be a dict')
self.config = v
elif k == 'global':
self.global_ = AgendaGlobalEntry(**v)
@@ -237,7 +248,13 @@ def dict_representer(dumper, data):
def dict_constructor(loader, node):
return OrderedDict(loader.construct_pairs(node))
pairs = loader.construct_pairs(node)
seen_keys = set()
for k, _ in pairs:
if k in seen_keys:
raise ValueError('Duplicate entry: {}'.format(k))
seen_keys.add(k)
return OrderedDict(pairs)
yaml.add_representer(OrderedDict, dict_representer)

View File

@@ -16,13 +16,13 @@
import os
import shutil
import imp
import sys
import re
from collections import namedtuple, OrderedDict
from wlauto.exceptions import ConfigError
from wlauto.utils.misc import merge_dicts, normalize, unique
from wlauto.utils.misc import load_struct_from_yaml, load_struct_from_python, LoadSyntaxError
from wlauto.utils.types import identifier
@@ -76,7 +76,7 @@ class ConfigLoader(object):
self._loaded = False
self._config = {}
self.config_count = 0
self._loaded_files = []
self.loaded_files = []
self.environment_root = None
self.output_directory = 'wa_output'
self.reboot_after_each_iteration = True
@@ -106,14 +106,22 @@ class ConfigLoader(object):
self.update_from_file(source)
def update_from_file(self, source):
ext = os.path.splitext(source)[1].lower() # pylint: disable=redefined-outer-name
try:
new_config = imp.load_source('config_{}'.format(self.config_count), source)
except SyntaxError, e:
message = 'Sytax error in config: {}'.format(str(e))
raise ConfigError(message)
self._config = merge_dicts(self._config, vars(new_config),
list_duplicates='first', match_types=False, dict_type=OrderedDict)
self._loaded_files.append(source)
if ext in ['.py', '.pyo', '.pyc']:
new_config = load_struct_from_python(source)
elif ext == '.yaml':
new_config = load_struct_from_yaml(source)
else:
raise ConfigError('Unknown config format: {}'.format(source))
except (LoadSyntaxError, ValueError) as e:
raise ConfigError('Invalid config "{}":\n\t{}'.format(source, e))
self._config = merge_dicts(self._config, new_config,
list_duplicates='first',
match_types=False,
dict_type=OrderedDict)
self.loaded_files.append(source)
self._loaded = True
def update_from_dict(self, source):
@@ -123,7 +131,7 @@ class ConfigLoader(object):
self._loaded = True
def get_config_paths(self):
return [lf.rstrip('c') for lf in self._loaded_files]
return [lf.rstrip('c') for lf in self.loaded_files]
def _check_loaded(self):
if not self._loaded:
@@ -151,33 +159,44 @@ def init_environment(env_root, dep_dir, extension_paths, overwrite_existing=Fals
for path in extension_paths:
os.makedirs(path)
# If running with sudo on POSIX, change the ownership to the real user.
real_user = os.getenv('SUDO_USER')
if real_user:
import pwd # done here as module won't import on win32
user_entry = pwd.getpwnam(real_user)
uid, gid = user_entry.pw_uid, user_entry.pw_gid
os.chown(env_root, uid, gid)
# why, oh why isn't there a recusive=True option for os.chown?
for root, dirs, files in os.walk(env_root):
for d in dirs:
os.chown(os.path.join(root, d), uid, gid)
for f in files: # pylint: disable=W0621
os.chown(os.path.join(root, f), uid, gid)
if os.getenv('USER') == 'root':
# If running with sudo on POSIX, change the ownership to the real user.
real_user = os.getenv('SUDO_USER')
if real_user:
import pwd # done here as module won't import on win32
user_entry = pwd.getpwnam(real_user)
uid, gid = user_entry.pw_uid, user_entry.pw_gid
os.chown(env_root, uid, gid)
# why, oh why isn't there a recusive=True option for os.chown?
for root, dirs, files in os.walk(env_root):
for d in dirs:
os.chown(os.path.join(root, d), uid, gid)
for f in files: # pylint: disable=W0621
os.chown(os.path.join(root, f), uid, gid)
_env_root = os.getenv('WA_USER_DIRECTORY', os.path.join(_user_home, '.workload_automation'))
_dep_dir = os.path.join(_env_root, 'dependencies')
_extension_paths = [os.path.join(_env_root, ext.default_path) for ext in _extensions]
_extension_paths.extend(os.getenv('WA_EXTENSION_PATHS', '').split(os.pathsep))
_env_var_paths = os.getenv('WA_EXTENSION_PATHS', '')
if _env_var_paths:
_extension_paths.extend(_env_var_paths.split(os.pathsep))
_env_configs = []
for filename in ['config.py', 'config.yaml']:
filepath = os.path.join(_env_root, filename)
if os.path.isfile(filepath):
_env_configs.append(filepath)
if not os.path.isdir(_env_root):
init_environment(_env_root, _dep_dir, _extension_paths)
elif not os.path.isfile(os.path.join(_env_root, 'config.py')):
elif not _env_configs:
filepath = os.path.join(_env_root, 'config.py')
with open(os.path.join(_this_dir, '..', 'config_example.py')) as f:
f_text = re.sub(r'""".*?"""', '', f.read(), 1, re.DOTALL)
with open(os.path.join(_env_root, 'config.py'), 'w') as f:
with open(filepath, 'w') as f:
f.write(f_text)
_env_configs.append(filepath)
settings = ConfigLoader()
settings.environment_root = _env_root
@@ -190,6 +209,5 @@ if os.path.isfile(_packages_file):
with open(_packages_file) as fh:
settings.extension_packages = unique(fh.read().split())
_env_config = os.path.join(settings.environment_root, 'config.py')
settings.update(_env_config)
for config in _env_configs:
settings.update(config)

View File

@@ -45,12 +45,12 @@ class Command(Extension):
parser_params['formatter_class'] = self.formatter_class
self.parser = subparsers.add_parser(self.name, **parser_params)
init_argument_parser(self.parser) # propagate top-level options
self.initialize()
self.initialize(None)
def initialize(self):
def initialize(self, context):
"""
Perform command-specific initialisation (e.g. adding command-specific options to the command's
parser).
parser). ``context`` is always ``None``.
"""
pass

View File

@@ -77,6 +77,7 @@ class WorkloadRunSpec(object):
runtime_parameters=None,
instrumentation=None,
flash=None,
classifiers=None,
): # pylint: disable=W0622
self.id = id
self.number_of_iterations = number_of_iterations
@@ -88,6 +89,7 @@ class WorkloadRunSpec(object):
self.workload_parameters = workload_parameters or OrderedDict()
self.instrumentation = instrumentation or []
self.flash = flash or OrderedDict()
self.classifiers = classifiers or OrderedDict()
self._workload = None
self._section = None
self.enabled = True
@@ -96,7 +98,7 @@ class WorkloadRunSpec(object):
if param in ['id', 'section_id', 'number_of_iterations', 'workload_name', 'label']:
if value is not None:
setattr(self, param, value)
elif param in ['boot_parameters', 'runtime_parameters', 'workload_parameters', 'flash']:
elif param in ['boot_parameters', 'runtime_parameters', 'workload_parameters', 'flash', 'classifiers']:
setattr(self, param, merge_dicts(getattr(self, param), value, list_duplicates='last',
dict_type=OrderedDict, should_normalize=False))
elif param in ['instrumentation']:
@@ -155,6 +157,23 @@ class WorkloadRunSpec(object):
del d['_section']
return d
def copy(self):
other = WorkloadRunSpec()
other.id = self.id
other.number_of_iterations = self.number_of_iterations
other.workload_name = self.workload_name
other.label = self.label
other.section_id = self.section_id
other.boot_parameters = copy(self.boot_parameters)
other.runtime_parameters = copy(self.runtime_parameters)
other.workload_parameters = copy(self.workload_parameters)
other.instrumentation = copy(self.instrumentation)
other.flash = copy(self.flash)
other.classifiers = copy(self.classifiers)
other._section = self._section # pylint: disable=protected-access
other.enabled = self.enabled
return other
def __str__(self):
return '{} {}'.format(self.id, self.label)
@@ -292,6 +311,12 @@ def _combine_ids(*args):
return '_'.join(args)
class status_list(list):
def append(self, item):
list.append(self, str(item).upper())
class RunConfiguration(object):
"""
Loads and maintains the unified configuration for this run. This includes configuration
@@ -400,7 +425,7 @@ class RunConfiguration(object):
is validated (to make sure there are no missing settings, etc).
- Extensions are loaded through the run config object, which instantiates
them with appropriate parameters based on the "raw" config collected earlier. When an
Extension is instantiated in such a way, it's config is "officially" added to run configuration
Extension is instantiated in such a way, its config is "officially" added to run configuration
tracked by the run config object. Raw config is discarded at the end of the run, so
that any config that wasn't loaded in this way is not recoded (as it was not actually used).
- Extension parameters a validated individually (for type, value ranges, etc) as they are
@@ -454,6 +479,9 @@ class RunConfiguration(object):
RunConfigurationItem('reboot_policy', 'scalar', 'replace'),
RunConfigurationItem('device', 'scalar', 'replace'),
RunConfigurationItem('flashing_config', 'dict', 'replace'),
RunConfigurationItem('retry_on_status', 'list', 'replace'),
RunConfigurationItem('max_retries', 'scalar', 'replace'),
RunConfigurationItem('clean_up', 'scalar', 'replace'),
]
# Configuration specified for each workload spec. "workload_parameters"
@@ -468,11 +496,12 @@ class RunConfiguration(object):
RunConfigurationItem('runtime_parameters', 'dict', 'merge'),
RunConfigurationItem('instrumentation', 'list', 'merge'),
RunConfigurationItem('flash', 'dict', 'merge'),
RunConfigurationItem('classifiers', 'dict', 'merge'),
]
# List of names that may be present in configuration (and it is valid for
# them to be there) but are not handled buy RunConfiguration.
ignore_names = ['logging']
ignore_names = ['logging', 'remote_assets_mount_point']
def get_reboot_policy(self):
if not self._reboot_policy:
@@ -507,6 +536,8 @@ class RunConfiguration(object):
self.workload_specs = []
self.flashing_config = {}
self.other_config = {} # keeps track of used config for extensions other than of the four main kinds.
self.retry_on_status = status_list(['FAILED', 'PARTIAL'])
self.max_retries = 3
self._used_config_items = []
self._global_instrumentation = []
self._reboot_policy = None
@@ -639,7 +670,7 @@ class RunConfiguration(object):
for param, ext in ga.iteritems():
for name in [ext.name] + [a.name for a in ext.aliases]:
self._load_default_config_if_necessary(name)
self._raw_config[name][param.name] = value
self._raw_config[identifier(name)][param.name] = value
def _set_run_config_item(self, name, value):
item = self._general_config_map[name]
@@ -653,12 +684,12 @@ class RunConfiguration(object):
def _set_raw_dict(self, name, value, default_config=None):
existing_config = self._raw_config.get(name, default_config or {})
new_config = _merge_config_dicts(existing_config, value)
self._raw_config[name] = new_config
self._raw_config[identifier(name)] = new_config
def _set_raw_list(self, name, value):
old_value = self._raw_config.get(name, [])
new_value = merge_lists(old_value, value, duplicates='last')
self._raw_config[name] = new_value
self._raw_config[identifier(name)] = new_value
def _finalize_config_list(self, attr_name):
"""Note: the name is somewhat misleading. This finalizes a list
@@ -668,18 +699,21 @@ class RunConfiguration(object):
raw_list = self._raw_config.get(attr_name, [])
for extname in raw_list:
default_config = self.ext_loader.get_default_config(extname)
ext_config[extname] = self._raw_config.get(extname, default_config)
ext_config[extname] = self._raw_config.get(identifier(extname), default_config)
list_name = '_global_{}'.format(attr_name)
setattr(self, list_name, raw_list)
global_list = self._raw_config.get(list_name, [])
setattr(self, list_name, global_list)
setattr(self, attr_name, ext_config)
def _finalize_device_config(self):
self._load_default_config_if_necessary(self.device)
config = _merge_config_dicts(self._raw_config.get(self.device),
self._raw_config.get('device_config', {}))
config = _merge_config_dicts(self._raw_config.get(self.device, {}),
self._raw_config.get('device_config', {}),
list_duplicates='all')
self.device_config = config
def _load_default_config_if_necessary(self, name):
name = identifier(name)
if name not in self._raw_config:
self._raw_config[name] = self.ext_loader.get_default_config(name)
@@ -724,7 +758,7 @@ class RunConfiguration(object):
if spec.match_selectors(selectors):
instrumentation_config = self._raw_config['instrumentation']
for instname in spec.instrumentation:
if instname not in instrumentation_config:
if instname not in instrumentation_config and not instname.startswith('~'):
instrumentation_config.append(instname)
self.workload_specs.append(spec)

View File

@@ -35,8 +35,9 @@ from collections import OrderedDict
from contextlib import contextmanager
from wlauto.core.extension import Extension, ExtensionMeta, AttributeCollection, Parameter
from wlauto.core.extension_loader import ExtensionLoader
from wlauto.exceptions import DeviceError, ConfigError
from wlauto.utils.types import list_of_strings, list_of_integers
from wlauto.utils.types import list_of_integers, list_of, caseless_string
__all__ = ['RuntimeParameter', 'CoreParameter', 'Device', 'DeviceMeta']
@@ -93,10 +94,34 @@ class CoreParameter(RuntimeParameter):
return params
class DynamicModuleSpec(dict):
@property
def name(self):
return self.keys()[0]
def __init__(self, *args, **kwargs):
dict.__init__(self)
if args:
if len(args) > 1:
raise ValueError(args)
value = args[0]
else:
value = kwargs
if isinstance(value, basestring):
self[value] = {}
elif isinstance(value, dict) and len(value) == 1:
for k, v in value.iteritems():
self[k] = v
else:
raise ValueError(value)
class DeviceMeta(ExtensionMeta):
to_propagate = ExtensionMeta.to_propagate + [
('runtime_parameters', RuntimeParameter, AttributeCollection),
('dynamic_modules', DynamicModuleSpec, AttributeCollection),
]
@@ -137,7 +162,7 @@ class Device(Extension):
__metaclass__ = DeviceMeta
parameters = [
Parameter('core_names', kind=list_of_strings, mandatory=True, default=None,
Parameter('core_names', kind=list_of(caseless_string), mandatory=True, default=None,
description="""
This is a list of all cpu cores on the device with each
element being the core type, e.g. ``['a7', 'a7', 'a15']``. The
@@ -149,12 +174,17 @@ class Device(Extension):
description="""
This is a list indicating the cluster affinity of the CPU cores,
each element correponding to the cluster ID of the core coresponding
to it's index. E.g. ``[0, 0, 1]`` indicates that cpu0 and cpu1 are on
cluster 0, while cpu2 is on cluster 1.
to its index. E.g. ``[0, 0, 1]`` indicates that cpu0 and cpu1 are on
cluster 0, while cpu2 is on cluster 1. If this is not specified, this
will be inferred from ``core_names`` if possible (assuming all cores with
the same name are on the same cluster).
"""),
]
runtime_parameters = []
# dynamic modules are loaded or not based on whether the device supports
# them (established at runtime by module probling the device).
dynamic_modules = []
# These must be overwritten by subclasses.
name = None
@@ -177,6 +207,36 @@ class Device(Extension):
except IOError:
raise DeviceError('Unsupported path module: {}'.format(self.path_module))
def validate(self):
# pylint: disable=access-member-before-definition,attribute-defined-outside-init
if self.core_names and not self.core_clusters:
self.core_clusters = []
clusters = []
for cn in self.core_names:
if cn not in clusters:
clusters.append(cn)
self.core_clusters.append(clusters.index(cn))
if len(self.core_names) != len(self.core_clusters):
raise ConfigError('core_names and core_clusters are of different lengths.')
def initialize(self, context):
"""
Initialization that is performed at the begining of the run (after the device has
been connecte).
"""
loader = ExtensionLoader()
for module_spec in self.dynamic_modules:
module = self._load_module(loader, module_spec)
if not hasattr(module, 'probe'):
message = 'Module {} does not have "probe" attribute; cannot be loaded dynamically'
raise ValueError(message.format(module.name))
if module.probe(self):
self.logger.debug('Installing module "{}"'.format(module.name))
self._install_module(module)
else:
self.logger.debug('Module "{}" is not supported by the device'.format(module.name))
def reset(self):
"""
Initiate rebooting of the device.
@@ -208,35 +268,6 @@ class Device(Extension):
""" Close the established connection to the device. """
raise NotImplementedError()
def initialize(self, context, *args, **kwargs):
"""
Default implementation just calls through to init(). May be overriden by specialised
abstract sub-cleasses to implent platform-specific intialization without requiring
concrete implementations to explicitly invoke parent's init().
Added in version 2.1.3.
"""
self.init(context, *args, **kwargs)
def init(self, context, *args, **kwargs):
"""
Initialize the device. This method *must* be called after a device reboot before
any other commands can be issued, however it may also be called without rebooting.
It is up to device-specific implementations to identify what initialisation needs
to be preformed on a particular invocation. Bear in mind that no assumptions can be
made about the state of the device prior to the initiation of workload execution,
so full initialisation must be performed at least once, even if no reboot has occurred.
After that, the device-specific implementation may choose to skip initialization if
the device has not been rebooted; it is up to the implementation to keep track of
that, however.
All arguments are device-specific (see the documentation for the your device).
"""
pass
def ping(self):
"""
This must return successfully if the device is able to receive commands, or must
@@ -269,14 +300,15 @@ class Device(Extension):
runtime_parameters = self._expand_runtime_parameters()
rtp_map = {rtp.name.lower(): rtp for rtp in runtime_parameters}
params = OrderedDict((k.lower(), v) for k, v in params.iteritems())
params = OrderedDict((k.lower(), v) for k, v in params.iteritems() if v is not None)
expected_keys = rtp_map.keys()
if not set(params.keys()) <= set(expected_keys):
if not set(params.keys()).issubset(set(expected_keys)):
unknown_params = list(set(params.keys()).difference(set(expected_keys)))
raise ConfigError('Unknown runtime parameter(s): {}'.format(unknown_params))
for param in params:
self.logger.debug('Setting runtime parameter "{}"'.format(param))
rtp = rtp_map[param]
setter = getattr(self, rtp.setter)
args = dict(rtp.setter_args.items() + [(rtp.value_name, params[rtp.name.lower()])])
@@ -394,6 +426,13 @@ class Device(Extension):
"""
pass
def is_network_connected(self):
"""
Checks if the device is connected to the internet
"""
raise NotImplementedError()
def __str__(self):
return 'Device<{}>'.format(self.name)
@@ -415,4 +454,3 @@ class Device(Extension):
except Exception as e:
self.ping()
raise e

View File

@@ -17,17 +17,19 @@
import sys
import argparse
import logging
import os
import subprocess
import warnings
from wlauto.core.bootstrap import settings
from wlauto.core.extension_loader import ExtensionLoader
from wlauto.exceptions import WAError
from wlauto.exceptions import WAError, ConfigError
from wlauto.utils.misc import get_traceback
from wlauto.utils.log import init_logging
from wlauto.utils.cli import init_argument_parser
from wlauto.utils.doc import format_body
import warnings
warnings.filterwarnings(action='ignore', category=UserWarning, module='zope')
@@ -55,6 +57,8 @@ def main():
settings.verbosity = args.verbose
settings.debug = args.debug
if args.config:
if not os.path.exists(args.config):
raise ConfigError("Config file {} not found".format(args.config))
settings.update(args.config)
init_logging(settings.verbosity)
@@ -64,12 +68,27 @@ def main():
except KeyboardInterrupt:
logging.info('Got CTRL-C. Aborting.')
sys.exit(3)
except WAError, e:
except WAError as e:
logging.critical(e)
sys.exit(1)
except Exception, e: # pylint: disable=broad-except
except subprocess.CalledProcessError as e:
tb = get_traceback()
logging.critical(tb)
command = e.cmd
if e.args:
command = '{} {}'.format(command, ' '.join(e.args))
message = 'Command \'{}\' returned non-zero exit status {}\nOUTPUT:\n{}\n'
logging.critical(message.format(command, e.returncode, e.output))
sys.exit(2)
except SyntaxError as e:
tb = get_traceback()
logging.critical(tb)
message = 'Syntax Error in {}, line {}, offset {}:'
logging.critical(message.format(e.filename, e.lineno, e.offset))
logging.critical('\t{}'.format(e.msg))
sys.exit(2)
except Exception as e: # pylint: disable=broad-except
tb = get_traceback()
logging.critical(tb)
logging.critical('{}({})'.format(e.__class__.__name__, e))
sys.exit(2)

View File

@@ -56,7 +56,8 @@ from wlauto.core.extension_loader import ExtensionLoader
from wlauto.core.resolver import ResourceResolver
from wlauto.core.result import ResultManager, IterationResult, RunResult
from wlauto.exceptions import (WAError, ConfigError, TimeoutError, InstrumentError,
DeviceError, DeviceNotRespondingError)
DeviceError, DeviceNotRespondingError, ResourceError,
HostError)
from wlauto.utils.misc import ensure_directory_exists as _d, get_traceback, merge_dicts, format_duration
@@ -72,7 +73,7 @@ REBOOT_DELAY = 3
class RunInfo(object):
"""
Information about the current run, such as it's unique ID, run
Information about the current run, such as its unique ID, run
time, etc.
"""
@@ -85,7 +86,8 @@ class RunInfo(object):
self.duration = None
self.project = config.project
self.project_stage = config.project_stage
self.run_name = config.run_name
self.run_name = config.run_name or "{}_{}".format(os.path.split(settings.output_directory)[1],
datetime.utcnow().strftime("%Y-%m-%d_%H-%M-%S"))
self.notes = None
self.device_properties = {}
@@ -123,6 +125,12 @@ class ExecutionContext(object):
else:
return None
@property
def job_status(self):
if not self.current_job:
return None
return self.current_job.result.status
@property
def workload(self):
return getattr(self.spec, 'workload', None)
@@ -133,7 +141,7 @@ class ExecutionContext(object):
@property
def result(self):
return getattr(self.current_job, 'result', None)
return getattr(self.current_job, 'result', self.run_result)
def __init__(self, device, config):
self.device = device
@@ -151,6 +159,7 @@ class ExecutionContext(object):
self.run_artifacts = copy(self.default_run_artifacts)
self.job_iteration_counts = defaultdict(int)
self.aborted = False
self.runner = None
if settings.agenda:
self.run_artifacts.append(Artifact('agenda',
os.path.join(self.host_working_directory,
@@ -158,10 +167,12 @@ class ExecutionContext(object):
'meta',
mandatory=True,
description='Agenda for this run.'))
for i in xrange(1, settings.config_count + 1):
self.run_artifacts.append(Artifact('config_{}'.format(i),
os.path.join(self.host_working_directory,
'config_{}.py'.format(i)),
for i, filepath in enumerate(settings.loaded_files, 1):
name = 'config_{}'.format(i)
path = os.path.join(self.host_working_directory,
name + os.path.splitext(filepath)[1])
self.run_artifacts.append(Artifact(name,
path,
kind='meta',
mandatory=True,
description='Config file used for the run.'))
@@ -172,17 +183,18 @@ class ExecutionContext(object):
self.output_directory = self.run_output_directory
self.resolver = ResourceResolver(self.config)
self.run_info = RunInfo(self.config)
self.run_result = RunResult(self.run_info)
self.run_result = RunResult(self.run_info, self.run_output_directory)
def next_job(self, job):
"""Invoked by the runner when starting a new iteration of workload execution."""
self.current_job = job
self.job_iteration_counts[self.spec.id] += 1
self.current_job.result.iteration = self.current_iteration
if not self.aborted:
outdir_name = '_'.join(map(str, [self.spec.label, self.spec.id, self.current_iteration]))
self.output_directory = _d(os.path.join(self.run_output_directory, outdir_name))
self.iteration_artifacts = [wa for wa in self.workload.artifacts]
self.current_job.result.iteration = self.current_iteration
self.current_job.result.output_directory = self.output_directory
def end_job(self):
if self.current_job.result.status == IterationResult.ABORTED:
@@ -190,6 +202,12 @@ class ExecutionContext(object):
self.current_job = None
self.output_directory = self.run_output_directory
def add_metric(self, *args, **kwargs):
self.result.add_metric(*args, **kwargs)
def add_classifiers(self, **kwargs):
self.result.classifiers.update(kwargs)
def add_artifact(self, name, path, kind, *args, **kwargs):
if self.current_job is None:
self.add_run_artifact(name, path, kind, *args, **kwargs)
@@ -327,6 +345,11 @@ class Executor(object):
runner = self._get_runner(result_manager)
runner.init_queue(self.config.workload_specs)
runner.run()
if getattr(self.config, "clean_up", False):
self.logger.info('Clearing WA files from device')
self.device.delete_file(self.device.binaries_directory)
self.device.delete_file(self.device.working_directory)
self.execute_postamble()
def execute_postamble(self):
@@ -388,8 +411,9 @@ class RunnerJob(object):
"""
def __init__(self, spec):
def __init__(self, spec, retry=0):
self.spec = spec
self.retry = retry
self.iteration = None
self.result = IterationResult(self.spec)
@@ -410,6 +434,10 @@ class Runner(object):
"""Internal runner error."""
pass
@property
def config(self):
return self.context.config
@property
def current_job(self):
if self.job_queue:
@@ -477,7 +505,7 @@ class Runner(object):
if self.context.reboot_policy.can_reboot and self.device.can('reset_power'):
self.logger.info('Attempting to hard-reset the device...')
try:
self.device.hard_reset()
self.device.boot(hard=True)
self.device.connect()
except DeviceError: # hard_boot not implemented for the device.
raise e
@@ -510,17 +538,16 @@ class Runner(object):
self._send(signal.RUN_END)
def _initialize_run(self):
self.context.runner = self
self.context.run_info.start_time = datetime.utcnow()
if self.context.reboot_policy.perform_initial_boot:
self.logger.info('\tBooting device')
with self._signal_wrap('INITIAL_BOOT'):
self._reboot_device()
else:
self.logger.info('Connecting to device')
self.device.connect()
self._connect_to_device()
self.logger.info('Initializing device')
self.device.initialize(self.context)
self.logger.info('Initializing workloads')
for workload_spec in self.context.config.workload_specs:
workload_spec.workload.initialize(self.context)
props = self.device.get_properties(self.context)
self.context.run_info.device_properties = props
self.result_manager.initialize(self.context)
@@ -529,6 +556,25 @@ class Runner(object):
if instrumentation.check_failures():
raise InstrumentError('Detected failure(s) during instrumentation initialization.')
def _connect_to_device(self):
if self.context.reboot_policy.perform_initial_boot:
try:
self.device.connect()
except DeviceError: # device may be offline
if self.device.can('reset_power'):
with self._signal_wrap('INITIAL_BOOT'):
self.device.boot(hard=True)
else:
raise DeviceError('Cannot connect to device for initial reboot; '
'and device does not support hard reset.')
else: # successfully connected
self.logger.info('\tBooting device')
with self._signal_wrap('INITIAL_BOOT'):
self._reboot_device()
else:
self.logger.info('Connecting to device')
self.device.connect()
def _init_job(self):
self.current_job.result.status = IterationResult.RUNNING
self.context.next_job(self.current_job)
@@ -592,11 +638,23 @@ class Runner(object):
def _finalize_job(self):
self.context.run_result.iteration_results.append(self.current_job.result)
self.job_queue[0].iteration = self.context.current_iteration
self.completed_jobs.append(self.job_queue.pop(0))
job = self.job_queue.pop(0)
job.iteration = self.context.current_iteration
if job.result.status in self.config.retry_on_status:
if job.retry >= self.config.max_retries:
self.logger.error('Exceeded maxium number of retries. Abandoning job.')
else:
self.logger.info('Job status was {}. Retrying...'.format(job.result.status))
retry_job = RunnerJob(job.spec, job.retry + 1)
self.job_queue.insert(0, retry_job)
self.completed_jobs.append(job)
self.context.end_job()
def _finalize_run(self):
self.logger.info('Finalizing workloads')
for workload_spec in self.context.config.workload_specs:
workload_spec.workload.finalize(self.context)
self.logger.info('Finalizing.')
self._send(signal.RUN_FIN)
@@ -679,6 +737,13 @@ class Runner(object):
filepath = os.path.join(settings.output_directory, filename)
self.device.capture_screen(filepath)
def _take_uiautomator_dump(self, filename):
if self.context.output_directory:
filepath = os.path.join(self.context.output_directory, filename)
else:
filepath = os.path.join(settings.output_directory, filename)
self.device.capture_ui_hierarchy(filepath)
@contextmanager
def _handle_errors(self, action, on_error_status=IterationResult.FAILED):
try:
@@ -692,15 +757,21 @@ class Runner(object):
if self.current_job:
self.current_job.result.status = on_error_status
self.current_job.result.add_event(str(we))
try:
self._take_screenshot('error.png')
except Exception, e: # pylint: disable=W0703
# We're already in error state, so the fact that taking a
# screenshot failed is not surprising...
pass
# There is no point in taking a screenshot ect if the issue is not
# with the device but with the host or a missing resource
if not (isinstance(we, ResourceError) or isinstance(we, HostError)):
try:
self._take_screenshot('error.png')
if self.device.platform == 'android':
self._take_uiautomator_dump('error.uix')
except Exception, e: # pylint: disable=W0703
# We're already in error state, so the fact that taking a
# screenshot failed is not surprising...
pass
if action:
action = action[0].lower() + action[1:]
self.logger.error('Error while {}:\n\t{}'.format(action, we))
self.logger.error('Error while {}:\n\t{}'.format(action, str(we).replace("\n", "\n\t")))
except Exception, e: # pylint: disable=W0703
error_text = '{}("{}")'.format(e.__class__.__name__, e)
if self.current_job:

View File

@@ -24,7 +24,7 @@ from collections import OrderedDict
from wlauto.core.bootstrap import settings
from wlauto.exceptions import ValidationError, ConfigError
from wlauto.utils.misc import isiterable, ensure_directory_exists as _d, get_article
from wlauto.utils.types import identifier
from wlauto.utils.types import identifier, integer, boolean
class AttributeCollection(object):
@@ -41,9 +41,10 @@ class AttributeCollection(object):
def values(self):
return self._attrs.values()
def __init__(self, attrcls):
def __init__(self, attrcls, owner):
self._attrcls = attrcls
self._attrs = OrderedDict()
self.owner = owner
def add(self, p):
p = self._to_attrcls(p)
@@ -53,6 +54,8 @@ class AttributeCollection(object):
for a, v in p.__dict__.iteritems():
if v is not None:
setattr(newp, a, v)
if not hasattr(newp, "_overridden"):
newp._overridden = self.owner # pylint: disable=protected-access
self._attrs[p.name] = newp
else:
# Duplicate attribute condition is check elsewhere.
@@ -82,7 +85,12 @@ class AttributeCollection(object):
return p
def __iadd__(self, other):
other = [self._to_attrcls(p) for p in other]
names = []
for p in other:
if p.name in names:
raise ValueError("Duplicate '{}' {}".format(p.name, p.__class__.__name__.split('.')[-1]))
names.append(p.name)
self.add(p)
return self
@@ -102,7 +110,7 @@ class AttributeCollection(object):
class AliasCollection(AttributeCollection):
def __init__(self):
super(AliasCollection, self).__init__(Alias)
super(AliasCollection, self).__init__(Alias, None)
def _to_attrcls(self, p):
if isinstance(p, tuple) or isinstance(p, list):
@@ -117,8 +125,9 @@ class AliasCollection(AttributeCollection):
class ListCollection(list):
def __init__(self, attrcls): # pylint: disable=unused-argument
def __init__(self, attrcls, owner): # pylint: disable=unused-argument
super(ListCollection, self).__init__()
self.owner = owner
class Param(object):
@@ -128,8 +137,14 @@ class Param(object):
"""
# Mapping for kind conversion; see docs for convert_types below
kind_map = {
int: integer,
bool: boolean,
}
def __init__(self, name, kind=None, mandatory=None, default=None, override=False,
allowed_values=None, description=None, constraint=None, global_alias=None):
allowed_values=None, description=None, constraint=None, global_alias=None, convert_types=True):
"""
Create a new Parameter object.
@@ -139,9 +154,7 @@ class Param(object):
:param kind: The type of parameter this is. This must be a callable that takes an arbitrary
object and converts it to the expected type, or raised ``ValueError`` if such
conversion is not possible. Most Python standard types -- ``str``, ``int``, ``bool``, etc. --
can be used here (though for ``bool``, ``wlauto.utils.misc.as_bool`` is preferred
as it intuitively handles strings like ``'false'``). This defaults to ``str`` if
not specified.
can be used here. This defaults to ``str`` if not specified.
:param mandatory: If set to ``True``, then a non-``None`` value for this parameter *must* be
provided on extension object construction, otherwise ``ConfigError`` will be
raised.
@@ -164,10 +177,17 @@ class Param(object):
that old extension settings names still work. This should not be used for
new parameters.
:param convert_types: If ``True`` (the default), will automatically convert ``kind`` values from
native Python types to WA equivalents. This allows more ituitive interprestation
of parameter values, e.g. the string ``"false"`` being interpreted as ``False``
when specifed as the value for a boolean Parameter.
"""
self.name = identifier(name)
if kind is not None and not callable(kind):
raise ValueError('Kind must be callable.')
if convert_types and kind in self.kind_map:
kind = self.kind_map[kind]
self.kind = kind
self.mandatory = mandatory
self.default = default
@@ -204,18 +224,11 @@ class Param(object):
else:
new_value = current_value + [value]
setattr(obj, self.name, new_value)
def validate(self, obj):
value = getattr(obj, self.name, None)
if value is not None:
if self.allowed_values:
self._validate_allowed_values(obj, value)
if self.constraint:
self._validate_constraint(obj, value)
else:
if self.mandatory:
msg = 'No value specified for mandatory parameter {} in {}.'
raise ConfigError(msg.format(self.name, obj.name))
def get_type_name(self):
typename = str(self.kind)
@@ -292,7 +305,7 @@ class Artifact(object):
network filer archiver may choose to archive them).
.. note: The kind parameter is intended to represent the logical function of a particular
artifact, not it's intended means of processing -- this is left entirely up to the
artifact, not its intended means of processing -- this is left entirely up to the
result processors.
"""
@@ -381,34 +394,42 @@ class ExtensionMeta(type):
('core_modules', str, ListCollection),
]
virtual_methods = ['validate']
virtual_methods = ['validate', 'initialize', 'finalize']
global_virtuals = ['initialize', 'finalize']
def __new__(mcs, clsname, bases, attrs):
mcs._propagate_attributes(bases, attrs)
mcs._propagate_attributes(bases, attrs, clsname)
cls = type.__new__(mcs, clsname, bases, attrs)
mcs._setup_aliases(cls)
mcs._implement_virtual(cls, bases)
return cls
@classmethod
def _propagate_attributes(mcs, bases, attrs):
def _propagate_attributes(mcs, bases, attrs, clsname):
"""
For attributes specified by to_propagate, their values will be a union of
that specified for cls and it's bases (cls values overriding those of bases
that specified for cls and its bases (cls values overriding those of bases
in case of conflicts).
"""
for prop_attr, attr_cls, attr_collector_cls in mcs.to_propagate:
should_propagate = False
propagated = attr_collector_cls(attr_cls)
propagated = attr_collector_cls(attr_cls, clsname)
for base in bases:
if hasattr(base, prop_attr):
propagated += getattr(base, prop_attr) or []
should_propagate = True
if prop_attr in attrs:
propagated += attrs[prop_attr] or []
pattrs = attrs[prop_attr] or []
propagated += pattrs
should_propagate = True
if should_propagate:
for p in propagated:
override = bool(getattr(p, "override", None))
overridden = bool(getattr(p, "_overridden", None))
if override != overridden:
msg = "Overriding non existing parameter '{}' inside '{}'"
raise ValueError(msg.format(p.name, clsname))
attrs[prop_attr] = propagated
@classmethod
@@ -430,13 +451,13 @@ class ExtensionMeta(type):
super(cls, self).vmname()
.. note:: current implementation imposes a restriction in that
parameters into the function *must* be passed as keyword
arguments. There *must not* be positional arguments on
virutal method invocation.
This also ensures that the methods that have beend identified as
"globally virtual" are executed exactly once per WA execution, even if
invoked through instances of different subclasses
"""
methods = {}
called_globals = set()
for vmname in mcs.virtual_methods:
clsmethod = getattr(cls, vmname, None)
if clsmethod:
@@ -444,11 +465,24 @@ class ExtensionMeta(type):
methods[vmname] = [bm for bm in basemethods if bm != clsmethod]
methods[vmname].append(clsmethod)
def wrapper(self, __name=vmname, **kwargs):
for dm in methods[__name]:
dm(self, **kwargs)
def generate_method_wrapper(vname): # pylint: disable=unused-argument
# this creates a closure with the method name so that it
# does not need to be passed to the wrapper as an argument,
# leaving the wrapper to accept exactly the same set of
# arguments as the method it is wrapping.
name__ = vmname # pylint: disable=cell-var-from-loop
setattr(cls, vmname, wrapper)
def wrapper(self, *args, **kwargs):
for dm in methods[name__]:
if name__ in mcs.global_virtuals:
if dm not in called_globals:
dm(self, *args, **kwargs)
called_globals.add(dm)
else:
dm(self, *args, **kwargs)
return wrapper
setattr(cls, vmname, generate_method_wrapper(vmname))
class Extension(object):
@@ -526,7 +560,15 @@ class Extension(object):
if self.name is None:
raise ValidationError('Name not set for {}'.format(self._classname))
for param in self.parameters:
param.validate(self)
if param.mandatory and getattr(self, param.name, None) is None:
msg = 'No value specified for mandatory parameter {} in {}.'
raise ConfigError(msg.format(param.name, self.name))
def initialize(self, context):
pass
def finalize(self, context):
pass
def check_artifacts(self, context, level):
"""
@@ -567,28 +609,8 @@ class Extension(object):
for module_spec in modules:
if not module_spec:
continue
if isinstance(module_spec, basestring):
name = module_spec
params = {}
elif isinstance(module_spec, dict):
if len(module_spec) != 1:
message = 'Invalid module spec: {}; dict must have exctly one key -- the module name.'
raise ValueError(message.format(module_spec))
name, params = module_spec.items()[0]
else:
message = 'Invalid module spec: {}; must be a string or a one-key dict.'
raise ValueError(message.format(module_spec))
if not isinstance(params, dict):
message = 'Invalid module spec: {}; dict value must also be a dict.'
raise ValueError(message.format(module_spec))
module = loader.get_module(name, owner=self, **params)
module.initialize()
for capability in module.capabilities:
if capability not in self.capabilities:
self.capabilities.append(capability)
self._modules.append(module)
module = self._load_module(loader, module_spec)
self._install_module(module)
def has(self, capability):
"""Check if this extension has the specified capability. The alternative method ``can`` is
@@ -598,6 +620,33 @@ class Extension(object):
can = has
def _load_module(self, loader, module_spec):
if isinstance(module_spec, basestring):
name = module_spec
params = {}
elif isinstance(module_spec, dict):
if len(module_spec) != 1:
message = 'Invalid module spec: {}; dict must have exctly one key -- the module name.'
raise ValueError(message.format(module_spec))
name, params = module_spec.items()[0]
else:
message = 'Invalid module spec: {}; must be a string or a one-key dict.'
raise ValueError(message.format(module_spec))
if not isinstance(params, dict):
message = 'Invalid module spec: {}; dict value must also be a dict.'
raise ValueError(message.format(module_spec))
module = loader.get_module(name, owner=self, **params)
module.initialize(None)
return module
def _install_module(self, module):
for capability in module.capabilities:
if capability not in self.capabilities:
self.capabilities.append(capability)
self._modules.append(module)
def __check_from_loader(self):
"""
There are a few things that need to happen in order to get a valide extension instance.
@@ -627,7 +676,7 @@ class Module(Extension):
In other words, a Module is roughly equivalent to a kernel module and its primary purpose is to
implement WA "drivers" for various peripherals that may or may not be present in a particular setup.
.. note:: A mudule is itself an Extension and can therefore have it's own modules.
.. note:: A mudule is itself an Extension and can therefore have its own modules.
"""
@@ -647,6 +696,5 @@ class Module(Extension):
if owner.name == self.name:
raise ValueError('Circular module import for {}'.format(self.name))
def initialize(self):
def initialize(self, context):
pass

View File

@@ -80,8 +80,8 @@ class GlobalParameterAlias(object):
other_param.kind != param.kind):
message = 'Duplicate global alias {} declared in {} and {} extensions with different types'
raise LoaderError(message.format(self.name, ext.name, other_ext.name))
if not param.name == other_param.name:
message = 'Two params {} in {} and {} in {} both declare global alias {}'
if param.kind != other_param.kind:
message = 'Two params {} in {} and {} in {} both declare global alias {}, and are of different kinds'
raise LoaderError(message.format(param.name, ext.name,
other_param.name, other_ext.name, self.name))
@@ -304,14 +304,14 @@ class ExtensionLoader(object):
for module in walk_modules(package):
self._load_module(module)
except ImportError as e:
message = 'Problem loading extensions from extra packages: {}'
raise LoaderError(message.format(e.message))
message = 'Problem loading extensions from package {}: {}'
raise LoaderError(message.format(package, e.message))
def _load_from_paths(self, paths, ignore_paths):
self.logger.debug('Loading from paths.')
for path in paths:
self.logger.debug('Checking path %s', path)
for root, _, files in os.walk(path):
for root, _, files in os.walk(path, followlinks=True):
should_skip = False
for igpath in ignore_paths:
if root.startswith(igpath):
@@ -320,7 +320,7 @@ class ExtensionLoader(object):
if should_skip:
continue
for fname in files:
if not os.path.splitext(fname)[1].lower() == '.py':
if os.path.splitext(fname)[1].lower() != '.py':
continue
filepath = os.path.join(root, fname)
try:
@@ -333,6 +333,9 @@ class ExtensionLoader(object):
self.logger.warn('Got: {}'.format(e))
else:
raise LoaderError('Failed to load {}'.format(filepath), sys.exc_info())
except Exception as e:
message = 'Problem loading extensions from {}: {}'
raise LoaderError(message.format(filepath, e))
def _load_module(self, module): # NOQA pylint: disable=too-many-branches
self.logger.debug('Checking module %s', module.__name__)
@@ -371,9 +374,10 @@ class ExtensionLoader(object):
store = self._get_store(ext)
store[key] = obj
for alias in obj.aliases:
if alias in self.extensions or alias in self.aliases:
alias_id = identifier(alias.name)
if alias_id in self.extensions or alias_id in self.aliases:
raise LoaderError('{} {} already exists.'.format(ext.name, obj.name))
self.aliases[alias.name] = alias
self.aliases[alias_id] = alias
# Update global aliases list. If a global alias is already in the list,
# then make sure this extension is in the same parent/child hierarchy
@@ -397,4 +401,3 @@ def _instantiate(cls, args=None, kwargs=None):
return cls(*args, **kwargs)
except Exception:
raise LoaderError('Could not load {}'.format(cls), sys.exc_info())

View File

@@ -32,4 +32,3 @@ def get_extension_type(ext):
if isinstance(ext, cls):
return name
raise ValueError('Unknown extension type: {}'.format(ext.__class__.__name__))

View File

@@ -106,6 +106,7 @@ import wlauto.core.signal as signal
from wlauto.core.extension import Extension
from wlauto.exceptions import WAError, DeviceNotRespondingError, TimeoutError
from wlauto.utils.misc import get_traceback, isiterable
from wlauto.utils.types import identifier
logger = logging.getLogger('instrumentation')
@@ -191,11 +192,23 @@ def is_installed(instrument):
if instrument in [i.__class__ for i in installed]:
return True
else: # assume string
if instrument in [i.name for i in installed]:
if identifier(instrument) in [identifier(i.name) for i in installed]:
return True
return False
def is_enabled(instrument):
if isinstance(instrument, Instrument) or isinstance(instrument, type):
name = instrument.name
else: # assume string
name = instrument
try:
installed_instrument = get_instrument(name)
return installed_instrument.is_enabled
except ValueError:
return False
failures_detected = False
@@ -228,7 +241,7 @@ class ManagedCallback(object):
except (KeyboardInterrupt, DeviceNotRespondingError, TimeoutError): # pylint: disable=W0703
raise
except Exception as e: # pylint: disable=W0703
logger.error('Error in insturment {}'.format(self.instrument.name))
logger.error('Error in instrument {}'.format(self.instrument.name))
global failures_detected # pylint: disable=W0603
failures_detected = True
if isinstance(e, WAError):
@@ -275,9 +288,15 @@ def install(instrument):
attr = getattr(instrument, attr_name)
if not callable(attr):
raise ValueError('Attribute {} not callable in {}.'.format(attr_name, instrument))
arg_num = len(inspect.getargspec(attr).args)
if not arg_num == 2:
raise ValueError('{} must take exactly 2 arguments; {} given.'.format(attr_name, arg_num))
argspec = inspect.getargspec(attr)
arg_num = len(argspec.args)
# Instrument callbacks will be passed exactly two arguments: self
# (the instrument instance to which the callback is bound) and
# context. However, we also allow callbacks to capture the context
# in variable arguments (declared as "*args" in the definition).
if arg_num > 2 or (arg_num < 2 and argspec.varargs is None):
message = '{} must take exactly 2 positional arguments; {} given.'
raise ValueError(message.format(attr_name, arg_num))
logger.debug('\tConnecting %s to %s', attr.__name__, SIGNAL_MAP[stripped_attr_name])
mc = ManagedCallback(instrument, attr)
@@ -300,7 +319,7 @@ def get_instrument(inst):
if isinstance(inst, Instrument):
return inst
for installed_inst in installed:
if installed_inst.name == inst:
if identifier(installed_inst.name) == identifier(inst):
return installed_inst
raise ValueError('Instrument {} is not installed'.format(inst))
@@ -366,9 +385,14 @@ class Instrument(Extension):
self.is_enabled = True
self.is_broken = False
def initialize(self, context):
pass
def finalize(self, context):
pass
def __str__(self):
return self.name
def __repr__(self):
return 'Instrument({})'.format(self.name)

View File

@@ -65,10 +65,15 @@ class ResourceResolver(object):
self.logger.debug('Trying {}'.format(getter))
result = getter.get(resource, *args, **kwargs)
if result is not None:
self.logger.debug('Resource {} found using {}'.format(resource, getter))
self.logger.debug('Resource {} found using {}:'.format(resource, getter))
self.logger.debug('\t{}'.format(result))
return result
if strict:
raise ResourceError('{} could not be found'.format(resource))
if kwargs:
criteria = ', '.join(['{}:{}'.format(k, v) for k, v in kwargs.iteritems()])
raise ResourceError('{} ({}) could not be found'.format(resource, criteria))
else:
raise ResourceError('{} could not be found'.format(resource))
self.logger.debug('Resource {} not found.'.format(resource))
return None

View File

@@ -13,6 +13,7 @@
# limitations under the License.
#
from wlauto.core.bootstrap import settings
from wlauto.core.extension import Extension
@@ -37,10 +38,10 @@ class GetterPriority(object):
"""
cached = 20
preferred = 10
remote = 5
environment = 0
external_package = -5
package = -10
remote = -20
class Resource(object):
@@ -81,7 +82,7 @@ class ResourceGetter(Extension):
Base class for implementing resolvers. Defines resolver interface. Resolvers are
responsible for discovering resources (such as particular kinds of files) they know
about based on the parameters that are passed to them. Each resolver also has a dict of
attributes that describe it's operation, and may be used to determine which get invoked.
attributes that describe its operation, and may be used to determine which get invoked.
There is no pre-defined set of attributes and resolvers may define their own.
Class attributes:
@@ -169,6 +170,7 @@ class __NullOwner(object):
"""Represents an owner for a resource not owned by anyone."""
name = 'noone'
dependencies_directory = settings.dependencies_directory
def __getattr__(self, name):
return None

View File

@@ -44,7 +44,7 @@ from datetime import datetime
from wlauto.core.extension import Extension
from wlauto.exceptions import WAError
from wlauto.utils.types import numeric
from wlauto.utils.misc import enum_metaclass
from wlauto.utils.misc import enum_metaclass, merge_dicts
class ResultManager(object):
@@ -191,12 +191,13 @@ class RunResult(object):
else:
return self.UNKNOWN # should never happen
def __init__(self, run_info):
def __init__(self, run_info, output_directory=None):
self.info = run_info
self.iteration_results = []
self.artifacts = []
self.events = []
self.non_iteration_errors = False
self.output_directory = output_directory
class RunEvent(object):
@@ -253,14 +254,18 @@ class IterationResult(object):
self.spec = spec
self.id = spec.id
self.workload = spec.workload
self.classifiers = copy(spec.classifiers)
self.iteration = None
self.status = self.NOT_STARTED
self.output_directory = None
self.events = []
self.metrics = []
self.artifacts = []
def add_metric(self, name, value, units=None, lower_is_better=False):
self.metrics.append(Metric(name, value, units, lower_is_better))
def add_metric(self, name, value, units=None, lower_is_better=False, classifiers=None):
classifiers = merge_dicts(self.classifiers, classifiers or {},
list_duplicates='last', should_normalize=False)
self.metrics.append(Metric(name, value, units, lower_is_better, classifiers))
def has_metric(self, name):
for metric in self.metrics:
@@ -298,14 +303,18 @@ class Metric(object):
has no units (e.g. it's a count or a standardised score).
:param lower_is_better: Boolean flag indicating where lower values are
better than higher ones. Defaults to False.
:param classifiers: A set of key-value pairs to further classify this metric
beyond current iteration (e.g. this can be used to identify
sub-tests).
"""
def __init__(self, name, value, units=None, lower_is_better=False):
def __init__(self, name, value, units=None, lower_is_better=False, classifiers=None):
self.name = name
self.value = numeric(value)
self.units = units
self.lower_is_better = lower_is_better
self.classifiers = classifiers or {}
def to_dict(self):
return self.__dict__
@@ -318,4 +327,3 @@ class Metric(object):
return '<{}>'.format(result)
__repr__ = __str__

View File

@@ -186,4 +186,3 @@ def send(signal, sender, *args, **kwargs):
"""
dispatcher.send(signal, sender, *args, **kwargs)

View File

@@ -18,7 +18,7 @@ from collections import namedtuple
VersionTuple = namedtuple('Version', ['major', 'minor', 'revision'])
version = VersionTuple(2, 3, 0)
version = VersionTuple(2, 6, 0)
def get_wa_version():

View File

@@ -37,6 +37,7 @@ class Workload(Extension):
supported_devices = []
supported_platforms = []
summary_metrics = []
requires_network = False
def __init__(self, device, **kwargs):
"""
@@ -53,25 +54,33 @@ class Workload(Extension):
def init_resources(self, context):
"""
May be optionally overridden by concrete instances in order to discover and initialise
necessary resources. This method will be invoked at most once during the execution:
before running any workloads, and before invocation of ``validate()``, but after it is
clear that this workload will run (i.e. this method will not be invoked for workloads
that have been discovered but have not been scheduled run in the agenda).
This method may be used to perform early resource discovery and initialization. This is invoked
during the initial loading stage and before the device is ready, so cannot be used for any
device-dependent initialization. This method is invoked before the workload instance is
validated.
"""
pass
def setup(self, context):
def initialize(self, context):
"""
Perform the setup necessary to run the workload, such as copying the necessry files
This method should be used to perform once-per-run initialization of a workload instance, i.e.,
unlike ``setup()`` it will not be invoked on each iteration.
"""
pass
def setup(self, context): # pylint: disable=unused-argument
"""
Perform the setup necessary to run the workload, such as copying the necessary files
to the device, configuring the environments, etc.
This is also the place to perform any on-device checks prior to attempting to execute
the workload.
"""
pass
if self.requires_network:
self.check_network_connected()
def run(self, context):
"""Execute the workload. This is the method that performs the actual "work" of the"""
@@ -89,6 +98,13 @@ class Workload(Extension):
""" Perform any final clean up for the Workload. """
pass
def finalize(self, context):
pass
def check_network_connected(self):
if not self.device.is_network_connected():
message = 'Workload "{}" requires internet. Device "{}" does not appear to be connected to the internet.'
raise WorkloadError(message.format(self.name, self.device.name))
def __str__(self):
return '<Workload {}>'.format(self.name)

Some files were not shown because too many files have changed in this diff Show More