diff options
| -rw-r--r-- | common.py | 26 | ||||
| -rw-r--r-- | config/config.py | 16 | ||||
| -rw-r--r-- | gen/__init__.py | 0 | ||||
| -rw-r--r-- | gen/dp.py | 33 | ||||
| -rw-r--r-- | gen/generators.py | 257 | ||||
| -rw-r--r-- | gen/rv.py | 86 | ||||
| -rwxr-xr-x[-rw-r--r--] | gen_exps.py | 98 | ||||
| -rw-r--r-- | parse/ft.py | 4 | ||||
| -rw-r--r-- | parse/sched.py | 2 | ||||
| -rw-r--r-- | parse/tuple_table.py | 9 | ||||
| -rwxr-xr-x | parse_exps.py | 13 | ||||
| -rwxr-xr-x | run_exps.py | 1 |
12 files changed, 525 insertions, 20 deletions
| @@ -1,9 +1,14 @@ | |||
| 1 | import os | ||
| 2 | import re | ||
| 3 | import subprocess | ||
| 1 | import sys | 4 | import sys |
| 5 | |||
| 2 | from collections import defaultdict | 6 | from collections import defaultdict |
| 3 | from textwrap import dedent | 7 | from textwrap import dedent |
| 4 | 8 | ||
| 5 | def get_executable(prog, hint, optional=False): | 9 | def get_executable(prog, hint, optional=False): |
| 6 | import os | 10 | '''Search for @prog in system PATH. Print @hint if no binary is found.''' |
| 11 | |||
| 7 | def is_exe(fpath): | 12 | def is_exe(fpath): |
| 8 | return os.path.isfile(fpath) and os.access(fpath, os.X_OK) | 13 | return os.path.isfile(fpath) and os.access(fpath, os.X_OK) |
| 9 | 14 | ||
| @@ -19,12 +24,29 @@ def get_executable(prog, hint, optional=False): | |||
| 19 | 24 | ||
| 20 | if not optional: | 25 | if not optional: |
| 21 | sys.stderr.write("Cannot find executable '%s' in PATH. This is a part " | 26 | sys.stderr.write("Cannot find executable '%s' in PATH. This is a part " |
| 22 | "of '%s' which should be added to PATH to run." % | 27 | "of '%s' which should be added to PATH to run.\n" % |
| 23 | (prog, hint)) | 28 | (prog, hint)) |
| 24 | sys.exit(1) | 29 | sys.exit(1) |
| 25 | else: | 30 | else: |
| 26 | return None | 31 | return None |
| 27 | 32 | ||
| 33 | def get_config_option(option): | ||
| 34 | '''Search for @option in installed kernel config (if present). | ||
| 35 | Raise an IOError if the kernel config isn't found in /boot/.''' | ||
| 36 | uname = subprocess.check_output(["uname", "-r"])[-1] | ||
| 37 | fname = "/boot/config-%s" % uname | ||
| 38 | |||
| 39 | if os.path.exists(fname): | ||
| 40 | config_regex = "^CONFIG_{}=(?P<val>.*)$".format(option) | ||
| 41 | match = re.search(config_regex, open(fname, 'r').read()) | ||
| 42 | if not match: | ||
| 43 | return None | ||
| 44 | else: | ||
| 45 | return match.group("val") | ||
| 46 | |||
| 47 | else: | ||
| 48 | raise IOError("No config file exists!") | ||
| 49 | |||
| 28 | def recordtype(typename, field_names, default=0): | 50 | def recordtype(typename, field_names, default=0): |
| 29 | ''' Mutable namedtuple. Recipe from George Sakkis of MIT.''' | 51 | ''' Mutable namedtuple. Recipe from George Sakkis of MIT.''' |
| 30 | field_names = tuple(map(str, field_names)) | 52 | field_names = tuple(map(str, field_names)) |
diff --git a/config/config.py b/config/config.py index 3282705..d463999 100644 --- a/config/config.py +++ b/config/config.py | |||
| @@ -17,18 +17,20 @@ BINS = {'rtspin' : get_executable('rtspin', 'liblitmus'), | |||
| 17 | FILES = {'ft_data' : 'ft.bin', | 17 | FILES = {'ft_data' : 'ft.bin', |
| 18 | 'linux_data' : 'trace.dat', | 18 | 'linux_data' : 'trace.dat', |
| 19 | 'sched_data' : 'st-{}.bin', | 19 | 'sched_data' : 'st-{}.bin', |
| 20 | 'log_data' : 'trace.slog',} | 20 | 'log_data' : 'trace.slog'} |
| 21 | 21 | ||
| 22 | '''Default parameter names in params.py.''' | 22 | '''Default parameter names in params.py.''' |
| 23 | PARAMS = {'sched' : 'scheduler', | 23 | # TODO: add check for config options |
| 24 | 'dur' : 'duration', | 24 | PARAMS = {'sched' : 'scheduler', # Scheduler used by run_exps |
| 25 | 'kernel' : 'uname', | 25 | 'dur' : 'duration', # Duration of tests in run_exps |
| 26 | 'cycles' : 'cpu-frequency'} | 26 | 'kernel' : 'uname', # Regex of required OS name in run_exps |
| 27 | 'cycles' : 'cpu-frequency', # Frequency run_exps was run with | ||
| 28 | 'tasks' : 'tasks' # Number of tasks | ||
| 29 | } | ||
| 27 | 30 | ||
| 28 | '''Default values for program parameters.''' | 31 | '''Default values for program options.''' |
| 29 | DEFAULTS = {'params_file' : 'params.py', | 32 | DEFAULTS = {'params_file' : 'params.py', |
| 30 | 'sched_file' : 'sched.py', | 33 | 'sched_file' : 'sched.py', |
| 31 | 'exps_file' : 'exps.py', | ||
| 32 | 'duration' : 10, | 34 | 'duration' : 10, |
| 33 | 'spin' : 'rtspin', | 35 | 'spin' : 'rtspin', |
| 34 | 'cycles' : 2000} | 36 | 'cycles' : 2000} |
diff --git a/gen/__init__.py b/gen/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/gen/__init__.py | |||
diff --git a/gen/dp.py b/gen/dp.py new file mode 100644 index 0000000..0ac8cce --- /dev/null +++ b/gen/dp.py | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | from __future__ import division | ||
| 2 | |||
| 3 | class DesignPointGenerator(object): | ||
| 4 | '''Iterates over all combinations of values specified in options. | ||
| 5 | Shamelessly stolen (and simplified) from bcw.''' | ||
| 6 | def __init__(self, options): | ||
| 7 | self.point_idx = 0 # Current point | ||
| 8 | self.options = options | ||
| 9 | self.total = 1 | ||
| 10 | for x in options.itervalues(): | ||
| 11 | self.total *= len(x) | ||
| 12 | |||
| 13 | def __iter__(self): | ||
| 14 | return self | ||
| 15 | |||
| 16 | def next(self): | ||
| 17 | while True: | ||
| 18 | if self.point_idx == self.total: | ||
| 19 | raise StopIteration | ||
| 20 | else: | ||
| 21 | point = {} | ||
| 22 | |||
| 23 | divisor = 1 | ||
| 24 | for key in sorted(self.options.keys()): | ||
| 25 | size = len(self.options[key]) | ||
| 26 | |||
| 27 | option_idx = int(self.point_idx / divisor) % size | ||
| 28 | point[key] = self.options[key][option_idx] | ||
| 29 | |||
| 30 | divisor *= size | ||
| 31 | self.point_idx += 1 | ||
| 32 | |||
| 33 | return point | ||
diff --git a/gen/generators.py b/gen/generators.py new file mode 100644 index 0000000..2fc77a7 --- /dev/null +++ b/gen/generators.py | |||
| @@ -0,0 +1,257 @@ | |||
| 1 | from Cheetah.Template import Template | ||
| 2 | from collections import namedtuple | ||
| 3 | from common import get_config_option | ||
| 4 | from config.config import DEFAULTS | ||
| 5 | from gen.dp import DesignPointGenerator | ||
| 6 | from parse.tuple_table import ColMap | ||
| 7 | |||
| 8 | import gen.rv as rv | ||
| 9 | import os | ||
| 10 | import random | ||
| 11 | import run.litmus_util as lu | ||
| 12 | import schedcat.generator.tasks as tasks | ||
| 13 | import shutil as sh | ||
| 14 | |||
| 15 | NAMED_PERIODS = { | ||
| 16 | 'harmonic' : rv.uniform_choice([25, 50, 100, 200]), | ||
| 17 | 'uni-short' : rv.uniform_int( 3, 33), | ||
| 18 | 'uni-moderate' : rv.uniform_int(10, 100), | ||
| 19 | 'uni-long' : rv.uniform_int(50, 250), | ||
| 20 | } | ||
| 21 | |||
| 22 | NAMED_UTILIZATIONS = { | ||
| 23 | 'uni-very-light': rv.uniform(0.0001, 0.001), | ||
| 24 | 'uni-light' : rv.uniform(0.001, 0.1), | ||
| 25 | 'uni-medium' : rv.uniform( 0.1, 0.4), | ||
| 26 | 'uni-heavy' : rv.uniform( 0.5, 0.9), | ||
| 27 | |||
| 28 | 'exp-light' : rv.exponential(0, 1, 0.10), | ||
| 29 | 'exp-medium' : rv.exponential(0, 1, 0.25), | ||
| 30 | 'exp-heavy' : rv.exponential(0, 1, 0.50), | ||
| 31 | |||
| 32 | 'bimo-light' : rv.multimodal([(rv.uniform(0.001, 0.5), 8), | ||
| 33 | (rv.uniform( 0.5, 0.9), 1)]), | ||
| 34 | 'bimo-medium' : rv.multimodal([(rv.uniform(0.001, 0.5), 6), | ||
| 35 | (rv.uniform( 0.5, 0.9), 3)]), | ||
| 36 | 'bimo-heavy' : rv.multimodal([(rv.uniform(0.001, 0.5), 4), | ||
| 37 | (rv.uniform( 0.5, 0.9), 5)]), | ||
| 38 | } | ||
| 39 | |||
| 40 | # Cheetah templates for schedule files | ||
| 41 | TP_CLUSTER = "plugins/C-EDF/cluster{$level}" | ||
| 42 | TP_RM = """#if $release_master | ||
| 43 | release_master{1} | ||
| 44 | #end if""" | ||
| 45 | TP_TBASE = """#for $t in $task_set | ||
| 46 | {}$t.cost $t.period | ||
| 47 | #end for""" | ||
| 48 | TP_PART_TASK = TP_TBASE.format("-p $t.cpu ") | ||
| 49 | TP_GLOB_TASK = TP_TBASE.format("") | ||
| 50 | |||
| 51 | GenOption = namedtuple('GenOption', ['name', 'types', 'default', 'help']) | ||
| 52 | |||
| 53 | class BaseGenerator(object): | ||
| 54 | '''Creates sporadic task sets with the most common Litmus options.''' | ||
| 55 | def __init__(self, name, templates, options, params): | ||
| 56 | self.options = self.__make_options() + options | ||
| 57 | |||
| 58 | self.__setup_params(params) | ||
| 59 | |||
| 60 | self.params = params | ||
| 61 | self.template = "\n".join([TP_RM] + templates) | ||
| 62 | self.name = name | ||
| 63 | |||
| 64 | def __make_options(self): | ||
| 65 | '''Return generic Litmus options.''' | ||
| 66 | |||
| 67 | # Guess defaults using the properties of this computer | ||
| 68 | cpus = lu.num_cpus() | ||
| 69 | try: | ||
| 70 | config = get_config_option("RELEASE_MASTER") and True | ||
| 71 | except: | ||
| 72 | config = False | ||
| 73 | release_master = list(set([False, config])) | ||
| 74 | |||
| 75 | list_types = [str, float, type([])] | ||
| 76 | |||
| 77 | return [GenOption('cpus', int, [cpus], | ||
| 78 | 'Number of processors on target system.'), | ||
| 79 | GenOption('num_tasks', int, range(cpus, 5*cpus, cpus), | ||
| 80 | 'Number of tasks per experiment.'), | ||
| 81 | GenOption('utils', list_types + NAMED_UTILIZATIONS.keys(), | ||
| 82 | ['uni-medium'],'Task utilization distributions.'), | ||
| 83 | GenOption('periods', list_types + NAMED_PERIODS.keys(), | ||
| 84 | |||
