mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-09-02 11:22:41 +01:00
Merge pull request #78 from ep1cman/binary_install
BaseLinuxDevice: Tidied up the way binaries are handled
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
.. _resources:
|
||||||
|
|
||||||
Dynamic Resource Resolution
|
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
|
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
|
*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
|
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
|
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
|
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
|
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
|
specific resource types may define other parameters that describe an instance of
|
||||||
|
@@ -31,7 +31,7 @@ Extension Basics
|
|||||||
================
|
================
|
||||||
|
|
||||||
This sub-section covers things common to implementing extensions of all types.
|
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.
|
proceeding onto guidance for specific extension types.
|
||||||
|
|
||||||
To create an extension, you basically subclass an appropriate base class and them
|
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
|
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
|
of information about current state of execution of WA and keeps track of things
|
||||||
like which workload is currently running and the current iteration.
|
like which workload is currently running and the current iteration.
|
||||||
|
|
||||||
Notable attributes of the context are
|
Notable attributes of the context are
|
||||||
|
|
||||||
context.spec
|
context.spec
|
||||||
the current workload specification being executed. This is an
|
the current workload specification being executed. This is an
|
||||||
instance of :class:`wlauto.core.configuration.WorkloadRunSpec`
|
instance of :class:`wlauto.core.configuration.WorkloadRunSpec`
|
||||||
and defines the workload and the parameters under which it is
|
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.
|
``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
|
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
|
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
|
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
|
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
|
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
|
platforms. To help avoid hard-coded absolute paths, WA automation defines
|
||||||
a number of standard locations. You should strive to define your paths relative
|
a number of standard locations. You should strive to define your paths relative
|
||||||
to one of those.
|
to one of those.
|
||||||
@@ -95,7 +95,7 @@ extension methods.
|
|||||||
context.run_output_directory
|
context.run_output_directory
|
||||||
This is the top-level output directory for all WA results (by default,
|
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.
|
this will be "wa_output" in the directory in which WA was invoked.
|
||||||
|
|
||||||
context.output_directory
|
context.output_directory
|
||||||
This is the output directory for the current iteration. This will an
|
This is the output directory for the current iteration. This will an
|
||||||
iteration-specific subdirectory under the main results location. If
|
iteration-specific subdirectory under the main results location. If
|
||||||
@@ -104,7 +104,7 @@ context.output_directory
|
|||||||
|
|
||||||
context.host_working_directory
|
context.host_working_directory
|
||||||
This an addition location that may be used by extensions to store
|
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:
|
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
|
manipulation. Instead device has an equipment module exposed through
|
||||||
``device.path`` attribute. This has all the same attributes and behaves the
|
``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,
|
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
|
.. note:: result processors, unlike workloads and instruments, do not have their
|
||||||
own device attribute; however they can access the device through the
|
own device attribute; however they can access the device through the
|
||||||
context.
|
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
|
Parameters
|
||||||
----------
|
----------
|
||||||
@@ -188,11 +239,11 @@ mandatory
|
|||||||
and there really is no sensible default that could be given
|
and there really is no sensible default that could be given
|
||||||
(e.g. something like login credentials), should you consider
|
(e.g. something like login credentials), should you consider
|
||||||
making it mandatory.
|
making it mandatory.
|
||||||
|
|
||||||
constraint
|
constraint
|
||||||
This is an additional constraint to be enforced on the parameter beyond
|
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
|
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
|
that takes a single argument -- the user-supplied value -- and returns
|
||||||
a ``bool`` indicating whether the constraint has been satisfied).
|
a ``bool`` indicating whether the constraint has been satisfied).
|
||||||
|
|
||||||
override
|
override
|
||||||
@@ -201,7 +252,7 @@ override
|
|||||||
with the same name as already exists, you will get an error. If you do
|
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
|
want to override a parameter from further up in the inheritance
|
||||||
hierarchy, you can indicate that by setting ``override`` attribute to
|
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
|
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
|
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
|
The contract for ``validate`` method is that it should raise an exception
|
||||||
(either ``wlauto.exceptions.ConfigError`` or extension-specific exception type -- see
|
(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
|
If the method returns without raising an exception, then the extension is in a
|
||||||
valid internal state.
|
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.
|
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.
|
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
|
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
|
you should add logging is before doing something that might take a significant amount
|
||||||
of time, such as downloading a file.
|
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.
|
detailed description, including any limitations and setup instructions.
|
||||||
|
|
||||||
For parameters, the description is passed as an argument on creation. Please
|
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
|
parameter, they do not need to be explicitly mentioned in the description (wa
|
||||||
documentation utilities will automatically pull those). If the ``default`` is set
|
documentation utilities will automatically pull those). If the ``default`` is set
|
||||||
in ``validate`` or additional cross-parameter constraints exist, this *should*
|
in ``validate`` or additional cross-parameter constraints exist, this *should*
|
||||||
@@ -304,7 +355,7 @@ Utils
|
|||||||
Workload Automation defines a number of utilities collected under
|
Workload Automation defines a number of utilities collected under
|
||||||
:mod:`wlauto.utils` subpackage. These utilities were created to help with the
|
:mod:`wlauto.utils` subpackage. These utilities were created to help with the
|
||||||
implementation of the framework itself, but may be also be useful when
|
implementation of the framework itself, but may be also be useful when
|
||||||
implementing extensions.
|
implementing extensions.
|
||||||
|
|
||||||
|
|
||||||
Adding a Workload
|
Adding a Workload
|
||||||
@@ -329,7 +380,7 @@ The Workload class defines the following interface::
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def initialize(self, context):
|
def initialize(self, context):
|
||||||
pass
|
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
|
:name: This identifies the workload (e.g. it used to specify it in the
|
||||||
agenda_.
|
agenda_.
|
||||||
:init_resources: This method may be optionally override to implement dynamic
|
: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
|
early on, before the device has been initialized, so it
|
||||||
should only be used to initialize resources that do not
|
should only be used to initialize resources that do not
|
||||||
depend on the device to resolve. This method is executed
|
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
|
makes about the environment (e.g. that required files are
|
||||||
present, environment variables are set, etc) and should raise
|
present, environment variables are set, etc) and should raise
|
||||||
a :class:`wlauto.exceptions.WorkloadError` if that is not the
|
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.
|
the name attribute has been set.
|
||||||
:initialize: This method will be executed exactly once per run (no matter
|
:initialize: This method will be executed exactly once per run (no matter
|
||||||
how many instances of the workload there are). It will run
|
how many instances of the workload there are). It will run
|
||||||
after the device has been initialized, so it may be used to
|
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
|
be repeated on each iteration (e.g. as installing executables
|
||||||
required by the workload on the device).
|
required by the workload on the device).
|
||||||
:setup: Everything that needs to be in place for workload execution should
|
: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
|
then '.revent'. All your custom revent files should reside at
|
||||||
'~/.workload_automation/dependencies/WORKLOAD NAME/'. These are the current
|
'~/.workload_automation/dependencies/WORKLOAD NAME/'. These are the current
|
||||||
supported stages:
|
supported stages:
|
||||||
|
|
||||||
:setup: This stage is where the game is loaded. It is a good place to
|
: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
|
record revent here to modify the game settings and get it ready
|
||||||
to start.
|
to start.
|
||||||
:run: This stage is where the game actually starts. This will allow for
|
:run: This stage is where the game actually starts. This will allow for
|
||||||
more accurate results if the revent file for this stage only
|
more accurate results if the revent file for this stage only
|
||||||
records the game being played.
|
records the game being played.
|
||||||
|
|
||||||
For instance, to add a custom revent files for a device named mydevice and
|
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
|
a workload name mygame, you create a new directory called mygame in
|
||||||
'~/.workload_automation/dependencies/'. Then you add the revent files for
|
'~/.workload_automation/dependencies/'. Then you add the revent files for
|
||||||
the stages you want in ~/.workload_automation/dependencies/mygame/::
|
the stages you want in ~/.workload_automation/dependencies/mygame/::
|
||||||
|
|
||||||
mydevice.setup.revent
|
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
|
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
|
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.
|
setup in the dependencies and use the run.revent that is in the workload directory.
|
||||||
|
|
||||||
Adding an Instrument
|
Adding an Instrument
|
||||||
====================
|
====================
|
||||||
|
|
||||||
@@ -751,19 +802,19 @@ table::
|
|||||||
with open(outfile, 'w') as wfh:
|
with open(outfile, 'w') as wfh:
|
||||||
write_table(rows, wfh)
|
write_table(rows, wfh)
|
||||||
|
|
||||||
|
|
||||||
Adding a Resource Getter
|
Adding a Resource Getter
|
||||||
========================
|
========================
|
||||||
|
|
||||||
A resource getter is a new extension type added in version 2.1.3. A resource
|
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
|
getter implement a method of acquiring resources of a particular type (such as
|
||||||
APK files or additional workload assets). Resource getters are invoked in
|
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
|
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
|
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
|
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::
|
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):
|
def get(self, resource, **kwargs):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
The getter should define a name (as with all extensions), a resource
|
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
|
type, which should be a string, e.g. ``'jar'``, and a priority (see `Getter
|
||||||
Prioritization`_ below). In addition, ``get`` method should be implemented. The
|
Prioritization`_ below). In addition, ``get`` method should be implemented. The
|
||||||
@@ -847,7 +898,7 @@ looks for the file under
|
|||||||
elif not found_files:
|
elif not found_files:
|
||||||
return None
|
return None
|
||||||
else:
|
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))
|
resource.owner.name))
|
||||||
|
|
||||||
.. _adding_a_device:
|
.. _adding_a_device:
|
||||||
@@ -947,7 +998,7 @@ top-level package directory is created by default, and it is OK to have
|
|||||||
everything in there.
|
everything in there.
|
||||||
|
|
||||||
.. note:: When discovering extensions thorugh this mechanism, WA traveries the
|
.. 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
|
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
|
created for you, it is important that your make sure they are valid
|
||||||
Python packages; i.e. each subdirectory must contain a __init__.py
|
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
|
the ``setup.py`` to add correct author, license and contact information (see
|
||||||
"Writing the Setup Script" section in standard Python documentation for
|
"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
|
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 ::
|
you can generate the package by running ::
|
||||||
|
|
||||||
cd my_wa_exts
|
cd my_wa_exts
|
||||||
|
@@ -51,7 +51,7 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
|
|||||||
description='The format of matching the shell prompt in Android.'),
|
description='The format of matching the shell prompt in Android.'),
|
||||||
Parameter('working_directory', default='/sdcard/wa-working',
|
Parameter('working_directory', default='/sdcard/wa-working',
|
||||||
description='Directory that will be used WA on the device for output files etc.'),
|
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.'),
|
description='Location of binaries on the device.'),
|
||||||
Parameter('package_data_directory', default='/data/data',
|
Parameter('package_data_directory', default='/data/data',
|
||||||
description='Location of of data for an installed package (APK).'),
|
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.
|
If set a swipe of the specified direction will be performed.
|
||||||
This should unlock the screen.
|
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
|
default_timeout = 30
|
||||||
@@ -193,9 +195,7 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
|
|||||||
self._is_ready = True
|
self._is_ready = True
|
||||||
|
|
||||||
def initialize(self, context):
|
def initialize(self, context):
|
||||||
self.execute('mkdir -p {}'.format(self.working_directory))
|
|
||||||
if self.is_rooted:
|
if self.is_rooted:
|
||||||
self.busybox = self.deploy_busybox(context)
|
|
||||||
self.disable_screen_lock()
|
self.disable_screen_lock()
|
||||||
self.disable_selinux()
|
self.disable_selinux()
|
||||||
if self.enable_screen_check:
|
if self.enable_screen_check:
|
||||||
@@ -281,11 +281,24 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
|
|||||||
"""
|
"""
|
||||||
return package_name in self.list_packages()
|
return package_name in self.list_packages()
|
||||||
|
|
||||||
def executable_is_installed(self, executable_name):
|
def executable_is_installed(self, executable_name): # pylint: disable=unused-argument,no-self-use
|
||||||
return executable_name in self.listdir(self.binaries_directory)
|
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):
|
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):
|
def listdir(self, path, as_root=False, **kwargs):
|
||||||
contents = self.execute('ls {}'.format(path), as_root=as_root)
|
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):
|
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.
|
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
|
Optionally, ``with_name`` parameter may be used to specify a different name under
|
||||||
which the executable will be installed.
|
which the executable will be installed.
|
||||||
@@ -376,12 +389,13 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
|
|||||||
|
|
||||||
def uninstall_executable(self, executable_name):
|
def uninstall_executable(self, executable_name):
|
||||||
"""
|
"""
|
||||||
Requires root access.
|
|
||||||
|
|
||||||
Added in version 2.1.3.
|
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._ensure_binaries_directory_is_writable()
|
||||||
self.delete_file(on_device_executable, as_root=self.is_rooted)
|
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
|
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
|
: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``.
|
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:
|
if as_root and not self.is_rooted:
|
||||||
raise DeviceError('Attempting to execute "{}" as root on unrooted device.'.format(command))
|
raise DeviceError('Attempting to execute "{}" as root on unrooted device.'.format(command))
|
||||||
if busybox:
|
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])
|
command = ' '.join([self.busybox, command])
|
||||||
if background:
|
if background:
|
||||||
return adb_background_shell(self.adb_name, command, as_root=as_root)
|
return adb_background_shell(self.adb_name, command, as_root=as_root)
|
||||||
|
@@ -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
|
These paths do not have to exist and will be ignored if the path is not present on a
|
||||||
particular device.
|
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):
|
def initialize(self, context):
|
||||||
self.execute('mkdir -p {}'.format(self.working_directory))
|
self.execute('mkdir -p {}'.format(self.working_directory))
|
||||||
if self.is_rooted:
|
if not self.binaries_directory:
|
||||||
if not self.is_installed('busybox'):
|
self._set_binaries_dir()
|
||||||
self.busybox = self.deploy_busybox(context)
|
self.execute('mkdir -p {}'.format(self.binaries_directory))
|
||||||
else:
|
self.busybox = self.deploy_busybox(context)
|
||||||
self.busybox = 'busybox'
|
|
||||||
|
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):
|
def is_file(self, filepath):
|
||||||
output = self.execute('if [ -f \'{}\' ]; then echo 1; else echo 0; fi'.format(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
|
Deploys the busybox binary to the specified device and returns
|
||||||
the path to the binary on the device.
|
the path to the binary on the device.
|
||||||
|
|
||||||
:param device: device to deploy the binary to.
|
|
||||||
:param context: an instance of ExecutionContext
|
:param context: an instance of ExecutionContext
|
||||||
:param force: by default, if the binary is already present on the
|
:param force: by default, if the binary is already present on the
|
||||||
device, it will not be deployed again. Setting force
|
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.
|
:returns: The on-device path to the busybox binary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
on_device_executable = self.path.join(self.binaries_directory, 'busybox')
|
on_device_executable = self.get_binary_path("busybox", search_system_binaries=False)
|
||||||
if not force and self.file_exists(on_device_executable):
|
if force or not on_device_executable:
|
||||||
return on_device_executable
|
host_file = context.resolver.get(Executable(NO_ONE, self.abi, 'busybox'))
|
||||||
host_file = context.resolver.get(Executable(NO_ONE, self.abi, 'busybox'))
|
return self.install(host_file)
|
||||||
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):
|
def list_file_systems(self):
|
||||||
output = self.execute('mount')
|
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
|
has write permissions. This will default to /home/<username>/wa (or to /root/wa, if
|
||||||
username is 'root').
|
username is 'root').
|
||||||
'''),
|
'''),
|
||||||
Parameter('binaries_directory', default='/usr/local/bin',
|
|
||||||
description='Location of executable binaries on this device (must be in PATH).'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -554,7 +606,6 @@ class LinuxDevice(BaseLinuxDevice):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(LinuxDevice, self).__init__(*args, **kwargs)
|
super(LinuxDevice, self).__init__(*args, **kwargs)
|
||||||
self.shell = None
|
self.shell = None
|
||||||
self.local_binaries_directory = None
|
|
||||||
self._is_rooted = None
|
self._is_rooted = None
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@@ -563,12 +614,9 @@ class LinuxDevice(BaseLinuxDevice):
|
|||||||
self.working_directory = '/root/wa' # pylint: disable=attribute-defined-outside-init
|
self.working_directory = '/root/wa' # pylint: disable=attribute-defined-outside-init
|
||||||
else:
|
else:
|
||||||
self.working_directory = '/home/{}/wa'.format(self.username) # pylint: disable=attribute-defined-outside-init
|
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):
|
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('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))
|
self.execute('export PATH={}:$PATH'.format(self.binaries_directory))
|
||||||
super(LinuxDevice, self).initialize(context, *args, **kwargs)
|
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
|
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
|
def install(self, filepath, timeout=default_timeout, with_name=None): # pylint: disable=W0221
|
||||||
if self.is_rooted:
|
destpath = self.path.join(self.binaries_directory,
|
||||||
destpath = self.path.join(self.binaries_directory,
|
with_name or self.path.basename(filepath))
|
||||||
with_name and with_name or self.path.basename(filepath))
|
self.push_file(filepath, destpath, as_root=True)
|
||||||
self.push_file(filepath, destpath, as_root=True)
|
self.execute('chmod a+x {}'.format(destpath), timeout=timeout, 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)
|
|
||||||
return destpath
|
return destpath
|
||||||
|
|
||||||
install_executable = install # compatibility
|
install_executable = install # compatibility
|
||||||
|
|
||||||
def uninstall(self, name):
|
def uninstall(self, executable_name):
|
||||||
if self.is_rooted:
|
on_device_executable = self.get_binary_path(executable_name, search_system_binaries=False)
|
||||||
path = self.path.join(self.binaries_directory, name)
|
if not on_device_executable:
|
||||||
self.delete_file(path, as_root=True)
|
raise DeviceError("Could not uninstall {}, binary not found".format(on_device_executable))
|
||||||
else:
|
self.delete_file(on_device_executable, as_root=self.is_rooted)
|
||||||
path = self.path.join(self.local_binaries_directory, name)
|
|
||||||
self.delete_file(path)
|
|
||||||
|
|
||||||
uninstall_executable = uninstall # compatibility
|
uninstall_executable = uninstall # compatibility
|
||||||
|
|
||||||
def is_installed(self, name):
|
|
||||||
try:
|
|
||||||
self.execute('which {}'.format(name))
|
|
||||||
return True
|
|
||||||
except DeviceError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
|
|
||||||
def ping(self):
|
def ping(self):
|
||||||
@@ -788,7 +821,7 @@ class LinuxDevice(BaseLinuxDevice):
|
|||||||
raise DeviceNotRespondingError(self.host)
|
raise DeviceNotRespondingError(self.host)
|
||||||
|
|
||||||
def capture_screen(self, filepath):
|
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.')
|
self.logger.debug('Could not take screenshot as scrot is not installed.')
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
|
@@ -91,11 +91,11 @@ class PerfInstrument(Instrument):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def on_run_init(self, context):
|
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)
|
self.binary = self.device.install(binary)
|
||||||
else:
|
else:
|
||||||
self.binary = 'perf'
|
self.binary = self.device.install_if_needed(binary)
|
||||||
self.commands = self._build_commands()
|
self.commands = self._build_commands()
|
||||||
|
|
||||||
def setup(self, context):
|
def setup(self, context):
|
||||||
|
@@ -164,11 +164,12 @@ class TraceCmdInstrument(Instrument):
|
|||||||
raise InstrumentError('trace-cmd instrument cannot be used on an unrooted device.')
|
raise InstrumentError('trace-cmd instrument cannot be used on an unrooted device.')
|
||||||
if not self.no_install:
|
if not self.no_install:
|
||||||
host_file = context.resolver.get(Executable(self, self.device.abi, 'trace-cmd'))
|
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:
|
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.')
|
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
|
# Register ourselves as absolute last event before and
|
||||||
# first after so we can mark the trace at the right time
|
# first after so we can mark the trace at the right time
|
||||||
signal.connect(self.insert_start_mark, signal.BEFORE_WORKLOAD_EXECUTION, priority=11)
|
signal.connect(self.insert_start_mark, signal.BEFORE_WORKLOAD_EXECUTION, priority=11)
|
||||||
|
@@ -80,6 +80,8 @@ class Antutu(AndroidUiAutoBenchmark):
|
|||||||
info = ApkInfo(antutu_3d)
|
info = ApkInfo(antutu_3d)
|
||||||
if not context.device.is_installed(info.package):
|
if not context.device.is_installed(info.package):
|
||||||
self.device.install_apk(antutu_3d, timeout=120)
|
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)
|
super(Antutu, self).setup(context)
|
||||||
|
|
||||||
def update_result(self, context):
|
def update_result(self, context):
|
||||||
|
@@ -79,11 +79,8 @@ class Cyclictest(Workload):
|
|||||||
if not self.device.is_rooted:
|
if not self.device.is_rooted:
|
||||||
raise WorkloadError("This workload requires a device with root premissions to run")
|
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'))
|
||||||
host_binary = context.resolver.get(Executable(self, self.device.abi, 'cyclictest'))
|
self.device_binary = self.device.install(host_binary)
|
||||||
self.device_binary = self.device.install(host_binary)
|
|
||||||
else:
|
|
||||||
self.device_binary = 'cyclictest'
|
|
||||||
|
|
||||||
self.cyclictest_command = self.cyclictest_command.format(self.device_binary,
|
self.cyclictest_command = self.cyclictest_command.format(self.device_binary,
|
||||||
0 if self.clock == 'monotonic' else 1,
|
0 if self.clock == 'monotonic' else 1,
|
||||||
|
@@ -52,16 +52,13 @@ class Ebizzy(Workload):
|
|||||||
def setup(self, context):
|
def setup(self, context):
|
||||||
timeout_buf = 10
|
timeout_buf = 10
|
||||||
self.command = '{} -t {} -S {} -n {} {} > {}'
|
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.device_binary = None
|
||||||
self.run_timeout = self.seconds + timeout_buf
|
self.run_timeout = self.seconds + timeout_buf
|
||||||
|
|
||||||
self.binary_name = 'ebizzy'
|
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))
|
||||||
host_binary = context.resolver.get(Executable(self, self.device.abi, self.binary_name))
|
self.device_binary = self.device.install_if_needed(host_binary)
|
||||||
self.device_binary = self.device.install(host_binary)
|
|
||||||
else:
|
|
||||||
self.device_binary = self.binary_name
|
|
||||||
|
|
||||||
self.command = self.command.format(self.device_binary, self.threads, self.seconds,
|
self.command = self.command.format(self.device_binary, self.threads, self.seconds,
|
||||||
self.chunks, self.extra_params, self.ebizzy_results)
|
self.chunks, self.extra_params, self.ebizzy_results)
|
||||||
|
@@ -61,11 +61,8 @@ class Hackbench(Workload):
|
|||||||
self.run_timeout = self.duration + timeout_buf
|
self.run_timeout = self.duration + timeout_buf
|
||||||
|
|
||||||
self.binary_name = 'hackbench'
|
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))
|
||||||
host_binary = context.resolver.get(Executable(self, self.device.abi, self.binary_name))
|
self.device_binary = self.device.install(host_binary)
|
||||||
self.device_binary = self.device.install(host_binary)
|
|
||||||
else:
|
|
||||||
self.device_binary = self.binary_name
|
|
||||||
|
|
||||||
self.command = self.command.format(self.device_binary, self.datasize, self.groups,
|
self.command = self.command.format(self.device_binary, self.datasize, self.groups,
|
||||||
self.loops, self.extra_params, self.hackbench_result)
|
self.loops, self.extra_params, self.hackbench_result)
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from wlauto import Workload, Parameter
|
from wlauto import Workload, Parameter, Executable
|
||||||
|
|
||||||
|
|
||||||
THIS_DIR = os.path.dirname(__file__)
|
THIS_DIR = os.path.dirname(__file__)
|
||||||
@@ -54,11 +54,10 @@ class MemcpyTest(Workload):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def setup(self, context):
|
def setup(self, context):
|
||||||
self.host_binary = os.path.join(THIS_DIR, 'memcpy')
|
self.binary_name = 'memcpy'
|
||||||
if not self.device.is_installed('memcpy'):
|
host_binary = context.resolver.get(Executable(self, self.device.abi, self.binary_name))
|
||||||
self.device_binary = self.device.install(self.host_binary)
|
self.device_binary = self.device.install_if_needed(host_binary)
|
||||||
else:
|
|
||||||
self.device_binary = 'memcpy'
|
|
||||||
self.command = '{} -i {} -s {}'.format(self.device_binary, self.iterations, self.buffer_size)
|
self.command = '{} -i {} -s {}'.format(self.device_binary, self.iterations, self.buffer_size)
|
||||||
if self.cpus:
|
if self.cpus:
|
||||||
for c in self.cpus:
|
for c in self.cpus:
|
||||||
|
BIN
wlauto/workloads/memcpy/bin/arm64/memcpy
Executable file
BIN
wlauto/workloads/memcpy/bin/arm64/memcpy
Executable file
Binary file not shown.
@@ -216,14 +216,13 @@ class RtApp(Workload):
|
|||||||
|
|
||||||
def _deploy_rt_app_binary_if_necessary(self):
|
def _deploy_rt_app_binary_if_necessary(self):
|
||||||
# called from initialize() so gets invoked once per run
|
# 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:
|
if not self.host_binary:
|
||||||
message = '''rt-app is not installed on the device and could not be
|
message = '''rt-app is not installed on the device and could not be
|
||||||
found in workload resources'''
|
found in workload resources'''
|
||||||
raise ResourceError(message)
|
raise ResourceError(message)
|
||||||
RtApp.device_binary = self.device.install(self.host_binary)
|
RtApp.device_binary = self.device.install(self.host_binary)
|
||||||
else:
|
|
||||||
RtApp.device_binary = BINARY_NAME
|
|
||||||
|
|
||||||
def _load_json_config(self, context):
|
def _load_json_config(self, context):
|
||||||
user_config_file = self._get_raw_json_config(context.resolver)
|
user_config_file = self._get_raw_json_config(context.resolver)
|
||||||
@@ -280,4 +279,3 @@ class RtApp(Workload):
|
|||||||
tf.extractall(context.output_directory)
|
tf.extractall(context.output_directory)
|
||||||
os.remove(host_path)
|
os.remove(host_path)
|
||||||
self.device.execute('rm -rf {}/*'.format(self.device_working_directory))
|
self.device.execute('rm -rf {}/*'.format(self.device_working_directory))
|
||||||
|
|
||||||
|
@@ -132,13 +132,13 @@ class Sysbench(Workload):
|
|||||||
self.device.delete_file(self.results_file)
|
self.device.delete_file(self.results_file)
|
||||||
|
|
||||||
def _check_executable(self):
|
def _check_executable(self):
|
||||||
self.on_device_binary = self.device.path.join(self.device.binaries_directory, 'sysbench')
|
self.on_device_binary = self.device.get_binary_path("sysbench")
|
||||||
if self.device.is_installed('sysbench') and not self.force_install:
|
if not self.on_device_binary and not self.on_host_binary:
|
||||||
self.logger.debug('sysbench found on device')
|
|
||||||
return
|
|
||||||
if not self.on_host_binary:
|
|
||||||
raise WorkloadError('sysbench binary is not installed on the device, and it is not found on the host.')
|
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):
|
def _build_command(self, **parameters):
|
||||||
param_strings = ['--{}={}'.format(k.replace('_', '-'), v)
|
param_strings = ['--{}={}'.format(k.replace('_', '-'), v)
|
||||||
|
Reference in New Issue
Block a user