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 |