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

Merge pull request #78 from ep1cman/binary_install

BaseLinuxDevice: Tidied up the way binaries are handled
This commit is contained in:
setrofim 2016-01-19 10:52:54 +00:00
commit 120f0ff94f
15 changed files with 218 additions and 130 deletions

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

@ -31,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
@ -41,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
@ -79,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.
@ -95,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
@ -104,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:
@ -132,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
----------
@ -188,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
@ -201,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
@ -222,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.
@ -242,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.
@ -259,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*
@ -304,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
@ -329,7 +380,7 @@ The Workload class defines the following interface::
def validate(self):
pass
def initialize(self, context):
pass
@ -359,7 +410,7 @@ 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. This method executes
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
@ -368,12 +419,12 @@ The interface should be implemented as follows
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
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
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
@ -536,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
@ -555,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
====================
@ -751,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::
@ -775,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
@ -847,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:
@ -947,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
@ -958,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

@ -51,7 +51,7 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
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('binaries_directory', default='/data/local/tmp', 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).'),
@ -78,6 +78,8 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
If set a swipe of the specified direction will be performed.
This should unlock the screen.
"""),
Parameter('binaries_directory', default="/data/local/tmp", override=True,
description='Location of executable binaries on this device (must be in PATH).'),
]
default_timeout = 30
@ -193,9 +195,7 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
self._is_ready = True
def initialize(self, context):
self.execute('mkdir -p {}'.format(self.working_directory))
if self.is_rooted:
self.busybox = self.deploy_busybox(context)
self.disable_screen_lock()
self.disable_selinux()
if self.enable_screen_check:
@ -281,11 +281,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)
@ -352,7 +365,7 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
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.
@ -376,12 +389,13 @@ 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)
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)
@ -405,7 +419,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``.
@ -424,9 +438,6 @@ 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)

View File

@ -89,6 +89,8 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
These paths do not have to exist and will be ignored if the path is not present on a
particular device.
'''),
Parameter('binaries_directory',
description='Location of executable binaries on this device (must be in PATH).'),
]
@ -183,11 +185,14 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
def initialize(self, context):
self.execute('mkdir -p {}'.format(self.working_directory))
if self.is_rooted:
if not self.is_installed('busybox'):
self.busybox = self.deploy_busybox(context)
else:
self.busybox = 'busybox'
if not self.binaries_directory:
self._set_binaries_dir()
self.execute('mkdir -p {}'.format(self.binaries_directory))
self.busybox = self.deploy_busybox(context)
def _set_binaries_dir(self):
# pylint: disable=attribute-defined-outside-init
self.binaries_directory = self.path.join(self.working_directory, "bin")
def is_file(self, filepath):
output = self.execute('if [ -f \'{}\' ]; then echo 1; else echo 0; fi'.format(filepath))
@ -281,7 +286,6 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
Deploys the busybox binary to the specified device and returns
the path to the binary on the device.
:param device: device to deploy the binary to.
:param context: an instance of ExecutionContext
:param force: by default, if the binary is already present on the
device, it will not be deployed again. Setting force
@ -291,11 +295,61 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
:returns: The on-device path to the busybox binary.
"""
on_device_executable = self.path.join(self.binaries_directory, 'busybox')
if not force and self.file_exists(on_device_executable):
return on_device_executable
host_file = context.resolver.get(Executable(NO_ONE, self.abi, 'busybox'))
return self.install(host_file)
on_device_executable = self.get_binary_path("busybox", search_system_binaries=False)
if force or not on_device_executable:
host_file = context.resolver.get(Executable(NO_ONE, self.abi, 'busybox'))
return self.install(host_file)
return on_device_executable
def is_installed(self, 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 get_binary_path(self, name, search_system_binaries=True):
"""
Searches the devices ``binary_directory`` for the given binary,
if it cant find it there it tries using which to find it.
:param name: The name of the binary
:param search_system_binaries: By default this function will try using
which to find the binary if it isn't in
``binary_directory``. When this is set
to ``False`` it will not try this.
:returns: The on-device path to the binary.
"""
wa_binary = self.path.join(self.binaries_directory, name)
if self.file_exists(wa_binary):
return wa_binary
if search_system_binaries:
try:
return self.execute('{} which {}'.format(self.busybox, name)).strip()
except DeviceError:
pass
return None
def install_if_needed(self, host_path, search_system_binaries=True):
"""
Similar to get_binary_path but will install the binary if not found.
:param host_path: The path to the binary on the host
:param search_system_binaries: By default this function will try using
which to find the binary if it isn't in
``binary_directory``. When this is set
to ``False`` it will not try this.
:returns: The on-device path to the binary.
"""
binary_path = self.get_binary_path(os.path.split(host_path)[1],
search_system_binaries=search_system_binaries)
if not binary_path:
binary_path = self.install(host_path)
return binary_path
def list_file_systems(self):
output = self.execute('mount')
@ -527,8 +581,6 @@ class LinuxDevice(BaseLinuxDevice):
has write permissions. This will default to /home/<username>/wa (or to /root/wa, if
username is 'root').
'''),
Parameter('binaries_directory', default='/usr/local/bin',
description='Location of executable binaries on this device (must be in PATH).'),
]
@property
@ -554,7 +606,6 @@ class LinuxDevice(BaseLinuxDevice):
def __init__(self, *args, **kwargs):
super(LinuxDevice, self).__init__(*args, **kwargs)
self.shell = None
self.local_binaries_directory = None
self._is_rooted = None
def validate(self):
@ -563,12 +614,9 @@ class LinuxDevice(BaseLinuxDevice):
self.working_directory = '/root/wa' # pylint: disable=attribute-defined-outside-init
else:
self.working_directory = '/home/{}/wa'.format(self.username) # pylint: disable=attribute-defined-outside-init
self.local_binaries_directory = self.path.join(self.working_directory, 'bin')
def initialize(self, context, *args, **kwargs):
self.execute('mkdir -p {}'.format(self.local_binaries_directory))
self.execute('mkdir -p {}'.format(self.binaries_directory))
self.execute('export PATH={}:$PATH'.format(self.local_binaries_directory))
self.execute('export PATH={}:$PATH'.format(self.binaries_directory))
super(LinuxDevice, self).initialize(context, *args, **kwargs)
@ -747,37 +795,22 @@ class LinuxDevice(BaseLinuxDevice):
return [x.strip() for x in contents.split('\n')] # pylint: disable=maybe-no-member
def install(self, filepath, timeout=default_timeout, with_name=None): # pylint: disable=W0221
if self.is_rooted:
destpath = self.path.join(self.binaries_directory,
with_name and with_name or self.path.basename(filepath))
self.push_file(filepath, destpath, as_root=True)
self.execute('chmod a+x {}'.format(destpath), timeout=timeout, as_root=True)
else:
destpath = self.path.join(self.local_binaries_directory,
with_name and with_name or self.path.basename(filepath))
self.push_file(filepath, destpath)
self.execute('chmod a+x {}'.format(destpath), timeout=timeout)
destpath = self.path.join(self.binaries_directory,
with_name or self.path.basename(filepath))
self.push_file(filepath, destpath, as_root=True)
self.execute('chmod a+x {}'.format(destpath), timeout=timeout, as_root=True)
return destpath
install_executable = install # compatibility
def uninstall(self, name):
if self.is_rooted:
path = self.path.join(self.binaries_directory, name)
self.delete_file(path, as_root=True)
else:
path = self.path.join(self.local_binaries_directory, name)
self.delete_file(path)
def uninstall(self, executable_name):
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.delete_file(on_device_executable, as_root=self.is_rooted)
uninstall_executable = uninstall # compatibility
def is_installed(self, name):
try:
self.execute('which {}'.format(name))
return True
except DeviceError:
return False
# misc
def ping(self):
@ -788,7 +821,7 @@ class LinuxDevice(BaseLinuxDevice):
raise DeviceNotRespondingError(self.host)
def capture_screen(self, filepath):
if not self.is_installed('scrot'):
if not self.get_binary_path('scrot'):
self.logger.debug('Could not take screenshot as scrot is not installed.')
return
try:

View File

@ -91,11 +91,11 @@ class PerfInstrument(Instrument):
]
def on_run_init(self, context):
if not self.device.is_installed('perf') or self.force_install:
binary = context.resolver.get(Executable(self, self.device.abi, 'perf'))
binary = context.resolver.get(Executable(self, self.device.abi, 'perf'))
if self.force_install:
self.binary = self.device.install(binary)
else:
self.binary = 'perf'
self.binary = self.device.install_if_needed(binary)
self.commands = self._build_commands()
def setup(self, context):

View File

@ -164,11 +164,12 @@ class TraceCmdInstrument(Instrument):
raise InstrumentError('trace-cmd instrument cannot be used on an unrooted device.')
if not self.no_install:
host_file = context.resolver.get(Executable(self, self.device.abi, 'trace-cmd'))
self.trace_cmd = self.device.install_executable(host_file)
self.trace_cmd = self.device.install(host_file)
else:
if not self.device.is_installed('trace-cmd'):
self.trace_cmd = self.device.get_binary_path("trace-cmd")
if not self.trace_cmd:
raise ConfigError('No trace-cmd found on device and no_install=True is specified.')
self.trace_cmd = 'trace-cmd'
# Register ourselves as absolute last event before and
# first after so we can mark the trace at the right time
signal.connect(self.insert_start_mark, signal.BEFORE_WORKLOAD_EXECUTION, priority=11)

View File

@ -80,6 +80,8 @@ class Antutu(AndroidUiAutoBenchmark):
info = ApkInfo(antutu_3d)
if not context.device.is_installed(info.package):
self.device.install_apk(antutu_3d, timeout=120)
# Antutu doesnt seem to list this as one of its permissions, but it asks for it.
self.device.execute("pm grant com.antutu.ABenchMark android.permission.ACCESS_FINE_LOCATION")
super(Antutu, self).setup(context)
def update_result(self, context):

View File

@ -79,11 +79,8 @@ class Cyclictest(Workload):
if not self.device.is_rooted:
raise WorkloadError("This workload requires a device with root premissions to run")
if not self.device.is_installed('cyclictest'):
host_binary = context.resolver.get(Executable(self, self.device.abi, 'cyclictest'))
self.device_binary = self.device.install(host_binary)
else:
self.device_binary = 'cyclictest'
host_binary = context.resolver.get(Executable(self, self.device.abi, 'cyclictest'))
self.device_binary = self.device.install(host_binary)
self.cyclictest_command = self.cyclictest_command.format(self.device_binary,
0 if self.clock == 'monotonic' else 1,

View File

@ -52,16 +52,13 @@ class Ebizzy(Workload):
def setup(self, context):
timeout_buf = 10
self.command = '{} -t {} -S {} -n {} {} > {}'
self.ebizzy_results = os.path.join(self.device.working_directory, results_txt)
self.ebizzy_results = self.device.path.join(self.device.working_directory, results_txt)
self.device_binary = None
self.run_timeout = self.seconds + timeout_buf
self.binary_name = 'ebizzy'
if not self.device.is_installed(self.binary_name):
host_binary = context.resolver.get(Executable(self, self.device.abi, self.binary_name))
self.device_binary = self.device.install(host_binary)
else:
self.device_binary = self.binary_name
host_binary = context.resolver.get(Executable(self, self.device.abi, self.binary_name))
self.device_binary = self.device.install_if_needed(host_binary)
self.command = self.command.format(self.device_binary, self.threads, self.seconds,
self.chunks, self.extra_params, self.ebizzy_results)

View File

@ -61,11 +61,8 @@ class Hackbench(Workload):
self.run_timeout = self.duration + timeout_buf
self.binary_name = 'hackbench'
if not self.device.is_installed(self.binary_name):
host_binary = context.resolver.get(Executable(self, self.device.abi, self.binary_name))
self.device_binary = self.device.install(host_binary)
else:
self.device_binary = self.binary_name
host_binary = context.resolver.get(Executable(self, self.device.abi, self.binary_name))
self.device_binary = self.device.install(host_binary)
self.command = self.command.format(self.device_binary, self.datasize, self.groups,
self.loops, self.extra_params, self.hackbench_result)

View File

@ -18,7 +18,7 @@
import os
import re
from wlauto import Workload, Parameter
from wlauto import Workload, Parameter, Executable
THIS_DIR = os.path.dirname(__file__)
@ -54,11 +54,10 @@ class MemcpyTest(Workload):
]
def setup(self, context):
self.host_binary = os.path.join(THIS_DIR, 'memcpy')
if not self.device.is_installed('memcpy'):
self.device_binary = self.device.install(self.host_binary)
else:
self.device_binary = 'memcpy'
self.binary_name = 'memcpy'
host_binary = context.resolver.get(Executable(self, self.device.abi, self.binary_name))
self.device_binary = self.device.install_if_needed(host_binary)
self.command = '{} -i {} -s {}'.format(self.device_binary, self.iterations, self.buffer_size)
if self.cpus:
for c in self.cpus:

Binary file not shown.

View File

@ -216,14 +216,13 @@ class RtApp(Workload):
def _deploy_rt_app_binary_if_necessary(self):
# called from initialize() so gets invoked once per run
if self.force_install or not self.device.is_installed(BINARY_NAME):
RtApp.device_binary = self.device.get_binary_path("rt-app")
if self.force_install or not RtApp.device_binary:
if not self.host_binary:
message = '''rt-app is not installed on the device and could not be
found in workload resources'''
raise ResourceError(message)
RtApp.device_binary = self.device.install(self.host_binary)
else:
RtApp.device_binary = BINARY_NAME
def _load_json_config(self, context):
user_config_file = self._get_raw_json_config(context.resolver)
@ -280,4 +279,3 @@ class RtApp(Workload):
tf.extractall(context.output_directory)
os.remove(host_path)
self.device.execute('rm -rf {}/*'.format(self.device_working_directory))

View File

@ -132,13 +132,13 @@ class Sysbench(Workload):
self.device.delete_file(self.results_file)
def _check_executable(self):
self.on_device_binary = self.device.path.join(self.device.binaries_directory, 'sysbench')
if self.device.is_installed('sysbench') and not self.force_install:
self.logger.debug('sysbench found on device')
return
if not self.on_host_binary:
self.on_device_binary = self.device.get_binary_path("sysbench")
if not self.on_device_binary and not self.on_host_binary:
raise WorkloadError('sysbench binary is not installed on the device, and it is not found on the host.')
self.device.install(self.on_host_binary)
if self.force_install:
self.device.install(self.on_host_binary)
else:
self.device.install_if_needed(self.on_host_binary)
def _build_command(self, **parameters):
param_strings = ['--{}={}'.format(k.replace('_', '-'), v)