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:
parent
c6cdd8c0e6
commit
6d9a03ad8f
@ -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))
|
||||
|
165
wlauto/common/linux/workload.py
Normal file
165
wlauto/common/linux/workload.py
Normal 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)
|
@ -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():
|
||||
|
Loading…
x
Reference in New Issue
Block a user