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 29from __future__ import print_function 30from __future__ import absolute_import 31 32import sys 33 34class Data(object): 35 def __init__(self, name, desc, **kwargs): 36 self.name = name 37 self.desc = desc 38 self.__dict__.update(kwargs) 39 40 def update(self, obj): 41 if not isinstance(obj, Data): 42 raise AttributeError("can only update from Data object") 43 44 for key,val in obj.__dict__.items(): 45 if key.startswith('_') or key in ('name', 'desc'): 46 continue 47 48 if key not in self.__dict__: 49 self.__dict__[key] = val 50 continue 51 52 if not isinstance(val, dict): 53 if self.__dict__[key] == val: 54 continue 55 56 raise AttributeError( 57 "%s specified more than once old: %s new: %s" % \ 58 (key, self.__dict__[key], val)) 59 60 d = self.__dict__[key] 61 for k,v in val.items(): 62 if k in d: 63 raise AttributeError( 64 "%s specified more than once in %s" % (k, key)) 65 d[k] = v 66 67 if hasattr(self, 'system') and hasattr(obj, 'system'): 68 if self.system != obj.system: 69 raise AttributeError( 70 "conflicting values for system: '%s'/'%s'" % \ 71 (self.system, obj.system)) 72 73 def printinfo(self): 74 if self.name: 75 print('name: %s' % self.name) 76 if self.desc: 77 print('desc: %s' % self.desc) 78 try: 79 if self.system: 80 print('system: %s' % self.system) 81 except AttributeError: 82 pass 83 84 def printverbose(self): 85 for key in self: 86 val = self[key] 87 if isinstance(val, dict): 88 import pprint 89 val = pprint.pformat(val) 90 print('%-20s = %s' % (key, val)) 91 print() 92 93 def __contains__(self, attr): 94 if attr.startswith('_'): 95 return False 96 return attr in self.__dict__ 97 98 def __getitem__(self, key): 99 if key.startswith('_'): 100 raise KeyError("Key '%s' not found" % attr) 101 return self.__dict__[key] 102 103 def __iter__(self): 104 keys = list(self.__dict__.keys()) 105 keys.sort() 106 for key in keys: 107 if not key.startswith('_'): 108 yield key 109 110 def optiondict(self): 111 import m5.util 112 result = m5.util.optiondict() 113 for key in self: 114 result[key] = self[key] 115 return result 116 117 def __repr__(self): 118 d = {} 119 for key,value in self.__dict__.items(): 120 if not key.startswith('_'): 121 d[key] = value 122 123 return "<%s: %s>" % (type(self).__name__, d) 124 125 def __str__(self): 126 return self.name 127 128class Job(Data): 129 def __init__(self, options): 130 super(Job, self).__init__('', '') 131 132 config = options[0]._config 133 for opt in options: 134 if opt._config != config: 135 raise AttributeError( 136 "All options are not from the same Configuration") 137 138 self._config = config 139 self._groups = [ opt._group for opt in options ] 140 self._options = options 141 142 self.update(self._config) 143 for group in self._groups: 144 self.update(group) 145 146 self._is_checkpoint = True 147 148 for option in self._options: 149 self.update(option) 150 if not option._group._checkpoint: 151 self._is_checkpoint = False 152 153 if option._suboption: 154 self.update(option._suboption) 155 self._is_checkpoint = False 156 157 names = [ ] 158 for opt in self._options: 159 if opt.name: 160 names.append(opt.name) 161 self.name = ':'.join(names) 162 163 descs = [ ] 164 for opt in self._options: 165 if opt.desc: 166 descs.append(opt.desc) 167 self.desc = ', '.join(descs) 168 169 self._checkpoint = None 170 if not self._is_checkpoint: 171 opts = [] 172 for opt in options: 173 cpt = opt._group._checkpoint 174 if not cpt: 175 continue 176 if isinstance(cpt, Option): 177 opt = cpt.clone(suboptions=False) 178 else: 179 opt = opt.clone(suboptions=False) 180 181 opts.append(opt) 182 183 if opts: 184 self._checkpoint = Job(opts) 185 186 def clone(self): 187 return Job(self._options) 188 189 def printinfo(self): 190 super(Job, self).printinfo() 191 if self._checkpoint: 192 print('checkpoint: %s' % self._checkpoint.name) 193 print('config: %s' % self._config.name) 194 print('groups: %s' % [ g.name for g in self._groups ]) 195 print('options: %s' % [ o.name for o in self._options ]) 196 super(Job, self).printverbose() 197 198class SubOption(Data): 199 def __init__(self, name, desc, **kwargs): 200 super(SubOption, self).__init__(name, desc, **kwargs) 201 self._number = None 202 203class Option(Data): 204 def __init__(self, name, desc, **kwargs): 205 super(Option, self).__init__(name, desc, **kwargs) 206 self._suboptions = [] 207 self._suboption = None 208 self._number = None 209 210 def __getattribute__(self, attr): 211 if attr == 'name': 212 name = self.__dict__[attr] 213 if self._suboption is not None: 214 name = '%s:%s' % (name, self._suboption.name) 215 return name 216 217 if attr == 'desc': 218 desc = [ self.__dict__[attr] ] 219 if self._suboption is not None and self._suboption.desc: 220 desc.append(self._suboption.desc) 221 return ', '.join(desc) 222 223 return super(Option, self).__getattribute__(attr) 224 225 def suboption(self, name, desc, **kwargs): 226 subo = SubOption(name, desc, **kwargs) 227 subo._config = self._config 228 subo._group = self._group 229 subo._option = self 230 subo._number = len(self._suboptions) 231 self._suboptions.append(subo) 232 return subo 233 234 def clone(self, suboptions=True): 235 option = Option(self.__dict__['name'], self.__dict__['desc']) 236 option.update(self) 237 option._group = self._group 238 option._config = self._config 239 option._number = self._number 240 if suboptions: 241 option._suboptions.extend(self._suboptions) 242 option._suboption = self._suboption 243 return option 244 245 def subopts(self): 246 if not self._suboptions: 247 return [ self ] 248 249 subopts = [] 250 for subo in self._suboptions: 251 option = self.clone() 252 option._suboption = subo 253 subopts.append(option) 254 255 return subopts 256 257 def printinfo(self): 258 super(Option, self).printinfo() 259 print('config: %s' % self._config.name) 260 super(Option, self).printverbose() 261 262class Group(Data): 263 def __init__(self, name, desc, **kwargs): 264 super(Group, self).__init__(name, desc, **kwargs) 265 self._options = [] 266 self._number = None 267 self._checkpoint = False 268 269 def option(self, name, desc, **kwargs): 270 opt = Option(name, desc, **kwargs) 271 opt._config = self._config 272 opt._group = self 273 opt._number = len(self._options) 274 self._options.append(opt) 275 return opt 276 277 def options(self): 278 return self._options 279 280 def subopts(self): 281 subopts = [] 282 for opt in self._options: 283 for subo in opt.subopts(): 284 subopts.append(subo) 285 return subopts 286 287 def printinfo(self): 288 super(Group, self).printinfo() 289 print('config: %s' % self._config.name) 290 print('options: %s' % [ o.name for o in self._options ]) 291 super(Group, self).printverbose() 292 293class Configuration(Data): 294 def __init__(self, name, desc, **kwargs): 295 super(Configuration, self).__init__(name, desc, **kwargs) 296 self._groups = [] 297 self._posfilters = [] 298 self._negfilters = [] 299 300 def group(self, name, desc, **kwargs): 301 grp = Group(name, desc, **kwargs) 302 grp._config = self 303 grp._number = len(self._groups) 304 self._groups.append(grp) 305 return grp 306 307 def groups(self): 308 return self._groups 309 310 def checkchildren(self, kids): 311 for kid in kids: 312 if kid._config != self: 313 raise AttributeError("child from the wrong configuration") 314 315 def sortgroups(self, groups): 316 groups = [ (grp._number, grp) for grp in groups ] 317 groups.sort() 318 return [ grp[1] for grp in groups ] 319 320 def options(self, groups=None, checkpoint=False): 321 if groups is None: 322 groups = self._groups 323 self.checkchildren(groups) 324 groups = self.sortgroups(groups) 325 if checkpoint: 326 groups = [ grp for grp in groups if grp._checkpoint ] 327 optgroups = [ g.options() for g in groups ] 328 else: 329 optgroups = [ g.subopts() for g in groups ] 330 if not optgroups: 331 return 332 333 import m5.util 334 for options in m5.util.crossproduct(optgroups): 335 for opt in options: 336 cpt = opt._group._checkpoint 337 if not isinstance(cpt, bool) and cpt != opt: 338 if checkpoint: 339 break 340 else: 341 yield options 342 else: 343 if checkpoint: 344 yield options 345 346 def addfilter(self, filt, pos=True): 347 import re 348 filt = re.compile(filt) 349 if pos: 350 self._posfilters.append(filt) 351 else: 352 self._negfilters.append(filt) 353 354 def jobfilter(self, job): 355 for filt in self._negfilters: 356 if filt.match(job.name): 357 return False 358 359 if not self._posfilters: 360 return True 361 362 for filt in self._posfilters: 363 if filt.match(job.name): 364 return True 365 366 return False 367 368 def checkpoints(self, groups=None): 369 for options in self.options(groups, True): 370 job = Job(options) 371 if self.jobfilter(job): 372 yield job 373 374 def jobs(self, groups=None): 375 for options in self.options(groups, False): 376 job = Job(options) 377 if self.jobfilter(job): 378 yield job 379 380 def alljobs(self, groups=None): 381 for options in self.options(groups, True): 382 yield Job(options) 383 for options in self.options(groups, False): 384 yield Job(options) 385 386 def find(self, jobname): 387 for job in self.alljobs(): 388 if job.name == jobname: 389 return job 390 else: 391 raise AttributeError("job '%s' not found" % jobname) 392 393 def job(self, options): 394 self.checkchildren(options) 395 options = [ (opt._group._number, opt) for opt in options ] 396 options.sort() 397 options = [ opt[1] for opt in options ] 398 job = Job(options) 399 return job 400 401 def printinfo(self): 402 super(Configuration, self).printinfo() 403 print('groups: %s' % [ g.name for g in self._groups ]) 404 super(Configuration, self).printverbose() 405 406def JobFile(jobfile): 407 from os.path import expanduser, isfile, join as joinpath 408 filename = expanduser(jobfile) 409 410 # Can't find filename in the current path, search sys.path 411 if not isfile(filename): 412 for path in sys.path: 413 testname = joinpath(path, filename) 414 if isfile(testname): 415 filename = testname 416 break 417 else: 418 raise AttributeError("Could not find file '%s'" % jobfile) 419 420 data = {} 421 exec(compile(open(filename).read(), filename, 'exec'), data) 422 if 'conf' not in data: 423 raise ImportError('cannot import name conf from %s' % jobfile) 424 return data['conf'] 425 426def main(conf=None): 427 usage = 'Usage: %s [-b] [-c] [-v]' % sys.argv[0] 428 if conf is None: 429 usage += ' <jobfile>' 430 431 try: 432 import getopt 433 opts, args = getopt.getopt(sys.argv[1:], '-bcv') 434 except getopt.GetoptError: 435 sys.exit(usage) 436 437 both = False 438 checkpoint = False 439 verbose = False 440 for opt,arg in opts: 441 if opt == '-b': 442 both = True 443 checkpoint = True 444 if opt == '-c': 445 checkpoint = True 446 if opt == '-v': 447 verbose = True 448 449 if conf is None: 450 if len(args) != 1: 451 raise AttributeError(usage) 452 conf = JobFile(args[0]) 453 else: 454 if len(args) != 0: 455 raise AttributeError(usage) 456 457 if both: 458 jobs = conf.alljobs() 459 elif checkpoint: 460 jobs = conf.checkpoints() 461 else: 462 jobs = conf.jobs() 463 464 for job in jobs: 465 if verbose: 466 job.printinfo() 467 else: 468 cpt = '' 469 if job._checkpoint: 470 cpt = job._checkpoint.name 471 print(job.name, cpt) 472 473if __name__ == '__main__': 474 main() 475