mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-04-20 17:50:49 +01:00
doc: Improve Adding a Workload
how to
This commit is contained in:
parent
23eb428829
commit
37d6433214
@ -58,6 +58,8 @@ will automatically generate a workload in the your ``WA_CONFIG_DIR/plugins``. If
|
|||||||
you wish to specify a custom location this can be provided with ``-p
|
you wish to specify a custom location this can be provided with ``-p
|
||||||
<path>``
|
<path>``
|
||||||
|
|
||||||
|
.. _adding-a-basic-workload:
|
||||||
|
|
||||||
Adding a Basic Workload Example
|
Adding a Basic Workload Example
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
@ -79,6 +81,14 @@ to compress a file of a particular size on the device.
|
|||||||
perform the actual measurement is not necessarily sound, and this
|
perform the actual measurement is not necessarily sound, and this
|
||||||
Workload should not be used to collect real measurements.
|
Workload should not be used to collect real measurements.
|
||||||
|
|
||||||
|
The first step is to subclass our desired
|
||||||
|
:ref:`workload type <workload-types>` depending on the purpose of our workload,
|
||||||
|
in this example we are implementing a very simple workload and do not
|
||||||
|
require any additional feature so shall inherit directly from the the base
|
||||||
|
:class:`Workload` class. We then need to provide a ``name`` for our workload
|
||||||
|
which is what will be used to identify your workload for example in an
|
||||||
|
agenda or via the show command.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@ -87,6 +97,125 @@ to compress a file of a particular size on the device.
|
|||||||
class ZipTestWorkload(Workload):
|
class ZipTestWorkload(Workload):
|
||||||
|
|
||||||
name = 'ziptest'
|
name = 'ziptest'
|
||||||
|
|
||||||
|
The ``description`` attribute should be a string in the structure of a short
|
||||||
|
summary of the purpose of the workload, and will be shown when using the
|
||||||
|
:ref:`list command <list-command>`, followed by a more in- depth explanation
|
||||||
|
separated by a new line.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
description = '''
|
||||||
|
Times how long it takes to gzip a file of a particular size on a device.
|
||||||
|
|
||||||
|
This workload was created for illustration purposes only. It should not be
|
||||||
|
used to collect actual measurements.
|
||||||
|
'''
|
||||||
|
|
||||||
|
In order to allow for additional configuration of the workload from a user a
|
||||||
|
list of :ref:`parameters <plugin-parmeters>` can be supplied. These can be
|
||||||
|
configured in a variety of different ways. For example here we are ensuring that
|
||||||
|
the value of the parameter is an integer and larger than 0 using the ``kind``
|
||||||
|
and ``constraint`` options, also if no value is provided we are providing a
|
||||||
|
``default`` value of 2000000. These parameters will automatically have their
|
||||||
|
value set as an attribute of the workload so later on we will be able to use the
|
||||||
|
value provided here as ``self.file_size``.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
parameters = [
|
||||||
|
Parameter('file_size', kind=int, default=2000000,
|
||||||
|
constraint=lambda x: 0 < x,
|
||||||
|
description='Size of the file (in bytes) to be gzipped.')
|
||||||
|
]
|
||||||
|
|
||||||
|
Next we will implement our ``setup`` method. This is where we do any preparation
|
||||||
|
that is required before the workload is ran, this is usually things like setting
|
||||||
|
up required files on the device and generating commands from user input. In this
|
||||||
|
case we will generate our input file on the host system and then push it to a
|
||||||
|
known location on the target for use in the 'run' stage.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def setup(self, context):
|
||||||
|
super(ZipTestWorkload, self).setup(context)
|
||||||
|
# Generate a file of the specified size containing random garbage.
|
||||||
|
host_infile = os.path.join(context.output_directory, 'infile')
|
||||||
|
command = 'openssl rand -base64 {} > {}'.format(self.file_size, host_infile)
|
||||||
|
os.system(command)
|
||||||
|
# Set up on-device paths
|
||||||
|
devpath = self.target.path # os.path equivalent for the target
|
||||||
|
self.target_infile = devpath.join(self.target.working_directory, 'infile')
|
||||||
|
self.target_outfile = devpath.join(self.target.working_directory, 'outfile')
|
||||||
|
# Push the file to the target
|
||||||
|
self.target.push(host_infile, self.target_infile)
|
||||||
|
|
||||||
|
|
||||||
|
The ``run`` method is where the actual 'work' of the workload takes place and is
|
||||||
|
what is measured by any instrumentation. So for this example this is the
|
||||||
|
execution of creating the zip file on the target.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def run(self, context):
|
||||||
|
cmd = 'cd {} && (time gzip {}) &>> {}'
|
||||||
|
self.target.execute(cmd.format(self.target.working_directory,
|
||||||
|
self.target_infile,
|
||||||
|
self.target_outfile))
|
||||||
|
|
||||||
|
The ``extract_results`` method is used to extract any results from the target
|
||||||
|
for example we want to pull the file containing the timing information that we
|
||||||
|
will use to generate metrics for our workload and then we add this file as an
|
||||||
|
artifact with a 'raw' kind, which means once WA has finished processing it will
|
||||||
|
allow it to decide whether to keep the file or not.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def extract_results(self, context):
|
||||||
|
super(ZipTestWorkload, self).extract_results(context)
|
||||||
|
# Pull the results file to the host
|
||||||
|
self.host_outfile = os.path.join(context.output_directory, 'timing_results')
|
||||||
|
self.target.pull(self.target_outfile, self.host_outfile)
|
||||||
|
context.add_artifact('ziptest-results', host_output_file, kind='raw')
|
||||||
|
|
||||||
|
The ``update_output`` method we can do any generation of metrics that we wish to
|
||||||
|
for our workload. In this case we are going to simply convert the times reported
|
||||||
|
into seconds and add them as 'metrics' to WA which can then be displayed to the
|
||||||
|
user along with any others in a format dependant on which output processors they
|
||||||
|
have enabled for the run.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def update_output(self, context):
|
||||||
|
super(ZipTestWorkload, self).update_output(context)
|
||||||
|
# Extract metrics form the file's contents and update the result
|
||||||
|
# with them.
|
||||||
|
content = iter(open(self.host_outfile).read().strip().split())
|
||||||
|
for value, metric in zip(content, content):
|
||||||
|
mins, secs = map(float, value[:-1].split('m'))
|
||||||
|
context.add_metric(metric, secs + 60 * mins, 'seconds')
|
||||||
|
|
||||||
|
Finally in the ``teardown`` method we will perform any required clean up for the
|
||||||
|
workload so we will delete the input and output files from the device.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def teardown(self, context):
|
||||||
|
super(ZipTestWorkload, self).teardown(context)
|
||||||
|
self.target.remove(self.target_infile)
|
||||||
|
self.target.remove(self.target_outfile)
|
||||||
|
|
||||||
|
The full implementation of this workload would look something like:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import os
|
||||||
|
from wa import Workload, Parameter
|
||||||
|
|
||||||
|
class ZipTestWorkload(Workload):
|
||||||
|
|
||||||
|
name = 'ziptest'
|
||||||
|
|
||||||
description = '''
|
description = '''
|
||||||
Times how long it takes to gzip a file of a particular size on a device.
|
Times how long it takes to gzip a file of a particular size on a device.
|
||||||
|
|
||||||
@ -96,18 +225,11 @@ to compress a file of a particular size on the device.
|
|||||||
|
|
||||||
parameters = [
|
parameters = [
|
||||||
Parameter('file_size', kind=int, default=2000000,
|
Parameter('file_size', kind=int, default=2000000,
|
||||||
|
constraint=lambda x: 0 < x,
|
||||||
description='Size of the file (in bytes) to be gzipped.')
|
description='Size of the file (in bytes) to be gzipped.')
|
||||||
]
|
]
|
||||||
|
|
||||||
def setup(self, context):
|
def setup(self, context):
|
||||||
"""
|
|
||||||
In the setup method we do any preparation that is required before
|
|
||||||
the workload is ran, this is usually things like setting up required
|
|
||||||
files on the device and generating commands from user input. In this
|
|
||||||
case we will generate our input file on the host system and then
|
|
||||||
push it to a known location on the target for use in the 'run'
|
|
||||||
stage.
|
|
||||||
"""
|
|
||||||
super(ZipTestWorkload, self).setup(context)
|
super(ZipTestWorkload, self).setup(context)
|
||||||
# Generate a file of the specified size containing random garbage.
|
# Generate a file of the specified size containing random garbage.
|
||||||
host_infile = os.path.join(context.output_directory, 'infile')
|
host_infile = os.path.join(context.output_directory, 'infile')
|
||||||
@ -121,25 +243,11 @@ to compress a file of a particular size on the device.
|
|||||||
self.target.push(host_infile, self.target_infile)
|
self.target.push(host_infile, self.target_infile)
|
||||||
|
|
||||||
def run(self, context):
|
def run(self, context):
|
||||||
"""
|
|
||||||
The run method is where the actual 'work' of the workload takes
|
|
||||||
place and is what is measured by any instrumentation. So for this
|
|
||||||
example this is the execution of creating the zip file on the
|
|
||||||
target.
|
|
||||||
"""
|
|
||||||
cmd = 'cd {} && (time gzip {}) &>> {}'
|
cmd = 'cd {} && (time gzip {}) &>> {}'
|
||||||
self.target.execute(cmd.format(self.target.working_directory,
|
self.target.execute(cmd.format(self.target.working_directory,
|
||||||
self.target_infile,
|
self.target_infile,
|
||||||
self.target_outfile))
|
self.target_outfile))
|
||||||
def extract_results(self, context):
|
def extract_results(self, context):
|
||||||
"""
|
|
||||||
This method is used to extract any results from the target for
|
|
||||||
example we want to pull the file containing the timing information
|
|
||||||
that we will use to generate metrics for our workload and then we
|
|
||||||
add this file as an artifact with a 'raw' kind, which means once WA
|
|
||||||
has finished processing it will allow it to decide whether to keep
|
|
||||||
the file or not.
|
|
||||||
"""
|
|
||||||
super(ZipTestWorkload, self).extract_results(context)
|
super(ZipTestWorkload, self).extract_results(context)
|
||||||
# Pull the results file to the host
|
# Pull the results file to the host
|
||||||
self.host_outfile = os.path.join(context.output_directory, 'timing_results')
|
self.host_outfile = os.path.join(context.output_directory, 'timing_results')
|
||||||
@ -147,13 +255,6 @@ to compress a file of a particular size on the device.
|
|||||||
context.add_artifact('ziptest-results', host_output_file, kind='raw')
|
context.add_artifact('ziptest-results', host_output_file, kind='raw')
|
||||||
|
|
||||||
def update_output(self, context):
|
def update_output(self, context):
|
||||||
"""
|
|
||||||
In this method we can do any generation of metrics that we wish to
|
|
||||||
for our workload. In this case we are going to simply convert the
|
|
||||||
times reported into seconds and add them as 'metrics' to WA which can
|
|
||||||
then be displayed to the user along with any others in a format
|
|
||||||
dependant on which output processors they have enabled for the run.
|
|
||||||
"""
|
|
||||||
super(ZipTestWorkload, self).update_output(context)
|
super(ZipTestWorkload, self).update_output(context)
|
||||||
# Extract metrics form the file's contents and update the result
|
# Extract metrics form the file's contents and update the result
|
||||||
# with them.
|
# with them.
|
||||||
@ -163,15 +264,12 @@ to compress a file of a particular size on the device.
|
|||||||
context.add_metric(metric, secs + 60 * mins, 'seconds')
|
context.add_metric(metric, secs + 60 * mins, 'seconds')
|
||||||
|
|
||||||
def teardown(self, context):
|
def teardown(self, context):
|
||||||
"""
|
|
||||||
Here we will perform any required clean up for the workload so we
|
|
||||||
will delete the input and output files from the device.
|
|
||||||
"""
|
|
||||||
super(ZipTestWorkload, self).teardown(context)
|
super(ZipTestWorkload, self).teardown(context)
|
||||||
self.target.remove(self.target_infile)
|
self.target.remove(self.target_infile)
|
||||||
self.target.remove(self.target_outfile)
|
self.target.remove(self.target_outfile)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. _apkuiautomator-example:
|
.. _apkuiautomator-example:
|
||||||
|
|
||||||
Adding a ApkUiAutomator Workload Example
|
Adding a ApkUiAutomator Workload Example
|
||||||
@ -189,7 +287,9 @@ therefore we would choose the :ref:`ApkUiAutomator workload
|
|||||||
|
|
||||||
From here you can navigate to the displayed directory and you will find your
|
From here you can navigate to the displayed directory and you will find your
|
||||||
``__init__.py`` and a ``uiauto`` directory. The former is your python WA
|
``__init__.py`` and a ``uiauto`` directory. The former is your python WA
|
||||||
workload and will look something like this
|
workload and will look something like this. For an example of what should be
|
||||||
|
done in each of the main method please see
|
||||||
|
:ref:`adding a basic example <adding-a-basic-workload>` above.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user