1# Copyright (c) 2005-2006 The Regents of The University of Michigan
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met: redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer;
8# redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27# Authors: Nathan Binkert
28
29import sys
30
31from attrdict import optiondict
32from misc import crossproduct
33
31class Data(object):
32 def __init__(self, name, desc, **kwargs):
33 self.name = name
34 self.desc = desc
35 self.__dict__.update(kwargs)
36
37 def update(self, obj):
38 if not isinstance(obj, Data):
39 raise AttributeError, "can only update from Data object"
40
41 for key,val in obj.__dict__.iteritems():
42 if key.startswith('_') or key in ('name', 'desc'):
43 continue
44
45 if key not in self.__dict__:
46 self.__dict__[key] = val
47 continue
48
49 if not isinstance(val, dict):
50 if self.__dict__[key] == val:
51 continue
52
53 raise AttributeError, \
54 "%s specified more than once old: %s new: %s" % \
55 (key, self.__dict__[key], val)
56
57 d = self.__dict__[key]
58 for k,v in val.iteritems():
59 if k in d:
60 raise AttributeError, \
61 "%s specified more than once in %s" % (k, key)
62 d[k] = v
63
64 if hasattr(self, 'system') and hasattr(obj, 'system'):
65 if self.system != obj.system:
66 raise AttributeError, \
67 "conflicting values for system: '%s'/'%s'" % \
68 (self.system, obj.system)
69
70 def printinfo(self):
71 if self.name:
72 print 'name: %s' % self.name
73 if self.desc:
74 print 'desc: %s' % self.desc
75 try:
76 if self.system:
77 print 'system: %s' % self.system
78 except AttributeError:
79 pass
80
81 def printverbose(self):
82 for key in self:
83 val = self[key]
84 if isinstance(val, dict):
85 import pprint
86 val = pprint.pformat(val)
87 print '%-20s = %s' % (key, val)
88 print
89
90 def __contains__(self, attr):
91 if attr.startswith('_'):
92 return False
93 return attr in self.__dict__
94
95 def __getitem__(self, key):
96 if key.startswith('_'):
97 raise KeyError, "Key '%s' not found" % attr
98 return self.__dict__[key]
99
100 def __iter__(self):
101 keys = self.__dict__.keys()
102 keys.sort()
103 for key in keys:
104 if not key.startswith('_'):
105 yield key
106
107 def optiondict(self):
111 result = optiondict()
108 import m5.util
109 result = m5.util.optiondict()
110 for key in self:
111 result[key] = self[key]
112 return result
113
114 def __repr__(self):
115 d = {}
116 for key,value in self.__dict__.iteritems():
117 if not key.startswith('_'):
118 d[key] = value
119
120 return "<%s: %s>" % (type(self).__name__, d)
121
122 def __str__(self):
123 return self.name
124
125class Job(Data):
126 def __init__(self, options):
127 super(Job, self).__init__('', '')
128
129 config = options[0]._config
130 for opt in options:
131 if opt._config != config:
132 raise AttributeError, \
133 "All options are not from the same Configuration"
134
135 self._config = config
136 self._groups = [ opt._group for opt in options ]
137 self._options = options
138
139 self.update(self._config)
140 for group in self._groups:
141 self.update(group)
142
143 self._is_checkpoint = True
144
145 for option in self._options:
146 self.update(option)
147 if not option._group._checkpoint:
148 self._is_checkpoint = False
149
150 if option._suboption:
151 self.update(option._suboption)
152 self._is_checkpoint = False
153
154 names = [ ]
155 for opt in self._options:
156 if opt.name:
157 names.append(opt.name)
158 self.name = ':'.join(names)
159
160 descs = [ ]
161 for opt in self._options:
162 if opt.desc:
163 descs.append(opt.desc)
164 self.desc = ', '.join(descs)
165
166 self._checkpoint = None
167 if not self._is_checkpoint:
168 opts = []
169 for opt in options:
170 cpt = opt._group._checkpoint
171 if not cpt:
172 continue
173 if isinstance(cpt, Option):
174 opt = cpt.clone(suboptions=False)
175 else:
176 opt = opt.clone(suboptions=False)
177
178 opts.append(opt)
179
180 if opts:
181 self._checkpoint = Job(opts)
182
183 def clone(self):
184 return Job(self._options)
185
186 def printinfo(self):
187 super(Job, self).printinfo()
188 if self._checkpoint:
189 print 'checkpoint: %s' % self._checkpoint.name
190 print 'config: %s' % self._config.name
191 print 'groups: %s' % [ g.name for g in self._groups ]
192 print 'options: %s' % [ o.name for o in self._options ]
193 super(Job, self).printverbose()
194
195class SubOption(Data):
196 def __init__(self, name, desc, **kwargs):
197 super(SubOption, self).__init__(name, desc, **kwargs)
198 self._number = None
199
200class Option(Data):
201 def __init__(self, name, desc, **kwargs):
202 super(Option, self).__init__(name, desc, **kwargs)
203 self._suboptions = []
204 self._suboption = None
205 self._number = None
206
207 def __getattribute__(self, attr):
208 if attr == 'name':
209 name = self.__dict__[attr]
210 if self._suboption is not None:
211 name = '%s:%s' % (name, self._suboption.name)
212 return name
213
214 if attr == 'desc':
215 desc = [ self.__dict__[attr] ]
216 if self._suboption is not None and self._suboption.desc:
217 desc.append(self._suboption.desc)
218 return ', '.join(desc)
219
220 return super(Option, self).__getattribute__(attr)
221
222 def suboption(self, name, desc, **kwargs):
223 subo = SubOption(name, desc, **kwargs)
224 subo._config = self._config
225 subo._group = self._group
226 subo._option = self
227 subo._number = len(self._suboptions)
228 self._suboptions.append(subo)
229 return subo
230
231 def clone(self, suboptions=True):
232 option = Option(self.__dict__['name'], self.__dict__['desc'])
233 option.update(self)
234 option._group = self._group
235 option._config = self._config
236 option._number = self._number
237 if suboptions:
238 option._suboptions.extend(self._suboptions)
239 option._suboption = self._suboption
240 return option
241
242 def subopts(self):
243 if not self._suboptions:
244 return [ self ]
245
246 subopts = []
247 for subo in self._suboptions:
248 option = self.clone()
249 option._suboption = subo
250 subopts.append(option)
251
252 return subopts
253
254 def printinfo(self):
255 super(Option, self).printinfo()
256 print 'config: %s' % self._config.name
257 super(Option, self).printverbose()
258
259class Group(Data):
260 def __init__(self, name, desc, **kwargs):
261 super(Group, self).__init__(name, desc, **kwargs)
262 self._options = []
263 self._number = None
264 self._checkpoint = False
265
266 def option(self, name, desc, **kwargs):
267 opt = Option(name, desc, **kwargs)
268 opt._config = self._config
269 opt._group = self
270 opt._number = len(self._options)
271 self._options.append(opt)
272 return opt
273
274 def options(self):
275 return self._options
276
277 def subopts(self):
278 subopts = []
279 for opt in self._options:
280 for subo in opt.subopts():
281 subopts.append(subo)
282 return subopts
283
284 def printinfo(self):
285 super(Group, self).printinfo()
286 print 'config: %s' % self._config.name
287 print 'options: %s' % [ o.name for o in self._options ]
288 super(Group, self).printverbose()
289
290class Configuration(Data):
291 def __init__(self, name, desc, **kwargs):
292 super(Configuration, self).__init__(name, desc, **kwargs)
293 self._groups = []
294 self._posfilters = []
295 self._negfilters = []
296
297 def group(self, name, desc, **kwargs):
298 grp = Group(name, desc, **kwargs)
299 grp._config = self
300 grp._number = len(self._groups)
301 self._groups.append(grp)
302 return grp
303
304 def groups(self):
305 return self._groups
306
307 def checkchildren(self, kids):
308 for kid in kids:
309 if kid._config != self:
310 raise AttributeError, "child from the wrong configuration"
311
312 def sortgroups(self, groups):
313 groups = [ (grp._number, grp) for grp in groups ]
314 groups.sort()
315 return [ grp[1] for grp in groups ]
316
317 def options(self, groups=None, checkpoint=False):
318 if groups is None:
319 groups = self._groups
320 self.checkchildren(groups)
321 groups = self.sortgroups(groups)
322 if checkpoint:
323 groups = [ grp for grp in groups if grp._checkpoint ]
324 optgroups = [ g.options() for g in groups ]
325 else:
326 optgroups = [ g.subopts() for g in groups ]
327 if not optgroups:
328 return
331 for options in crossproduct(optgroups):
329
330 import m5.util
331 for options in m5.util.crossproduct(optgroups):
332 for opt in options:
333 cpt = opt._group._checkpoint
334 if not isinstance(cpt, bool) and cpt != opt:
335 if checkpoint:
336 break
337 else:
338 yield options
339 else:
340 if checkpoint:
341 yield options
342
343 def addfilter(self, filt, pos=True):
344 import re
345 filt = re.compile(filt)
346 if pos:
347 self._posfilters.append(filt)
348 else:
349 self._negfilters.append(filt)
350
351 def jobfilter(self, job):
352 for filt in self._negfilters:
353 if filt.match(job.name):
354 return False
355
356 if not self._posfilters:
357 return True
358
359 for filt in self._posfilters:
360 if filt.match(job.name):
361 return True
362
363 return False
364
365 def checkpoints(self, groups=None):
366 for options in self.options(groups, True):
367 job = Job(options)
368 if self.jobfilter(job):
369 yield job
370
371 def jobs(self, groups=None):
372 for options in self.options(groups, False):
373 job = Job(options)
374 if self.jobfilter(job):
375 yield job
376
377 def alljobs(self, groups=None):
378 for options in self.options(groups, True):
379 yield Job(options)
380 for options in self.options(groups, False):
381 yield Job(options)
382
383 def find(self, jobname):
384 for job in self.alljobs():
385 if job.name == jobname:
386 return job
387 else:
388 raise AttributeError, "job '%s' not found" % jobname
389
390 def job(self, options):
391 self.checkchildren(options)
392 options = [ (opt._group._number, opt) for opt in options ]
393 options.sort()
394 options = [ opt[1] for opt in options ]
395 job = Job(options)
396 return job
397
398 def printinfo(self):
399 super(Configuration, self).printinfo()
400 print 'groups: %s' % [ g.name for g in self._groups ]
401 super(Configuration, self).printverbose()
402
403def JobFile(jobfile):
404 from os.path import expanduser, isfile, join as joinpath
405 filename = expanduser(jobfile)
406
407 # Can't find filename in the current path, search sys.path
408 if not isfile(filename):
409 for path in sys.path:
410 testname = joinpath(path, filename)
411 if isfile(testname):
412 filename = testname
413 break
414 else:
415 raise AttributeError, \
416 "Could not find file '%s'" % jobfile
417
418 data = {}
419 execfile(filename, data)
420 if 'conf' not in data:
421 raise ImportError, 'cannot import name conf from %s' % jobfile
422 return data['conf']
423
424def main(conf=None):
425 usage = 'Usage: %s [-b] [-c] [-v]' % sys.argv[0]
426 if conf is None:
427 usage += ' <jobfile>'
428
429 try:
430 import getopt
431 opts, args = getopt.getopt(sys.argv[1:], '-bcv')
432 except getopt.GetoptError:
433 sys.exit(usage)
434
435 both = False
436 checkpoint = False
437 verbose = False
438 for opt,arg in opts:
439 if opt == '-b':
440 both = True
441 checkpoint = True
442 if opt == '-c':
443 checkpoint = True
444 if opt == '-v':
445 verbose = True
446
447 if conf is None:
448 if len(args) != 1:
449 raise AttributeError, usage
450 conf = JobFile(args[0])
451 else:
452 if len(args) != 0:
453 raise AttributeError, usage
454
455 if both:
456 jobs = conf.alljobs()
457 elif checkpoint:
458 jobs = conf.checkpoints()
459 else:
460 jobs = conf.jobs()
461
462 for job in jobs:
463 if verbose:
464 job.printinfo()
465 else:
466 cpt = ''
467 if job._checkpoint:
468 cpt = job._checkpoint.name
469 print job.name, cpt
470
471if __name__ == '__main__':
472 main()