1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-01-18 20:11:20 +00:00

ReventWorkload: Move class to linux and add features

The ReventWorkload class has been moved to the linux directory and
two new features have been added: the option to run an idle workload
and the option to specify a .teardown revent file as well as a .setup file
which runs in the eponymous stage.
This commit is contained in:
Waleed El-Geresy 2017-08-07 18:35:20 +01:00
parent c6cdd8c0e6
commit 6d9a03ad8f
3 changed files with 192 additions and 100 deletions

View File

@ -16,22 +16,19 @@
import os
import sys
import time
from math import ceil
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.android.resources import ApkFile, ReventFile
from wlauto.common.resources import ExtensionAsset, Executable, File
from wlauto.common.android.resources import ApkFile
from wlauto.common.resources import ExtensionAsset, File
from wlauto.exceptions import WorkloadError, ResourceError, DeviceError
from wlauto.utils.android import (ApkInfo, ANDROID_NORMAL_PERMISSIONS,
ANDROID_UNCHANGEABLE_PERMISSIONS, UNSUPPORTED_PACKAGES)
from wlauto.utils.types import boolean, ParameterDict
from wlauto.utils.revent import ReventRecording
import wlauto.utils.statedetect as state_detector
import wlauto.common.android.resources
from wlauto.common.linux.workload import ReventWorkload
DELAY = 5
@ -481,102 +478,8 @@ class ApkWorkload(Workload):
if self.uninstall_apk:
self.device.uninstall(self.package)
AndroidBenchmark = ApkWorkload # backward compatibility
class ReventWorkload(Workload):
# pylint: disable=attribute-defined-outside-init
def __init__(self, device, _call_super=True, **kwargs):
if _call_super:
Workload.__init__(self, device, **kwargs)
devpath = self.device.path
self.on_device_revent_binary = devpath.join(self.device.binaries_directory, 'revent')
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
if self.check_states:
state_detector.check_match_state_dependencies()
def setup(self, context):
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)
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)
self.device.killall('revent')
command = '{} replay {}'.format(self.on_device_revent_binary, 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)
self.logger.debug('Replaying {}'.format(os.path.basename(self.on_device_run_revent)))
self.device.execute(command, timeout=self.run_timeout)
self.logger.debug('Replay completed.')
def update_result(self, context):
pass
def teardown(self, context):
self.device.killall('revent')
self.device.delete_file(self.on_device_setup_revent)
self.device.delete_file(self.on_device_run_revent)
def _check_revent_files(self, context):
# check the revent binary
revent_binary = context.resolver.get(Executable(NO_ONE, self.device.abi, 'revent'))
if not os.path.isfile(revent_binary):
message = '{} does not exist. '.format(revent_binary)
message += 'Please build revent for your system and place it in that location'
raise WorkloadError(message)
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)
raise WorkloadError(message)
if not self.revent_run_file:
# pylint: disable=too-few-format-args
message = '{0}.run.revent file does not exist, Please provide one for your device, {0}'.format(self.device.name)
raise WorkloadError(message)
self.on_device_revent_binary = self.device.install_executable(revent_binary)
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']
@ -731,6 +634,7 @@ class GameWorkload(ApkWorkload, ReventWorkload):
view = 'SurfaceView'
loading_time = 10
supported_platforms = ['android']
setup_required = True
parameters = [
Parameter('install_timeout', default=500, override=True),
@ -749,6 +653,8 @@ class GameWorkload(ApkWorkload, ReventWorkload):
def __init__(self, device, **kwargs): # pylint: disable=W0613
ApkWorkload.__init__(self, device, **kwargs)
ReventWorkload.__init__(self, device, _call_super=False, **kwargs)
if self.check_states:
state_detector.check_match_state_dependencies()
self.logcat_process = None
self.module_dir = os.path.dirname(sys.modules[self.__module__].__file__)
self.revent_dir = os.path.join(self.module_dir, 'revent_files')
@ -823,3 +729,22 @@ class GameWorkload(ApkWorkload, ReventWorkload):
self.device.busybox,
ondevice_cache)
self.device.execute(deploy_command, timeout=timeout, as_root=True)
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 # pylint: disable=W0201
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))

View File

@ -0,0 +1,165 @@
# Copyright 2017 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
from math import ceil
from wlauto.core.extension import Parameter
from wlauto.core.workload import Workload
from wlauto.core.resource import NO_ONE
from wlauto.common.resources import Executable
from wlauto.common.android.resources import ReventFile
from wlauto.exceptions import WorkloadError
from wlauto.utils.revent import ReventRecording
class ReventWorkload(Workload):
# pylint: disable=attribute-defined-outside-init
description = """
A workload for playing back revent recordings. You can supply three
different files:
1. {device_model}.setup.revent
2. {device_model}.run.revent
3. {device_model}.teardown.revent
You may generate these files using the wa record command using the -s flag
to specify the stage (``setup``, ``run``, ``teardown``)
You may also supply an 'idle_time' in seconds in place of the run file.
The ``run`` file may only be omitted if you choose to run this way, but
while running idle may supply ``setup`` and ``teardown`` files.
To use a ``setup`` or ``teardown`` file set the setup_required and/or
teardown_required class attributes to True (default: False).
N.B. This is the default description. You may overwrite this for your
workload to include more specific information.
"""
setup_required = False
teardown_required = False
parameters = [
Parameter(
'idle_time', kind=int, default=None,
description='''
The time you wish the device to remain idle for (if a value is
given then this overrides any .run revent file).
'''),
]
def __init__(self, device, _call_super=True, **kwargs):
if _call_super:
Workload.__init__(self, device, **kwargs)
self.setup_timeout = kwargs.get('setup_timeout', None)
self.run_timeout = kwargs.get('run_timeout', None)
self.teardown_timeout = kwargs.get('teardown_timeout', None)
self.revent_setup_file = None
self.revent_run_file = None
self.revent_teardown_file = None
self.on_device_setup_revent = None
self.on_device_run_revent = None
self.on_device_teardown_revent = None
self.statedefs_dir = None
def initialize(self, context):
devpath = self.device.path
self.on_device_revent_binary = devpath.join(self.device.binaries_directory, 'revent')
def setup(self, context):
devpath = self.device.path
if self.setup_required:
self.revent_setup_file = context.resolver.get(ReventFile(self, 'setup'))
if self.revent_setup_file:
self.on_device_setup_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_setup_file)[-1])
duration = ReventRecording(self.revent_setup_file).duration
self.default_setup_timeout = ceil(duration) + 30
if not self.idle_time:
self.revent_run_file = context.resolver.get(ReventFile(self, 'run'))
if self.revent_run_file:
self.on_device_run_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_run_file)[-1])
self.default_run_timeout = ceil(ReventRecording(self.revent_run_file).duration) + 30
if self.teardown_required:
self.revent_teardown_file = context.resolver.get(ReventFile(self, 'teardown'))
if self.revent_teardown_file:
self.on_device_teardown_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_teardown_file)[-1])
duration = ReventRecording(self.revent_teardown_file).duration
self.default_teardown_timeout = ceil(duration) + 30
self._check_revent_files(context)
Workload.setup(self, context)
if self.revent_setup_file is not None:
self.setup_timeout = self.setup_timeout or self.default_setup_timeout
self.device.killall('revent')
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_setup_revent)
self.device.execute(command, timeout=self.setup_timeout)
self.logger.debug('Revent setup completed.')
def run(self, context):
if not self.idle_time:
self.run_timeout = self.run_timeout or self.default_run_timeout
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_run_revent)
self.logger.debug('Replaying {}'.format(os.path.basename(self.on_device_run_revent)))
self.device.execute(command, timeout=self.run_timeout)
self.logger.debug('Replay completed.')
else:
self.logger.info('Idling for ' + str(self.idle_time) + ' seconds.')
self.device.sleep(self.idle_time)
self.logger.info('Successfully did nothing for ' + str(self.idle_time) + ' seconds!')
def update_result(self, context):
pass
def teardown(self, context):
if self.revent_teardown_file is not None:
self.teardown_timeout = self.teardown_timeout or self.default_teardown_timeout
command = '{} replay {}'.format(self.on_device_revent_binary,
self.on_device_teardown_revent)
self.device.execute(command, timeout=self.teardown_timeout)
self.logger.debug('Replay completed.')
self.device.killall('revent')
if self.revent_setup_file is not None:
self.device.delete_file(self.on_device_setup_revent)
if not self.idle_time:
self.device.delete_file(self.on_device_run_revent)
if self.revent_teardown_file is not None:
self.device.delete_file(self.on_device_teardown_revent)
def _check_revent_files(self, context):
# check the revent binary
revent_binary = context.resolver.get(Executable(NO_ONE, self.device.abi, 'revent'))
if not os.path.isfile(revent_binary):
message = '{} does not exist. '.format(revent_binary)
message += 'Please build revent for your system and place it in that location'
raise WorkloadError(message)
if not self.revent_run_file and not self.idle_time:
# pylint: disable=too-few-format-args
message = 'It seems a {0}.run.revent file does not exist, '\
'Please provide one for your device: {0}.'
raise WorkloadError(message.format(self.device.name))
self.on_device_revent_binary = self.device.install_executable(revent_binary)
if self.revent_setup_file is not None:
self.device.push_file(self.revent_setup_file, self.on_device_setup_revent)
if not self.idle_time:
self.device.push_file(self.revent_run_file, self.on_device_run_revent)
if self.revent_teardown_file is not None:
self.device.push_file(self.revent_teardown_file, self.on_device_teardown_revent)

View File

@ -90,12 +90,14 @@ class ReventGetter(ResourceGetter):
self.resolver.register(self, 'revent', GetterPriority.package)
def get(self, resource, **kwargs):
# name format: [model/device_name.stage.revent]
device_model = resource.owner.device.get_device_model()
wa_device_name = resource.owner.device.name
for name in [device_model, wa_device_name]:
if not name:
continue
filename = '.'.join([name, resource.stage, 'revent']).lower()
self.logger.debug('Trying to get {0}.'.format(str(filename)))
location = _d(os.path.join(self.get_base_location(resource), 'revent_files'))
for candidate in os.listdir(location):
if candidate.lower() == filename.lower():