aboutsummaryrefslogtreecommitdiffstats
path: root/gen/generator.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/generator.py
parente5d531eabf3091af18ca1a331e52b184a67750f7 (diff)
Seperated BaseGenerator into EdfGenerator and its superclass Generator.
Diffstat (limited to 'gen/generator.py')
-rw-r--r--gen/generator.py222
1 files changed, 222 insertions, 0 deletions
diff --git a/gen/generator.py b/gen/generator.py
new file mode 100644
index 0000000..28a6387
--- /dev/null
+++ b/gen/generator.py
@@ -0,0 +1,222 @@
1import gen.rv as rv
2import os
3import run.litmus_util as lu
4import shutil as sh
5
6from Cheetah.Template import Template
7from collections import namedtuple
8from common import get_config_option
9from config.config import DEFAULTS
10from gen.dp import DesignPointGenerator
11from parse.col_map import ColMapBuilder
12
13NAMED_PERIODS = {
14 'harmonic' : rv.uniform_choice([25, 50, 100, 200]),
15 'uni-short' : rv.uniform_int( 3, 33),
16 'uni-moderate' : rv.uniform_int(10, 100),
17 'uni-long' : rv.uniform_int(50, 250),
18}
19
20NAMED_UTILIZATIONS = {
21 'uni-very-light': rv.uniform(0.0001, 0.001),
22 'uni-light' : rv.uniform(0.001, 0.1),
23 'uni-medium' : rv.uniform( 0.1, 0.4),
24 'uni-heavy' : rv.uniform( 0.5, 0.9),
25
26 'exp-light' : rv.exponential(0, 1, 0.10),
27 'exp-medium' : rv.exponential(0, 1, 0.25),
28 'exp-heavy' : rv.exponential(0, 1, 0.50),
29
30 'bimo-light' : rv.multimodal([(rv.uniform(0.001, 0.5), 8),
31 (rv.uniform( 0.5, 0.9), 1)]),
32 'bimo-medium' : rv.multimodal([(rv.uniform(0.001, 0.5), 6),
33 (rv.uniform( 0.5, 0.9), 3)]),
34 'bimo-heavy' : rv.multimodal([(rv.uniform(0.001, 0.5), 4),
35 (rv.uniform( 0.5, 0.9), 5)]),
36}
37
38'''Components of Cheetah template for schedule file'''
39TP_RM = """#if $release_master
40release_master{1}
41#end if"""
42TP_TBASE = """#for $t in $task_set
43{} $t.cost $t.period
44#end for"""
45TP_GLOB_TASK = TP_TBASE.format("")
46TP_PART_TASK = TP_TBASE.format("-p $t.cpu")
47
48GenOption = namedtuple('GenOption', ['name', 'types', 'default', 'help'])
49
50class Generator(object):
51 '''Creates all combinations @options specified by @params.
52
53 This class also performs checks of parameter values and prints out help.
54 All subclasses must implement _create_exp.
55 '''
56 def __init__(self, name, templates, options, params):
57 self.options = self.__make_options(params) + options
58
59 self.__setup_params(params)
60
61 self.params = params
62 self.template = "\n".join([TP_RM] + templates)
63 self.name = name
64
65 def __make_options(self, params):
66 '''Return generic Litmus options.'''
67
68 # Guess defaults using the properties of this computer
69 if 'cpus' in params:
70 cpus = min(map(int, params['cpus']))
71 else:
72 cpus = lu.num_cpus()
73 try:
74 config = get_config_option("RELEASE_MASTER") and True
75 except:
76 config = False
77 release_master = list(set([False, config]))
78
79
80 return [GenOption('cpus', int, [cpus],
81 'Number of processors on target system.'),
82 GenOption('release_master', [True,False], release_master,
83 'Redirect release interrupts to a single CPU.'),
84 GenOption('duration', float, [30], 'Experiment duration.')]
85
86 @staticmethod
87 def _dist_option(name, default, distribution, help):
88 return GenOption(name, [str, float, type([])] + distribution.keys(),
89 default, help)
90
91 def _create_dist(self, name, value, named_dists):
92 '''Attempt to create a distribution representing the data in @value.
93 If @value is a string, use it as a key for @named_dists.'''
94 name = "%s distribution" % name
95 # A list of values
96 if type(value) == type([]):
97 map(lambda x : self.__check_value(name, x, [float, int]), value)
98 return rv.uniform_choice(value)
99 elif type(value) in [float, int]:
100 return lambda : value
101 elif value in named_dists:
102 return named_dists[value]
103 else:
104 raise ValueError("Invalid %s value: %s" % (name, value))
105
106 def _write_schedule(self, params):
107 '''Write schedule file using current template for @params.'''
108 sched_file = self.out_dir + "/" + DEFAULTS['sched_file']
109 with open(sched_file, 'wa') as f:
110 f.write(str(Template(self.template, searchList=[params])))
111
112 def _write_params(self, params):
113 '''Write out file with relevant parameters.'''
114 exp_params_file = self.out_dir + "/" + DEFAULTS['params_file']
115 with open(exp_params_file, 'wa') as f:
116 params['scheduler'] = self.name
117 f.write(str(params))
118
119 def __setup_params(self, params):
120 '''Set default parameter values and check that values are valid.'''
121 for option in self.options:
122 if option.name not in params:
123 params[option.name] = option.default
124 params[option.name] = self._check_value(option.name,
125 option.types,
126 params[option.name])
127 return params
128
129
130 def _check_value(self, name, types, val):
131 '''Raise an exception if the value of type of @val is not specified
132 in @types. Returns a copy of @val with strings converted to raw
133 Python types, if possible.'''
134 if types == float:
135 types = [float, int]
136 if type(types) != type([]):
137 types = [types]
138 if type(val) != type([]):
139 val = [val]
140
141 retval = []
142 for v in val:
143 # Has to be a better way to find this
144 v = False if v in ['f', 'False', 'false', 'n', 'no'] else v
145 v = True if v in ['t', 'True', 'true', 'y', 'yes'] else v
146
147 if type(v) not in types and v not in types:
148 # Try and convert v to one of the specified types
149 parsed = None
150 for t in types:
151 try:
152 parsed = t(v)
153 break
154 except:
155 pass
156
157 if parsed:
158 retval += [parsed]
159 else:
160 raise TypeError("Invalid %s value: '%s'" % (name, v))
161 else:
162 retval += [v]
163 return retval
164
165 def _create_exp(self, exp_params, out_dir):
166 '''Overridden by subclasses.'''
167 raise NotImplementedError
168
169 def create_exps(self, out_dir, force, trials):
170 '''Create experiments for all possible combinations of params in
171 @out_dir. Overwrite existing files if @force is True.'''
172 builder = ColMapBuilder()
173
174 # Track changing values so only relevant parameters are included
175 # in directory names
176 for dp in DesignPointGenerator(self.params):
177 for k, v in dp.iteritems():
178 builder.try_add(k, v)
179 col_map = builder.build()
180
181 for dp in DesignPointGenerator(self.params):
182 for trial in xrange(trials):
183 # Create directory name from relevant parameters
184 dir_leaf = "sched=%s_%s" % (self.name, col_map.encode(dp))
185 dir_leaf = dir_leaf.strip('_') # If there are none
186 dir_leaf += ("_trial=%s" % trial) if trials > 1 else ""
187
188 dir_path = "%s/%s" % (out_dir, dir_leaf.strip('_'))
189
190 if os.path.exists(dir_path):
191 if force:
192 sh.rmtree(dir_path)
193 else:
194 print("Skipping existing experiment: '%s'" % dir_path)
195 continue
196
197 os.mkdir(dir_path)
198
199 self.out_dir = dir_path
200 self._create_exp(dict(dp))
201 del(self.out_dir)
202
203 def print_help(self):
204 s = str(Template("""Generator $name:
205 #for $o in $options
206 $o.name -- $o.help
207 \tDefault: $o.default
208 \tAllowed: $o.types
209 #end for""", searchList=vars(self)))
210
211 # Has to be an easier way to print this out...
212 for line in s.split("\n"):
213 res = []
214 i = 0
215 for word in line.split(", "):
216 i += len(word)
217 res += [word]
218 if i > 80:
219 print(", ".join(res[:-1]))
220 res = ["\t\t "+res[-1]]
221 i = line.index("'")
222 print(", ".join(res))