diff options
| -rw-r--r-- | common.py | 11 | ||||
| -rw-r--r-- | gen/edf_generators.py | 30 | ||||
| -rw-r--r-- | gen/generator.py | 62 | ||||
| -rwxr-xr-x | gen_exps.py | 4 | ||||
| -rw-r--r-- | run/proc_entry.py | 7 | ||||
| -rwxr-xr-x | run_exps.py | 28 |
6 files changed, 93 insertions, 49 deletions
| @@ -50,6 +50,12 @@ def get_config_option(option): | |||
| 50 | else: | 50 | else: |
| 51 | raise IOError("No config file exists!") | 51 | raise IOError("No config file exists!") |
| 52 | 52 | ||
| 53 | def try_get_config_option(option, default): | ||
| 54 | try: | ||
| 55 | get_config_option(option) | ||
| 56 | except: | ||
| 57 | return default | ||
| 58 | |||
| 53 | def recordtype(typename, field_names, default=0): | 59 | def recordtype(typename, field_names, default=0): |
| 54 | ''' Mutable namedtuple. Recipe from George Sakkis of MIT.''' | 60 | ''' Mutable namedtuple. Recipe from George Sakkis of MIT.''' |
| 55 | field_names = tuple(map(str, field_names)) | 61 | field_names = tuple(map(str, field_names)) |
| @@ -127,10 +133,7 @@ def load_params(fname): | |||
| 127 | with open(fname, 'r') as f: | 133 | with open(fname, 'r') as f: |
| 128 | data = f.read() | 134 | data = f.read() |
| 129 | try: | 135 | try: |
| 130 | parsed = eval(data) | 136 | params = eval(data) |
| 131 | # Convert to defaultdict | ||
| 132 | for k in parsed: | ||
| 133 | params[k] = str(parsed[k]) | ||
| 134 | except Exception as e: | 137 | except Exception as e: |
| 135 | raise IOError("Invalid param file: %s\n%s" % (fname, e)) | 138 | raise IOError("Invalid param file: %s\n%s" % (fname, e)) |
| 136 | 139 | ||
diff --git a/gen/edf_generators.py b/gen/edf_generators.py index c7267f7..9bf6b8f 100644 --- a/gen/edf_generators.py +++ b/gen/edf_generators.py | |||
| @@ -1,15 +1,20 @@ | |||
| 1 | import generator as gen | 1 | import generator as gen |
| 2 | import random | 2 | import random |
| 3 | import schedcat.generator.tasks as tasks | 3 | |
| 4 | TP_TBASE = """#for $t in $task_set | ||
| 5 | {} $t.cost $t.period | ||
| 6 | #end for""" | ||
| 7 | TP_GLOB_TASK = TP_TBASE.format("") | ||
| 8 | TP_PART_TASK = TP_TBASE.format("-p $t.cpu") | ||
| 4 | 9 | ||
| 5 | class EdfGenerator(gen.Generator): | 10 | class EdfGenerator(gen.Generator): |
| 6 | '''Creates sporadic task sets with the most common Litmus options.''' | 11 | '''Creates sporadic task sets with the most common Litmus options.''' |
| 7 | def __init__(self, name, templates, options, params): | 12 | def __init__(self, name, templates, options, params): |
| 8 | super(EdfGenerator, self).__init__(name, templates, | 13 | super(EdfGenerator, self).__init__(name, templates, |
| 9 | self.__make_options(params) + options, | 14 | self.__make_options() + options, |
| 10 | params) | 15 | params) |
| 11 | 16 | ||
| 12 | def __make_options(self, params): | 17 | def __make_options(self): |
| 13 | '''Return generic EDF options.''' | 18 | '''Return generic EDF options.''' |
| 14 | return [gen.Generator._dist_option('utils', ['uni-medium'], | 19 | return [gen.Generator._dist_option('utils', ['uni-medium'], |
| 15 | gen.NAMED_UTILIZATIONS, | 20 | gen.NAMED_UTILIZATIONS, |
| @@ -26,23 +31,12 @@ class EdfGenerator(gen.Generator): | |||
| 26 | udist = self._create_dist('utilization', | 31 | udist = self._create_dist('utilization', |
| 27 | exp_params['utils'], | 32 | exp_params['utils'], |
| 28 | gen.NAMED_UTILIZATIONS) | 33 | gen.NAMED_UTILIZATIONS) |
| 29 | tg = tasks.TaskGenerator(period=pdist, util=udist) | ||
| 30 | 34 | ||
| 31 | ts = [] | 35 | ts = self._create_taskset(exp_params, pdist, udist) |
| 32 | tries = 0 | ||
| 33 | while len(ts) != exp_params['num_tasks'] and tries < 5: | ||
| 34 | ts = tg.make_task_set(max_tasks = exp_params['num_tasks']) | ||
| 35 | tries += 1 | ||
| 36 | if len(ts) != exp_params['num_tasks']: | ||
| 37 | print("Failed to create task set with parameters: %s" % exp_params) | ||
| 38 | 36 | ||
| 39 | self._customize(ts, exp_params) | 37 | self._customize(ts, exp_params) |
| 40 | 38 | ||
| 41 | exp_params['task_set'] = ts | 39 | self._write_schedule(dict(exp_params.items() + ('task_set', ts))) |
| 42 | self._write_schedule(exp_params) | ||
| 43 | |||
| 44 | del exp_params['task_set'] | ||
| 45 | del exp_params['num_tasks'] | ||
| 46 | self._write_params(exp_params) | 40 | self._write_params(exp_params) |
| 47 | 41 | ||
| 48 | def _customize(self, taskset, exp_params): | 42 | def _customize(self, taskset, exp_params): |
| @@ -53,7 +47,7 @@ class EdfGenerator(gen.Generator): | |||
| 53 | class PartitionedGenerator(EdfGenerator): | 47 | class PartitionedGenerator(EdfGenerator): |
| 54 | def __init__(self, name, templates, options, params): | 48 | def __init__(self, name, templates, options, params): |
| 55 | super(PartitionedGenerator, self).__init__(name, | 49 | super(PartitionedGenerator, self).__init__(name, |
| 56 | templates + [gen.TP_PART_TASK], options, params) | 50 | templates + [TP_PART_TASK], options, params) |
| 57 | 51 | ||
| 58 | def _customize(self, taskset, exp_params): | 52 | def _customize(self, taskset, exp_params): |
| 59 | start = 1 if exp_params['release_master'] else 0 | 53 | start = 1 if exp_params['release_master'] else 0 |
| @@ -78,5 +72,5 @@ class CedfGenerator(PartitionedGenerator): | |||
| 78 | 72 | ||
| 79 | class GedfGenerator(EdfGenerator): | 73 | class GedfGenerator(EdfGenerator): |
| 80 | def __init__(self, params={}): | 74 | def __init__(self, params={}): |
| 81 | super(GedfGenerator, self).__init__("GSN-EDF", [gen.TP_GLOB_TASK], | 75 | super(GedfGenerator, self).__init__("GSN-EDF", [TP_GLOB_TASK], |
| 82 | [], params) | 76 | [], params) |
diff --git a/gen/generator.py b/gen/generator.py index 8c3048b..3a6524d 100644 --- a/gen/generator.py +++ b/gen/generator.py | |||
| @@ -1,10 +1,11 @@ | |||
| 1 | import gen.rv as rv | 1 | import gen.rv as rv |
| 2 | import os | 2 | import os |
| 3 | import pprint | ||
| 4 | import schedcat.generator.tasks as tasks | ||
| 3 | import shutil as sh | 5 | import shutil as sh |
| 4 | 6 | ||
| 5 | from Cheetah.Template import Template | 7 | from Cheetah.Template import Template |
| 6 | from collections import namedtuple | 8 | from common import get_config_option,num_cpus,recordtype |
| 7 | from common import get_config_option,num_cpus | ||
| 8 | from config.config import DEFAULTS,PARAMS | 9 | from config.config import DEFAULTS,PARAMS |
| 9 | from gen.dp import DesignPointGenerator | 10 | from gen.dp import DesignPointGenerator |
| 10 | from parse.col_map import ColMapBuilder | 11 | from parse.col_map import ColMapBuilder |
| @@ -21,6 +22,7 @@ NAMED_UTILIZATIONS = { | |||
| 21 | 'uni-light' : rv.uniform(0.001, 0.1), | 22 | 'uni-light' : rv.uniform(0.001, 0.1), |
| 22 | 'uni-medium' : rv.uniform( 0.1, 0.4), | 23 | 'uni-medium' : rv.uniform( 0.1, 0.4), |
| 23 | 'uni-heavy' : rv.uniform( 0.5, 0.9), | 24 | 'uni-heavy' : rv.uniform( 0.5, 0.9), |
| 25 | 'uni-mixed' : rv.uniform(0.001, .4), | ||
| 24 | 26 | ||
| 25 | 'exp-light' : rv.exponential(0, 1, 0.10), | 27 | 'exp-light' : rv.exponential(0, 1, 0.10), |
| 26 | 'exp-medium' : rv.exponential(0, 1, 0.25), | 28 | 'exp-medium' : rv.exponential(0, 1, 0.25), |
| @@ -36,15 +38,12 @@ NAMED_UTILIZATIONS = { | |||
| 36 | 38 | ||
| 37 | '''Components of Cheetah template for schedule file''' | 39 | '''Components of Cheetah template for schedule file''' |
| 38 | TP_RM = """#if $release_master | 40 | TP_RM = """#if $release_master |
| 39 | release_master{1} | 41 | release_master{0} |
| 40 | #end if""" | 42 | #end if""" |
| 41 | TP_TBASE = """#for $t in $task_set | ||
| 42 | {} $t.cost $t.period | ||
| 43 | #end for""" | ||
| 44 | TP_GLOB_TASK = TP_TBASE.format("") | ||
| 45 | TP_PART_TASK = TP_TBASE.format("-p $t.cpu") | ||
| 46 | 43 | ||
| 47 | GenOption = namedtuple('GenOption', ['name', 'types', 'default', 'help']) | 44 | GenOptionT = recordtype('GenOption', ['name', 'types', 'default', 'help', 'hidden']) |
| 45 | def GenOption(name, types, default, help, hidden = False): | ||
| 46 | return GenOptionT(name, types, default, help, hidden) | ||
| 48 | 47 | ||
| 49 | class Generator(object): | 48 | class Generator(object): |
| 50 | '''Creates all combinations @options specified by @params. | 49 | '''Creates all combinations @options specified by @params. |
| @@ -92,36 +91,65 @@ class Generator(object): | |||
| 92 | def _create_dist(self, name, value, named_dists): | 91 | def _create_dist(self, name, value, named_dists): |
| 93 | '''Attempt to create a distribution representing the data in @value. | 92 | '''Attempt to create a distribution representing the data in @value. |
| 94 | If @value is a string, use it as a key for @named_dists.''' | 93 | If @value is a string, use it as a key for @named_dists.''' |
| 95 | name = "%s distribution" % name | ||
| 96 | # A list of values | 94 | # A list of values |
| 97 | if type(value) == type([]): | 95 | if type(value) == type([]): |
| 98 | map(lambda x : self.__check_value(name, x, [float, int]), value) | 96 | map(lambda x : self.__check_value(name, x, [float, int]), value) |
| 99 | return rv.uniform_choice(value) | 97 | return rv.uniform_choice(value) |
| 100 | elif type(value) in [float, int]: | 98 | elif type(value) in [float, int]: |
| 101 | return lambda : value | 99 | return lambda : value |
| 102 | elif value in named_dists: | 100 | elif named_dists and value in named_dists: |
| 103 | return named_dists[value] | 101 | return named_dists[value] |
| 104 | else: | 102 | else: |
| 105 | raise ValueError("Invalid %s value: %s" % (name, value)) | 103 | raise ValueError("Invalid %s value: %s" % (name, value)) |
| 106 | 104 | ||
| 105 | def _create_taskset(self, params, periods, utils, max_util = None): | ||
| 106 | tg = tasks.TaskGenerator(period=periods, util=utils) | ||
| 107 | ts = [] | ||
| 108 | tries = 0 | ||
| 109 | while len(ts) != params['num_tasks'] and tries < 100: | ||
| 110 | ts = tg.make_task_set(max_tasks = params['num_tasks'], max_util=max_util) | ||
| 111 | tries += 1 | ||
| 112 | if len(ts) != params['num_tasks']: | ||
| 113 | print(("Only created task set of size %d < %d for params %s. " + | ||
| 114 | "Switching to light utilization.") % | ||
| 115 | (len(ts), params['num_tasks'], params)) | ||
| 116 | print("Switching to light util. This usually means the " + | ||
| 117 | "utilization distribution is too agressive.") | ||
| 118 | return self._create_taskset(params, periods, NAMED_UTILIZATIONS['uni-light'], | ||
| 119 | max_util) | ||
| 120 | return ts | ||
| 121 | |||
| 107 | def _write_schedule(self, params): | 122 | def _write_schedule(self, params): |
| 108 | '''Write schedule file using current template for @params.''' | 123 | '''Write schedule file using current template for @params.''' |
| 109 | sched_file = self.out_dir + "/" + DEFAULTS['sched_file'] | 124 | sched_file = self.out_dir + "/" + DEFAULTS['sched_file'] |
| 110 | with open(sched_file, 'wa') as f: | 125 | with open(sched_file, 'wa') as f: |
| 111 | f.write(str(Template(self.template, searchList=[params]))) | 126 | f.write(str(Template(self.template, searchList=[params]))) |
| 112 | 127 | ||
| 128 | |||
| 113 | def _write_params(self, params): | 129 | def _write_params(self, params): |
| 114 | '''Write out file with relevant parameters.''' | 130 | '''Write out file with relevant parameters.''' |
| 131 | # Don't include this in the parameters. It will be automatically added | ||
| 132 | # in run_exps.py | ||
| 133 | if 'num_tasks' in params: | ||
| 134 | num_tasks = params.pop('num_tasks') | ||
| 135 | else: | ||
| 136 | num_tasks = 0 | ||
| 137 | |||
| 115 | exp_params_file = self.out_dir + "/" + DEFAULTS['params_file'] | 138 | exp_params_file = self.out_dir + "/" + DEFAULTS['params_file'] |
| 116 | with open(exp_params_file, 'wa') as f: | 139 | with open(exp_params_file, 'wa') as f: |
| 117 | params['scheduler'] = self.name | 140 | params['scheduler'] = self.name |
| 118 | f.write(str(params)) | 141 | pprint.pprint(params, f) |
| 142 | |||
| 143 | if num_tasks: | ||
| 144 | params['num_tasks'] = num_tasks | ||
| 119 | 145 | ||
| 120 | def __setup_params(self, params): | 146 | def __setup_params(self, params): |
| 121 | '''Set default parameter values and check that values are valid.''' | 147 | '''Set default parameter values and check that values are valid.''' |
| 122 | for option in self.options: | 148 | for option in self.options: |
| 123 | if option.name not in params: | 149 | if option.name not in params: |
| 124 | params[option.name] = option.default | 150 | params[option.name] = option.default |
| 151 | else: | ||
| 152 | option.hidden = True | ||
| 125 | params[option.name] = self._check_value(option.name, | 153 | params[option.name] = self._check_value(option.name, |
| 126 | option.types, | 154 | option.types, |
| 127 | params[option.name]) | 155 | params[option.name]) |
| @@ -207,14 +235,16 @@ class Generator(object): | |||
| 207 | if PARAMS['trial'] in dp: | 235 | if PARAMS['trial'] in dp: |
| 208 | del dp[PARAMS['trial']] | 236 | del dp[PARAMS['trial']] |
| 209 | 237 | ||
| 238 | HELP_INDENT = 17 | ||
| 210 | 239 | ||
| 211 | def print_help(self): | 240 | def print_help(self): |
| 241 | display_options = [o for o in self.options if not o.hidden] | ||
| 212 | s = str(Template("""Generator $name: | 242 | s = str(Template("""Generator $name: |
| 213 | #for $o in $options | 243 | #for $o in $options |
| 214 | $o.name -- $o.help | 244 | $o.name -- $o.help |
| 215 | \tDefault: $o.default | 245 | \tDefault: $o.default |
| 216 | \tAllowed: $o.types | 246 | \tAllowed: $o.types |
| 217 | #end for""", searchList=vars(self))) | 247 | #end for""", searchList={'name':self.name, 'options':display_options})) |
| 218 | 248 | ||
| 219 | # Has to be an easier way to print this out... | 249 | # Has to be an easier way to print this out... |
| 220 | for line in s.split("\n"): | 250 | for line in s.split("\n"): |
| @@ -223,8 +253,8 @@ class Generator(object): | |||
| 223 | for word in line.split(", "): | 253 | for word in line.split(", "): |
| 224 | i += len(word) | 254 | i += len(word) |
| 225 | res += [word] | 255 | res += [word] |
| 226 | if i > 80: | 256 | if i > 80 and len(word) < 80: |
| 227 | print(", ".join(res[:-1])) | 257 | print(", ".join(res[:-1])) |
| 228 | res = ["\t\t "+res[-1]] | 258 | res = [" "*Generator.HELP_INDENT +res[-1]] |
| 229 | i = line.index("'") | 259 | i = Generator.HELP_INDENT + len(word) |
| 230 | print(", ".join(res)) | 260 | print(", ".join(res)) |
diff --git a/gen_exps.py b/gen_exps.py index 20a6c6f..cb05fe7 100755 --- a/gen_exps.py +++ b/gen_exps.py | |||
| @@ -6,12 +6,14 @@ import re | |||
| 6 | import shutil as sh | 6 | import shutil as sh |
| 7 | 7 | ||
| 8 | from gen.edf_generators import GedfGenerator,PedfGenerator,CedfGenerator | 8 | from gen.edf_generators import GedfGenerator,PedfGenerator,CedfGenerator |
| 9 | from gen.mc_generators import McGenerator | ||
| 9 | from optparse import OptionParser | 10 | from optparse import OptionParser |
| 10 | 11 | ||
| 11 | # There has to be a better way to do this... | 12 | # There has to be a better way to do this... |
| 12 | GENERATORS = {'C-EDF':CedfGenerator, | 13 | GENERATORS = {'C-EDF':CedfGenerator, |
| 13 | 'P-EDF':PedfGenerator, | 14 | 'P-EDF':PedfGenerator, |
| 14 | 'G-EDF':GedfGenerator} | 15 | 'G-EDF':GedfGenerator, |
| 16 | 'MC':McGenerator} | ||
| 15 | 17 | ||
| 16 | def parse_args(): | 18 | def parse_args(): |
| 17 | parser = OptionParser("usage: %prog [options] [files...] " | 19 | parser = OptionParser("usage: %prog [options] [files...] " |
diff --git a/run/proc_entry.py b/run/proc_entry.py index 0b7f9ce..4ac2c51 100644 --- a/run/proc_entry.py +++ b/run/proc_entry.py | |||
| @@ -8,5 +8,8 @@ class ProcEntry(object): | |||
| 8 | def write_proc(self): | 8 | def write_proc(self): |
| 9 | if not os.path.exists(self.proc): | 9 | if not os.path.exists(self.proc): |
| 10 | raise Exception("Invalid proc entry %s" % self.proc) | 10 | raise Exception("Invalid proc entry %s" % self.proc) |
| 11 | with open(self.proc, 'w') as entry: | 11 | try: |
| 12 | entry.write(self.data) | 12 | with open(self.proc, 'w') as entry: |
| 13 | entry.write(self.data) | ||
| 14 | except: | ||
| 15 | print("Failed to write into %s value:\n%s" % (self.proc, self.data)) | ||
diff --git a/run_exps.py b/run_exps.py index 6873877..4a2d8ab 100755 --- a/run_exps.py +++ b/run_exps.py | |||
| @@ -27,15 +27,24 @@ class InvalidConfig(Exception): | |||
| 27 | self.results = results | 27 | self.results = results |
| 28 | 28 | ||
| 29 | def __str__(self): | 29 | def __str__(self): |
| 30 | rstr = "'%s' - wanted: '%s', found: %s" | 30 | rstr = "'%s'%swanted: '%s', found: %s" |
| 31 | result = [rstr % (r.actual, r.param, r.wanted) for r in self.results] | 31 | messages = [] |
| 32 | return "Invalid kernel configuration\n" + result.join("\n") | 32 | for r in self.results: |
| 33 | # For pretty alignment | ||
| 34 | tabs = (3 - len(r.param)/8) | ||
| 35 | messages += [rstr % (r.param, '\t'*tabs, r.wanted, r.actual)] | ||
| 36 | |||
| 37 | return "Invalid kernel configuration " +\ | ||
| 38 | "(ignore configuration with -i option).\n" + "\n".join(messages) | ||
| 33 | 39 | ||
| 34 | def parse_args(): | 40 | def parse_args(): |
| 35 | parser = OptionParser("usage: %prog [options] [sched_file]... [exp_dir]...") | 41 | parser = OptionParser("usage: %prog [options] [sched_file]... [exp_dir]...") |
| 36 | 42 | ||
| 37 | parser.add_option('-s', '--scheduler', dest='scheduler', | 43 | parser.add_option('-s', '--scheduler', dest='scheduler', |
| 38 | help='scheduler for all experiments') | 44 | help='scheduler for all experiments') |
| 45 | parser.add_option('-i', '--ignore-environment', dest='ignore', | ||
| 46 | action='store_true', default=False, | ||
| 47 | help='run experiments even in invalid environments ') | ||
| 39 | parser.add_option('-d', '--duration', dest='duration', type='int', | 48 | parser.add_option('-d', '--duration', dest='duration', type='int', |
| 40 | help='duration (seconds) of tasks') | 49 | help='duration (seconds) of tasks') |
| 41 | parser.add_option('-o', '--out-dir', dest='out_dir', | 50 | parser.add_option('-o', '--out-dir', dest='out_dir', |
| @@ -87,7 +96,7 @@ def fix_paths(schedule, exp_dir, sched_file): | |||
| 87 | if os.path.exists(abspath): | 96 | if os.path.exists(abspath): |
| 88 | args = args.replace(arg, abspath) | 97 | args = args.replace(arg, abspath) |
| 89 | break | 98 | break |
| 90 | elif re.match(r'.*\w+\.\w+', arg): | 99 | elif re.match(r'.*\w+\.[a-zA-Z]\w*', arg): |
| 91 | print("WARNING: non-existent file '%s' may be referenced:\n\t%s" | 100 | print("WARNING: non-existent file '%s' may be referenced:\n\t%s" |
| 92 | % (arg, sched_file)) | 101 | % (arg, sched_file)) |
| 93 | 102 | ||
| @@ -108,9 +117,10 @@ def verify_environment(kernel, copts): | |||
| 108 | results += [ConfigResult(param, wanted, actual)] | 117 | results += [ConfigResult(param, wanted, actual)] |
| 109 | 118 | ||
| 110 | if results: | 119 | if results: |
| 111 | raise InvalidKernel(results) | 120 | raise InvalidConfig(results) |
| 112 | 121 | ||
| 113 | def load_experiment(sched_file, scheduler, duration, param_file, out_dir): | 122 | def load_experiment(sched_file, scheduler, duration, |
| 123 | param_file, out_dir, ignore): | ||
| 114 | if not os.path.isfile(sched_file): | 124 | if not os.path.isfile(sched_file): |
| 115 | raise IOError("Cannot find schedule file: %s" % sched_file) | 125 | raise IOError("Cannot find schedule file: %s" % sched_file) |
| 116 | 126 | ||
| @@ -146,7 +156,8 @@ def load_experiment(sched_file, scheduler, duration, param_file, out_dir): | |||
| 146 | 156 | ||
| 147 | fix_paths(schedule, os.path.split(sched_file)[0], sched_file) | 157 | fix_paths(schedule, os.path.split(sched_file)[0], sched_file) |
| 148 | 158 | ||
| 149 | verify_environment(kernel, copts) | 159 | if not ignore: |
| 160 | verify_environment(kernel, copts) | ||
| 150 | 161 | ||
| 151 | run_exp(exp_name, schedule, scheduler, kernel, duration, work_dir, out_dir) | 162 | run_exp(exp_name, schedule, scheduler, kernel, duration, work_dir, out_dir) |
| 152 | 163 | ||
| @@ -251,7 +262,8 @@ def main(): | |||
| 251 | path = "%s/%s" % (path, opts.sched_file) | 262 | path = "%s/%s" % (path, opts.sched_file) |
| 252 | 263 | ||
| 253 | try: | 264 | try: |
| 254 | load_experiment(path, scheduler, duration, param_file, out_dir) | 265 | load_experiment(path, scheduler, duration, param_file, |
| 266 | out_dir, opts.ignore) | ||
| 255 | succ += 1 | 267 | succ += 1 |
| 256 | except ExperimentDone: | 268 | except ExperimentDone: |
| 257 | done += 1 | 269 | done += 1 |
