diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-03-07 14:51:32 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-03-07 14:51:32 -0500 |
commit | e3b7c78aa5b96af6bdbad20a13e0f540d1658b7f (patch) | |
tree | dc9590fb22e5d6484088d2c730b8eeea8db6a7b0 /gen/generators.py | |
parent | e5d531eabf3091af18ca1a331e52b184a67750f7 (diff) |
Seperated BaseGenerator into EdfGenerator and its superclass Generator.
Diffstat (limited to 'gen/generators.py')
-rw-r--r-- | gen/generators.py | 267 |
1 files changed, 0 insertions, 267 deletions
diff --git a/gen/generators.py b/gen/generators.py deleted file mode 100644 index fccc747..0000000 --- a/gen/generators.py +++ /dev/null | |||
@@ -1,267 +0,0 @@ | |||
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.col_map import ColMapBuilder | ||
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(params) + 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, params): | ||
65 | '''Return generic Litmus options.''' | ||
66 | |||
67 | # Guess defaults using the properties of this computer | ||
68 | if 'cpus' in params: | ||
69 | cpus = min(map(int, params['cpus'])) | ||
70 | else: | ||
71 | cpus = lu.num_cpus() | ||
72 | try: | ||
73 | config = get_config_option("RELEASE_MASTER") and True | ||
74 | except: | ||
75 | config = False | ||
76 | release_master = list(set([False, config])) | ||
77 | |||
78 | list_types = [str, float, type([])] | ||
79 | |||
80 | return [GenOption('cpus', int, [cpus], | ||
81 | 'Number of processors on target system.'), | ||
82 | GenOption('num_tasks', int, range(cpus, 5*cpus, cpus), | ||
83 | 'Number of tasks per experiment.'), | ||
84 | GenOption('utils', list_types + NAMED_UTILIZATIONS.keys(), | ||
85 | ['uni-medium'],'Task utilization distributions.'), | ||
86 | GenOption('periods', list_types + NAMED_PERIODS.keys(), | ||
87 | ['harmonic'], 'Task period distributions.'), | ||
88 | GenOption('release_master', [True,False], release_master, | ||
89 | 'Redirect release interrupts to a single CPU.'), | ||
90 | GenOption('duration', float, [30], 'Experiment duration.')] | ||
91 | |||
92 | def __create_dist(self, name, value, named_dists): | ||
93 | '''Attempt to create a distribution representing the data in @value. | ||
94 | If @value is a string, use it as a key for @named_dists.''' | ||
95 | name = "%s distribution" % name | ||
96 | # A list of values | ||
97 | if type(value) == type([]): | ||
98 | map(lambda x : self.__check_value(name, x, [float, int]), value) | ||
99 | return rv.uniform_choice(value) | ||
100 | elif type(value) in [float, int]: | ||
101 | return lambda : value | ||
102 | elif value in named_dists: | ||
103 | return named_dists[value] | ||
104 | else: | ||
105 | raise ValueError("Invalid %s value: %s" % (name, value)) | ||
106 | |||
107 | def __create_exp(self, exp_params, out_dir): | ||
108 | '''Create a single experiment with @exp_params in @out_dir.''' | ||
109 | pdist = self.__create_dist('period', | ||
110 | exp_params['periods'], | ||
111 | NAMED_PERIODS) | ||
112 | udist = self.__create_dist('utilization', | ||
113 | exp_params['utils'], | ||
114 | NAMED_UTILIZATIONS) | ||
115 | tg = tasks.TaskGenerator(period=pdist, util=udist) | ||
116 | |||
117 | ts = [] | ||
118 | tries = 0 | ||
119 | while len(ts) != exp_params['num_tasks'] and tries < 5: | ||
120 | ts = tg.make_task_set(max_tasks = exp_params['num_tasks']) | ||
121 | tries += 1 | ||
122 | if len(ts) != exp_params['num_tasks']: | ||
123 | print("Failed to create task set with parameters: %s" % exp_params) | ||
124 | |||
125 | self._customize(ts, exp_params) | ||
126 | |||
127 | sched_file = out_dir + "/" + DEFAULTS['sched_file'] | ||
128 | with open(sched_file, 'wa') as f: | ||
129 | exp_params['task_set'] = ts | ||
130 | f.write(str(Template(self.template, searchList=[exp_params]))) | ||
131 | |||
132 | del exp_params['task_set'] | ||
133 | del exp_params['num_tasks'] | ||
134 | exp_params_file = out_dir + "/" + DEFAULTS['params_file'] | ||
135 | with open(exp_params_file, 'wa') as f: | ||
136 | exp_params['scheduler'] = self.name | ||
137 | f.write(str(exp_params)) | ||
138 | |||
139 | def __setup_params(self, params): | ||
140 | '''Set default parameter values and check that values are valid.''' | ||
141 | for option in self.options: | ||
142 | if option.name not in params: | ||
143 | params[option.name] = option.default | ||
144 | params[option.name] = self._check_value(option.name, | ||
145 | option.types, | ||
146 | params[option.name]) | ||
147 | return params | ||
148 | |||
149 | |||
150 | def _check_value(self, name, types, val): | ||
151 | '''Raise an exception if the value of type of @val is not specified | ||
152 | in @types. Returns a copy of @val with strings converted to raw | ||
153 | Python types, if possible.''' | ||
154 | if types == float: | ||
155 | types = [float, int] | ||
156 | if type(types) != type([]): | ||
157 | types = [types] | ||
158 | if type(val) != type([]): | ||
159 | val = [val] | ||
160 | |||
161 | retval = [] | ||
162 | for v in val: | ||
163 | # Has to be a better way to find this | ||
164 | v = False if v in ['f', 'False', 'false', 'n', 'no'] else v | ||
165 | v = True if v in ['t', 'True', 'true', 'y', 'yes'] else v | ||
166 | |||
167 | if type(v) not in types and v not in types: | ||
168 | # Try and convert v to one of the specified types | ||
169 | parsed = None | ||
170 | for t in types: | ||
171 | try: | ||
172 | parsed = t(v) | ||
173 | break | ||
174 | except: | ||
175 | pass | ||
176 | |||
177 | if parsed: | ||
178 | retval += [parsed] | ||
179 | else: | ||
180 | raise TypeError("Invalid %s value: '%s'" % (name, v)) | ||
181 | else: | ||
182 | retval += [v] | ||
183 | return retval | ||
184 | |||
185 | def _customize(self, taskset, exp_params): | ||
186 | '''Configure a generated taskset with extra parameters.''' | ||
187 | pass | ||
188 | |||
189 | def create_exps(self, out_dir, force, trials): | ||
190 | '''Create experiments for all possible combinations of params in | ||
191 | @out_dir. Overwrite existing files if @force is True.''' | ||
192 | builder = ColMapBuilder() | ||
193 | |||
194 | # Track changing values so only relevant parameters are included | ||
195 | # in directory names | ||
196 | for dp in DesignPointGenerator(self.params): | ||
197 | for k, v in dp.iteritems(): | ||
198 | builder.try_add(k, v) | ||
199 | col_map = builder.build() | ||
200 | |||
201 | for dp in DesignPointGenerator(self.params): | ||
202 | for trial in xrange(trials): | ||
203 | # Create directory name from relevant parameters | ||
204 | dir_leaf = "sched=%s_%s" % (self.name, col_map.encode(dp)) | ||
205 | dir_leaf = dir_leaf.strip('_') # If there are none | ||
206 | dir_leaf += ("_trial=%s" % trial) if trials > 1 else "" | ||
207 | |||
208 | dir_path = "%s/%s" % (out_dir, dir_leaf.strip('_')) | ||
209 | |||
210 | if os.path.exists(dir_path): | ||
211 | if force: | ||
212 | sh.rmtree(dir_path) | ||
213 | else: | ||
214 | print("Skipping existing experiment: '%s'" % dir_path) | ||
215 | continue | ||
216 | |||
217 | os.mkdir(dir_path) | ||
218 | |||
219 | self.__create_exp(dict(dp), dir_path) | ||
220 | |||
221 | def print_help(self): | ||
222 | s = str(Template("""Generator $name: | ||
223 | #for $o in $options | ||
224 | $o.name -- $o.help | ||
225 | \tDefault: $o.default | ||
226 | \tAllowed: $o.types | ||
227 | #end for""", searchList=vars(self))) | ||
228 | |||
229 | # Has to be an easier way to print this out... | ||
230 | for line in s.split("\n"): | ||
231 | res = [] | ||
232 | i = 0 | ||
233 | for word in line.split(", "): | ||
234 | i+= len(word) | ||
235 | res += [word] | ||
236 | if i > 80: | ||
237 | print(", ".join(res[:-1])) | ||
238 | res = ["\t\t "+res[-1]] | ||
239 | i = line.index("'") | ||
240 | print(", ".join(res)) | ||
241 | |||
242 | class PartitionedGenerator(BaseGenerator): | ||
243 | def __init__(self, name, templates, options, params): | ||
244 | super(PartitionedGenerator, self).__init__(name, | ||
245 | templates + [TP_PART_TASK], options, params) | ||
246 | |||
247 | def _customize(self, taskset, exp_params): | ||
248 | start = 1 if exp_params['release_master'] else 0 | ||
249 | # Random partition for now: could do a smart partitioning | ||
250 | for t in taskset: | ||
251 | t.cpu = random.randint(start, exp_params['cpus'] - 1) | ||
252 | |||
253 | class PedfGenerator(PartitionedGenerator): | ||
254 | def __init__(self, params={}): | ||
255 | super(PedfGenerator, self).__init__("PSN-EDF", [], [], params) | ||
256 | |||
257 | class CedfGenerator(PartitionedGenerator): | ||
258 | LEVEL_OPTION = GenOption('level', ['L2', 'L3', 'All'], ['L2'], | ||
259 | 'Cache clustering level.',) | ||
260 | |||
261 | def __init__(self, params={}): | ||
262 | super(CedfGenerator, self).__init__("C-EDF", [TP_CLUSTER], | ||
263 | [CedfGenerator.LEVEL_OPTION], params) | ||
264 | |||
265 | class GedfGenerator(BaseGenerator): | ||
266 | def __init__(self, params={}): | ||
267 | super(GedfGenerator, self).__init__("GSN-EDF", [TP_GLOB_TASK], [], params) | ||