aboutsummaryrefslogtreecommitdiffstats
path: root/gen/generators.py
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-03-07 14:51:32 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-03-07 14:51:32 -0500
commite3b7c78aa5b96af6bdbad20a13e0f540d1658b7f (patch)
treedc9590fb22e5d6484088d2c730b8eeea8db6a7b0 /gen/generators.py
parente5d531eabf3091af18ca1a331e52b184a67750f7 (diff)
Seperated BaseGenerator into EdfGenerator and its superclass Generator.
Diffstat (limited to 'gen/generators.py')
-rw-r--r--gen/generators.py267
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 @@
1from Cheetah.Template import Template
2from collections import namedtuple
3from common import get_config_option
4from config.config import DEFAULTS
5from gen.dp import DesignPointGenerator
6from parse.col_map import ColMapBuilder
7
8import gen.rv as rv
9import os
10import random
11import run.litmus_util as lu
12import schedcat.generator.tasks as tasks
13import shutil as sh
14
15NAMED_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
22NAMED_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
41TP_CLUSTER = "plugins/C-EDF/cluster{$level}"
42TP_RM = """#if $release_master
43release_master{1}
44#end if"""
45TP_TBASE = """#for $t in $task_set
46{}$t.cost $t.period
47#end for"""
48TP_PART_TASK = TP_TBASE.format("-p $t.cpu ")
49TP_GLOB_TASK = TP_TBASE.format("")
50
51GenOption = namedtuple('GenOption', ['name', 'types', 'default', 'help'])
52
53class 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
242class 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
253class PedfGenerator(PartitionedGenerator):
254 def __init__(self, params={}):
255 super(PedfGenerator, self).__init__("PSN-EDF", [], [], params)
256
257class 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
265class GedfGenerator(BaseGenerator):
266 def __init__(self, params={}):
267 super(GedfGenerator, self).__init__("GSN-EDF", [TP_GLOB_TASK], [], params)