diff --git a/wlauto/workloads/rt_app/LICENSE b/wlauto/workloads/rt_app/LICENSE new file mode 100644 index 00000000..e03ab67e --- /dev/null +++ b/wlauto/workloads/rt_app/LICENSE @@ -0,0 +1,8 @@ +rt-app binaries and workgen script included with this workload are distributed +under GPL version 2; The full text of the license may be viewed here: + +http://www.gnu.org/licenses/gpl-2.0.html + +Source for these binaries may be obtained from Linaro here: + +https://git.linaro.org/power/rt-app.git diff --git a/wlauto/workloads/rt_app/__init__.py b/wlauto/workloads/rt_app/__init__.py new file mode 100644 index 00000000..3787f50f --- /dev/null +++ b/wlauto/workloads/rt_app/__init__.py @@ -0,0 +1,275 @@ +# Copyright 2015 ARM Limited +# +# 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. +# + +import os +import re +import json +import tarfile +from collections import OrderedDict +from subprocess import CalledProcessError + +from wlauto import Workload, Parameter, Executable, File +from wlauto.exceptions import WorkloadError, ResourceError +from wlauto.instrumentation import instrument_is_enabled +from wlauto.utils.misc import check_output + +RAW_OUTPUT_FILENAME = 'raw-output.txt' +TARBALL_FILENAME = 'rtapp-logs.tar.gz' +BINARY_NAME = 'rt-app' +PACKAGED_USE_CASE_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), 'use_cases')) + +PLOAD_REGEX = re.compile(r'pLoad = (\d+)(\w+) : calib_cpu (\d+)') +ERROR_REGEX = re.compile(r'error') +CRIT_REGEX = re.compile(r'crit') + + +class RtApp(Workload): + # pylint: disable=no-member,attribute-defined-outside-init + + name = 'rt-app' + description = """ + A test application that simulates cofigurable real-time periodic load. + + rt-app is a test application that starts multiple periodic threads in order to + simulate a real-time periodic load. It supports SCHED_OTHER, SCHED_FIFO, + SCHED_RR as well as the AQuoSA framework and SCHED_DEADLINE. + + The load is described using JSON-like config files. Below are a couple of simple + examples. + + .. code-block:: json + + { + /* + * Simple use case which creates a thread that run 1ms then sleep 9ms + * until the use case is stopped with Ctrl+C + */ + "tasks" : { + "thread0" : { + "loop" : -1, + "run" : 20000, + "sleep" : 80000 + } + }, + "global" : { + "duration" : 2, + "calibration" : "CPU0", + "default_policy" : "SCHED_OTHER", + "pi_enabled" : false, + "lock_pages" : false, + "logdir" : "./", + "log_basename" : "rt-app1", + "ftrace" : false, + "gnuplot" : true, + } + } + + .. code-block:: json + + { + /* + * Simple use case with 2 threads that runs for 10 ms and wake up each + * other until the use case is stopped with Ctrl+C + */ + "tasks" : { + "thread0" : { + "loop" : -1, + "run" : 10000, + "resume" : "thread1", + "suspend" : "thread0" + }, + "thread1" : { + "loop" : -1, + "run" : 10000, + "resume" : "thread0", + "suspend" : "thread1" + } + } + } + + Please refer to the exising configs in ``%s`` for more examples. + + The version of rt-app currently used with this workload contains enhancements and + modifications done by Linaro. The source code for this version may be obtained here: + + http://git.linaro.org/power/rt-app.git + + The upstream version of rt-app is hosted here: + + https://github.com/scheduler-tools/rt-app + + """ % PACKAGED_USE_CASE_DIRECTORY + + parameters = [ + Parameter('config', kind=str, default='taskset', + description=''' + Use case configuration file to run with rt-app. This may be + either the name of one of the "standard" configuratons included + with the workload. or a path to a custom JSON file provided by + the user. Either way, the ".json" extension is implied and will + be added automatically if not specified in the argument. + + The following is th list of standard configuraionts currently + included with the workload: {} + + '''.format(', '.join(os.listdir(PACKAGED_USE_CASE_DIRECTORY)))), + Parameter('duration', kind=int, + description=''' + Duration of the workload execution in Seconds. If specified, this + will override the corresponing parameter in the JSON config. + '''), + ] + + def initialize(self, context): + # initialize() runs once per run. setting a class variable to make it + # available to other instances of the workload + RtApp.device_working_directory = self.device.path.join(self.device.working_directory, + 'rt-app-working') + RtApp.host_binary = context.resolver.get(Executable(self, + self.device.abi, + BINARY_NAME), strict=False) + RtApp.workgen_script = context.resolver.get(File(self, 'workgen')) + if not self.device.is_rooted: # some use cases require root privileges + raise WorkloadError('rt-app requires the device to be rooted.') + self.device.execute('mkdir -p {}'.format(self.device_working_directory)) + self._deploy_rt_app_binary_if_necessary() + + def setup(self, context): + self.log_basename = context.spec.label + self.host_json_config = self._load_json_config(context) + self.config_file_on_device = self.device.path.join(self.device_working_directory, + os.path.basename(self.host_json_config)) + self.device.push_file(self.host_json_config, self.config_file_on_device, timeout=60) + self.command = '{} {}'.format(self.device_binary, self.config_file_on_device) + + time_buffer = 30 + self.timeout = self.duration + time_buffer + + def run(self, context): + self.output = self.device.execute(self.command, + timeout=self.timeout, + as_root=True) + + def update_result(self, context): + self._pull_rt_app_logs(context) + context.result.classifiers = dict( + duration=self.duration, + task_count=self.task_count, + ) + + outfile = os.path.join(context.output_directory, RAW_OUTPUT_FILENAME) + with open(outfile, 'w') as wfh: + wfh.write(self.output) + + error_count = 0 + crit_count = 0 + for line in self.output.split('\n'): + match = PLOAD_REGEX.search(line) + if match: + pload_value = match.group(1) + pload_unit = match.group(2) + calib_cpu_value = match.group(3) + context.result.add_metric('pLoad', float(pload_value), pload_unit) + context.result.add_metric('calib_cpu', float(calib_cpu_value)) + + error_match = ERROR_REGEX.search(line) + if error_match: + error_count += 1 + + crit_match = CRIT_REGEX.search(line) + if crit_match: + crit_count += 1 + + context.result.add_metric('total_tasks', self.task_count, 'tasks') + context.result.add_metric('error_count', error_count, 'count') + context.result.add_metric('crit_count', crit_count, 'count') + + def finalize(self, context): + self.device.uninstall(self.device_binary) + self.device.execute('rm -rf {}'.format(self.device_working_directory)) + + def _deploy_rt_app_binary_if_necessary(self): + # called from initialize() so gets invoked once per run + if not self.device.is_installed(BINARY_NAME): + if not self.host_binary: + message = '''rt-app is not installed on the device and could not be + found in workload resources''' + raise ResourceError(message) + RtApp.device_binary = self.device.install(self.host_binary) + else: + RtApp.device_binary = BINARY_NAME + + def _load_json_config(self, context): + user_config_file = self._get_raw_json_config(context.resolver) + config_file = self._generate_workgen_config(user_config_file, + context.output_directory) + with open(config_file) as fh: + config_data = json.load(fh, object_pairs_hook=OrderedDict) + self._update_rt_app_config(config_data) + self.duration = config_data['global'].get('duration', 0) + self.task_count = len(config_data.get('tasks', [])) + with open(config_file, 'w') as wfh: + json.dump(config_data, wfh, indent=4) + return config_file + + def _get_raw_json_config(self, resolver): + if os.path.splitext(self.config)[1] != '.json': + self.config += '.json' + if os.path.isfile(self.config): + return os.path.abspath(self.config) + partial_path = os.path.join('use_cases', self.config) + return resolver.get(File(self, partial_path)) + + def _generate_workgen_config(self, user_file, output_directory): + output_file = os.path.join(output_directory, 'unkind.json') + # use workgen dry run option to generate a use case + # file with proper JSON grammar on host first + try: + check_output('python {} -d -o {} {}'.format(self.workgen_script, + output_file, + user_file), + shell=True) + except CalledProcessError as e: + message = 'Could not generate config using workgen, got "{}"' + raise WorkloadError(message.format(e)) + return output_file + + def _update_rt_app_config(self, config_data): + config_data['global'] = config_data.get('global', {}) + if 'ftrace' in config_data['global'] and instrument_is_enabled('trace-cmd'): + raise WorkloadError('trace-cmd instrument cannot be enabled ' + 'at the same time as ftrace rt-app setting. ' + 'Please disable trace-cmd instrument in your ' + 'WA config file or set ftrace to false in the ' + 'JSON file.') + config_data['global']['logdir'] = self.device_working_directory + config_data['global']['log_basename'] = self.log_basename + if self.duration is not None: + config_data['global']['duration'] = self.duration + + def _pull_rt_app_logs(self, context): + tar_command = '{} tar czf {}/{} -C {} .'.format(self.device.busybox, + self.device_working_directory, + TARBALL_FILENAME, + self.device_working_directory) + self.device.execute(tar_command) + device_path = self.device.path.join(self.device_working_directory, TARBALL_FILENAME) + host_path = os.path.join(context.output_directory, TARBALL_FILENAME) + self.device.pull_file(device_path, host_path, timeout=20) + with tarfile.open(host_path, 'r:gz') as tf: + tf.extractall(context.output_directory) + os.remove(host_path) + self.device.execute('rm -rf {}/*'.format(self.device_working_directory)) + diff --git a/wlauto/workloads/rt_app/bin/arm64/rt-app b/wlauto/workloads/rt_app/bin/arm64/rt-app new file mode 100755 index 00000000..6dbda67a Binary files /dev/null and b/wlauto/workloads/rt_app/bin/arm64/rt-app differ diff --git a/wlauto/workloads/rt_app/bin/armeabi/rt-app b/wlauto/workloads/rt_app/bin/armeabi/rt-app new file mode 100755 index 00000000..5a7d0105 Binary files /dev/null and b/wlauto/workloads/rt_app/bin/armeabi/rt-app differ diff --git a/wlauto/workloads/rt_app/use_cases/browser-long.json b/wlauto/workloads/rt_app/use_cases/browser-long.json new file mode 100644 index 00000000..be8df0c4 --- /dev/null +++ b/wlauto/workloads/rt_app/use_cases/browser-long.json @@ -0,0 +1,134 @@ +{ + "tasks" : { + "BrowserMain" : { + "loop" : 3, + "phases" : { + "start" : { + "loop" : 1, + "sleep" : 400000, + "run" : 15000, + "resume" : "Browser", + "run" : 7000, + "sleep" : 8000 + }, + "render1" : { + "loop" : 50, + "resume" : "BrowserSub", + "run" : 3000 + }, + "render2" : { + "loop" : 1, + "suspend" : "Browser", + "run" : 10000, + "resume" : "Browser", + "run" : 5000 + }, + "render3" : { + "loop" : 20, + "resume" : "BrowserSub", + "run" : 3000 + }, + "stop" : { + "loop" : 1, + "run" : 2000, + "sleep" : 200000, + "suspend" : "Browser", + "sleep" : 600000 + }, + "scroll" : { + "loop" : 4, + "resume" : "Browser", + "suspend" : "BrowserNext", + "run" : 1000 + }, + "stop2" : { + "loop" : 1, + "suspend" : "Browser", + "run" : 200, + "sleep" : 800000 + } + } + }, + "BrowserSub1" : { + "priority" : -6, + "loop" : -1, + "suspend" : "BrowserSub", + "run" : 100 + }, + "BrowserSub2" : { + "priority" : -6, + "loop" : -1, + "suspend" : "BrowserSub", + "run" : 100 + }, + "BrowserDisplay" : { + "priority" : -6, + "loop" : -1, + "suspend" : "Browser", + "run" : 300, + "resume" : "BrowserNext", + "run" : 12000, + "lock" : "mutex11", + "sync" : { "ref" : "queue11", "mutex": "mutex11" }, + "unlock" : "mutex11", + "run" : 300, + "resume" : "Binder-display", + "run" : 400 + }, + "Binder-dummy" : { + "priority" : -6, + "loop" : -1, + "lock" : "mutex11", + "wait" : { "ref" : "queue11", "mutex": "mutex11" }, + "unlock" : "mutex11", + "run" : 200, + "lock" : "mutex11", + "signal" : "queue11", + "unlock" : "mutex11", + "run" : 100 + }, + "Binder-display" : { + "priority" : -6, + "loop" : -1, + "suspend" : "Binder-display", + "run" : 300, + "resume" : "Event-Browser", + "resume" : "Event-Display" + }, + "Event-Browser" : { + "priority" : -9, + "loop" : -1, + "suspend" : "Event-Browser", + "run" : 50, + "sleep" : 16000, + "run" : 50, + "resume" : "Browser" + }, + "Event-Display" : { + "priority" : -9, + "loop" : -1, + "suspend" : "Event-Display", + "run" : 50, + "sleep" : 16000, + "run" : 50, + "resume" : "Display" + }, + "Display" : { + "priority" : -8, + "loop" : -1, + "suspend" : "Display", + "run" : 16000 + }, + }, + "global" : { + "default_policy" : "SCHED_OTHER", + "duration" : 600, + "ftrace" : false, + "gnuplot" : false, + "logdir" : "./", + "log_basename" : "web", + "lock_pages" : true, + "frag" : 1, + "calibration" : "CPU0" + } +} diff --git a/wlauto/workloads/rt_app/use_cases/browser-short.json b/wlauto/workloads/rt_app/use_cases/browser-short.json new file mode 100644 index 00000000..46631040 --- /dev/null +++ b/wlauto/workloads/rt_app/use_cases/browser-short.json @@ -0,0 +1,134 @@ +{ + "tasks" : { + "BrowserMain" : { + "loop" : 3, + "phases" : { + "start" : { + "loop" : 1, + "sleep" : 400000, + "run" : 15000, + "resume" : "Browser", + "run" : 7000, + "sleep" : 8000 + }, + "render1" : { + "loop" : 50, + "resume" : "BrowserSub", + "run" : 3000 + }, + "render2" : { + "loop" : 1, + "suspend" : "Browser", + "run" : 10000, + "resume" : "Browser", + "run" : 5000 + }, + "render3" : { + "loop" : 20, + "resume" : "BrowserSub", + "run" : 3000 + }, + "stop" : { + "loop" : 1, + "run" : 2000, + "sleep" : 200000, + "suspend" : "Browser", + "sleep" : 600000 + }, + "scroll" : { + "loop" : 4, + "resume" : "Browser", + "suspend" : "BrowserNext", + "run" : 1000 + }, + "stop2" : { + "loop" : 1, + "suspend" : "Browser", + "run" : 200, + "sleep" : 800000 + } + } + }, + "BrowserSub1" : { + "priority" : -6, + "loop" : -1, + "suspend" : "BrowserSub", + "run" : 100 + }, + "BrowserSub2" : { + "priority" : -6, + "loop" : -1, + "suspend" : "BrowserSub", + "run" : 100 + }, + "BrowserDisplay" : { + "priority" : -6, + "loop" : -1, + "suspend" : "Browser", + "run" : 300, + "resume" : "BrowserNext", + "run" : 12000, + "lock" : "mutex11", + "sync" : { "ref" : "queue11", "mutex": "mutex11" }, + "unlock" : "mutex11", + "run" : 300, + "resume" : "Binder-display", + "run" : 400 + }, + "Binder-dummy" : { + "priority" : -6, + "loop" : -1, + "lock" : "mutex11", + "wait" : { "ref" : "queue11", "mutex": "mutex11" }, + "unlock" : "mutex11", + "run" : 200, + "lock" : "mutex11", + "signal" : "queue11", + "unlock" : "mutex11", + "run" : 100 + }, + "Binder-display" : { + "priority" : -6, + "loop" : -1, + "suspend" : "Binder-display", + "run" : 300, + "resume" : "Event-Browser", + "resume" : "Event-Display" + }, + "Event-Browser" : { + "priority" : -9, + "loop" : -1, + "suspend" : "Event-Browser", + "run" : 50, + "sleep" : 16000, + "run" : 50, + "resume" : "Browser" + }, + "Event-Display" : { + "priority" : -9, + "loop" : -1, + "suspend" : "Event-Display", + "run" : 50, + "sleep" : 16000, + "run" : 50, + "resume" : "Display" + }, + "Display" : { + "priority" : -8, + "loop" : -1, + "suspend" : "Display", + "run" : 16000 + }, + }, + "global" : { + "default_policy" : "SCHED_OTHER", + "duration" : 6, + "ftrace" : false, + "gnuplot" : false, + "logdir" : "./", + "log_basename" : "web", + "lock_pages" : true, + "frag" : 1, + "calibration" : "CPU0" + } +} diff --git a/wlauto/workloads/rt_app/use_cases/mp3-long.json b/wlauto/workloads/rt_app/use_cases/mp3-long.json new file mode 100644 index 00000000..7c179d0e --- /dev/null +++ b/wlauto/workloads/rt_app/use_cases/mp3-long.json @@ -0,0 +1,68 @@ +{ + "tasks" : { + "AudioTick" : { + "priority" : -19, + "loop" : -1, + "cpus" : [0], + "phases" : { + "p1" : { + "loop" : 1, + "resume" : "AudioOut", + "timer" : { "ref" : "tick", "period": 6000 } + }, + "p2" : { + "loop" : 4, + "timer" : { "ref" : "tick", "period": 6000 } + } + } + }, + "AudioOut" : { + "priority" : -19, + "loop" : -1, + "run" : 275, + "resume" : "AudioTrack", + "run" : 4725, + "suspend" : "AudioOut" + }, + "AudioTrack" : { + "priority" : -16, + "loop" : -1, + "suspend" : "AudioTrack", + "run" : 300, + "resume" : "mp3.decoder" + }, + "mp3.decoder" : { + "priority" : -2, + "loop" : -1, + "suspend" : "mp3.decoder", + "run" : 1000, + "lock" : "mutex", + "signal" : "queue", + "wait" : { "ref" : "queue", "mutex": "mutex" }, + "unlock" : "mutex", + "run" : 150 + }, + "OMXCall" : { + "priority" : -2, + "loop" : -1, + "lock" : "mutex", + "wait" : { "ref" : "queue", "mutex": "mutex" }, + "unlock" : "mutex", + "run" : 300, + "lock" : "mutex", + "signal" : "queue", + "unlock" : "mutex" + } + }, + "global" : { + "default_policy" : "SCHED_OTHER", + "duration" : 600, + "ftrace" : false, + "gnuplot" : false, + "logdir" : "./", + "log_basename" : "mp3", + "lock_pages" : true, + "frag" : 1, + "calibration" : "CPU0" + } +} diff --git a/wlauto/workloads/rt_app/use_cases/mp3-short.json b/wlauto/workloads/rt_app/use_cases/mp3-short.json new file mode 100644 index 00000000..ad307233 --- /dev/null +++ b/wlauto/workloads/rt_app/use_cases/mp3-short.json @@ -0,0 +1,68 @@ +{ + "tasks" : { + "AudioTick" : { + "priority" : -19, + "loop" : -1, + "cpus" : [0], + "phases" : { + "p1" : { + "loop" : 1, + "resume" : "AudioOut", + "timer" : { "ref" : "tick", "period": 6000 } + }, + "p2" : { + "loop" : 4, + "timer" : { "ref" : "tick", "period": 6000 } + } + } + }, + "AudioOut" : { + "priority" : -19, + "loop" : -1, + "run" : 275, + "resume" : "AudioTrack", + "run" : 4725, + "suspend" : "AudioOut" + }, + "AudioTrack" : { + "priority" : -16, + "loop" : -1, + "suspend" : "AudioTrack", + "run" : 300, + "resume" : "mp3.decoder" + }, + "mp3.decoder" : { + "priority" : -2, + "loop" : -1, + "suspend" : "mp3.decoder", + "run" : 1000, + "lock" : "mutex", + "signal" : "queue", + "wait" : { "ref" : "queue", "mutex": "mutex" }, + "unlock" : "mutex", + "run" : 150 + }, + "OMXCall" : { + "priority" : -2, + "loop" : -1, + "lock" : "mutex", + "wait" : { "ref" : "queue", "mutex": "mutex" }, + "unlock" : "mutex", + "run" : 300, + "lock" : "mutex", + "signal" : "queue", + "unlock" : "mutex" + } + }, + "global" : { + "default_policy" : "SCHED_OTHER", + "duration" : 6, + "ftrace" : false, + "gnuplot" : false, + "logdir" : "./", + "log_basename" : "mp3", + "lock_pages" : true, + "frag" : 1, + "calibration" : "CPU0" + } +} diff --git a/wlauto/workloads/rt_app/use_cases/spreading-tasks.json b/wlauto/workloads/rt_app/use_cases/spreading-tasks.json new file mode 100644 index 00000000..844db44a --- /dev/null +++ b/wlauto/workloads/rt_app/use_cases/spreading-tasks.json @@ -0,0 +1,26 @@ +{ + "tasks" : { + "thread" : { + "instance" : 2, + "loop" : -1, + "phases" : { + "light" : { + "loop" : 600, + "run" : 1000, + "timer" : { "ref" : "unique", "period" : 10000 } + }, + "heavy" : { + "loop" : 600, + "run" : 7000, + "timer" : { "ref" : "unique", "period" : 10000 } + } + } + } + }, + "global" : { + "duration" : 60, + "default_policy" : "SCHED_OTHER", + "calibration" : "CPU0" + } +} + diff --git a/wlauto/workloads/rt_app/use_cases/taskset.json b/wlauto/workloads/rt_app/use_cases/taskset.json new file mode 100644 index 00000000..ddcb389d --- /dev/null +++ b/wlauto/workloads/rt_app/use_cases/taskset.json @@ -0,0 +1,186 @@ +{ + "tasks": { + "ThreadA": { + "exec": 5000, + "period": 24000, + "priority": -19, + "cpus": [ + 0 + ], + "lock_order": [ + "r0", + "trig1" + ], + "resources": { + "r0": { + "duration": 1000 + }, + "trig1": { + "duration": 0 + } + } + }, + "ThreadB": { + "priority": -16, + "phases": { + "phase1": { + "exec": 300, + "period": 24000, + "sleep": false, + "loop": 1, + "lock_order": [ + "wait1", + "r0", + "trig2" + ], + "resources": { + "wait1": { + "duration": 0, + "access": [ + "trig1_mutex" + ] + }, + "r0": { + "duration": 300 + }, + "trig2": { + "duration": 0 + } + } + }, + "phase2": { + "exec": 4000, + "period": 24000, + "loop": 2, + "sleep": false, + "lock_order": [ + "wait1", + "r0", + "trig2" + ], + "resources": { + "wait1": { + "duration": 0, + "access": [ + "trig1_mutex" + ] + }, + "r0": { + "duration": 300 + }, + "trig2": { + "duration": 0 + } + } + } + } + }, + "ThreadC": { + "exec": 1150, + "period": 24000, + "priority": -2, + "sleep": false, + "lock_order": [ + "wait2", + "r0", + "sync3" + ], + "resources": { + "wait2": { + "duration": 0, + "access": [ + "trig2_mutex" + ] + }, + "r0": { + "duration": 1000 + }, + "sync3": { + "duration": 0, + "access": [ + "trig3_mutex" + ] + } + } + }, + "ThreadD": { + "exec": 300, + "period": 24000, + "deadline": 24000, + "priority": -2, + "sleep": false, + "lock_order": [ + "wait3", + "r0", + "trig3" + ], + "resources": { + "wait3": { + "duration": 0, + "access": [ + "trig3_mutex" + ] + }, + "r0": { + "duration": 300 + }, + "trig3": { + "duration": 0, + "access": [ + "trig3_mutex" + ] + } + } + } + }, + "resources": { + "trig1_mutex": { + "type": "mutex" + }, + "wait1": { + "type": "wait" + }, + "trig1": { + "type": "signal", + "target": "wait1" + }, + "trig2_mutex": { + "type": "mutex" + }, + "wait2": { + "type": "wait" + }, + "trig2": { + "type": "signal", + "target": "wait2" + }, + "trig3_mutex": { + "type": "mutex" + }, + "wait3": { + "type": "wait" + }, + "trig3": { + "type": "signal", + "target": "wait3" + }, + "sync3": { + "type": "sync", + "target": "wait3" + }, + "r0": { + "type": "run" + } + }, + "global": { + "default_policy": "SCHED_OTHER", + "duration": 5, + "ftrace": true, + "gnuplot": false, + "logdir": "/root/wa", + "log_basename": "rt-app", + "lock_pages": true, + "frag": 1, + "calibration": "CPU1" + } +} diff --git a/wlauto/workloads/rt_app/workgen b/wlauto/workloads/rt_app/workgen new file mode 100755 index 00000000..c85d6b0a --- /dev/null +++ b/wlauto/workloads/rt_app/workgen @@ -0,0 +1,236 @@ +#!/usr/bin/env python + +import os +import sys +import getopt +import subprocess +import signal +import re + +def check_unikid_json(infile, outfile, verbose=0): + if not os.path.exists(infile): + print "WARN: %s does not exist", infile + + try: + fi = open(infile, "r") + except IOError: + print "WARN: Unable to open %s", infile + sys.exit(2) + + lines = fi.readlines() + fi.close() + + try: + fo = open(outfile, "w+") + except IOError: + print "WARN: Unable to open %s", f + sys.exit(2) + + curid = 1 + refcount = 0 + idlist = {} + myid = [] + for myline in lines: + if "{" in myline: + refcount += 1 + myid.append(curid) + curid = 1 + idlist[refcount] = {} + + if "}" in myline: + del idlist[refcount] + curid = myid.pop() + refcount -= 1 + + try: + key_id, value = myline.split(":", 1) + except ValueError: + fo.write(myline) + continue + + key_id = key_id.strip('\"\t\n\r ') + value = value.strip(',\"\t\n\r ') + + if key_id in idlist[refcount]: + newkey_id = key_id + str(curid) + while newkey_id in idlist[refcount]: + curid += 1 + newkey_id = key_id + str(curid) + + if verbose: + print "level ", refcount, " : key ", key_id, " changed into ", newkey_id + + myline = myline.replace(key_id, newkey_id, 1) + key_id = newkey_id + + idlist[refcount][key_id] = value + fo.write(myline) + + fo.close() + + return + +def check_suspend_json(infile, outfile, verbose=0): + if not os.path.exists(infile): + print "WARN: %s does not exist", infile + + try: + fi = open(infile, "r") + except IOError: + print "WARN: Unable to open %s", infile + sys.exit(2) + + lines = fi.readlines() + fi.close() + + try: + fo = open(outfile, "w+") + except IOError: + print "WARN: Unable to open %s", f + sys.exit(2) + + + taskobj = 0 + curid = "" + for myline in lines: + + exception = 0 + key_id = "exception" + + try: + key_id, value = myline.split(":", 1) + except ValueError: + if "suspend" in myline: + key_id = "suspend" + exception = 1 + + key_id = key_id.strip('\"\t\n\r ') + + if not "tasks" in key_id and \ + taskobj == 0: + fo.write(myline) + continue + + if "{" in myline: + taskobj += 1 + if taskobj == 2: + curid = key_id + + if "}" in myline: + taskobj -= 1 + + if "suspend" in key_id and \ + exception == 1: + + if verbose: + print "value ", curid, " added to suspend key" + + if "," in myline: + myline = myline.replace(",", " : " + "\"" + curid + "\",", 1) + else: + myline = myline.replace("\n", " : " + "\"" + curid + "\"\n", 1) + + fo.write(myline) + + fo.close() + + return + +# remove trailing commas that may appear after closing +# brackets and last entries in every section +def remove_trailing_commas(outfile): + try: + f = open(outfile, 'r+') + except IOError: + print "WARN: Unable to open %s", f + sys.exit(2) + + lines = f.read() + check_last_entry_regex = r'(.),(\n\s*})' + check_end_bracket_regex = r'(}),(\n\s*})' + + lines = re.sub(check_last_entry_regex, r'\g<1>\g<2>', lines) + lines = re.sub(check_end_bracket_regex, r'\g<1>\g<2>', lines) + + f.seek(0) + f.write(lines) + f.truncate() + f.close() + + return + + +# Search for comments to remove +def comment_remover(text): + def replacer(match): + s = match.group(0) + if s.startswith('/'): + return " " # note: a space and not an empty string + else: + return s + + pattern = re.compile( + r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', + re.DOTALL | re.MULTILINE) + + return re.sub(pattern, replacer, text) + +# Remove all comments inside the file +def remove_all_comments(outfile): + try: + f = open(outfile, 'r+') + except IOError: + print "WARN: Unable to open %s", f + sys.exit(2) + + lines = f.read() + + lines = comment_remover(lines) + f.seek(0) + f.write(lines) + f.truncate() + + f.close() + + return + +if __name__ == '__main__': + + def handleSigTERM(signum, frame): + sys.exit() + + signal.signal(signal.SIGTERM, handleSigTERM) + signal.signal(signal.SIGINT, handleSigTERM) + + outfile = "unikid.json" + selfupdate = 0 + verbose = 0 + dry_run = False + + try: + opts, args = getopt.getopt(sys.argv[1:], "o:avd") + except getopt.GetoptError as err: + print str(err) # will print something like "option -a not recognized" + sys.exit(2) + + for o, a in opts: + if o == "-o": + outfile = a + if o == "-a": + selfupdate = 1 + if o == "-v": + verbose = 1 + if o == "-d": + dry_run = True + + for f in args: + if selfupdate: + outfile = f + + check_suspend_json(f, outfile) + check_unikid_json(outfile, outfile) + remove_trailing_commas(outfile) + remove_all_comments(outfile) + + if not dry_run: + subprocess.call(["rt-app", outfile])