From 2eb43b32feb25b1a9d475efa06af604bf82e1bae Mon Sep 17 00:00:00 2001 From: Brendan Jackman Date: Tue, 3 Jan 2017 15:22:13 +0000 Subject: [PATCH 1/2] rta: Rename _TaskBase -> RTATask This is just to make the class public so we can document it with sphinx --- libs/wlgen/wlgen/rta.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/wlgen/wlgen/rta.py b/libs/wlgen/wlgen/rta.py index ceaa8b6fc..391ad6777 100644 --- a/libs/wlgen/wlgen/rta.py +++ b/libs/wlgen/wlgen/rta.py @@ -536,7 +536,7 @@ class RTA(Workload): self.test_label = '{0:s}_{1:02d}'.format(self.name, self.exc_id) return self.test_label -class _TaskBase(object): +class RTATask(object): def __init__(self): self._task = {} @@ -549,7 +549,7 @@ class _TaskBase(object): return self -class Ramp(_TaskBase): +class Ramp(RTATask): def __init__(self, start_pct=0, end_pct=100, delta_pct=10, time_s=1, period_ms=100, delay_s=0, loops=1, sched=None, cpus=None): @@ -641,7 +641,7 @@ class Step(Ramp): super(Step, self).__init__(start_pct, end_pct, delta_pct, time_s, period_ms, delay_s, loops, sched, cpus) -class Pulse(_TaskBase): +class Pulse(RTATask): def __init__(self, start_pct=100, end_pct=0, time_s=1, period_ms=100, delay_s=0, loops=1, sched=None, cpus=None): -- GitLab From b117b255584479470fe5e8f2c2f480ca3e1eb597 Mon Sep 17 00:00:00 2001 From: Brendan Jackman Date: Tue, 3 Jan 2017 12:08:14 +0000 Subject: [PATCH 2/2] wlgen: Add some Sphinx-compatible docstrings --- libs/wlgen/wlgen/rta.py | 271 +++++++++++++++++++---------------- libs/wlgen/wlgen/workload.py | 40 +++++- 2 files changed, 182 insertions(+), 129 deletions(-) diff --git a/libs/wlgen/wlgen/rta.py b/libs/wlgen/wlgen/rta.py index 391ad6777..08f988c1f 100644 --- a/libs/wlgen/wlgen/rta.py +++ b/libs/wlgen/wlgen/rta.py @@ -31,23 +31,32 @@ class Phase(_Phase): """ Descriptor for an RT-App load phase - :param duration_s: the phase duration in [s] + :param duration_s: the phase duration in [s]. :type duration_s: int - :param period_ms: the phase period in [ms] + :param period_ms: the phase period in [ms]. :type period_ms: int - :param duty_cycle_pct: the generated load in [%] + :param duty_cycle_pct: the generated load in [%]. :type duty_cycle_pct: int """ pass class RTA(Workload): + """ + Class for creating RT-App workloads + """ def __init__(self, target, name, calibration=None): + """ + :param target: Devlib target to run workload on. + :param name: Human-readable name for the workload. + :param calibration: CPU calibration specification. Can be obtained from + :meth:`calibrate`. + """ # Setup logging self._log = logging.getLogger('RTApp') @@ -77,6 +86,12 @@ class RTA(Workload): @staticmethod def calibrate(target): + """ + Calibrate RT-App on each CPU in the system + + :param target: Devlib target to run calibration on. + :returns: Dict mapping CPU numbers to RT-App calibration values. + """ pload_regexp = re.compile(r'pLoad = ([0-9]+)ns') pload = {} @@ -483,32 +498,41 @@ class RTA(Workload): workloads. The classes supported so far are detailed hereafter. Custom workloads - ---------------- - When 'kind' is 'custom' the tasks generated by this workload are the - ones defined in a provided rt-app JSON configuration file. - In this case the 'params' parameter must be used to specify the - complete path of the rt-app JSON configuration file to use. - + When 'kind' is 'custom' the tasks generated by this workload are the + ones defined in a provided rt-app JSON configuration file. + In this case the 'params' parameter must be used to specify the + complete path of the rt-app JSON configuration file to use. Profile based workloads - ----------------------- - When 'kind' is 'profile' the tasks generated by this workload have a - profile which is defined by a sequence of phases and they are defined - according to the following grammar: + When ``kind`` is "profile", ``params`` is a dictionary mapping task + names to task specifications. The easiest way to create these task + specifications using :meth:`RTATask.get`. + + For example, the following configures an RTA workload with a single + task, named 't1', using the default parameters for a Periodic RTATask: + + :: + + wl = RTA(...) + wl.conf(kind='profile', params={'t1': Periodic().get()}) - params := {task, ...} - task := NAME : {SCLASS, PRIO, [phase, ...]} - phase := (PTIME, PRIOD, DCYCLE) + :param kind: Either 'custom' or 'profile' - see above. + :param params: RT-App parameters - see above. + :param duration: Maximum duration of the workload in seconds. Any + remaining tasks are killed by rt-app when this time has + elapsed. + :param cpus: CPUs to restrict this workload to, using ``taskset``. + :type cpus: list(int) - where the terminals are: + :param sched: Global RT-App scheduler configuration. Dict with fields: - NAME : string, the task name (max 16 chars) - SCLASS : string, the scheduling class (OTHER, FIFO, RR) - PRIO : int, the priority of the task - PTIME : float, length of the current phase in [s] - PERIOD : float, task activation interval in [ms] - DCYCLE : int, task running interval in [0..100]% within each period + policy + The default scheduler policy. Choose from 'OTHER', 'FIFO', 'RR', + and 'DEADLINE'. + :param run_dir: Target dir to store output and config files in. + + .. TODO: document or remove loadref """ if not sched: @@ -537,11 +561,24 @@ class RTA(Workload): return self.test_label class RTATask(object): + """ + Base class for conveniently constructing params to :meth:`RTA.conf` + + This class represents an RT-App task which may contain multiple phases. It + implements ``__add__`` so that using ``+`` on two tasks concatenates their + phases. For example ``Ramp() + Periodic()`` would yield an ``RTATask`` that + executes the default phases for ``Ramp`` followed by the default phases for + ``Periodic``. + """ def __init__(self): self._task = {} def get(self): + """ + Return a dict that can be passed as an element of the ``params`` field + to :meth:`RTA.conf`. + """ return self._task def __add__(self, next_phases): @@ -550,34 +587,31 @@ class RTATask(object): class Ramp(RTATask): + """ + Configure a ramp load. + + This class defines a task which load is a ramp with a configured number + of steps according to the input parameters. + + :param start_pct: the initial load percentage. + :param end_pct: the final load percentage. + :param delta_pct: the load increase/decrease at each step, in percentage + points. + :param time_s: the duration in seconds of each load step. + :param period_ms: the period used to define the load in [ms]. + :param delay_s: the delay in seconds before ramp start. + :param loops: number of time to repeat the ramp, with the specified delay in + between. + + :param sched: the scheduler configuration for this task. + :type sched: dict + + :param cpus: the list of CPUs on which task can run. + :type cpus: list(int) + """ def __init__(self, start_pct=0, end_pct=100, delta_pct=10, time_s=1, period_ms=100, delay_s=0, loops=1, sched=None, cpus=None): - """ - Configure a ramp load. - - This class defines a task which load is a ramp with a configured number - of steps according to the input parameters. - - Args: - start_pct (int, [0-100]): the initial load [%], (default 0[%]) - end_pct (int, [0-100]): the final load [%], (default 100[%]) - delta_pct (int, [0-100]): the load increase/decrease [%], - default: 10[%] - increase if start_prc < end_prc - decrease if start_prc > end_prc - time_s (float): the duration in [s] of each load step - default: 1.0[s] - period_ms (float): the period used to define the load in [ms] - default: 100.0[ms] - delay_s (float): the delay in [s] before ramp start - default: 0[s] - loops (int): number of time to repeat the ramp, with the - specified delay in between - default: 0 - sched (dict): the scheduler configuration for this task - cpus (list): the list of CPUs on which task can run - """ super(Ramp, self).__init__() self._task['cpus'] = cpus @@ -611,73 +645,67 @@ class Ramp(RTATask): self._task['phases'] = phases class Step(Ramp): + """ + Configure a step load. + + This class defines a task which load is a step with a configured initial and + final load. Using the ``loops`` param, this can be used to create a workload + that alternates between two load values. + + :param start_pct: the initial load percentage. + :param end_pct: the final load percentage. + :param time_s: the duration in seconds of each load step. + :param period_ms: the period used to define the load in [ms]. + :param delay_s: the delay in seconds before ramp start. + :param loops: number of time to repeat the step, with the specified delay in + between. + + :param sched: the scheduler configuration for this task. + :type sched: dict + + :param cpus: the list of CPUs on which task can run. + :type cpus: list(int) + """ def __init__(self, start_pct=0, end_pct=100, time_s=1, period_ms=100, delay_s=0, loops=1, sched=None, cpus=None): - """ - Configure a step load. - - This class defines a task which load is a step with a configured - initial and final load. - - Args: - start_pct (int, [0-100]): the initial load [%] - default 0[%]) - end_pct (int, [0-100]): the final load [%] - default 100[%] - time_s (float): the duration in [s] of the start and end load - default: 1.0[s] - period_ms (float): the period used to define the load in [ms] - default 100.0[ms] - delay_s (float): the delay in [s] before ramp start - default 0[s] - loops (int): number of time to repeat the ramp, with the - specified delay in between - default: 0 - sched (dict): the scheduler configuration for this task - cpus (list): the list of CPUs on which task can run - """ delta_pct = abs(end_pct - start_pct) super(Step, self).__init__(start_pct, end_pct, delta_pct, time_s, period_ms, delay_s, loops, sched, cpus) class Pulse(RTATask): + """ + Configure a pulse load. + + This class defines a task which load is a pulse with a configured + initial and final load. + + The main difference with the 'step' class is that a pulse workload is + by definition a 'step down', i.e. the workload switch from an finial + load to a final one which is always lower than the initial one. + Moreover, a pulse load does not generate a sleep phase in case of 0[%] + load, i.e. the task ends as soon as the non null initial load has + completed. + + :param start_pct: the initial load percentage. + :param end_pct: the final load percentage. Must be lower than ``start_pct`` + value. If end_pct is 0, the task end after the ``start_pct`` + period has completed. + :param time_s: the duration in seconds of each load step. + :param period_ms: the period used to define the load in [ms]. + :param delay_s: the delay in seconds before ramp start. + :param loops: number of time to repeat the pulse, with the specified delay + in between. + + :param sched: the scheduler configuration for this task. + :type sched: dict + + :param cpus: the list of CPUs on which task can run + :type cpus: list(int) + """ def __init__(self, start_pct=100, end_pct=0, time_s=1, period_ms=100, delay_s=0, loops=1, sched=None, cpus=None): - """ - Configure a pulse load. - - This class defines a task which load is a pulse with a configured - initial and final load. - - The main difference with the 'step' class is that a pulse workload is - by definition a 'step down', i.e. the workload switch from an finial - load to a final one which is always lower than the initial one. - Moreover, a pulse load does not generate a sleep phase in case of 0[%] - load, i.e. the task ends as soon as the non null initial load has - completed. - - Args: - start_pct (int, [0-100]): the initial load [%] - default: 0[%] - end_pct (int, [0-100]): the final load [%] - default: 100[%] - NOTE: must be lower than start_pct value - time_s (float): the duration in [s] of the start and end load - default: 1.0[s] - NOTE: if end_pct is 0, the task end after the - start_pct period completed - period_ms (float): the period used to define the load in [ms] - default: 100.0[ms] - delay_s (float): the delay in [s] before ramp start - default: 0[s] - loops (int): number of time to repeat the ramp, with the - specified delay in between - default: 0 - sched (dict): the scheduler configuration for this task - cpus (list): the list of CPUs on which task can run - """ super(Pulse, self).__init__() if end_pct >= start_pct: @@ -709,30 +737,25 @@ class Pulse(RTATask): class Periodic(Pulse): + """ + Configure a periodic load. This is the simplest type of RTA task. - def __init__(self, duty_cycle_pct=50, duration_s=1, period_ms=100, - delay_s=0, sched=None, cpus=None): - """ - Configure a periodic load. + This class defines a task which load is periodic with a configured + period and duty-cycle. - This class defines a task which load is periodic with a configured - period and duty-cycle. + :param duty_cycle_pct: the load percentage. + :param duration_s: the total duration in seconds of the task. + :param period_ms: the period used to define the load in milliseconds. + :param delay_s: the delay in seconds before starting the periodic phase. - This class is a specialization of the 'pulse' class since a periodic - load is generated as a sequence of pulse loads. + :param sched: the scheduler configuration for this task. + :type sched: dict - Args: - cuty_cycle_pct (int, [0-100]): the pulses load [%] - default: 50[%] - duration_s (float): the duration in [s] of the entire workload - default: 1.0[s] - period_ms (float): the period used to define the load in [ms] - default: 100.0[ms] - delay_s (float): the delay in [s] before ramp start - default: 0[s] - sched (dict): the scheduler configuration for this task + :param cpus: the list of CPUs on which task can run. + :type cpus: list(int) + """ - """ + def __init__(self, duty_cycle_pct=50, duration_s=1, period_ms=100, + delay_s=0, sched=None, cpus=None): super(Periodic, self).__init__(duty_cycle_pct, 0, duration_s, period_ms, delay_s, 1, sched, cpus) - diff --git a/libs/wlgen/wlgen/workload.py b/libs/wlgen/wlgen/workload.py index 6e65ca9cb..465f904d4 100644 --- a/libs/wlgen/wlgen/workload.py +++ b/libs/wlgen/wlgen/workload.py @@ -24,6 +24,20 @@ from time import sleep import logging class Workload(object): + """ + Base class for workload specifications + + To use this class, you'll need to instantiate it, then call :meth:`conf` on + the instance. + + :param target: Devlib target to run workload on. May be None, in which case + an RT-App configuration file can be generated but the + workload cannot be run, and calibration features will be + missing. + :param name: Human-readable name for the workload. + :param calibration: CPU calibration specification. Can be obtained from + :meth:`RTA.calibration`. + """ def __init__(self, target, @@ -102,6 +116,21 @@ class Workload(object): self.steps[step](kwords) def setCallback(self, step, func): + """ + Add a callback to be called during an execution stage. + + Intended for use by subclasses. Only one callback can exist for each + stage. Available callback stages are: + + "postrun" + Called after the workload has finished executing, unless it's being + run in the background. Receives a ``params`` dictionary with + ``params["destdir"]`` set to the host directory to store workload + output in. + + :param step: Name of the step at which to call the callback. + :param func: Callback function. + """ self._log.debug('Setup step [%s] callback to [%s] function', step, func.__name__) self.steps[step] = func @@ -121,6 +150,7 @@ class Workload(object): sched={'policy': 'OTHER'}, run_dir=None, exc_id=0): + """Configure workload. See documentation for subclasses""" self.cpus = cpus self.sched = sched @@ -174,8 +204,9 @@ class Workload(object): :type cgroup: str :param cpus: the CPUs on which to run the workload. - NOTE: if specified it overrides the CPUs specified at - configuration time + + .. note:: if specified it overrides the CPUs specified at + configuration time :type cpus: list(int) :param background: run the workload in background. In this case the @@ -184,8 +215,8 @@ class Workload(object): collection :type background: bool - :param out_dir: output directory where to store the collected trace (if - any) + :param out_dir: output directory where to store the collected trace or + other workload report (if any) :type out_dir: str :param as_root: run the workload as root on the target @@ -337,4 +368,3 @@ class Workload(object): return self._log.info('Killing all [%s] instances:', self.executor) self.listAll(True) - -- GitLab