def primitives_from_buses(buses): """Generate a list of primitives from a list of buses. This creates a single phase communication primitive for each storage device that is connected to one of the buses. Processors that can reach the storage folowing the bus hierarchy are added as sources and sinks to these primitives. The buses that are required to reach the storage device from a processor are added as communication_resources to the consume or produce phases. """ # first, get a list of all storages storages = [] for b in buses: storages.extend(b._storages) primitives = [] # create a primitive per storage for storage in storages: prim = Primitive("cp_%s" % (storage.name)) # find the bus that connects to this storage storage_bus = None for b in buses: if storage in b._storages: storage_bus = b break connections = storage_bus.get_processor_connections() for c_buses, c_processors in connections: produce = CommunicationPhase("produce", c_buses + [storage], "write") consume = CommunicationPhase("consume", c_buses + [storage], "read") for p in c_processors: prim.add_producer(p, produce) prim.add_consumer(p, consume) primitives.append(prim) return primitives
def test_produce(self, env, channel, running_process, mocker): sink1 = mocker.Mock() sink2 = mocker.Mock() src = running_process channel.set_src(src) channel.add_sink(sink1) channel.add_sink(sink2) # setup the primitive prim = Primitive("test_prim") info = ChannelMappingInfo(primitive=prim, capacity=4) channel.update_mapping_info(info) # src processor not added yet -> should fail with pytest.raises(RuntimeError): list(channel.produce(src, 1)) # add the src processor to the primitive prim.add_producer(src.processor, []) # first try start = env.now event = channel.tokens_produced process = env.process(channel.produce(src, 1)) env.run() assert event.ok assert process.ok assert channel._fifo_state[sink1.name] == 1 assert channel._fifo_state[sink2.name] == 1 # should not consume any time since we did not add any communication # phases assert env.now - start == 0 # try again with some communication phases phases = [] for i in range(1, 6): p = mocker.Mock() p.get_costs.side_effect = lambda x, i=i: i * 10 p.resources = [] phases.append(p) prim.produce_phases[src.processor.name] = phases event = channel.tokens_produced process = env.process(channel.produce(src, 2)) env.run() assert event.ok assert process.ok assert channel._fifo_state[sink1.name] == 3 assert channel._fifo_state[sink2.name] == 3 assert env.now - start == 150 for p in phases: p.get_costs.assert_called_once_with(16) # and again with resources resources = [] for p in phases: for i in range(3): r = mocker.Mock() r.simpy_resource = simpy.Resource(env) resources.append(r) p.resources.append(r) start = env.now event = channel.tokens_produced process = env.process(channel.produce(src, 1)) # peek into each phase env.run(env.now + 1) x = 10 for p in phases: for r in p.resources: # all resources of the phase should be hold assert r.simpy_resource.count == 1 env.run(env.now + x) x += 10 for r in p.resources: # all resources of the phase should be released assert r.simpy_resource.count == 0 assert event.ok assert process.ok assert channel._fifo_state[sink1.name] == 4 assert channel._fifo_state[sink2.name] == 4 assert env.now - start == 151 assert all([r.simpy_resource.count == 0 for r in resources])
def test_multi_phase_primitive(slow_resource, mediocre_resource, fast_resource, mocker): src = mocker.Mock(name="src") sink = mocker.Mock(name="sink") read_phases = [ CommunicationPhase("read_ph1", [fast_resource], "read"), CommunicationPhase("read_ph2", [mediocre_resource], "read"), CommunicationPhase("read_ph3", [slow_resource], "read"), ] write_phases = [ CommunicationPhase("write_ph1", [fast_resource], "write"), CommunicationPhase("write_ph2", [mediocre_resource], "write"), CommunicationPhase("write_ph3", [slow_resource], "write"), ] prim = Primitive("prim") prim.add_consumer(sink, read_phases) prim.add_producer(src, write_phases) expected_consume_costs_8 = sum([p.get_costs(8) for p in read_phases]) expected_consume_costs_100 = sum([p.get_costs(100) for p in read_phases]) assert prim.static_consume_costs(sink) == expected_consume_costs_8 assert prim.static_consume_costs(sink, 100) == expected_consume_costs_100 expected_produce_costs_8 = sum([p.get_costs(8) for p in write_phases]) expected_produce_costs_100 = sum([p.get_costs(100) for p in write_phases]) assert prim.static_produce_costs(src) == expected_produce_costs_8 assert prim.static_produce_costs(src, 100) == expected_produce_costs_100 expected_costs_8 = expected_consume_costs_8 + expected_produce_costs_8 expected_costs_100 = expected_consume_costs_100 + expected_produce_costs_100 assert prim.static_costs(src, sink) == expected_costs_8 assert prim.static_costs(src, sink, 100) == expected_costs_100 assert prim.static_costs(src, sink, 8) <= prim.static_costs(src, sink, 16)
def createNetworkForChips( self, networkName, adjacencyList, routingFunction, frequencyDomain, readLatency, writeLatency, readThroughput, writeThroughput, ): """Creates a network between the given elements. :param networkName: The name of the network. (primitives belonging to the network will be named like this. :type networkName: String :param adjacencyList: The adjacency list of the elements within the network. The key is the name of an element and the list contains the names of elements the key has a physical link to. :type adjacencyList: dict {String : list[String]} :param routingFunction: A function, that takes the name of a source element, a target element and the adjacency list. Should return the path, taken to communicate between source and target, in case there is no direct physical link between them. :type routingFunction: function :param frequencyDomain: The frequency of the physical links an network routers. :type frequencyDomaing: int :param readLatency: The read latency of the physical links an network routers. :type readLatency: int :param writeLatency: The write latency of the physical links an network routers. :type writeLatency: int :param readThroughput: The read throughput of the physical links an network routers. :type readThroughput: int :param writeThroughput: The write throughput of the physical links and network routers. :type writeThroughput: int """ fd = FrequencyDomain("fd_" + networkName, frequencyDomain) if self.__activeScope != None: """Creating a network between independent chips""" if self.__elementDict == {}: return for key in adjacencyList: """workaround with i, because different elements can have the same adjacency entry """ name = networkName + "_" + "router_" + key communicationResource = CommunicationResource( name, CommunicationResourceType.Router, fd, readLatency, writeLatency, readThroughput, writeThroughput, ) self.__platform.add_communication_resource( communicationResource ) for target in adjacencyList[key]: name = networkName + "_pl_" + str(target) + "_" + key communicationResource = CommunicationResource( name, CommunicationResourceType.PhysicalLink, fd, readLatency, writeLatency, readThroughput, writeThroughput, ) self.__platform.add_communication_resource( communicationResource ) for key in self.__elementDict[self.__activeScope]: if adjacencyList[key] == []: continue for pe in self.__elementDict[self.__activeScope][key]: """Adding a primitive for each pe in the network""" prim = Primitive("prim_" + networkName + "_" + pe[0].name) routerName = networkName + "_" + "router_" + str(key) router = self.__platform.find_communication_resource( routerName ) for innerKey in self.__elementDict[self.__activeScope]: if adjacencyList[innerKey] == []: continue resourceList = [router] if innerKey != key: path = routingFunction(adjacencyList, key, innerKey) lastPoint = None for point in path: if lastPoint != None: name = ( networkName + "_pl_" + str(lastPoint) + "_" + str(point) ) resource = self.__platform.find_communication_resource( name ) resourceList.append(resource) lastPoint = point for innerPe in self.__elementDict[self.__activeScope][ innerKey ]: """Iterating again over all pe's in the network to create their consumer and producer phases etc. for the primitive. """ produce = CommunicationPhase( "produce", resourceList, "write" ) consume = CommunicationPhase( "consume", resourceList, "read" ) prim.add_producer(innerPe[0], [produce]) prim.add_consumer(innerPe[0], [consume]) self.__platform.add_primitive(prim) if self.__symLibrary: chipIds = set(adjacencyList.keys()) | set( c for v in adjacencyList.values() for c in v ) if not self._ag_classifyIdentifiers(chipIds): raise ValueError( "mpsym: chip network must consist of chips only" ) if self._ag_hasIdenticalChips(): if not self._ag_hasSuperGraph(): self._ag_createSuperGraph() self._ag_connectSuperGraph(adjacencyList, networkName) if self.__activeScope == "base": self._ag_updateBaseAgs() else: return
def test_single_phase_primitive(resource, mocker): read_phase = CommunicationPhase(name="read", resources=[resource], direction="read") write_phase = CommunicationPhase(name="write", resources=[resource], direction="write") src = mocker.Mock(name="src") sink = mocker.Mock(name="sink") prim = Primitive("prim") prim.add_consumer(sink, [read_phase]) prim.add_producer(src, [write_phase]) with pytest.raises(RuntimeError): prim.add_consumer(sink, []) with pytest.raises(RuntimeError): prim.add_producer(src, []) with pytest.raises(RuntimeError): prim.add_producer(sink, [read_phase]) with pytest.raises(RuntimeError): prim.add_consumer(src, [write_phase]) assert prim.static_consume_costs(sink) == read_phase.get_costs(8) assert prim.static_consume_costs(sink, 100) == read_phase.get_costs(100) assert prim.static_produce_costs(src) == write_phase.get_costs(8) assert prim.static_produce_costs(src, 100) == write_phase.get_costs(100) expected_costs_8 = write_phase.get_costs(8) + read_phase.get_costs(8) expected_costs_100 = write_phase.get_costs(100) + read_phase.get_costs(100) assert prim.static_costs(src, sink) == expected_costs_8 assert prim.static_costs(src, sink, 100) == expected_costs_100
def createNetworkForCluster( self, clusterIdentifier, networkName, adjacencyList, routingFunction, frequencyDomain, readLatency, writeLatency, readThroughput, writeThroughput, ): """Creates a network on chip topology for the given cluster. :param clusterIdentifier: The identifier of the cluster the network will be created for. :type clusterIdentifier: int :param networkName: The name of the network. (primitives belonging to the network will be named like this. :type networkName: String :param adjacencyList: The adjacency list of the processing elements within the network. The key is the name of a processing element and the list contains the names of processing elements the key has a physical link to. :type adjacencyList: dict {String : list[String]} :param routingFunction: A function that takes the name of a source processing element, a target processing element and the adjacency list. Should return the path taken to communicate between source and target, in case there is no direct physical link between them. :type routingFunction: function :param frequencyDomain: The frequency of the physical links an network routers. :type frequencyDomain: int :param readLatency: The read latency of the physical links an network routers. :type readLatency: int :param writeLatency: The write latency of the physical links an network routers. :type witeLatency: int :param readThroughput: The read throughput of the physical links an network routers. :type readThroughput: int :param writeThroughput: The write throughput of the physical links and network routers. :type writeThroughput: int """ fd = FrequencyDomain("fd_" + networkName, frequencyDomain) if self.__activeScope is not None: processorList = self.__elementDict[self.__activeScope][ clusterIdentifier ] processorNames = [p.name for p, _ in processorList] """Adding physical links and NOC memories according to the adjacency list """ for key in adjacencyList: name = str(clusterIdentifier) + "_noc_mem_" + str(key) communicationResource = Storage( name, fd, readLatency, writeLatency, readThroughput, writeThroughput, ) self.__platform.add_communication_resource( communicationResource ) for target in adjacencyList[key]: name = ( str(clusterIdentifier) + "_pl_" + str(target) + "_" + str(key) ) communicationResource = CommunicationResource( name, fd, CommunicationResourceType.PhysicalLink, readLatency, writeLatency, readThroughput, writeThroughput, ) self.__platform.add_communication_resource( communicationResource ) if self.__symLibrary: self._ag_addClusterChannel(key, target, networkName) for processor in processorList: if not adjacencyList[processor[0].name]: continue else: prim = Primitive(networkName + "_" + processor[0].name) memoryName = ( str(clusterIdentifier) # FIXME: this will lead to issues if we have >=2 NoCs + "_noc_mem_" + str(processor[0].name) ) memory = self.__platform.find_communication_resource( memoryName ) for innerProcessor in processorList: if not adjacencyList[innerProcessor[0].name]: continue resourceList = [memory] if innerProcessor != processor: path = routingFunction( adjacencyList, processor[0].name, innerProcessor[0].name, ) lastPoint = None for point in path: if lastPoint != None: name = ( str(clusterIdentifier) + "_pl_" + str(lastPoint) + "_" + str(point) ) resource = self.__platform.find_communication_resource( name ) resourceList.append(resource) lastPoint = point produce = CommunicationPhase( "produce", resourceList, "write" ) consume = CommunicationPhase( "consume", list(reversed(resourceList)), "read" ) prim.add_producer(innerProcessor[0], [produce]) prim.add_consumer(innerProcessor[0], [consume]) else: produce = CommunicationPhase( "produce", resourceList, "write" ) consume = CommunicationPhase( "consume", list(reversed(resourceList)), "read" ) prim.add_producer(innerProcessor[0], [produce]) prim.add_consumer(innerProcessor[0], [consume]) self.__platform.add_primitive(prim) else: return
def addCommunicationResource( self, name, clusterIds, readLatency, writeLatency, readThroughput, writeThroughput, # FIXME: probably we should just rename the method to add_storage resourceType=CommunicationResourceType.Storage, # FIXME: this argument should either be renamed to frequency or # expect an actual FrequencyDomain object frequencyDomain=0, ): """Adds a communication resource to the platform. All cores of the given cluster identifiers can communicate via this resource. :param name: The name of the storage :type name: String :param clusterIds: A list of identifiers for all clusters which will be connected. :type clusterIds: list[int] :param readLatency: The read latency of the communication resource. :type readLatency: int :param writeLatency: The write latency of the communication resource. :type writeLatency: int :param readThroughput: The read throughput of the communication resource. :type readThroughput: int :param writeThroughput: The write throughput of the communication resource. :type writeThroughput: int """ # FIXME: shouldn't these checks produce an error instead of just # silently aborting? if not self.__schedulingPolicy: return if not self.__activeScope: return for clusterId in clusterIds: if clusterId not in self.__elementDict[self.__activeScope]: return clusterDict = self.__elementDict[self.__activeScope] nameToGive = ( str(self.__activeScope) + "_" + name + "_" + str(self.__namingSuffix) ) fd = FrequencyDomain("fd_" + name, frequencyDomain) try: # FIXME: why distinguish storage and other types here? if resourceType == CommunicationResourceType.Storage: com_resource = Storage( nameToGive, fd, readLatency, writeLatency, readThroughput, writeThroughput, ) else: com_resource = CommunicationResource( nameToGive, fd, resourceType, readLatency, writeLatency, readThroughput, writeThroughput, ) self.__platform.add_communication_resource(com_resource) prim = Primitive("prim_" + nameToGive) for clusterId in clusterIds: for pe in clusterDict[clusterId]: pe[1].append(com_resource) produce = CommunicationPhase( "produce", [com_resource], "write" ) consume = CommunicationPhase( "consume", [com_resource], "read" ) prim.add_producer(pe[0], [produce]) prim.add_consumer(pe[0], [consume]) self.__platform.add_primitive(prim) except: # FIXME: this is fishy log.error("Exception caught: " + str(sys.exc_info()[0])) return if self.__symLibrary: idType = self._ag_classifyIdentifiers(clusterIds) if self._ag_hasChips(): if idType != "chips": raise ValueError( "mpsym: cannot mix clusters/chips connections" ) if self._ag_hasIdenticalChips(): if not self._ag_hasSuperGraph(): self._ag_createSuperGraph() self._ag_fullyConnectSuperGraph(clusterIds, name) if self.__activeScope == "base": self._ag_updateBaseAgs() else: if idType != "clusters": raise ValueError( "mpsym: cannot mix clusters/chips connections" ) self._ag_fullyConnectClusters(clusterIds, name)
def addCacheForPEs( self, identifier, readLatency, writeLatency, readThroughput, writeThroughput, # FIXME, this is a strange default frequencyDomain=100000, # TODO: this should be added to tests name="L1_", ): """Adds a level 1 cache to each PE of the given cluster. :param identifier: The identifier of the cluster to which the cache will be added. :type identifier: int :param readLatency: The read latency of the cache. :type readLatency: int :param writeLatency: The write latency of the cache. :type writeLatency: int :param readThroughput: The read throughput of the cache. :type readThroughput: int :param writeThroughput: The write throughput of the cache. :type writeThroughput: int :param name: The cache name, in case it differs from L1. :type name: String """ # FIXME: this should probably produce an error instead of returning # silently if self.__schedulingPolicy == None: return if self.__activeScope == None: return nameToGive = name if not identifier in self.__elementDict[self.__activeScope]: raise RuntimeWarning("Identifier does not exist in active scope.") peList = self.__elementDict[self.__activeScope][identifier] fd = FrequencyDomain("fd_" + name, frequencyDomain) try: for pe in peList: l1 = Storage( nameToGive + pe[0].name, frequency_domain=fd, read_latency=readLatency, write_latency=writeLatency, read_throughput=readThroughput, write_throughput=writeThroughput, ) self.__platform.add_communication_resource(l1) # FIXME: What is this doing?? pe[1].append(l1) prim = Primitive("prim_" + nameToGive + pe[0].name) produce = CommunicationPhase("produce", [l1], "write") consume = CommunicationPhase("consume", [l1], "read") prim.add_producer(pe[0], [produce]) prim.add_consumer(pe[0], [consume]) self.__platform.add_primitive(prim) except: # FIXME: This is fishy log.error("Exception caught: " + sys.exc_info()[0]) if self.__symLibrary: self._ag_addClusterCache(identifier, name)
def convert( platform, xml_platform, scheduler_cycles=None, fd_frequencies=None, ppm_power=None, ): # keep a map of scheduler names to processors, this helps when creating # scheduler objects schedulers_to_processors = {} for s in xml_platform.get_Scheduler(): schedulers_to_processors[s.get_id()] = [] # Check the fd_frequencies defined the frequencies of only known domains if fd_frequencies is not None: fd_names = map(lambda x: x.get_id(), xml_platform.get_FrequencyDomain()) for fd in fd_frequencies: if fd not in fd_names: log.warning(f"The fd_frequencies defines the frequency of " f"an unknown domain {fd}") # Collect all frequency and voltage domains voltage_domains = {} for vd in xml_platform.get_VoltageDomain(): name = vd.get_id() voltage_domains[name] = [] for v in vd.get_Voltage(): voltage = ur(v.get_value() + v.get_unit()).to("V").magnitude voltage_domains[name].append(voltage) frequency_domains = {} # We do not save voltage domains by their names defined in MAPS XML files, # instead we save under the same names as frequency domains fd_voltage_cond = {} for fd in xml_platform.get_FrequencyDomain(): name = fd.get_id() max_frequency = 0 supported_frequency_voltage_pairs = [] for f in fd.get_Frequency(): voltage_domain_conds = f.get_VoltageDomainCondition() if len(voltage_domain_conds) > 1: raise RuntimeError( f"The xml defines multiple voltages for the frequency domain " f"{name} at {f.get_value()}{f.get_unit()}.") voltage_cond = None for v in voltage_domain_conds: voltage_cond = (ur(v.get_value() + v.get_unit()).to("V").magnitude) frequency = ur(f.get_value() + f.get_unit()).to("Hz").magnitude supported_frequency_voltage_pairs.append( tuple((frequency, voltage_cond))) if fd_frequencies is not None and name in fd_frequencies: frequency = fd_frequencies[name] voltage_cond = None found = False for f, v in supported_frequency_voltage_pairs: if frequency != f: continue voltage_cond = v found = True if not found: log.warning( f"The fd_frequencies sets the frequency of the domain {name} " f"to {frequency} Hz, which is not defined in the xml. ") else: frequency, voltage_cond = max(supported_frequency_voltage_pairs) if len(fd.get_Frequency()) > 1: log.warning( "The xml defines multiple frequencies for the domain " "%s. -> Select Maximum", name, ) frequency_domains[name] = FrequencyDomain(name, frequency) fd_voltage_cond[name] = voltage_cond log.debug( "Found frequency domain %s (%d Hz).", name, frequency, ) # Collect processor power model parameters processor_power_params = {} for ppm in xml_platform.get_ProcessorPowerModel(): name = ppm.get_id() leakage_current = (ur(ppm.get_leakageCurrentValue() + ppm.get_leakageCurrentUnit()).to("A").magnitude) switched_capacitance = ( ur(ppm.get_switchedCapacitanceValue() + ppm.get_switchedCapacitanceUnit()).to("F").magnitude) processor_power_params[name] = { "leakage_current": leakage_current, "switched_capacitance": switched_capacitance, } # Check custom power if ppm_power is not None: for ppm, powers in ppm_power.items(): if ppm not in processor_power_params: log.warning(f"The ppm_power defines the power of " f"an unknown processor power model {ppm}") continue for power_mode in ["static", "dynamic"]: if power_mode not in powers: log.warning( f"The ppm_power does not define the {power_mode} power of " f"a processor power model {ppm}") processor_power_models = {} # Initialize all Processors for xp in xml_platform.get_Processor(): name = xp.get_id() type = xp.get_core() fd_name = xp.get_frequencyDomain() fd = frequency_domains[fd_name] # Initialize a processor power model vd_name = xp.get_voltageDomain() ppm_name = xp.get_processorPowerModel() if ppm_name is None: ppm = None else: if ppm_name not in processor_power_models: ppm = create_processor_power_model( fd_name, vd_name, ppm_name, frequency_domains, voltage_domains, fd_voltage_cond, processor_power_params, ppm_power, ) processor_power_models[ppm_name] = ppm else: ppm = processor_power_models[ppm_name] context_load = get_value_in_cycles(xp, "contextLoad", 0) context_store = get_value_in_cycles(xp, "contextStore", 0) p = Processor(name, type, fd, ppm, context_load, context_store) schedulers_to_processors[xp.get_scheduler()].append(p) platform.add_processor(p) log.debug("Found processor %s of type %s", name, type) # Initialize all Schedulers for xs in xml_platform.get_Scheduler(): name = xs.get_id() policy = create_policy(xml_platform, xs.get_schedulingPolicyList(), scheduler_cycles) s = Scheduler(name, schedulers_to_processors[name], policy) log.debug( "Found scheduler %s for %s supporting %s", name, schedulers_to_processors[name], policy.name, ) platform.add_scheduler(s) # Initialize all Memories, Caches, and Fifos as CommunicationResources for xm in xml_platform.get_Memory(): name = xm.get_id() read_latency = get_value_in_cycles(xm, "readLatency", 0) write_latency = get_value_in_cycles(xm, "writeLatency", 0) read_throughput = get_value_in_byte_per_cycle(xm, "readThroughput", float("inf")) write_throughput = get_value_in_byte_per_cycle(xm, "writeThroughput", float("inf")) fd = frequency_domains[xm.get_frequencyDomain()] mem = Storage( name, fd, read_latency, write_latency, read_throughput, write_throughput, ) platform.add_communication_resource(mem) log.debug("Found memory %s", name) for xc in xml_platform.get_Cache(): name = xc.get_id() # XXX we assume 100% cache hit rate read_latency = get_value_in_cycles(xc, "readHitLatency", 0) write_latency = get_value_in_cycles(xc, "writeHitLatency", 0) read_throughput = get_value_in_byte_per_cycle(xc, "readHitThroughput", float("inf")) write_throughput = get_value_in_byte_per_cycle(xc, "writeHitThroughput", float("inf")) fd = frequency_domains[xc.get_frequencyDomain()] cache = Storage( name, fd, read_latency, write_latency, read_throughput, write_throughput, ) platform.add_communication_resource(cache) log.debug("Found cache %s", name) for xf in xml_platform.get_Fifo(): name = xf.get_id() read_latency = get_value_in_cycles(xf, "readLatency", 0) write_latency = get_value_in_cycles(xf, "writeLatency", 0) read_throughput = get_value_in_byte_per_cycle(xf, "readThroughput", float("inf")) write_throughput = get_value_in_byte_per_cycle(xf, "writeThroughput", float("inf")) fd = frequency_domains[xf.get_frequencyDomain()] fifo = Storage( name, fd, read_latency, write_latency, read_throughput, write_throughput, ) platform.add_communication_resource(fifo) log.debug("Found FIFO %s", name) # We also need to collect all the physical links, logical links and dma # controllers # modified by Felix Teweleit 10.08.2018 for ll in xml_platform.get_PhysicalLink(): name = ll.get_id() latency = get_value_in_cycles(ll, "latency", 0) throughput = get_value_in_byte_per_cycle(ll, "throughput", float("inf")) fd = frequency_domains[ll.get_frequencyDomain()] link = CommunicationResource( name, fd, CommunicationResourceType.PhysicalLink, latency, latency, throughput, throughput, ) platform.add_communication_resource(link) log.debug("Found link or DMA %s", name) for ll in xml_platform.get_LogicalLink(): name = ll.get_id() latency = get_value_in_cycles(ll, "latency", 0) throughput = get_value_in_byte_per_cycle(ll, "throughput", float("inf")) fd = frequency_domains[ll.get_frequencyDomain()] link = CommunicationResource( name, fd, CommunicationResourceType.LogicalLink, latency, latency, throughput, throughput, ) platform.add_communication_resource(link) log.debug("Found link or DMA %s", name) for ll in xml_platform.get_DMAController(): name = ll.get_id() latency = get_value_in_cycles(ll, "latency", 0) throughput = get_value_in_byte_per_cycle(ll, "throughput", float("inf")) fd = frequency_domains[ll.get_frequencyDomain()] link = CommunicationResource( name, fd, CommunicationResourceType.DMAController, latency, latency, throughput, throughput, ) platform.add_communication_resource(link) log.debug("Found link or DMA %s", name) # end of modified code # Initialize all Communication Primitives for xcom in xml_platform.get_Communication(): name = xcom.get_id() producers = {} consumers = {} # Read the Producers for xp in xcom.get_Producer(): pn = xp.get_processor() # TODO implement passive producing costs if xp.get_Passive() is not None: log.warning( "Passive producing costs are not supported" " -> ignore passive phase of primitive %s", name, ) # We create a single phase for each producer active = CommunicationPhase( "Produce Active", resources_from_access(xp.get_Active(), platform), "write", ) producers[pn] = [active] # Read the Consumers for xc in xcom.get_Consumer(): cn = xc.get_processor() # TODO implement passive producing costs if xc.get_Passive() is not None: log.warning( "Passive consuming costs are not supported" " -> ignore passive phase of primitive %s", name, ) # We create a single phase for each producer active = CommunicationPhase( "Consume Active", resources_from_access(xc.get_Active(), platform), "read", ) consumers[cn] = [active] # Create a Primitive for each combination of producer and consumer primitive = Primitive(name) for pn in producers: primitive.add_producer(platform.find_processor(pn), producers[pn]) for cn in consumers: primitive.add_consumer(platform.find_processor(cn), consumers[cn]) log.debug("Found the communication primitive %s: %s -> %s" % (name, str(producers.keys()), str(consumers.keys()))) platform.add_primitive(primitive)
def __init__(self): super(Exynos2Chips, self).__init__("Exynos2Chips") # Frequency domains fd_a7 = FrequencyDomain("fd_a7", 1400000000) fd_a15 = FrequencyDomain("fd_a15", 2000000000) fd_l3 = FrequencyDomain("fd_l3", 1400000000) fd_ram = FrequencyDomain("fd_ram", 933000000) # Processors for i in range(0, 4): self.add_processor(Processor("PE%02d" % i, "ARM_CORTEX_A7", fd_a7)) for i in range(4, 8): self.add_processor( Processor("PE%02d" % i, "ARM_CORTEX_A15", fd_a15)) for i in range(8, 12): self.add_processor(Processor("PE%02d" % i, "ARM_CORTEX_A7", fd_a7)) for i in range(12, 16): self.add_processor( Processor("PE%02d" % i, "ARM_CORTEX_A15", fd_a15)) # Schedulers sp = SchedulingPolicy("FIFO", 1000) for i in range(0, 16): self.add_scheduler( Scheduler("sched%02d" % i, [self.find_processor("PE%02d" % i)], [sp])) # L1 Caches for i in range(0, 4): self.add_communication_resource( Storage( "L1_PE%02d" % i, fd_a7, read_latency=1, write_latency=4, read_throughput=8, write_throughput=8, )) for i in range(4, 8): self.add_communication_resource( Storage( "L1_PE%02d" % i, fd_a15, read_latency=1, write_latency=4, read_throughput=8, write_throughput=8, )) for i in range(8, 12): self.add_communication_resource( Storage( "L1_PE%02d" % i, fd_a7, read_latency=1, write_latency=4, read_throughput=8, write_throughput=8, )) for i in range(12, 16): self.add_communication_resource( Storage( "L1_PE%02d" % i, fd_a15, read_latency=1, write_latency=4, read_throughput=8, write_throughput=8, )) # L1 Primitives for i in range(0, 16): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1], "write") consume = CommunicationPhase("consume", [l1], "read") prim = Primitive("prim_L1_PE%02d" % i) prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) self.add_primitive(prim) # L2 Caches l2_C0_A7 = Storage( "L2_C0_A7", fd_a7, read_latency=16, write_latency=21, read_throughput=8, write_throughput=8, ) l2_C0_A15 = Storage( "L2_C0_A15", fd_a15, read_latency=16, write_latency=21, read_throughput=8, write_throughput=8, ) l2_C1_A7 = Storage( "L2_C1_A7", fd_a7, read_latency=16, write_latency=21, read_throughput=8, write_throughput=8, ) l2_C1_A15 = Storage( "L2_C1_A15", fd_a15, read_latency=16, write_latency=21, read_throughput=8, write_throughput=8, ) self.add_communication_resource(l2_C0_A7) self.add_communication_resource(l2_C0_A15) self.add_communication_resource(l2_C1_A7) self.add_communication_resource(l2_C1_A15) # L2 Primitives prim = Primitive("prim_L2_C0_A7") for i in range(0, 4): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C0_A7], "write") consume = CommunicationPhase("consume", [l1, l2_C0_A7], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) self.add_primitive(prim) prim = Primitive("prim_L2_C0_A15") for i in range(4, 8): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C0_A15], "write") consume = CommunicationPhase("consume", [l1, l2_C0_A15], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) self.add_primitive(prim) prim = Primitive("prim_L2_C1_A7") for i in range(8, 12): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C1_A7], "write") consume = CommunicationPhase("consume", [l1, l2_C1_A7], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) self.add_primitive(prim) prim = Primitive("prim_L2_C1_A15") for i in range(12, 16): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C1_A15], "write") consume = CommunicationPhase("consume", [l1, l2_C1_A15], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) self.add_primitive(prim) # L3 Caches l3_C0 = Storage( "L3_C0", fd_l3, read_latency=30, write_latency=21, read_throughput=8, write_throughput=8, ) l3_C1 = Storage( "L3_C1", fd_l3, read_latency=40, write_latency=21, read_throughput=8, write_throughput=8, ) self.add_communication_resource(l3_C0) self.add_communication_resource(l3_C1) # L3 Primitives prim = Primitive("prim_L3_C0") for i in range(0, 4): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C0_A7, l3_C0], "write") consume = CommunicationPhase("consume", [l1, l2_C0_A7, l3_C0], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) for i in range(4, 8): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C0_A15, l3_C0], "write") consume = CommunicationPhase("consume", [l1, l2_C0_A15, l3_C0], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) self.add_primitive(prim) prim = Primitive("prim_L3_C1") for i in range(8, 12): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C1_A7, l3_C1], "write") consume = CommunicationPhase("consume", [l1, l2_C1_A7, l3_C1], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) for i in range(12, 16): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C1_A15, l3_C1], "write") consume = CommunicationPhase("consume", [l1, l2_C1_A15, l3_C1], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) self.add_primitive(prim) # RAM ram = Storage( "RAM", fd_ram, read_latency=120, write_latency=120, read_throughput=8, write_throughput=8, ) self.add_communication_resource(ram) prim = Primitive("prim_RAM") for i in range(0, 4): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C0_A7, l3_C0, ram], "write") consume = CommunicationPhase("consume", [l1, l2_C0_A7, l3_C0, ram], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) for i in range(4, 8): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C0_A15, l3_C0, ram], "write") consume = CommunicationPhase("consume", [l1, l2_C0_A15, l3_C0, ram], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) for i in range(8, 12): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C1_A7, l3_C1, ram], "write") consume = CommunicationPhase("consume", [l1, l2_C1_A7, l3_C1, ram], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) for i in range(12, 16): pe = self.find_processor("PE%02d" % i) l1 = self.find_communication_resource("L1_PE%02d" % i) produce = CommunicationPhase("produce", [l1, l2_C1_A15, l3_C1, ram], "write") consume = CommunicationPhase("consume", [l1, l2_C1_A15, l3_C1, ram], "read") prim.add_producer(pe, [produce]) prim.add_consumer(pe, [consume]) self.add_primitive(prim)