diff -r be4990a2c764 SConstruct --- a/SConstruct Thu Feb 02 04:51:13 2012 -0500 +++ b/SConstruct Tue Mar 20 10:18:55 2012 +0100 @@ -889,6 +889,10 @@ main.SConscript('ext/gzstream/SConscript', variant_dir = joinpath(build_root, 'gzstream')) +# topaz build is shared across all configs in the build root. +main.SConscript('ext/TOPAZ/SConscript', + variant_dir = joinpath(build_root, 'topaz')) + ################################################### # # This function is used to set up a directory with switching headers diff -r be4990a2c764 build_opts/ALPHA_Network_Topaz_test --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build_opts/ALPHA_Network_Topaz_test Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,4 @@ +SS_COMPATIBLE_FP = 1 +CPU_MODELS = 'AtomicSimpleCPU,TimingSimpleCPU,O3CPU,InOrderCPU' +PROTOCOL = 'Network_test' +USE_TOPAZ = True diff -r be4990a2c764 build_opts/ALPHA_directory_topaz --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build_opts/ALPHA_directory_topaz Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,5 @@ +SS_COMPATIBLE_FP = 1 +CPU_MODELS = 'AtomicSimpleCPU,TimingSimpleCPU,O3CPU,InOrderCPU' +PROTOCOL = 'MOESI_CMP_directory' +USE_TOPAZ = True +USE_TOPAZ = True diff -r be4990a2c764 build_opts/ALPHA_token_topaz --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build_opts/ALPHA_token_topaz Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,4 @@ +SS_COMPATIBLE_FP = 1 +CPU_MODELS = 'AtomicSimpleCPU,TimingSimpleCPU,O3CPU,InOrderCPU' +PROTOCOL = 'MOESI_CMP_token' +USE_TOPAZ = True diff -r be4990a2c764 configs/ruby/Ruby.py --- a/configs/ruby/Ruby.py Thu Feb 02 04:51:13 2012 -0500 +++ b/configs/ruby/Ruby.py Tue Mar 20 10:18:55 2012 +0100 @@ -72,6 +72,22 @@ parser.add_option("--ruby_stats", type="string", default="ruby.stats") + #TOPAZ options + parser.add_option("--topaz-init-file", type = "string", default="./TPZSimul.ini", + help="TOPAZ: File that declares .sgm, .sgm and .sgm" ) + + parser.add_option("--topaz-network", type = "string", default=False, + help="TOPAZ: simulation listed in .sgm to be used by TOPAZ" ) + + parser.add_option("--topaz-flit-size", type="int", default=16, + help="TOPAZ: Number of bytes per physical router-to-router wire") + + parser.add_option("--topaz-clock-ratio", type="int", default=1, + help="TOPAZ: memory-network clock multiplier") + + parser.add_option("--topaz-adaptive-interface-threshold", type = "int", default=0, + help="TOPAZ: Number of messages that has to be transmitted before to activate TOPAZ" ) + protocol = buildEnv['PROTOCOL'] exec "import %s" % protocol eval("%s.define_options(parser)" % protocol) @@ -122,6 +138,11 @@ class IntLinkClass(GarnetIntLink): pass class ExtLinkClass(GarnetExtLink): pass class RouterClass(GarnetRouter): pass + elif options.topaz_network: + class NetworkClass(TopazNetwork): pass + class IntLinkClass(SimpleIntLink): pass + class ExtLinkClass(SimpleExtLink): pass + class RouterClass(BasicRouter): pass else: class NetworkClass(SimpleNetwork): pass class IntLinkClass(SimpleIntLink): pass @@ -142,13 +163,24 @@ print "Error: could not create topology %s" % options.topology raise + if options.network_fault_model: - assert(options.garnet_network == "fixed") - fault_model = FaultModel() - network = NetworkClass(ruby_system = ruby, topology = net_topology,\ - enable_fault_model=True, fault_model = fault_model) + assert(options.garnet_network == "fixed") + fault_model = FaultModel() + network = NetworkClass(ruby_system = ruby, topology = net_topology,\ + enable_fault_model=True, fault_model = fault_model) + elif options.topaz_network: + #Garnet and Topaz are explusive + assert (not(options.garnet_network !=None)) + network = NetworkClass(ruby_system = ruby, topology = net_topology, \ + topaz_network = options.topaz_network,\ + topaz_flit_size = options.topaz_flit_size,\ + topaz_clock_ratio = options.topaz_clock_ratio, \ + topaz_adaptive_interface_threshold = options.topaz_adaptive_interface_threshold, \ + topaz_init_file =options.topaz_init_file ) else: - network = NetworkClass(ruby_system = ruby, topology = net_topology) + network = NetworkClass(ruby_system = ruby, topology = net_topology) + # # Loop through the directory controlers. diff -r be4990a2c764 src/mem/ruby/buffers/MessageBuffer.hh --- a/src/mem/ruby/buffers/MessageBuffer.hh Thu Feb 02 04:51:13 2012 -0500 +++ b/src/mem/ruby/buffers/MessageBuffer.hh Tue Mar 20 10:18:55 2012 +0100 @@ -146,6 +146,11 @@ void setIncomingLink(int link_id) { m_input_link_id = link_id; } void setVnet(int net) { m_vnet_id = net; } + //REquired by TOPAZ adaptive interface + bool isToNet() {return m_toNet;} + void toNet() { m_toNet = true; } + bool isFromNet() { return m_fromNet; } + void fromNet() { m_fromNet = true; } private: //added by SS @@ -192,6 +197,8 @@ int m_input_link_id; int m_vnet_id; + bool m_toNet; + bool m_fromNet; }; inline std::ostream& diff -r be4990a2c764 src/mem/ruby/buffers/MessageBuffer.cc --- a/src/mem/ruby/buffers/MessageBuffer.cc Thu Feb 02 04:51:13 2012 -0500 +++ b/src/mem/ruby/buffers/MessageBuffer.cc Tue Mar 20 10:18:55 2012 +0100 @@ -57,10 +57,11 @@ m_not_avail_count = 0; m_priority_rank = 0; m_name = name; - m_stall_msg_map.clear(); m_input_link_id = 0; m_vnet_id = 0; + m_toNet = false; + m_fromNet = false; } int diff -r be4990a2c764 src/mem/ruby/network/Network.hh --- a/src/mem/ruby/network/Network.hh Thu Feb 02 04:51:13 2012 -0500 +++ b/src/mem/ruby/network/Network.hh Tue Mar 20 10:18:55 2012 +0100 @@ -95,6 +95,9 @@ virtual void printConfig(std::ostream& out) const = 0; virtual void print(std::ostream& out) const = 0; + //Required to let Topaz be aware of ruby node mapping + virtual void setTopazMapping (SwitchID node0, SwitchID node1) {}; + protected: // Private copy constructor and assignment operator Network(const Network& obj); diff -r be4990a2c764 src/mem/ruby/network/Topology.cc --- a/src/mem/ruby/network/Topology.cc Thu Feb 02 04:51:13 2012 -0500 +++ b/src/mem/ruby/network/Topology.cc Tue Mar 20 10:18:55 2012 +0100 @@ -244,7 +244,7 @@ src_dest.second = dest; link_entry = m_link_map[src_dest]; net->makeInLink(src, dest - (2 * m_nodes), link_entry.link, - link_entry.direction, + link_entry.direction, routing_table_entry, isReconfiguration); } else if (dest < 2*m_nodes) { @@ -257,6 +257,12 @@ link_entry.direction, routing_table_entry, isReconfiguration); + //REquired to make TOPAZ aware of ruby Mapping + //This should be done here in order to + //have the reay in Topology Builder + //I'm unable to circunvent this. It is the only + //change done in RUBY outside the network/topaz + net->setTopazMapping(dest-m_nodes, src); } else { assert((src >= 2 * m_nodes) && (dest >= 2 * m_nodes)); src_dest.first = src; diff -r be4990a2c764 src/mem/ruby/network/topaz/SConscript --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/ruby/network/topaz/SConscript Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,44 @@ +# -*- mode:python -*- + +# Copyright (c) 2012 Univerity of Cantabria (Spain) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Pablo Abad +# Valentin Puente + +Import('*') + +if env['PROTOCOL'] == 'None': + Return() + +if env['USE_TOPAZ'] == 'None': + Return() + +SimObject('TopazNetwork.py') + +Source('TopazNetwork.cc') +Source('TopazSwitchFlow.cc') +Source('TopazSwitch.cc') diff -r be4990a2c764 src/mem/ruby/network/topaz/SConsopts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/ruby/network/topaz/SConsopts Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,45 @@ +# -*- mode:python -*- + +# Copyright (c) 2012 The University of Cantabria (Spain) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Valentin Puente +# Pablo Abad + +Import('*') + +toOpts = [ + 'True', + 'None' + ] + + +sticky_vars.AddVariables( + EnumVariable('USE_TOPAZ',"Replace Ruby Network with TOPAZ", 'None', + toOpts), + ) + +export_vars += [ 'USE_TOPAZ' ] diff -r be4990a2c764 src/mem/ruby/network/topaz/TopazNetwork.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/ruby/network/topaz/TopazNetwork.hh Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2012 The University of Cantabria (Spain) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MEM_RUBY_NETWORK_SIMPLE_TOPAZNETWORK_HH__ +#define __MEM_RUBY_NETWORK_SIMPLE_TOPAZNETWORK_HH__ + +#include +#include +#include +#include + +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/network/Network.hh" +#include "params/TopazNetwork.hh" +#include "sim/sim_object.hh" + +//Main simulator include. Download simulator from +//http://www.atc.unican.es/topaz/ and follow the guide +#include + +#include "mem/ruby/slicc_interface/NetworkMessage.hh" +struct MessageTopaz{ + MsgPtr message; + int vnet; + int queue; + int destinations; + int bcast; + int id; + //multicast support + std::vector > Vector_aux; +}; + +class NetDest; +class MessageBuffer; +class Throttle; +class TopazSwitch; +class Topology; + +class TopazNetwork : public Network +{ + public: + typedef TopazNetworkParams Params; + TopazNetwork(const Params *p); + ~TopazNetwork(); + + void init(); + + int getBufferSize() { return m_buffer_size; } + int getEndpointBandwidth() { return m_endpoint_bandwidth; } + bool getAdaptiveRouting() {return m_adaptive_routing; } + + void printStats(std::ostream& out) const; + void clearStats(); + void printConfig(std::ostream& out) const; + + int getNumberOfNodes()const {return m_nodes;}; + unsigned getProcRouterRatio() const { return m_processorClockRatio;} + unsigned getFlitSize() const { return m_flitSize;} + unsigned getUnifiy() { return m_unify; } + int getNetSize() { return m_switch_ptr_vector.size(); } + int getMessageSizeTopaz(MessageSizeType size_type) const; + int getTriggerSwitch() const { return m_firstTrigger; } + void setTriggerSwitch(int router) { m_firstTrigger=router; } + bool inWarmup() { return m_in_warmup; } + bool useGemsNetwork(int vnet); + void enableTopaz(); + void disableTopaz(); + void increaseNumMsg(int num); + void decreaseNumMsg(int vnet); + void increaseNumOrderedMsg(int num); + void increaseNumTopazOrderedMsg (int num); + void increaseNumTopazMsg(int num); + void decreaseNumTopazMsg (int vnet); + int getTopazMessages() { return m_number_topaz_messages; } + void increaseTotalMsg (int num) { m_totalNetMsg+=num; } + int getTotalMsg () { return m_totalNetMsg; } + int getTotalTopazMsg() { return m_totalTopazMsg; } + const unsigned numberOfMessages() { return m_number_messages; } + const unsigned numberOfOrderedMessages() { return m_number_ordered_messages; } + const unsigned numberOfTopazOrderedMessages() { return m_number_topaz_ordered_messages; } + const unsigned numberOfTopazMessages() { return m_number_topaz_messages; } + void setTopazMapping (SwitchID node0, SwitchID node1); + SwitchID getSwitch(int ext_node) { return m_forward_mapping[ext_node]; } + NetDest getMachines(SwitchID sid) { return m_reverse_mapping[sid]; } + MessageBuffer* getToSimNetQueue(NodeID id, bool ordered, int network_num); + MessageBuffer* getFromSimNetQueue(NodeID id, bool ordered, int network_num); +//TOPAZ + + void reset(); + + // returns the queue requested for the given component + MessageBuffer* getToNetQueue(NodeID id, bool ordered, int network_num, std::string vnet_type); + MessageBuffer* getFromNetQueue(NodeID id, bool ordered, int network_num, std::string vnet_type); + virtual const std::vector* getThrottles(NodeID id) const; + + bool isVNetOrdered(int vnet) { return m_ordered[vnet]; } + bool validVirtualNetwork(int vnet) { return m_in_use[vnet]; } + + int getNumNodes() {return m_nodes; } + + // Methods used by Topology to setup the network + void makeOutLink(SwitchID src, NodeID dest, BasicLink* link, + LinkDirection direction, + const NetDest& routing_table_entry, + bool isReconfiguration); + void makeInLink(NodeID src, SwitchID dest, BasicLink* link, + LinkDirection direction, + const NetDest& routing_table_entry, + bool isReconfiguration); + void makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link, + LinkDirection direction, + const NetDest& routing_table_entry, + bool isReconfiguration); + + void print(std::ostream& out) const; + + private: + void checkNetworkAllocation(NodeID id, bool ordered, int network_num); + void addLink(SwitchID src, SwitchID dest, int link_latency); + void makeLink(SwitchID src, SwitchID dest, + const NetDest& routing_table_entry, int link_latency); + SwitchID createSwitch(); + void makeTopology(); + void linkTopology(); + + unsigned m_processorClockRatio; + unsigned m_flitSize; + unsigned m_unify; + int m_firstTrigger; + bool m_in_warmup; + unsigned m_permanentDisable; + int m_number_messages; + int m_number_ordered_messages; + int m_number_topaz_ordered_messages; + int m_number_topaz_messages; + //maps each MachineID to the internal node it is connected to + SwitchID *m_forward_mapping; + //maps each internal node to the MachineIDs it connects. + std::vector m_reverse_mapping; + int m_totalNetMsg; + int m_totalTopazMsg; + TPZString m_simulName; + TPZString m_topazInitFile; + unsigned m_block_size; + unsigned m_topaz_adaptive_interface_threshold; + + // Private copy constructor and assignment operator + TopazNetwork(const TopazNetwork& obj); + TopazNetwork& operator=(const TopazNetwork& obj); + + // vector of queues from the components + std::vector > m_toNetQueues; + std::vector > m_fromNetQueues; + + std::vector m_in_use; + std::vector m_ordered; + std::vector m_switch_ptr_vector; + std::vector m_buffers_to_free; + std::vector m_endpoint_switches; + + int m_buffer_size; + int m_endpoint_bandwidth; + bool m_adaptive_routing; +}; + +inline std::ostream& +operator<<(std::ostream& out, const TopazNetwork& obj) +{ + obj.print(out); + out << std::flush; + return out; +} + +#endif // __MEM_RUBY_NETWORK_SIMPLE_TOPAZNETWORK_HH__ diff -r be4990a2c764 src/mem/ruby/network/topaz/TopazNetwork.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/ruby/network/topaz/TopazNetwork.cc Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,601 @@ +/* + * Copyright (c) 2012 The University of Cantabria (Spain) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "base/cast.hh" +#include "base/stl_helpers.hh" +#include "debug/RubyNetwork.hh" +#include "mem/protocol/MachineType.hh" +#include "mem/protocol/TopologyType.hh" +#include "mem/ruby/buffers/MessageBuffer.hh" +#include "mem/ruby/common/NetDest.hh" +#include "mem/ruby/network/simple/SimpleLink.hh" +#include "mem/ruby/network/simple/Throttle.hh" +#include "mem/ruby/network/topaz/TopazNetwork.hh" +#include "mem/ruby/network/topaz/TopazSwitch.hh" +#include "mem/ruby/network/topaz/TopazSwitchFlow.hh" +#include "mem/ruby/network/BasicLink.hh" +#include "mem/ruby/network/Topology.hh" +#include "mem/ruby/profiler/Profiler.hh" +#include "mem/ruby/system/System.hh" + +using namespace std; +using m5::stl_helpers::deletePointers; + +// Helper for Ruby-Topaz Mapping +// Example for 8 L1s, 32 L2s and 8 memories. +// +// 0 -------- 7 8 -------- 39 40 -------- 47 -> node number received +// L1_0 -- L1_7 L2_0 -- L2_31 Mem_0 -- Mem_7 -> MachineID returned + +extern inline +MachineID _nodeNumber_to_MachineID(SwitchID node) { + for (MachineType m = MachineType_FIRST; m < MachineType_NUM; ++m) { + int num_machines = MachineType_base_count(m); + if (node < num_machines) { + MachineID mid = {m, node}; + return mid; + } + else { + node = node - num_machines; + } + } + MachineType merror = MachineType_FIRST; + MachineID error = {merror,node}; + return error; +} + +TopazNetwork::TopazNetwork(const Params *p) + : Network(p) +{ + m_buffer_size = p->buffer_size; + m_endpoint_bandwidth = p->endpoint_bandwidth; + m_adaptive_routing = p->adaptive_routing; + + // Note: the parent Network Object constructor is called before the + // TopazNetwork child constructor. Therefore, the member variables + // used below should already be initialized. + + m_endpoint_switches.resize(m_nodes); + + m_in_use.resize(m_virtual_networks); + m_ordered.resize(m_virtual_networks); + for (int i = 0; i < m_virtual_networks; i++) { + m_in_use[i] = false; + m_ordered[i] = false; + } + m_number_messages=0; + m_number_ordered_messages=0; + m_number_topaz_ordered_messages=0; + m_number_topaz_messages=0; + m_totalNetMsg=0; + m_totalTopazMsg=0; + m_forward_mapping = new SwitchID[m_nodes]; + m_reverse_mapping.resize(m_nodes); + + // Allocate to and from queues + m_toNetQueues.resize(m_nodes); + m_fromNetQueues.resize(m_nodes); + for (int node = 0; node < m_nodes; node++) { + m_toNetQueues[node].resize(m_virtual_networks); + m_fromNetQueues[node].resize(m_virtual_networks); + for (int j = 0; j < m_virtual_networks; j++) { + m_toNetQueues[node][j] = new + MessageBuffer(csprintf("toNet node %d j %d", node, j)); + m_toNetQueues[node][j]->toNet(); + m_fromNetQueues[node][j] = new + MessageBuffer(csprintf("fromNet node %d j %d", node, j)); + m_fromNetQueues[node][j]->fromNet(); + } + } + m_flitSize=p->topaz_flit_size; + m_processorClockRatio=p->topaz_clock_ratio; + m_simulName = (p->topaz_network).c_str(); + m_topazInitFile = (p->topaz_init_file).c_str(); + m_topaz_adaptive_interface_threshold = p->topaz_adaptive_interface_threshold; +} + +void +TopazNetwork::init() +{ + Network::init(); + + // The topology pointer should have already been initialized in + // the parent class network constructor. + assert(m_topology_ptr != NULL); + int number_of_switches = m_topology_ptr->numSwitches(); + for (int i = 0; i < number_of_switches; i++) { + m_switch_ptr_vector.push_back(new TopazSwitch(i, this)); + } + + // false because this isn't a reconfiguration + m_topology_ptr->createLinks(this, false); + // + // TOPAZ INITIALIZATION AND INSTALLERS + // + // + m_permanentDisable=false; + //TOPAZ initialization file is here? + //(otherwise segment.fault) + ifstream own(m_topazInitFile); + if( ! own.good() ){ + cerr << " Can't open topaz init file :: " << m_topazInitFile << endl; + cerr<<" That file must have the route to Router, Network & Simulation SGML"<< endl; + cerr<<" you can declare it with --topaz-init-file"<"<createSimulation(initString); + //Simulated networks go from 1,2... (Watch out! is +1 than slicc's vnets) + if (TPZSIMULATOR()->getSimulation(1)->needToUnify()) { + m_unify=1; + break; + } + else { + m_unify=m_virtual_networks; + } + } + if (m_flitSize == 0) { //Not specified by ruby con + m_flitSize=TPZSIMULATOR()->getSimulation(1)->getFlitSize(); + cerr<<"Warning:topaz_flit was not specified in in Ruby.py options."; + cerr<<" It will be get from SGML specification."< FLITSIZE must be specified in simulation sgml file as"; + cerr<<" " << endl; + assert(0); + } + + for (unsigned i = 1; i <= m_unify; i++) + TPZSIMULATOR()->getSimulation(i)->setPacketLength( + getMessageSizeTopaz(MessageSizeType_Data)); + //Clock ratio + if (m_processorClockRatio == 0 ) { + m_processorClockRatio=int(TPZSIMULATOR()-> + getSimulation(1)->getNetworkClockRatioSGML()); + } + //Network cant be faster than memory + assert(m_processorClockRatio>=1); + + this->enableTopaz(); + //Grab rubys seed and re-set it + //(Topaz may internally redefine seed if it is defined in SGM + srandom(g_system_ptr->getRandomSeed()); +} + +int TopazNetwork::getMessageSizeTopaz(MessageSizeType size_type) const { + //Padding last flit + return (int) ceil((double) RubySystem::getNetwork()-> MessageSizeType_to_int( + size_type)/m_flitSize); +} + + +bool TopazNetwork::useGemsNetwork(int vnet) { + bool useGems = false; + // During warmup we use GEMS' network + if (inWarmup()) useGems = true; + // Messages in order must go all through the same network. If this is an + // ordered virtual network, send the message through the network where you + // find any message. + if (isVNetOrdered(vnet)) { + if (numberOfOrderedMessages() > 0) { + assert(numberOfTopazOrderedMessages() == 0); + useGems = true; + } + else if (numberOfTopazOrderedMessages() > 0) { + useGems = false; + } + } + const int messages_in_ruby = numberOfMessages(); + if (m_number_topaz_messages < 0) { + static bool warn_topaz_count_is_wrong = true; + if (warn_topaz_count_is_wrong) { + DPRINTF(RubyNetwork,"Topaz is not counting messages correctly,"); + DPRINTF(RubyNetwork," ignoring g_MAX_MESSAGES_THROUGH_GEMS."); + DPRINTF(RubyNetwork,"Please, fix topaz if you want to use this parameter."); + warn_topaz_count_is_wrong = false; + } + useGems = false; + } + // If the total number of messages is small + //(less than m_topaz_adaptive_interface_threshold), we can use SimpleNetwor + if ((messages_in_ruby + m_number_topaz_messages) < + m_topaz_adaptive_interface_threshold) + useGems = true; + else + useGems = false; + return useGems; +} + +void TopazNetwork::enableTopaz(){ + if( m_permanentDisable ){ + cout<<"TOPAZ PERMANETLY DISABLED"< +++++++ Topaz Enabled! +++++++ "< ******* Topaz DISABLED! ******* "<clear(); + m_fromNetQueues[node][j]->clear(); + } + } + + for(int i = 0; i < m_switch_ptr_vector.size(); i++){ + m_switch_ptr_vector[i]->clearBuffers(); + } +} + +TopazNetwork::~TopazNetwork() +{ + for (int i = 0; i < m_nodes; i++) { + deletePointers(m_toNetQueues[i]); + deletePointers(m_fromNetQueues[i]); + } + deletePointers(m_switch_ptr_vector); + deletePointers(m_buffers_to_free); + // delete m_topology_ptr; +} + +// From a switch to an endpoint node +void +TopazNetwork::makeOutLink(SwitchID src, NodeID dest, BasicLink* link, + LinkDirection direction, + const NetDest& routing_table_entry, + bool isReconfiguration) +{ + assert(dest < m_nodes); + assert(src < m_switch_ptr_vector.size()); + assert(m_switch_ptr_vector[src] != NULL); + + if (isReconfiguration) { + m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry); + return; + } + + SimpleExtLink *simple_link = safe_cast(link); + + m_switch_ptr_vector[src]->addOutPort(m_fromNetQueues[dest], + routing_table_entry, + simple_link->m_latency, + simple_link->m_bw_multiplier); + + m_endpoint_switches[dest] = m_switch_ptr_vector[src]; +} + +// From an endpoint node to a switch +void +TopazNetwork::makeInLink(NodeID src, SwitchID dest, BasicLink* link, + LinkDirection direction, + const NetDest& routing_table_entry, + bool isReconfiguration) +{ + assert(src < m_nodes); + if (isReconfiguration) { + // do nothing + return; + } + + m_switch_ptr_vector[dest]->addInPort(m_toNetQueues[src]); +} + +// From a switch to a switch +void +TopazNetwork::makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link, + LinkDirection direction, + const NetDest& routing_table_entry, + bool isReconfiguration) +{ + if (isReconfiguration) { + m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry); + return; + } + + // Create a set of new MessageBuffers + std::vector queues; + for (int i = 0; i < m_virtual_networks; i++) { + // allocate a buffer + MessageBuffer* buffer_ptr = new MessageBuffer; + buffer_ptr->setOrdering(true); + if (m_buffer_size > 0) { + buffer_ptr->resize(m_buffer_size); + } + queues.push_back(buffer_ptr); + // remember to deallocate it + m_buffers_to_free.push_back(buffer_ptr); + } + // Connect it to the two switches + SimpleIntLink *simple_link = safe_cast(link); + + m_switch_ptr_vector[dest]->addInPort(queues); + m_switch_ptr_vector[src]->addOutPort(queues, routing_table_entry, + simple_link->m_latency, + simple_link->m_bw_multiplier); +} + +void +TopazNetwork::checkNetworkAllocation(NodeID id, bool ordered, int network_num) +{ + assert(id < m_nodes); + assert(network_num < m_virtual_networks); + + if (ordered) { + m_ordered[network_num] = true; + } + m_in_use[network_num] = true; +} + +MessageBuffer* +TopazNetwork::getToNetQueue(NodeID id, bool ordered, int network_num, + std::string vnet_type) +{ + checkNetworkAllocation(id, ordered, network_num); + return m_toNetQueues[id][network_num]; +} + +MessageBuffer* +TopazNetwork::getFromNetQueue(NodeID id, bool ordered, int network_num, + std::string vnet_type) +{ + checkNetworkAllocation(id, ordered, network_num); + return m_fromNetQueues[id][network_num]; +} + +const std::vector* +TopazNetwork::getThrottles(NodeID id) const +{ + assert(id >= 0); + assert(id < m_nodes); + assert(m_endpoint_switches[id] != NULL); + return m_endpoint_switches[id]->getThrottles(); +} + +void +TopazNetwork::printStats(ostream& out) const +{ + out<<""<getSimulation(currentVnet)->writeSimulationStatus(out); + TPZSIMULATOR()->getSimulation(currentVnet)-> + getNetwork()->writeComponentStatus(out); + } + out << endl; + TopazNetwork* net=static_cast(g_system_ptr->getNetwork()); + long int Topaz_messages=net->getTotalTopazMsg(); + int percent = 100*Topaz_messages/(Topaz_messages+net->getTotalMsg()+1); + out << "TOPAZ NETWORK USAGE" << endl; + out << "Usage TOPAZ network: " << percent << "%" << endl; + out << "Total TOPAZ messages: " << Topaz_messages << endl; + out << "Total Number of messages: " << Topaz_messages+net->getTotalMsg() << endl; + out << endl; + out <<""< total_msg_counts; + total_msg_counts.resize(MessageSizeType_NUM); + for (MessageSizeType type = MessageSizeType_FIRST; + type < MessageSizeType_NUM; + ++type) { + total_msg_counts[type] = 0; + } + + for (int i = 0; i < m_switch_ptr_vector.size(); i++) { + const std::vector* throttles = + m_switch_ptr_vector[i]->getThrottles(); + + for (int p = 0; p < throttles->size(); p++) { + + const std::vector >& message_counts = + ((*throttles)[p])->getCounters(); + + for (MessageSizeType type = MessageSizeType_FIRST; + type < MessageSizeType_NUM; + ++type) { + + const std::vector &mct = message_counts[type]; + int sum = accumulate(mct.begin(), mct.end(), 0); + total_msg_counts[type] += uint64(sum); + } + } + } + uint64 total_msgs = 0; + uint64 total_bytes = 0; + for (MessageSizeType type = MessageSizeType_FIRST; + type < MessageSizeType_NUM; + ++type) { + + if (total_msg_counts[type] > 0) { + out << "total_msg_count_" << type << ": " << total_msg_counts[type] + << " " << total_msg_counts[type] * + uint64(RubySystem::getNetwork()->MessageSizeType_to_int(type)) + << endl; + + total_msgs += total_msg_counts[type]; + + total_bytes += total_msg_counts[type] * + uint64(RubySystem::getNetwork()->MessageSizeType_to_int(type)); + + } + } + + out << "total_msgs: " << total_msgs + << " total_bytes: " << total_bytes << endl; + + out << endl; + for (int i = 0; i < m_switch_ptr_vector.size(); i++) { + m_switch_ptr_vector[i]->printStats(out); + } + m_topology_ptr->printStats(out); +} + +void +TopazNetwork::clearStats() +{ + for (int i = 0; i < m_switch_ptr_vector.size(); i++) { + m_switch_ptr_vector[i]->clearStats(); + } + m_topology_ptr->clearStats(); +} + +void +TopazNetwork::printConfig(ostream& out) const +{ + out << endl; + out << "Network Configuration" << endl; + out << "---------------------" << endl; + out << "network: SIMPLE_NETWORK" << endl; + out << "topology: " << m_topology_ptr->getName() << endl; + out << endl; + + for (int i = 0; i < m_virtual_networks; i++) { + out << "virtual_net_" << i << ": "; + if (m_in_use[i]) { + out << "active, "; + if (m_ordered[i]) { + out << "ordered" << endl; + } else { + out << "unordered" << endl; + } + } else { + out << "inactive" << endl; + } + } + out << endl; + + for(int i = 0; i < m_switch_ptr_vector.size(); i++) { + m_switch_ptr_vector[i]->printConfig(out); + } + + m_topology_ptr->printConfig(out); +} + +void +TopazNetwork::print(ostream& out) const +{ + out << "[TopazNetwork]"; +} + +void TopazNetwork::increaseNumMsg(int num){ + m_number_messages+=num; +} + +void TopazNetwork::increaseNumTopazMsg(int num){ + m_number_topaz_messages+=num; + m_totalTopazMsg+=num; +} + +void TopazNetwork::decreaseNumMsg(int vnet){ + m_number_messages--; + assert(m_number_messages >= 0); + if (m_ordered[vnet]){ + if ( numberOfOrderedMessages() > 0 ){ + assert(!(numberOfTopazOrderedMessages()>0)); + m_number_ordered_messages--; + } + } +} + +void TopazNetwork::decreaseNumTopazMsg (int vnet){ + m_number_topaz_messages--; + assert(m_number_messages >= 0); + if ( m_ordered[vnet] ){ + assert(!(numberOfOrderedMessages()>0)); + m_number_topaz_ordered_messages--; + } +} + +void TopazNetwork::increaseNumOrderedMsg(int num){ + m_number_ordered_messages+=num; +} + +void TopazNetwork::increaseNumTopazOrderedMsg(int num){ + m_number_topaz_ordered_messages+=num; +} + +void TopazNetwork::setTopazMapping (SwitchID ext_node, SwitchID int_node) { + int_node -= 2*m_nodes; + MachineID machine = _nodeNumber_to_MachineID(ext_node); + m_forward_mapping[ext_node] = int_node; + m_reverse_mapping[int_node].add(machine); +} + +TopazNetwork * +TopazNetworkParams::create() +{ + return new TopazNetwork(this); +} diff -r be4990a2c764 src/mem/ruby/network/topaz/TopazNetwork.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/ruby/network/topaz/TopazNetwork.py Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,45 @@ +# -*- mode:python -*- + +# Copyright (c) 2012 Univerity of Cantabria (Spain) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Pablo Abad +# Valentin Puente + +from m5.params import * +from Network import RubyNetwork + +class TopazNetwork(RubyNetwork): + type = 'TopazNetwork' + buffer_size = Param.Int(0, + "default buffer size; 0 indicates infinite buffering"); + endpoint_bandwidth = Param.Int(1000, "bandwidth adjustment factor"); + adaptive_routing = Param.Bool(False, "enable adaptive routing"); + topaz_init_file = Param.String("./TPZSimul__ini", "File that declares .sgm, .sgm and .sgm"); + topaz_network =Param.String (None, "TOPAZ: simulation listed in .sgm to be used by TOPAZ"); + topaz_flit_size = Param.Int(0, "Number of bytes per physical router-to-router wire"); + topaz_clock_ratio = Param.Int(1,"memory-network clock multiplier"); + topaz_adaptive_interface_threshold = Param.Int(0,"Number of messages that has to be transmitted before to activate TOPAZ"); diff -r be4990a2c764 src/mem/ruby/network/topaz/TopazSwitch.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/ruby/network/topaz/TopazSwitch.hh Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2012 The University of Cantabria (Spain) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * The actual modelled switch. It use the perfect switch and a + * Throttle object to control and bandwidth and timing *only for the + * output port*. So here we have un-realistic modelling, since the + * order of PerfectSwitch and Throttle objects get woke up affect the + * message timing. A more accurate model would be having two set of + * system states, one for this cycle, one for next cycle. And on the + * cycle boundary swap the two set of states. + */ + +#ifndef __MEM_RUBY_NETWORK_TOPAZSWITCH_HH__ +#define __MEM_RUBY_NETWORK_TOPAZSWITCH_HH__ + +#include +#include + +#include "mem/ruby/common/Global.hh" + +class MessageBuffer; +class TopazSwitchFlow; +class NetDest; +class TopazNetwork; +class Throttle; + +class TopazSwitch +{ + public: + TopazSwitch(SwitchID sid, TopazNetwork* network_ptr); + ~TopazSwitch(); + + void addInPort(const std::vector& in); + void addOutPort(const std::vector& out, + const NetDest& routing_table_entry, int link_latency, + int bw_multiplier); + const Throttle* getThrottle(LinkID link_number) const; + const std::vector* getThrottles() const; + void clearRoutingTables(); + void clearBuffers(); + void reconfigureOutPort(const NetDest& routing_table_entry); + + void printStats(std::ostream& out) const; + void clearStats(); + void printConfig(std::ostream& out) const; + + void print(std::ostream& out) const; + void addOutNetPort(const std::vector& out, + const NetDest& routing_table_entry, + int link_latency, + int bw_multiplier); + + private: + // Private copy constructor and assignment operator + TopazSwitch(const TopazSwitch& obj); + TopazSwitch& operator=(const TopazSwitch& obj); + + TopazSwitchFlow* m_perfect_switch_ptr; + TopazNetwork* m_network_ptr; + std::vector m_throttles; + std::vector m_buffers_to_free; + SwitchID m_switch_id; +}; + +inline std::ostream& +operator<<(std::ostream& out, const TopazSwitch& obj) +{ + obj.print(out); + out << std::flush; + return out; +} + +#endif // __MEM_RUBY_NETWORK_TOPAZ_SWITCH_HH__ diff -r be4990a2c764 src/mem/ruby/network/topaz/TopazSwitch.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/ruby/network/topaz/TopazSwitch.cc Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2012 The University of Cantabria (Spain) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "base/cast.hh" +#include "base/stl_helpers.hh" +#include "mem/protocol/MessageSizeType.hh" +#include "mem/ruby/buffers/MessageBuffer.hh" +#include "mem/ruby/network/simple/Throttle.hh" +#include "mem/ruby/network/topaz/TopazNetwork.hh" +#include "mem/ruby/network/topaz/TopazSwitch.hh" +#include "mem/ruby/network/topaz/TopazSwitchFlow.hh" + +using namespace std; +using m5::stl_helpers::deletePointers; +using m5::stl_helpers::operator<<; + +TopazSwitch::TopazSwitch(SwitchID sid, TopazNetwork* network_ptr) +{ + m_perfect_switch_ptr = new TopazSwitchFlow(sid, network_ptr); + m_switch_id = sid; +} + +TopazSwitch::~TopazSwitch() +{ + delete m_perfect_switch_ptr; + + // Delete throttles (one per output port) + deletePointers(m_throttles); + + // Delete MessageBuffers + deletePointers(m_buffers_to_free); +} + +void +TopazSwitch::addInPort(const vector& in) +{ + m_perfect_switch_ptr->addInPort(in); +} + +void +TopazSwitch::addOutPort(const vector& out, + const NetDest& routing_table_entry, int link_latency, int bw_multiplier) +{ + Throttle* throttle_ptr = NULL; + TopazNetwork* net_ptr = + safe_cast(RubySystem::getNetwork()); + + // Create a throttle + throttle_ptr = new Throttle(m_switch_id, m_throttles.size(), link_latency, + bw_multiplier, net_ptr->getEndpointBandwidth()); + m_throttles.push_back(throttle_ptr); + + // Create one buffer per vnet (these are intermediaryQueues) + vector intermediateBuffers; + for (int i = 0; i < out.size(); i++) { + MessageBuffer* buffer_ptr = new MessageBuffer; + // Make these queues ordered + buffer_ptr->setOrdering(true); + if (net_ptr->getBufferSize() > 0) { + buffer_ptr->resize(net_ptr->getBufferSize()); + } + intermediateBuffers.push_back(buffer_ptr); + m_buffers_to_free.push_back(buffer_ptr); + } + + // Hook the queues to the PerfectSwitch + m_perfect_switch_ptr->addOutPort(intermediateBuffers, routing_table_entry); + + // Hook the queues to the Throttle + throttle_ptr->addLinks(intermediateBuffers, out); +} + +void TopazSwitch::addOutNetPort(const vector& out, + const NetDest& routing_table_entry, + int link_latency, + int bw_multiplier) +{ + Throttle* throttle_ptr = NULL; + // + // Create a throttle + throttle_ptr = new Throttle(m_switch_id, + m_throttles.size(), + link_latency, + bw_multiplier); + m_throttles.push_back(throttle_ptr); + // + // Create one buffer per vnet (these are intermediaryQueues) + vector intermediateBuffers; + for (int i=0; isetOrdering(false); + intermediateBuffers.push_back(buffer_ptr); + m_buffers_to_free.push_back(buffer_ptr); + } + // Hook the queues to the PerfectSwitch + m_perfect_switch_ptr->addOutNetPort(intermediateBuffers, routing_table_entry); + // Hook the queues to the Throttle + throttle_ptr->addLinks(intermediateBuffers, out); +} + +void +TopazSwitch::clearRoutingTables() +{ + m_perfect_switch_ptr->clearRoutingTables(); +} + +void +TopazSwitch::clearBuffers() +{ + m_perfect_switch_ptr->clearBuffers(); + for (int i = 0; i < m_throttles.size(); i++) { + if (m_throttles[i] != NULL) { + m_throttles[i]->clear(); + } + } +} + +void +TopazSwitch::reconfigureOutPort(const NetDest& routing_table_entry) +{ + m_perfect_switch_ptr->reconfigureOutPort(routing_table_entry); +} + +const Throttle* +TopazSwitch::getThrottle(LinkID link_number) const +{ + assert(m_throttles[link_number] != NULL); + return m_throttles[link_number]; +} + +const vector* +TopazSwitch::getThrottles() const +{ + return &m_throttles; +} + +void +TopazSwitch::printStats(std::ostream& out) const +{ + ccprintf(out, "switch_%d_inlinks: %d\n", m_switch_id, + m_perfect_switch_ptr->getInLinks()); + ccprintf(out, "switch_%d_outlinks: %d\n", m_switch_id, + m_perfect_switch_ptr->getOutLinks()); + + // Average link utilizations + double average_utilization = 0.0; + int throttle_count = 0; + + for (int i = 0; i < m_throttles.size(); i++) { + Throttle* throttle_ptr = m_throttles[i]; + if (throttle_ptr) { + average_utilization += throttle_ptr->getUtilization(); + throttle_count++; + } + } + average_utilization = + throttle_count == 0 ? 0 : average_utilization / throttle_count; + + // Individual link utilizations + out << "links_utilized_percent_switch_" << m_switch_id << ": " + << average_utilization << endl; + + for (int link = 0; link < m_throttles.size(); link++) { + Throttle* throttle_ptr = m_throttles[link]; + if (throttle_ptr != NULL) { + out << " links_utilized_percent_switch_" << m_switch_id + << "_link_" << link << ": " + << throttle_ptr->getUtilization() << " bw: " + << throttle_ptr->getLinkBandwidth() + << " base_latency: " << throttle_ptr->getLatency() << endl; + } + } + out << endl; + + // Traffic breakdown + for (int link = 0; link < m_throttles.size(); link++) { + Throttle* throttle_ptr = m_throttles[link]; + if (!throttle_ptr) + continue; + + const vector >& message_counts = + throttle_ptr->getCounters(); + for (int int_type = 0; int_type < MessageSizeType_NUM; int_type++) { + MessageSizeType type = MessageSizeType(int_type); + const vector &mct = message_counts[type]; + int sum = accumulate(mct.begin(), mct.end(), 0); + if (sum == 0) + continue; + + out << " outgoing_messages_switch_" << m_switch_id + << "_link_" << link << "_" << type << ": " << sum << " " + << sum * RubySystem::getNetwork()->MessageSizeType_to_int(type) + << " "; + out << mct; + out << " base_latency: " + << throttle_ptr->getLatency() << endl; + } + } + out << endl; +} + +void +TopazSwitch::clearStats() +{ + m_perfect_switch_ptr->clearStats(); + for (int i = 0; i < m_throttles.size(); i++) { + if (m_throttles[i] != NULL) + m_throttles[i]->clearStats(); + } +} + +void +TopazSwitch::printConfig(std::ostream& out) const +{ + m_perfect_switch_ptr->printConfig(out); + for (int i = 0; i < m_throttles.size(); i++) { + if (m_throttles[i] != NULL) + m_throttles[i]->printConfig(out); + } +} + +void +TopazSwitch::print(std::ostream& out) const +{ + out << "[Switch]"; +} + diff -r be4990a2c764 src/mem/ruby/network/topaz/TopazSwitchFlow.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/ruby/network/topaz/TopazSwitchFlow.hh Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2012 The University of Cantabria (Spain) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Perfect switch, of course it is perfect and no latency or what so + * ever. Every cycle it is woke up and perform all the necessary + * routings that must be done. Note, this switch also has number of + * input ports/output ports and has a routing table as well. + */ + +#ifndef __MEM_RUBY_NETWORK_SIMPLE_TOPAZSWITCHFLOW_HH__ +#define __MEM_RUBY_NETWORK_SIMPLE_TOPAZSWITCHFLOW_HH__ + +#include +#include +#include + +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/common/Global.hh" + +class MessageBuffer; +class NetDest; +class TopazNetwork; + +struct LinkOrder +{ + int m_link; + int m_value; +}; + +class TopazSwitchFlow : public Consumer +{ + public: + TopazSwitchFlow(SwitchID sid, TopazNetwork* network_ptr); + ~TopazSwitchFlow(); + + std::string name() + { return csprintf("TopazSwitch-%i", m_switch_id); } + + void addInPort(const std::vector& in); + void addOutPort(const std::vector& out, + const NetDest& routing_table_entry); + void clearRoutingTables(); + void clearBuffers(); + void reconfigureOutPort(const NetDest& routing_table_entry); + int getInLinks() const { return m_in.size(); } + int getOutLinks() const { return m_out.size(); } + + void wakeup(); + void wakeupVnet(int vnet); + void storeEventInfo(int info); + int getUnicastDestination(NetDest destinations); + unsigned long long getMulticastDestination(NetDest& destinations); + void filterZeroDistanceMessages(MsgPtr& msg_ptr, int vnet, NetDest& destinations); + NetDest getConsumerDestinations(int switch_id, NetDest& mensaje); + void wakeUpTopaz(); + void addOutNetPort(const std::vector& out, + const NetDest& routing_table_entry); + void printStats(std::ostream& out) const; + void clearStats(); + void printConfig(std::ostream& out) const; + + void print(std::ostream& out) const; + + private: + // Private copy constructor and assignment operator + TopazSwitchFlow(const TopazSwitchFlow& obj); + TopazSwitchFlow& operator=(const TopazSwitchFlow& obj); + + SwitchID m_switch_id; + + // vector of queues from the components + std::vector > m_in; + std::vector > m_out; + std::vector m_routing_table; + std::vector m_link_order; + int m_virtual_networks; + int m_round_robin_start; + int m_wakeups_wo_switch; + TopazNetwork* m_network_ptr; + long unsigned m_ruby_start; + long unsigned m_minimunTimeAgain; + std::vector m_pending_message_count; +}; + +inline std::ostream& +operator<<(std::ostream& out, const TopazSwitchFlow& obj) +{ + obj.print(out); + out << std::flush; + return out; +} + +#endif // __MEM_RUBY_NETWORK_SIMPLE_TOPAZSWITCHFLOW_HH__ diff -r be4990a2c764 src/mem/ruby/network/topaz/TopazSwitchFlow.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/ruby/network/topaz/TopazSwitchFlow.cc Tue Mar 20 10:18:55 2012 +0100 @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2012 The University of Cantabria (Spain) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include "base/cast.hh" +#include "debug/RubyNetwork.hh" +#include "mem/ruby/buffers/MessageBuffer.hh" +#include "mem/ruby/network/topaz/TopazNetwork.hh" +#include "mem/ruby/network/topaz/TopazSwitchFlow.hh" +#include "mem/ruby/profiler/Profiler.hh" +#include "mem/ruby/slicc_interface/NetworkMessage.hh" +#include "mem/ruby/system/System.hh" + +using namespace std; + +const int PRIORITY_SWITCH_LIMIT = 128; + +// helpr for STL vector sorting +bool +predicateToSort (const LinkOrder& l1, const LinkOrder& l2) +{ + return (l1.m_value < l2.m_value); +} + +TopazSwitchFlow::TopazSwitchFlow(SwitchID sid, TopazNetwork* network_ptr) +{ + m_virtual_networks = network_ptr->getNumberOfVirtualNetworks(); + m_switch_id = sid; + m_round_robin_start = 0; + m_network_ptr = network_ptr; + m_wakeups_wo_switch = 0; + m_ruby_start=0; + for(int i = 0;i < m_virtual_networks;++i) + { + m_pending_message_count.push_back(0); + } +} + +void +TopazSwitchFlow::addInPort(const vector& in) +{ + assert(in.size() == m_virtual_networks); + NodeID port = m_in.size(); + m_in.push_back(in); + + for (int j = 0; j < m_virtual_networks; j++) { + m_in[port][j]->setConsumer(this); + string desc = csprintf("[Queue from port %s %s %s to TopazSwitchFlow]", + to_string(m_switch_id), to_string(port), to_string(j)); + m_in[port][j]->setDescription(desc); + m_in[port][j]->setIncomingLink(port); + m_in[port][j]->setVnet(j); + } +} + +void +TopazSwitchFlow::addOutPort(const vector& out, + const NetDest& routing_table_entry) +{ + assert(out.size() == m_virtual_networks); + + // Setup link order + LinkOrder l; + l.m_value = 0; + l.m_link = m_out.size(); + m_link_order.push_back(l); + + // Add to routing table + m_out.push_back(out); + m_routing_table.push_back(routing_table_entry); +} + +void +TopazSwitchFlow::addOutNetPort(const vector& out, + const NetDest& routing_table_entry){ + assert(out.size() == m_virtual_networks); + // Setup link order + LinkOrder l; + l.m_value = 0; + l.m_link = m_out.size(); + m_link_order.push_back(l); + // Add to routing table + m_out.push_back(out); + m_routing_table.push_back(routing_table_entry); + /*VPVFIX + for (int j = 0; j < m_virtual_networks; j++) { + m_out[l.m_link][j]->setOutSwitchPort(); + m_out[l.m_link][j]->setNetwork(m_network_ptr); + m_out[l.m_link][j]->setVNet(j); + }*/ +} + +void +TopazSwitchFlow::clearRoutingTables() +{ + m_routing_table.clear(); +} + +void +TopazSwitchFlow::clearBuffers() +{ + for (int i = 0; i < m_in.size(); i++){ + for(int vnet = 0; vnet < m_virtual_networks; vnet++) { + m_in[i][vnet]->clear(); + } + } + + for (int i = 0; i < m_out.size(); i++){ + for(int vnet = 0; vnet < m_virtual_networks; vnet++) { + m_out[i][vnet]->clear(); + } + } +} + +void +TopazSwitchFlow::reconfigureOutPort(const NetDest& routing_table_entry) +{ + m_routing_table.push_back(routing_table_entry); +} + +TopazSwitchFlow::~TopazSwitchFlow() +{ +} + +//****************************************************************************** +// Function in charge of calculating the destination of an Unicast message +//****************************************************************************** +int TopazSwitchFlow::getUnicastDestination(NetDest destinations) { + int this_id; + int m_queue=0; + for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) { + int limit = MachineType_base_count(mType); + for (int component = 0; component < limit; component++) { + MachineID mach = {mType, component}; + if (destinations.elementAt(mach)==1) { + this_id=m_network_ptr->getSwitch(m_queue+component); + return this_id; + } + } + m_queue += MachineType_base_count(mType); + } + assert(m_queue!=0); + return 1; +} + +//****************************************************************************** +// Function in charge of calculating the mask of a Multicast message +//****************************************************************************** +unsigned long long +TopazSwitchFlow::getMulticastDestination(NetDest& destinations) { + unsigned long long routers = 0; + int node_number = 0; + for (MachineType m = MachineType_FIRST; m < MachineType_NUM; ++m) { + for (int c = 0; cgetSwitch(node_number)); + routers = routers | mask; + } + node_number++; + } + } + return routers; +} + +//****************************************************************************** +// Function in charge of filtering messages with src=dst +// this kind of messages are not routed through TOPAZ network +//****************************************************************************** +void +TopazSwitchFlow::filterZeroDistanceMessages( MsgPtr& msg_ptr, int vnet, + NetDest& destinations) { + int source=m_switch_id; + int destination; + bool isOrdered= m_network_ptr->isVNetOrdered(vnet); + int m_queue=0; + for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType){ + int limit = MachineType_base_count(mType); + for (int component = 0; component < limit; component++) { + MachineID mach = {mType, component}; + if(destinations.elementAt(mach)==1) { + destination=m_network_ptr->getSwitch(m_queue+component); + if (source == destination){ + MessageBuffer* outputQueue=m_network_ptr-> + getFromSimNetQueue(component+m_queue, isOrdered, vnet); + MsgPtr unaMas=msg_ptr->clone(); + outputQueue->enqueue(unaMas); + destinations.remove(mach); // Here destinations are modified + } + } + } + m_queue += MachineType_base_count(mType); + } +} + +//****************************************************************************** +// This function returns a NetDest vector result of the following operation +// msg_destinations & Router_mask +// where Router_mask indicates which components are reachable through a certain +// switch +//****************************************************************************** +NetDest +TopazSwitchFlow::getConsumerDestinations(int switch_id, NetDest& dest) { + NetDest consumers = m_network_ptr->getMachines(switch_id); + return consumers.AND(dest); +} + +//****************************************************************************** +// Function in charge of deciding which network must be used, GEMS or TOPAZ +//****************************************************************************** +void TopazSwitchFlow::wakeup() { + m_wakeups_wo_switch++; + int highest_prio_vnet = m_virtual_networks-1; + int source=m_switch_id; + for (int vnet = highest_prio_vnet; vnet >= 0; vnet--) { + //If we are in warmup or the adaptive interface is used and then + //network is lightly loadad we may ruby network + if (m_network_ptr->useGemsNetwork(vnet)) { + wakeupVnet(vnet); + } + //Otherwise, use topaz + else{ + if(m_pending_message_count[vnet]>0) + for(int incoming=0;incomingisReady()){ + MsgPtr msg_ptr = m_in[incoming][vnet]->peekMsgPtr(); + NetworkMessage *net_msg_ptr = + dynamic_cast(msg_ptr.get()); + NetDest msg_destinations = + net_msg_ptr->getInternalDestination(); + int topaz_size=m_network_ptr-> + getMessageSizeTopaz(net_msg_ptr->getMessageSize()); + assert(topaz_size); + filterZeroDistanceMessages( msg_ptr, vnet, msg_destinations); + if ( msg_destinations.count() !=0) { + TPZMessage msg; + TPZPosition origen; + TPZPosition destino; + MessageTopaz* copia=new MessageTopaz; + copia->message=msg_ptr->clone(); + copia->vnet=vnet; + copia->destinations=msg_destinations.count(); + // TOPAZ message generation + msg.setExternalInfo(static_cast(copia)); + msg.setGenerationTime(TPZSIMULATOR()-> + getSimulation(1)->getCurrentTime()); + origen=TPZSIMULATOR()->getSimulation(1)-> + getNetwork()->CreatePosition(source); + msg.setSource(origen); + msg.setVnet(vnet+1); + msg.setMessageSize(1); + msg.setPacketSize(topaz_size); + if (m_network_ptr->isVNetOrdered(vnet)){ + msg.setOrdered(); + m_network_ptr-> + increaseNumTopazOrderedMsg(msg_destinations.count()); + } + if (msg_destinations.count()==1) { + msg.clearMulticast(); + int componente = getUnicastDestination(msg_destinations); + destino=TPZSIMULATOR()->getSimulation(1)-> + getNetwork()->CreatePosition(componente); + msg.setDestiny(destino); + } + else { + msg.setMulticast(); + //This destination is necessary because topaz + //checks the existence + //of src and destination routers + //this destination is only used for this purpose, + //no messages will arrive to it. + msg.setDestiny(origen); + unsigned long long msgMask= + getMulticastDestination(msg_destinations); + msg.setMsgmask(msgMask); + } + // Send the message to the network + DPRINTF(RubyNetwork, "Send at switch: [%d] vnet: [%d] time: [%d].\n", + m_switch_id, vnet, g_eventQueue_ptr->getTime()); + TPZSIMULATOR()->getSimulation(1)->getNetwork()->sendMessage(msg); + m_network_ptr->increaseNumTopazMsg(msg_destinations.count()); + } + m_in[incoming][vnet]->pop(); + m_pending_message_count[vnet]--; + } + } + } + } + //ijust a prewarmed simulation + if (m_network_ptr->inWarmup()) return; + if (m_network_ptr->getTriggerSwitch() == ~0) { + m_network_ptr->setTriggerSwitch(m_switch_id); + } + //Only first switch run and implement consumption. + if ( m_switch_id != m_network_ptr->getTriggerSwitch() ) return; + wakeUpTopaz(); +} + +//****************************************************************************** +// This function is in charge of running TOPAZ and collecting the messages +// to send then back to GEMS queues +//****************************************************************************** +void TopazSwitchFlow::wakeUpTopaz() { + long unsigned current_time = + static_cast(g_eventQueue_ptr->getTime()) - m_ruby_start; + int procesorNetRatio=m_network_ptr->getProcRouterRatio(); + int messagesOnNets=0; + long diff_time = current_time - TPZSIMULATOR()->getSimulation(1)->getCurrentTime()*procesorNetRatio; + if (diff_time > 0) { + TPZSIMULATOR()->getSimulation(1)->setCurrentTime((current_time/procesorNetRatio)-1); + TPZSIMULATOR()->getSimulation(1)->run(1); + for (int consumer = 0; + consumergetSimulation(1)->getNetwork()->Number_of_nodes(); + consumer++) { + TPZPosition position_f= + TPZSIMULATOR()->getSimulation(1)->getNetwork()->CreatePosition(consumer); + void* ptr =(TPZSIMULATOR()->getSimulation(1)->getExternalInfoAt(position_f)); + if (ptr!=NULL) { + MessageTopaz* topaz_message = static_cast(ptr); + assert (topaz_message->destinations>0); + MsgPtr localCopy = (topaz_message->message); + NetworkMessage* net_msg_ptr = + dynamic_cast(localCopy.get()); + int vvnet=topaz_message->vnet; + int isOrdered= m_network_ptr->isVNetOrdered(vvnet); + NetDest ConsDestinations = + getConsumerDestinations(consumer, + net_msg_ptr->getInternalDestination()); + DPRINTF(RubyNetwork, "Arrival at switch: [%d] vnet: [%d] time: [%d].\n", + consumer, vvnet, g_eventQueue_ptr->getTime()); + int m_queue=0; + for (MachineType mType = MachineType_FIRST; + mType < MachineType_NUM; ++mType) { + int limit = MachineType_base_count(mType); + for (int component = 0; component < limit; component++) { + MachineID mach = {mType, component}; + if(ConsDestinations.elementAt(mach)==1) { + MsgPtr unaMas = localCopy->clone(); + MessageBuffer* outputQueue= + m_network_ptr->getFromSimNetQueue(component+m_queue, + isOrdered, + vvnet); + outputQueue->enqueue(unaMas); + topaz_message->destinations=topaz_message->destinations-1; + m_network_ptr->decreaseNumTopazMsg(vvnet); + } + } + m_queue += MachineType_base_count(mType); + } + int pendientes=topaz_message->destinations; + if (pendientes==0) delete topaz_message; + } + } + messagesOnNets=m_network_ptr->getTopazMessages(); + } + if ( messagesOnNets!=0) + g_eventQueue_ptr->scheduleEvent(this, 1); +} + +void TopazSwitchFlow::wakeupVnet(int vnet) { + NetworkMessage* net_msg_ptr; + MsgPtr msg_ptr; + // This is for round-robin scheduling + int incoming = m_round_robin_start; + m_round_robin_start++; + if (m_round_robin_start >= m_in.size()) { + m_round_robin_start = 0; + } + + if(m_pending_message_count[vnet] > 0) { + // for all input ports, use round robin scheduling + for (int counter = 0; counter < m_in.size(); counter++) { + // Round robin scheduling + incoming++; + if (incoming >= m_in.size()) { + incoming = 0; + } + + // temporary vectors to store the routing results + vector output_links; + vector output_link_destinations; + + // Is there a message waiting? + while (m_in[incoming][vnet]->isReady()) { + DPRINTF(RubyNetwork, "incoming: %d\n", incoming); + + // Peek at message + msg_ptr = m_in[incoming][vnet]->peekMsgPtr(); + net_msg_ptr = safe_cast(msg_ptr.get()); + DPRINTF(RubyNetwork, "Message: %s\n", (*net_msg_ptr)); + //New adaptive interface. We have to catch al messages + //moving thorugh GEMS and TOPAZ + // Keeping track of messeges through GEMS + + if( m_in[incoming][vnet]->isToNet()) { + if (m_network_ptr->isVNetOrdered(vnet)) { + m_network_ptr->increaseNumOrderedMsg(net_msg_ptr->getInternalDestination().count()); + } + m_network_ptr->increaseTotalMsg(net_msg_ptr->getInternalDestination().count()); + m_network_ptr->increaseNumMsg(net_msg_ptr->getInternalDestination().count()); + } + + output_links.clear(); + output_link_destinations.clear(); + NetDest msg_dsts = + net_msg_ptr->getInternalDestination(); + + // Unfortunately, the token-protocol sends some + // zero-destination messages, so this assert isn't valid + // assert(msg_dsts.count() > 0); + + assert(m_link_order.size() == m_routing_table.size()); + assert(m_link_order.size() == m_out.size()); + if (m_network_ptr->getAdaptiveRouting()) { + if (m_network_ptr->isVNetOrdered(vnet)) { + + // Don't adaptively route + for (int out = 0; out < m_out.size(); out++) { + m_link_order[out].m_link = out; + m_link_order[out].m_value = 0; + } + } else { + + // Find how clogged each link is + for (int out = 0; out < m_out.size(); out++) { + int out_queue_length = 0; + for (int v = 0; v < m_virtual_networks; v++) { + out_queue_length += m_out[out][v]->getSize(); + } + int value = + (out_queue_length << 8) | (random() & 0xff); + m_link_order[out].m_link = out; + m_link_order[out].m_value = value; + } + + // Look at the most empty link first + sort(m_link_order.begin(), m_link_order.end(), predicateToSort); + } + } + for (int i = 0; i < m_routing_table.size(); i++) { + // pick the next link to look at + int link = m_link_order[i].m_link; + NetDest dst = m_routing_table[link]; + DPRINTF(RubyNetwork, "dst: %s\n", dst); + + if (!msg_dsts.intersectionIsNotEmpty(dst)) + continue; + + // Remember what link we're using + output_links.push_back(link); + + // Need to remember which destinations need this + // message in another vector. This Set is the + // intersection of the routing_table entry and the + // current destination set. The intersection must + // not be empty, since we are inside "if" + output_link_destinations.push_back(msg_dsts.AND(dst)); + + // Next, we update the msg_destination not to + // include those nodes that were already handled + // by this link + msg_dsts.removeNetDest(dst); + } + + assert(msg_dsts.count() == 0); + + // Check for resources - for all outgoing queues + bool enough = true; + for (int i = 0; i < output_links.size(); i++) { + int outgoing = output_links[i]; + if (!m_out[outgoing][vnet]->areNSlotsAvailable(1)) + enough = false; + DPRINTF(RubyNetwork, "Checking if node is blocked ..." + "outgoing: %d, vnet: %d, enough: %d\n", + outgoing, vnet, enough); + } + + // There were not enough resources + if (!enough) { + g_eventQueue_ptr->scheduleEvent(this, 1); + DPRINTF(RubyNetwork, "Can't deliver message since a node " + "is blocked\n"); + DPRINTF(RubyNetwork, "Message: %s\n", (*net_msg_ptr)); + break; // go to next incoming port + } + + MsgPtr unmodified_msg_ptr; + + if (output_links.size() > 1) { + // If we are sending this message down more than + // one link (size>1), we need to make a copy of + // the message so each branch can have a different + // internal destination we need to create an + // unmodified MsgPtr because the MessageBuffer + // enqueue func will modify the message + + // This magic line creates a private copy of the + // message + unmodified_msg_ptr = msg_ptr->clone(); + } + + // Enqueue it - for all outgoing queues + for (int i=0; i 0) { + // create a private copy of the unmodified + // message + msg_ptr = unmodified_msg_ptr->clone(); + } + + // Change the internal destination set of the + // message so it knows which destinations this + // link is responsible for. + net_msg_ptr = safe_cast(msg_ptr.get()); + net_msg_ptr->getInternalDestination() = + output_link_destinations[i]; + + // Enqeue msg + DPRINTF(RubyNetwork, "Enqueuing net msg from " + "inport[%d][%d] to outport [%d][%d].\n", + incoming, vnet, outgoing, vnet); + + int spooling_delay=1; + + if (m_out[outgoing][vnet]->isFromNet()) { + net_msg_ptr = safe_cast(msg_ptr.get()); + spooling_delay += m_network_ptr->getMessageSizeTopaz(net_msg_ptr->getMessageSize()); + m_network_ptr->decreaseNumMsg(vnet); + } + m_out[outgoing][vnet]->enqueue(msg_ptr,spooling_delay); + } + + // Dequeue msg + m_in[incoming][vnet]->pop(); + m_pending_message_count[vnet]--; + } + } + } +} + + +void +TopazSwitchFlow::storeEventInfo(int info) +{ + m_pending_message_count[info]++; +} + + +void +TopazSwitchFlow::printStats(std::ostream& out) const +{ + out << "TopazSwitchFlow printStats" << endl; +} + +void +TopazSwitchFlow::clearStats() +{ +} + +void +TopazSwitchFlow::printConfig(std::ostream& out) const +{ +} + +void +TopazSwitchFlow::print(std::ostream& out) const +{ + out << "[TopazSwitchFlow " << m_switch_id << "]"; +} +