48import argparse 49import ConfigParser 50import inspect 51import json 52import re 53import sys 54 55import m5 56import m5.ticks as ticks 57 58sim_object_classes_by_name = { 59 cls.__name__: cls for cls in m5.objects.__dict__.itervalues() 60 if inspect.isclass(cls) and issubclass(cls, m5.objects.SimObject) } 61 62# Add some parsing functions to Param classes to handle reading in .ini 63# file elements. This could be moved into src/python/m5/params.py if 64# reading .ini files from Python proves to be useful 65 66def no_parser(cls, flags, param): 67 raise Exception('Can\'t parse string: %s for parameter' 68 ' class: %s' % (str(param), cls.__name__)) 69 70def simple_parser(suffix='', cast=lambda i: i): 71 def body(cls, flags, param): 72 return cls(cast(param + suffix)) 73 return body 74 75# def tick_parser(cast=m5.objects.Latency): # lambda i: i): 76def tick_parser(cast=lambda i: i): 77 def body(cls, flags, param): 78 old_param = param 79 ret = cls(cast(str(param) + 't')) 80 return ret 81 return body 82 83def addr_range_parser(cls, flags, param): 84 sys.stdout.flush() 85 (low, high, intlv_high_bit, xor_high_bit, 86 intlv_bits, intlv_match) = param.split(':') 87 return m5.objects.AddrRange( 88 start=long(low), end=long(high), 89 intlvHighBit=long(intlv_high_bit), xorHighBit=long(xor_high_bit), 90 intlvBits=long(intlv_bits), intlvMatch=long(intlv_match)) 91 92def memory_bandwidth_parser(cls, flags, param): 93 # The string will be in tick/byte 94 # Convert to byte/tick 95 value = 1.0 / float(param) 96 # Convert to byte/s 97 value = ticks.fromSeconds(value) 98 return cls('%fB/s' % value) 99 100# These parameters have trickier parsing from .ini files than might be 101# expected 102param_parsers = { 103 'Bool': simple_parser(), 104 'ParamValue': no_parser, 105 'NumericParamValue': simple_parser(cast=long), 106 'TickParamValue': tick_parser(), 107 'Frequency': tick_parser(cast=m5.objects.Latency), 108 'Current': simple_parser(suffix='A'), 109 'Voltage': simple_parser(suffix='V'), 110 'Enum': simple_parser(), 111 'MemorySize': simple_parser(suffix='B'), 112 'MemorySize32': simple_parser(suffix='B'), 113 'AddrRange': addr_range_parser, 114 'String': simple_parser(), 115 'MemoryBandwidth': memory_bandwidth_parser, 116 'Time': simple_parser(), 117 'EthernetAddr': simple_parser() 118 } 119 120for name, parser in param_parsers.iteritems(): 121 setattr(m5.params.__dict__[name], 'parse_ini', classmethod(parser)) 122 123class PortConnection(object): 124 """This class is similar to m5.params.PortRef but with just enough 125 information for ConfigManager""" 126 127 def __init__(self, object_name, port_name, index): 128 self.object_name = object_name 129 self.port_name = port_name 130 self.index = index 131 132 @classmethod 133 def from_string(cls, str): 134 m = re.match('(.*)\.([^.\[]+)(\[(\d+)\])?', str) 135 object_name, port_name, whole_index, index = m.groups() 136 if index is not None: 137 index = int(index) 138 else: 139 index = 0 140 141 return PortConnection(object_name, port_name, index) 142 143 def __str__(self): 144 return '%s.%s[%d]' % (self.object_name, self.port_name, self.index) 145 146 def __cmp__(self, right): 147 return cmp((self.object_name, self.port_name, self.index), 148 (right.object_name, right.port_name, right.index)) 149 150def to_list(v): 151 """Convert any non list to a singleton list""" 152 if isinstance(v, list): 153 return v 154 else: 155 return [v] 156 157class ConfigManager(object): 158 """Manager for parsing a Root configuration from a config file""" 159 def __init__(self, config): 160 self.config = config 161 self.objects_by_name = {} 162 self.flags = config.get_flags() 163 164 def find_object(self, object_name): 165 """Find and configure (with just non-SimObject parameters) 166 a single object""" 167 168 if object_name == 'Null': 169 return NULL 170 171 if object_name in self.objects_by_name: 172 return self.objects_by_name[object_name] 173 174 object_type = self.config.get_param(object_name, 'type') 175 176 if object_type not in sim_object_classes_by_name: 177 raise Exception('No SimObject type %s is available to' 178 ' build: %s' % (object_type, object_name)) 179 180 object_class = sim_object_classes_by_name[object_type] 181 182 parsed_params = {} 183 184 for param_name, param in object_class._params.iteritems(): 185 if issubclass(param.ptype, m5.params.ParamValue): 186 if isinstance(param, m5.params.VectorParamDesc): 187 param_values = self.config.get_param_vector(object_name, 188 param_name) 189 190 param_value = [ param.ptype.parse_ini(self.flags, value) 191 for value in param_values ] 192 else: 193 param_value = param.ptype.parse_ini( 194 self.flags, self.config.get_param(object_name, 195 param_name)) 196 197 parsed_params[param_name] = param_value 198 199 obj = object_class(**parsed_params) 200 self.objects_by_name[object_name] = obj 201 202 return obj 203 204 def fill_in_simobj_parameters(self, object_name, obj): 205 """Fill in all references to other SimObjects in an objects 206 parameters. This relies on all referenced objects having been 207 created""" 208 209 if object_name == 'Null': 210 return NULL 211 212 for param_name, param in obj.__class__._params.iteritems(): 213 if issubclass(param.ptype, m5.objects.SimObject): 214 if isinstance(param, m5.params.VectorParamDesc): 215 param_values = self.config.get_param_vector(object_name, 216 param_name) 217 218 setattr(obj, param_name, 219 [ self.objects_by_name[name] 220 if name != 'Null' else m5.params.NULL 221 for name in param_values ]) 222 else: 223 param_value = self.config.get_param(object_name, 224 param_name) 225 226 if param_value != 'Null': 227 setattr(obj, param_name, self.objects_by_name[ 228 param_value]) 229 230 return obj 231 232 def fill_in_children(self, object_name, obj): 233 """Fill in the children of this object. This relies on all the 234 referenced objects having been created""" 235 236 children = self.config.get_object_children(object_name) 237 238 for child_name, child_paths in children: 239 param = obj.__class__._params.get(child_name, None) 240 if child_name == 'Null': 241 continue 242 243 if isinstance(child_paths, list): 244 child_list = [ self.objects_by_name[path] 245 for path in child_paths ] 246 else: 247 child_list = self.objects_by_name[child_paths] 248 249 obj.add_child(child_name, child_list) 250 251 for path in to_list(child_paths): 252 self.fill_in_children(path, self.objects_by_name[path]) 253 254 return obj 255 256 def parse_port_name(self, port): 257 """Parse the name of a port""" 258 259 m = re.match('(.*)\.([^.\[]+)(\[(\d+)\])?', port) 260 peer, peer_port, whole_index, index = m.groups() 261 if index is not None: 262 index = int(index) 263 else: 264 index = 0 265 266 return (peer, self.objects_by_name[peer], peer_port, index) 267 268 def gather_port_connections(self, object_name, obj): 269 """Gather all the port-to-port connections from the named object. 270 Returns a list of (PortConnection, PortConnection) with unordered 271 (wrt. master/slave) connection information""" 272 273 if object_name == 'Null': 274 return NULL 275 276 parsed_ports = [] 277 for port_name, port in obj.__class__._ports.iteritems(): 278 # Assume that unnamed ports are unconnected 279 peers = self.config.get_port_peers(object_name, port_name) 280 281 for index, peer in zip(xrange(0, len(peers)), peers): 282 parsed_ports.append(( 283 PortConnection(object_name, port.name, index), 284 PortConnection.from_string(peer))) 285 286 return parsed_ports 287 288 def bind_ports(self, connections): 289 """Bind all ports from the given connection list. Note that the 290 connection list *must* list all connections with both (slave,master) 291 and (master,slave) orderings""" 292 293 # Markup a dict of how many connections are made to each port. 294 # This will be used to check that the next-to-be-made connection 295 # has a suitable port index 296 port_bind_indices = {} 297 for from_port, to_port in connections: 298 port_bind_indices[ 299 (from_port.object_name, from_port.port_name)] = 0 300 301 def port_has_correct_index(port): 302 return port_bind_indices[ 303 (port.object_name, port.port_name)] == port.index 304 305 def increment_port_index(port): 306 port_bind_indices[ 307 (port.object_name, port.port_name)] += 1 308 309 # Step through the sorted connections. Exactly one of 310 # each (slave,master) and (master,slave) pairs will be 311 # bindable because the connections are sorted. 312 # For example: port_bind_indices 313 # left right left right 314 # a.b[0] -> d.f[1] 0 0 X 315 # a.b[1] -> e.g 0 0 BIND! 316 # e.g -> a.b[1] 1 X 0 317 # d.f[0] -> f.h 0 0 BIND! 318 # d.f[1] -> a.b[0] 1 0 BIND! 319 connections_to_make = [] 320 for connection in sorted(connections): 321 from_port, to_port = connection 322 323 if (port_has_correct_index(from_port) and 324 port_has_correct_index(to_port)): 325 326 connections_to_make.append((from_port, to_port)) 327 328 increment_port_index(from_port) 329 increment_port_index(to_port) 330 331 # Exactly half of the connections (ie. all of them, one per 332 # direction) must now have been made 333 if (len(connections_to_make) * 2) != len(connections): 334 raise Exception('Port bindings can\'t be ordered') 335 336 # Actually do the binding 337 for from_port, to_port in connections_to_make: 338 from_object = self.objects_by_name[from_port.object_name] 339 to_object = self.objects_by_name[to_port.object_name] 340 341 setattr(from_object, from_port.port_name, 342 getattr(to_object, to_port.port_name)) 343 344 def find_all_objects(self): 345 """Find and build all SimObjects from the config file and connect 346 their ports together as described. Does not instantiate system""" 347 348 # Build SimObjects for all sections of the config file 349 # populating not-SimObject-valued parameters 350 for object_name in self.config.get_all_object_names(): 351 self.find_object(object_name) 352 353 # Add children to objects in the hierarchy from root 354 self.fill_in_children('root', self.find_object('root')) 355 356 # Now fill in SimObject-valued parameters in the knowledge that 357 # this won't be interpreted as becoming the parent of objects 358 # which are already in the root hierarchy 359 for name, obj in self.objects_by_name.iteritems(): 360 self.fill_in_simobj_parameters(name, obj) 361 362 # Gather a list of all port-to-port connections 363 connections = [] 364 for name, obj in self.objects_by_name.iteritems(): 365 connections += self.gather_port_connections(name, obj) 366 367 # Find an acceptable order to bind those port connections and 368 # bind them 369 self.bind_ports(connections) 370 371class ConfigFile(object): 372 def get_flags(self): 373 return set() 374 375 def load(self, config_file): 376 """Load the named config file""" 377 pass 378 379 def get_all_object_names(self): 380 """Get a list of all the SimObject paths in the configuration""" 381 pass 382 383 def get_param(self, object_name, param_name): 384 """Get a single param or SimObject reference from the configuration 385 as a string""" 386 pass 387 388 def get_param_vector(self, object_name, param_name): 389 """Get a vector param or vector of SimObject references from the 390 configuration as a list of strings""" 391 pass 392 393 def get_object_children(self, object_name): 394 """Get a list of (name, paths) for each child of this object. 395 paths is either a single string object path or a list of object 396 paths""" 397 pass 398 399 def get_port_peers(self, object_name, port_name): 400 """Get the list of connected port names (in the string form 401 object.port(\[index\])?) of the port object_name.port_name""" 402 pass 403 404class ConfigIniFile(ConfigFile): 405 def __init__(self): 406 self.parser = ConfigParser.ConfigParser() 407 408 def load(self, config_file): 409 self.parser.read(config_file) 410 411 def get_all_object_names(self): 412 return self.parser.sections() 413 414 def get_param(self, object_name, param_name): 415 return self.parser.get(object_name, param_name) 416 417 def get_param_vector(self, object_name, param_name): 418 return self.parser.get(object_name, param_name).split() 419 420 def get_object_children(self, object_name): 421 if self.parser.has_option(object_name, 'children'): 422 children = self.parser.get(object_name, 'children') 423 child_names = children.split() 424 else: 425 child_names = [] 426 427 def make_path(child_name): 428 if object_name == 'root': 429 return child_name 430 else: 431 return '%s.%s' % (object_name, child_name) 432 433 return [ (name, make_path(name)) for name in child_names ] 434 435 def get_port_peers(self, object_name, port_name): 436 if self.parser.has_option(object_name, port_name): 437 peer_string = self.parser.get(object_name, port_name) 438 return peer_string.split() 439 else: 440 return [] 441 442class ConfigJsonFile(ConfigFile): 443 def __init__(self): 444 pass 445 446 def is_sim_object(self, node): 447 return isinstance(node, dict) and 'path' in node 448 449 def find_all_objects(self, node): 450 if self.is_sim_object(node): 451 self.object_dicts[node['path']] = node 452 453 if isinstance(node, list): 454 for elem in node: 455 self.find_all_objects(elem) 456 elif isinstance(node, dict): 457 for elem in node.itervalues(): 458 self.find_all_objects(elem) 459 460 def load(self, config_file): 461 root = json.load(open(config_file, 'r')) 462 self.object_dicts = {} 463 self.find_all_objects(root) 464 465 def get_all_object_names(self): 466 return sorted(self.object_dicts.keys()) 467 468 def parse_param_string(self, node): 469 if node is None: 470 return "Null" 471 elif self.is_sim_object(node): 472 return node['path'] 473 else: 474 return str(node) 475 476 def get_param(self, object_name, param_name): 477 obj = self.object_dicts[object_name] 478 479 return self.parse_param_string(obj[param_name]) 480 481 def get_param_vector(self, object_name, param_name): 482 obj = self.object_dicts[object_name] 483 484 return [ self.parse_param_string(p) for p in obj[param_name] ] 485 486 def get_object_children(self, object_name): 487 """It is difficult to tell which elements are children in the 488 JSON file as there is no explicit 'children' node. Take any 489 element which is a full SimObject description or a list of 490 SimObject descriptions. This will not work with a mixed list of 491 references and descriptions but that's a scenario that isn't 492 possible (very likely?) with gem5's binding/naming rules""" 493 obj = self.object_dicts[object_name] 494 495 children = [] 496 for name, node in obj.iteritems(): 497 if self.is_sim_object(node): 498 children.append((name, node['path'])) 499 elif isinstance(node, list) and node != [] and all([ 500 self.is_sim_object(e) for e in node ]): 501 children.append((name, [ e['path'] for e in node ])) 502 503 return children 504 505 def get_port_peers(self, object_name, port_name): 506 """Get the 'peer' element of any node with 'peer' and 'role' 507 elements""" 508 obj = self.object_dicts[object_name] 509 510 peers = [] 511 if port_name in obj and 'peer' in obj[port_name] and \ 512 'role' in obj[port_name]: 513 peers = to_list(obj[port_name]['peer']) 514 515 return peers 516 517parser = argparse.ArgumentParser() 518 519parser.add_argument('config_file', metavar='config-file.ini', 520 help='.ini configuration file to load and run') 521parser.add_argument('--checkpoint-dir', type=str, default=None, 522 help='A checkpoint to directory to restore when starting ' 523 'the simulation') 524 525args = parser.parse_args(sys.argv[1:]) 526 527if args.config_file.endswith('.ini'): 528 config = ConfigIniFile() 529 config.load(args.config_file) 530else: 531 config = ConfigJsonFile() 532 config.load(args.config_file) 533 534ticks.fixGlobalFrequency() 535 536mgr = ConfigManager(config) 537 538mgr.find_all_objects() 539 540m5.instantiate(args.checkpoint_dir) 541 542exit_event = m5.simulate()
| 50import argparse 51import ConfigParser 52import inspect 53import json 54import re 55import sys 56 57import m5 58import m5.ticks as ticks 59 60sim_object_classes_by_name = { 61 cls.__name__: cls for cls in m5.objects.__dict__.itervalues() 62 if inspect.isclass(cls) and issubclass(cls, m5.objects.SimObject) } 63 64# Add some parsing functions to Param classes to handle reading in .ini 65# file elements. This could be moved into src/python/m5/params.py if 66# reading .ini files from Python proves to be useful 67 68def no_parser(cls, flags, param): 69 raise Exception('Can\'t parse string: %s for parameter' 70 ' class: %s' % (str(param), cls.__name__)) 71 72def simple_parser(suffix='', cast=lambda i: i): 73 def body(cls, flags, param): 74 return cls(cast(param + suffix)) 75 return body 76 77# def tick_parser(cast=m5.objects.Latency): # lambda i: i): 78def tick_parser(cast=lambda i: i): 79 def body(cls, flags, param): 80 old_param = param 81 ret = cls(cast(str(param) + 't')) 82 return ret 83 return body 84 85def addr_range_parser(cls, flags, param): 86 sys.stdout.flush() 87 (low, high, intlv_high_bit, xor_high_bit, 88 intlv_bits, intlv_match) = param.split(':') 89 return m5.objects.AddrRange( 90 start=long(low), end=long(high), 91 intlvHighBit=long(intlv_high_bit), xorHighBit=long(xor_high_bit), 92 intlvBits=long(intlv_bits), intlvMatch=long(intlv_match)) 93 94def memory_bandwidth_parser(cls, flags, param): 95 # The string will be in tick/byte 96 # Convert to byte/tick 97 value = 1.0 / float(param) 98 # Convert to byte/s 99 value = ticks.fromSeconds(value) 100 return cls('%fB/s' % value) 101 102# These parameters have trickier parsing from .ini files than might be 103# expected 104param_parsers = { 105 'Bool': simple_parser(), 106 'ParamValue': no_parser, 107 'NumericParamValue': simple_parser(cast=long), 108 'TickParamValue': tick_parser(), 109 'Frequency': tick_parser(cast=m5.objects.Latency), 110 'Current': simple_parser(suffix='A'), 111 'Voltage': simple_parser(suffix='V'), 112 'Enum': simple_parser(), 113 'MemorySize': simple_parser(suffix='B'), 114 'MemorySize32': simple_parser(suffix='B'), 115 'AddrRange': addr_range_parser, 116 'String': simple_parser(), 117 'MemoryBandwidth': memory_bandwidth_parser, 118 'Time': simple_parser(), 119 'EthernetAddr': simple_parser() 120 } 121 122for name, parser in param_parsers.iteritems(): 123 setattr(m5.params.__dict__[name], 'parse_ini', classmethod(parser)) 124 125class PortConnection(object): 126 """This class is similar to m5.params.PortRef but with just enough 127 information for ConfigManager""" 128 129 def __init__(self, object_name, port_name, index): 130 self.object_name = object_name 131 self.port_name = port_name 132 self.index = index 133 134 @classmethod 135 def from_string(cls, str): 136 m = re.match('(.*)\.([^.\[]+)(\[(\d+)\])?', str) 137 object_name, port_name, whole_index, index = m.groups() 138 if index is not None: 139 index = int(index) 140 else: 141 index = 0 142 143 return PortConnection(object_name, port_name, index) 144 145 def __str__(self): 146 return '%s.%s[%d]' % (self.object_name, self.port_name, self.index) 147 148 def __cmp__(self, right): 149 return cmp((self.object_name, self.port_name, self.index), 150 (right.object_name, right.port_name, right.index)) 151 152def to_list(v): 153 """Convert any non list to a singleton list""" 154 if isinstance(v, list): 155 return v 156 else: 157 return [v] 158 159class ConfigManager(object): 160 """Manager for parsing a Root configuration from a config file""" 161 def __init__(self, config): 162 self.config = config 163 self.objects_by_name = {} 164 self.flags = config.get_flags() 165 166 def find_object(self, object_name): 167 """Find and configure (with just non-SimObject parameters) 168 a single object""" 169 170 if object_name == 'Null': 171 return NULL 172 173 if object_name in self.objects_by_name: 174 return self.objects_by_name[object_name] 175 176 object_type = self.config.get_param(object_name, 'type') 177 178 if object_type not in sim_object_classes_by_name: 179 raise Exception('No SimObject type %s is available to' 180 ' build: %s' % (object_type, object_name)) 181 182 object_class = sim_object_classes_by_name[object_type] 183 184 parsed_params = {} 185 186 for param_name, param in object_class._params.iteritems(): 187 if issubclass(param.ptype, m5.params.ParamValue): 188 if isinstance(param, m5.params.VectorParamDesc): 189 param_values = self.config.get_param_vector(object_name, 190 param_name) 191 192 param_value = [ param.ptype.parse_ini(self.flags, value) 193 for value in param_values ] 194 else: 195 param_value = param.ptype.parse_ini( 196 self.flags, self.config.get_param(object_name, 197 param_name)) 198 199 parsed_params[param_name] = param_value 200 201 obj = object_class(**parsed_params) 202 self.objects_by_name[object_name] = obj 203 204 return obj 205 206 def fill_in_simobj_parameters(self, object_name, obj): 207 """Fill in all references to other SimObjects in an objects 208 parameters. This relies on all referenced objects having been 209 created""" 210 211 if object_name == 'Null': 212 return NULL 213 214 for param_name, param in obj.__class__._params.iteritems(): 215 if issubclass(param.ptype, m5.objects.SimObject): 216 if isinstance(param, m5.params.VectorParamDesc): 217 param_values = self.config.get_param_vector(object_name, 218 param_name) 219 220 setattr(obj, param_name, 221 [ self.objects_by_name[name] 222 if name != 'Null' else m5.params.NULL 223 for name in param_values ]) 224 else: 225 param_value = self.config.get_param(object_name, 226 param_name) 227 228 if param_value != 'Null': 229 setattr(obj, param_name, self.objects_by_name[ 230 param_value]) 231 232 return obj 233 234 def fill_in_children(self, object_name, obj): 235 """Fill in the children of this object. This relies on all the 236 referenced objects having been created""" 237 238 children = self.config.get_object_children(object_name) 239 240 for child_name, child_paths in children: 241 param = obj.__class__._params.get(child_name, None) 242 if child_name == 'Null': 243 continue 244 245 if isinstance(child_paths, list): 246 child_list = [ self.objects_by_name[path] 247 for path in child_paths ] 248 else: 249 child_list = self.objects_by_name[child_paths] 250 251 obj.add_child(child_name, child_list) 252 253 for path in to_list(child_paths): 254 self.fill_in_children(path, self.objects_by_name[path]) 255 256 return obj 257 258 def parse_port_name(self, port): 259 """Parse the name of a port""" 260 261 m = re.match('(.*)\.([^.\[]+)(\[(\d+)\])?', port) 262 peer, peer_port, whole_index, index = m.groups() 263 if index is not None: 264 index = int(index) 265 else: 266 index = 0 267 268 return (peer, self.objects_by_name[peer], peer_port, index) 269 270 def gather_port_connections(self, object_name, obj): 271 """Gather all the port-to-port connections from the named object. 272 Returns a list of (PortConnection, PortConnection) with unordered 273 (wrt. master/slave) connection information""" 274 275 if object_name == 'Null': 276 return NULL 277 278 parsed_ports = [] 279 for port_name, port in obj.__class__._ports.iteritems(): 280 # Assume that unnamed ports are unconnected 281 peers = self.config.get_port_peers(object_name, port_name) 282 283 for index, peer in zip(xrange(0, len(peers)), peers): 284 parsed_ports.append(( 285 PortConnection(object_name, port.name, index), 286 PortConnection.from_string(peer))) 287 288 return parsed_ports 289 290 def bind_ports(self, connections): 291 """Bind all ports from the given connection list. Note that the 292 connection list *must* list all connections with both (slave,master) 293 and (master,slave) orderings""" 294 295 # Markup a dict of how many connections are made to each port. 296 # This will be used to check that the next-to-be-made connection 297 # has a suitable port index 298 port_bind_indices = {} 299 for from_port, to_port in connections: 300 port_bind_indices[ 301 (from_port.object_name, from_port.port_name)] = 0 302 303 def port_has_correct_index(port): 304 return port_bind_indices[ 305 (port.object_name, port.port_name)] == port.index 306 307 def increment_port_index(port): 308 port_bind_indices[ 309 (port.object_name, port.port_name)] += 1 310 311 # Step through the sorted connections. Exactly one of 312 # each (slave,master) and (master,slave) pairs will be 313 # bindable because the connections are sorted. 314 # For example: port_bind_indices 315 # left right left right 316 # a.b[0] -> d.f[1] 0 0 X 317 # a.b[1] -> e.g 0 0 BIND! 318 # e.g -> a.b[1] 1 X 0 319 # d.f[0] -> f.h 0 0 BIND! 320 # d.f[1] -> a.b[0] 1 0 BIND! 321 connections_to_make = [] 322 for connection in sorted(connections): 323 from_port, to_port = connection 324 325 if (port_has_correct_index(from_port) and 326 port_has_correct_index(to_port)): 327 328 connections_to_make.append((from_port, to_port)) 329 330 increment_port_index(from_port) 331 increment_port_index(to_port) 332 333 # Exactly half of the connections (ie. all of them, one per 334 # direction) must now have been made 335 if (len(connections_to_make) * 2) != len(connections): 336 raise Exception('Port bindings can\'t be ordered') 337 338 # Actually do the binding 339 for from_port, to_port in connections_to_make: 340 from_object = self.objects_by_name[from_port.object_name] 341 to_object = self.objects_by_name[to_port.object_name] 342 343 setattr(from_object, from_port.port_name, 344 getattr(to_object, to_port.port_name)) 345 346 def find_all_objects(self): 347 """Find and build all SimObjects from the config file and connect 348 their ports together as described. Does not instantiate system""" 349 350 # Build SimObjects for all sections of the config file 351 # populating not-SimObject-valued parameters 352 for object_name in self.config.get_all_object_names(): 353 self.find_object(object_name) 354 355 # Add children to objects in the hierarchy from root 356 self.fill_in_children('root', self.find_object('root')) 357 358 # Now fill in SimObject-valued parameters in the knowledge that 359 # this won't be interpreted as becoming the parent of objects 360 # which are already in the root hierarchy 361 for name, obj in self.objects_by_name.iteritems(): 362 self.fill_in_simobj_parameters(name, obj) 363 364 # Gather a list of all port-to-port connections 365 connections = [] 366 for name, obj in self.objects_by_name.iteritems(): 367 connections += self.gather_port_connections(name, obj) 368 369 # Find an acceptable order to bind those port connections and 370 # bind them 371 self.bind_ports(connections) 372 373class ConfigFile(object): 374 def get_flags(self): 375 return set() 376 377 def load(self, config_file): 378 """Load the named config file""" 379 pass 380 381 def get_all_object_names(self): 382 """Get a list of all the SimObject paths in the configuration""" 383 pass 384 385 def get_param(self, object_name, param_name): 386 """Get a single param or SimObject reference from the configuration 387 as a string""" 388 pass 389 390 def get_param_vector(self, object_name, param_name): 391 """Get a vector param or vector of SimObject references from the 392 configuration as a list of strings""" 393 pass 394 395 def get_object_children(self, object_name): 396 """Get a list of (name, paths) for each child of this object. 397 paths is either a single string object path or a list of object 398 paths""" 399 pass 400 401 def get_port_peers(self, object_name, port_name): 402 """Get the list of connected port names (in the string form 403 object.port(\[index\])?) of the port object_name.port_name""" 404 pass 405 406class ConfigIniFile(ConfigFile): 407 def __init__(self): 408 self.parser = ConfigParser.ConfigParser() 409 410 def load(self, config_file): 411 self.parser.read(config_file) 412 413 def get_all_object_names(self): 414 return self.parser.sections() 415 416 def get_param(self, object_name, param_name): 417 return self.parser.get(object_name, param_name) 418 419 def get_param_vector(self, object_name, param_name): 420 return self.parser.get(object_name, param_name).split() 421 422 def get_object_children(self, object_name): 423 if self.parser.has_option(object_name, 'children'): 424 children = self.parser.get(object_name, 'children') 425 child_names = children.split() 426 else: 427 child_names = [] 428 429 def make_path(child_name): 430 if object_name == 'root': 431 return child_name 432 else: 433 return '%s.%s' % (object_name, child_name) 434 435 return [ (name, make_path(name)) for name in child_names ] 436 437 def get_port_peers(self, object_name, port_name): 438 if self.parser.has_option(object_name, port_name): 439 peer_string = self.parser.get(object_name, port_name) 440 return peer_string.split() 441 else: 442 return [] 443 444class ConfigJsonFile(ConfigFile): 445 def __init__(self): 446 pass 447 448 def is_sim_object(self, node): 449 return isinstance(node, dict) and 'path' in node 450 451 def find_all_objects(self, node): 452 if self.is_sim_object(node): 453 self.object_dicts[node['path']] = node 454 455 if isinstance(node, list): 456 for elem in node: 457 self.find_all_objects(elem) 458 elif isinstance(node, dict): 459 for elem in node.itervalues(): 460 self.find_all_objects(elem) 461 462 def load(self, config_file): 463 root = json.load(open(config_file, 'r')) 464 self.object_dicts = {} 465 self.find_all_objects(root) 466 467 def get_all_object_names(self): 468 return sorted(self.object_dicts.keys()) 469 470 def parse_param_string(self, node): 471 if node is None: 472 return "Null" 473 elif self.is_sim_object(node): 474 return node['path'] 475 else: 476 return str(node) 477 478 def get_param(self, object_name, param_name): 479 obj = self.object_dicts[object_name] 480 481 return self.parse_param_string(obj[param_name]) 482 483 def get_param_vector(self, object_name, param_name): 484 obj = self.object_dicts[object_name] 485 486 return [ self.parse_param_string(p) for p in obj[param_name] ] 487 488 def get_object_children(self, object_name): 489 """It is difficult to tell which elements are children in the 490 JSON file as there is no explicit 'children' node. Take any 491 element which is a full SimObject description or a list of 492 SimObject descriptions. This will not work with a mixed list of 493 references and descriptions but that's a scenario that isn't 494 possible (very likely?) with gem5's binding/naming rules""" 495 obj = self.object_dicts[object_name] 496 497 children = [] 498 for name, node in obj.iteritems(): 499 if self.is_sim_object(node): 500 children.append((name, node['path'])) 501 elif isinstance(node, list) and node != [] and all([ 502 self.is_sim_object(e) for e in node ]): 503 children.append((name, [ e['path'] for e in node ])) 504 505 return children 506 507 def get_port_peers(self, object_name, port_name): 508 """Get the 'peer' element of any node with 'peer' and 'role' 509 elements""" 510 obj = self.object_dicts[object_name] 511 512 peers = [] 513 if port_name in obj and 'peer' in obj[port_name] and \ 514 'role' in obj[port_name]: 515 peers = to_list(obj[port_name]['peer']) 516 517 return peers 518 519parser = argparse.ArgumentParser() 520 521parser.add_argument('config_file', metavar='config-file.ini', 522 help='.ini configuration file to load and run') 523parser.add_argument('--checkpoint-dir', type=str, default=None, 524 help='A checkpoint to directory to restore when starting ' 525 'the simulation') 526 527args = parser.parse_args(sys.argv[1:]) 528 529if args.config_file.endswith('.ini'): 530 config = ConfigIniFile() 531 config.load(args.config_file) 532else: 533 config = ConfigJsonFile() 534 config.load(args.config_file) 535 536ticks.fixGlobalFrequency() 537 538mgr = ConfigManager(config) 539 540mgr.find_all_objects() 541 542m5.instantiate(args.checkpoint_dir) 543 544exit_event = m5.simulate()
|