jobfile.py revision 6654
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 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): 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 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() 473