From 725fe960725255564b4020c071e811907c072910 Mon Sep 17 00:00:00 2001 From: Brendan Jackman Date: Fri, 23 Dec 2016 12:15:34 +0000 Subject: [PATCH 1/2] rta: Allow configuring workloads with target=None for test - Defer pushing RT-App JSON until run() - Use default configuration when no target is supplied - Remove __WORKDIR__ replacement from the custom kind, we have no current users for it. This allows us to use .conf() in the absence of a target, so that we can add unit tests for the wlgen classes. --- libs/wlgen/wlgen/rta.py | 29 +++++++++++++++++------------ libs/wlgen/wlgen/workload.py | 8 ++++---- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/libs/wlgen/wlgen/rta.py b/libs/wlgen/wlgen/rta.py index ceaa8b6fc..442b47178 100644 --- a/libs/wlgen/wlgen/rta.py +++ b/libs/wlgen/wlgen/rta.py @@ -268,8 +268,10 @@ class RTA(Workload): if self.duration is None: raise ValueError('Workload duration not specified') - target_cpu = self.getTargetCpu(self.loadref) - calibration = self.getCalibrationConf(target_cpu) + calibration = '"CPU0"' + if self.target: + target_cpu = self.getTargetCpu(self.loadref) + calibration = self.getCalibrationConf(target_cpu) self._log.info('Loading custom configuration:') self._log.info(' %s', rtapp_conf) @@ -280,7 +282,6 @@ class RTA(Workload): '__DURATION__' : str(self.duration), '__PVALUE__' : str(calibration), '__LOGDIR__' : str(self.run_dir), - '__WORKDIR__' : '"'+self.target.working_directory+'"', } for line in ifile: @@ -304,7 +305,6 @@ class RTA(Workload): raise ValueError(msg) # Task configuration - target_cpu = self.getTargetCpu(self.loadref) self.rta_profile = { 'tasks': {}, 'global': {} @@ -314,13 +314,16 @@ class RTA(Workload): global_conf = { 'default_policy': 'SCHED_OTHER', 'duration': -1, - 'calibration': 'CPU'+str(target_cpu), 'logdir': self.run_dir, } # Setup calibration data - calibration = self.getCalibrationConf(target_cpu) - global_conf['calibration'] = calibration + target_cpu = None + if self.target: + target_cpu = self.getTargetCpu(self.loadref) + calibration = self.getCalibrationConf(target_cpu) + global_conf['calibration'] = calibration + if self.duration is not None: global_conf['duration'] = self.duration self._log.warn('Limiting workload duration to %d [s]', @@ -376,7 +379,7 @@ class RTA(Workload): self._log.info(' | start delay: %.6f [s]', task['delay']) - self._log.info(' | calibration CPU: %d', target_cpu) + self._log.info(' | calibration CPU: {}'.format(target_cpu)) if 'loops' not in task.keys(): task['loops'] = 1 @@ -525,16 +528,18 @@ class RTA(Workload): elif kind == 'profile': self._confProfile() + # Set and return the test label + self.test_label = '{0:s}_{1:02d}'.format(self.name, self.exc_id) + return self.test_label + + def run(self, *args, **kwargs): # Move configuration file to target self.target.push(self.json, self.run_dir) - self.rta_cmd = self.target.executables_directory + '/rt-app' self.rta_conf = self.run_dir + '/' + self.json self.command = '{0:s} {1:s} 2>&1'.format(self.rta_cmd, self.rta_conf) - # Set and return the test label - self.test_label = '{0:s}_{1:02d}'.format(self.name, self.exc_id) - return self.test_label + super(RTA, self).run(*args, **kwargs) class _TaskBase(object): diff --git a/libs/wlgen/wlgen/workload.py b/libs/wlgen/wlgen/workload.py index 66903f71f..ef9b7d8fa 100644 --- a/libs/wlgen/wlgen/workload.py +++ b/libs/wlgen/wlgen/workload.py @@ -134,10 +134,6 @@ class Workload(object): # Map of task/s parameters self.params = {} - # Initialize run folder - if self.run_dir is None: - self.run_dir = self.target.working_directory - # Configure a profile workload if kind == 'profile': self._log.debug('Configuring a profile-based workload...') @@ -201,6 +197,10 @@ class Workload(object): :type end_pause_s: float """ + # Initialize run folder + if self.run_dir is None: + self.run_dir = self.target.working_directory + self.cgroup = cgroup # Compose the actual execution command starting from the base command -- GitLab From 8a8b8301c256be769b922903a4f8bd27faf923f6 Mon Sep 17 00:00:00 2001 From: Brendan Jackman Date: Fri, 23 Dec 2016 14:12:34 +0000 Subject: [PATCH 2/2] Add smoke tests for wlgen RT-App classes These are just trivial smoke tests, essentially copied from the WlGenUsage tutorial notebook, the bare minimum to avoid issues like https://github.com/ARM-software/lisa/issues/253. As a hack to allow running tests without a target device we use target=None and an empty calibration dict. To make the tests really trivial I have just used hard-coded values for the expected JSON phase output, the rationale being that this avoids bugs in the test code. If we do more hacking on the wlgen classes then we should be able to add more interesting tests here. --- tests/lisa/test_wlgen.py | 175 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 tests/lisa/test_wlgen.py diff --git a/tests/lisa/test_wlgen.py b/tests/lisa/test_wlgen.py new file mode 100644 index 000000000..ebb83ed40 --- /dev/null +++ b/tests/lisa/test_wlgen.py @@ -0,0 +1,175 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2016, ARM Limited and contributors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from collections import OrderedDict +import json +import os +from unittest import TestCase + +from wlgen import RTA, Periodic, Ramp, Step, Pulse # todo remove unused + +dummy_calibration = {} + +class TestProfile(TestCase): + def test_profile_periodic_smoke(self): + """ + Smoke test for a RTA workload using kind='profile' and Periodic + """ + rtapp = RTA(None, 'test', calibration=dummy_calibration) + + rtapp.conf( + kind = 'profile', + params = { + 'task_p20': Periodic( + period_ms = 100, + duty_cycle_pct = 20, + duration_s = 5, + ).get(), + }, + run_dir='test', + ) + + with open(rtapp.json) as f: + conf = json.load(f) + + [phase] = conf['tasks']['task_p20']['phases'].values() + self.assertDictEqual(phase, { + "loop": 50, + "run": 20000, + "timer": { + "period": 100000, + "ref": "task_p20" + } + }) + +class TestComposition(TestCase): + def test_composition_smoke(self): + """ + Smoke test for a RTA workload using __add__ to compose phases + """ + rtapp = RTA(None, 'test', calibration=dummy_calibration) + + light = Periodic(duty_cycle_pct=10, duration_s=1.0, period_ms=10) + + start_pct = 10 + end_pct = 90 + delta_pct = 20 + num_ramp_phases = ((end_pct - start_pct) / delta_pct) + 1 + ramp = Ramp(start_pct=start_pct, end_pct=end_pct, delta_pct=delta_pct, + time_s=1, period_ms=50) + + heavy = Periodic(duty_cycle_pct=90, duration_s=0.1, period_ms=100) + + lrh_task = light + ramp + heavy + + rtapp.conf( + kind = 'profile', + params = { + 'task_ramp': lrh_task.get() + }, + ) + + with open(rtapp.json) as f: + conf = json.load(f, object_pairs_hook=OrderedDict) + + phases = conf['tasks']['task_ramp']['phases'].values() + + exp_phases = [ + # Light phase: + { + "loop": 100, + "run": 1000, + "timer": { + "period": 10000, + "ref": "task_ramp" + } + }, + # Ramp phases: + { + "loop": 20, + "run": 5000, + "timer": { + "period": 50000, + "ref": "task_ramp" + } + }, + { + "loop": 20, + "run": 15000, + "timer": { + "period": 50000, + "ref": "task_ramp" + } + }, + { + "loop": 20, + "run": 25000, + "timer": { + "period": 50000, + "ref": "task_ramp" + } + }, + { + "loop": 20, + "run": 35000, + "timer": { + "period": 50000, + "ref": "task_ramp" + } + }, + { + "loop": 20, + "run": 45000, + "timer": { + "period": 50000, + "ref": "task_ramp" + } + }, + # Heavy phase: + { + "loop": 1, + "run": 90000, + "timer": { + "period": 100000, + "ref": "task_ramp" + } + }] + + self.assertListEqual(phases, exp_phases) + +class TestCustom(TestCase): + def test_custom_smoke(self): + """ + Smoke test for a custom workload + """ + + json_path = os.path.join(os.getenv('LISA_HOME'), + 'assets', 'mp3-short.json') + rtapp = RTA(None, 'test', calibration=dummy_calibration) + + # Configure this RTApp instance to: + rtapp.conf(kind='custom', params=json_path, duration=5, run_dir='test') + + with open(rtapp.json) as f: + conf = json.load(f) + + # Convert to str because unicode + tasks = set([str(k) for k in conf['tasks'].keys()]) + self.assertSetEqual( + tasks, + set(['AudioTick', 'AudioOut', 'AudioTrack', + 'mp3.decoder', 'OMXCall'])) -- GitLab