diff options
Diffstat (limited to 'src/mem/ruby/network/simple/PerfectSwitch.cc')
-rw-r--r-- | src/mem/ruby/network/simple/PerfectSwitch.cc | 475 |
1 files changed, 247 insertions, 228 deletions
diff --git a/src/mem/ruby/network/simple/PerfectSwitch.cc b/src/mem/ruby/network/simple/PerfectSwitch.cc index d60c5332c..bddcb8412 100644 --- a/src/mem/ruby/network/simple/PerfectSwitch.cc +++ b/src/mem/ruby/network/simple/PerfectSwitch.cc @@ -1,4 +1,3 @@ - /* * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * All rights reserved. @@ -27,289 +26,309 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - * PerfectSwitch.cc - * - * Description: See PerfectSwitch.hh - * - * $Id$ - * - */ - - +#include "mem/gems_common/util.hh" +#include "mem/protocol/Protocol.hh" +#include "mem/ruby/buffers/MessageBuffer.hh" #include "mem/ruby/network/simple/PerfectSwitch.hh" -#include "mem/ruby/slicc_interface/NetworkMessage.hh" +#include "mem/ruby/network/simple/SimpleNetwork.hh" #include "mem/ruby/profiler/Profiler.hh" +#include "mem/ruby/slicc_interface/NetworkMessage.hh" #include "mem/ruby/system/System.hh" -#include "mem/ruby/network/simple/SimpleNetwork.hh" -#include "mem/gems_common/util.hh" -#include "mem/ruby/buffers/MessageBuffer.hh" -#include "mem/protocol/Protocol.hh" const int PRIORITY_SWITCH_LIMIT = 128; // Operator for helper class -bool operator<(const LinkOrder& l1, const LinkOrder& l2) { - return (l1.m_value < l2.m_value); +bool +operator<(const LinkOrder& l1, const LinkOrder& l2) +{ + return (l1.m_value < l2.m_value); } PerfectSwitch::PerfectSwitch(SwitchID sid, SimpleNetwork* 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_virtual_networks = network_ptr->getNumberOfVirtualNetworks(); + m_switch_id = sid; + m_round_robin_start = 0; + m_network_ptr = network_ptr; + m_wakeups_wo_switch = 0; } -void PerfectSwitch::addInPort(const Vector<MessageBuffer*>& in) +void +PerfectSwitch::addInPort(const Vector<MessageBuffer*>& in) { - assert(in.size() == m_virtual_networks); - NodeID port = m_in.size(); - m_in.insertAtBottom(in); - for (int j = 0; j < m_virtual_networks; j++) { - m_in[port][j]->setConsumer(this); - string desc = "[Queue from port " + NodeIDToString(m_switch_id) + " " + NodeIDToString(port) + " " + NodeIDToString(j) + " to PerfectSwitch]"; - m_in[port][j]->setDescription(desc); - } + assert(in.size() == m_virtual_networks); + NodeID port = m_in.size(); + m_in.insertAtBottom(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 PerfectSwitch]", + NodeIDToString(m_switch_id), NodeIDToString(port), + NodeIDToString(j)); + m_in[port][j]->setDescription(desc); + } } -void PerfectSwitch::addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routing_table_entry) +void +PerfectSwitch::addOutPort(const Vector<MessageBuffer*>& out, + const NetDest& routing_table_entry) { - assert(out.size() == m_virtual_networks); + assert(out.size() == m_virtual_networks); - // Setup link order - LinkOrder l; - l.m_value = 0; - l.m_link = m_out.size(); - m_link_order.insertAtBottom(l); - - // Add to routing table - m_out.insertAtBottom(out); - m_routing_table.insertAtBottom(routing_table_entry); + // Setup link order + LinkOrder l; + l.m_value = 0; + l.m_link = m_out.size(); + m_link_order.insertAtBottom(l); + // Add to routing table + m_out.insertAtBottom(out); + m_routing_table.insertAtBottom(routing_table_entry); } -void PerfectSwitch::clearRoutingTables() +void +PerfectSwitch::clearRoutingTables() { - m_routing_table.clear(); + m_routing_table.clear(); } -void PerfectSwitch::clearBuffers() +void +PerfectSwitch::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_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(); + for (int i = 0; i < m_out.size(); i++){ + for(int vnet = 0; vnet < m_virtual_networks; vnet++) { + m_out[i][vnet]->clear(); + } } - } } -void PerfectSwitch::reconfigureOutPort(const NetDest& routing_table_entry) +void +PerfectSwitch::reconfigureOutPort(const NetDest& routing_table_entry) { - m_routing_table.insertAtBottom(routing_table_entry); + m_routing_table.insertAtBottom(routing_table_entry); } PerfectSwitch::~PerfectSwitch() { } -void PerfectSwitch::wakeup() +void +PerfectSwitch::wakeup() { - - DEBUG_EXPR(NETWORK_COMP, MedPrio, m_switch_id); - - MsgPtr msg_ptr; - - // Give the highest numbered link priority most of the time - m_wakeups_wo_switch++; - int highest_prio_vnet = m_virtual_networks-1; - int lowest_prio_vnet = 0; - int decrementer = 1; - NetworkMessage* net_msg_ptr = NULL; - - // invert priorities to avoid starvation seen in the component network - if (m_wakeups_wo_switch > PRIORITY_SWITCH_LIMIT) { - m_wakeups_wo_switch = 0; - highest_prio_vnet = 0; - lowest_prio_vnet = m_virtual_networks-1; - decrementer = -1; - } - - for (int vnet = highest_prio_vnet; (vnet*decrementer) >= (decrementer*lowest_prio_vnet); vnet -= decrementer) { - - // For all components incoming queues - int incoming = m_round_robin_start; // This is for round-robin scheduling - m_round_robin_start++; - if (m_round_robin_start >= m_in.size()) { - m_round_robin_start = 0; + DEBUG_EXPR(NETWORK_COMP, MedPrio, m_switch_id); + + MsgPtr msg_ptr; + + // Give the highest numbered link priority most of the time + m_wakeups_wo_switch++; + int highest_prio_vnet = m_virtual_networks-1; + int lowest_prio_vnet = 0; + int decrementer = 1; + NetworkMessage* net_msg_ptr = NULL; + + // invert priorities to avoid starvation seen in the component network + if (m_wakeups_wo_switch > PRIORITY_SWITCH_LIMIT) { + m_wakeups_wo_switch = 0; + highest_prio_vnet = 0; + lowest_prio_vnet = m_virtual_networks-1; + decrementer = -1; } - // 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<LinkID> output_links; - Vector<NetDest> output_link_destinations; - - // Is there a message waiting? - while (m_in[incoming][vnet]->isReady()) { - - DEBUG_EXPR(NETWORK_COMP, MedPrio, incoming); - - // Peek at message - msg_ptr = m_in[incoming][vnet]->peekMsgPtr(); - net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref()); - DEBUG_EXPR(NETWORK_COMP, MedPrio, *net_msg_ptr); - - output_links.clear(); - output_link_destinations.clear(); - NetDest msg_destinations = net_msg_ptr->getInternalDestination(); - - // Unfortunately, the token-protocol sends some - // zero-destination messages, so this assert isn't valid - // assert(msg_destinations.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 outlink=0; outlink<m_out.size(); outlink++) { - m_link_order[outlink].m_link = outlink; - m_link_order[outlink].m_value = 0; - } - } else { - // Find how clogged each link is - for (int outlink=0; outlink<m_out.size(); outlink++) { - int out_queue_length = 0; - for (int v=0; v<m_virtual_networks; v++) { - out_queue_length += m_out[outlink][v]->getSize(); - } - m_link_order[outlink].m_link = outlink; - m_link_order[outlink].m_value = 0; - m_link_order[outlink].m_value |= (out_queue_length << 8); - m_link_order[outlink].m_value |= (random() & 0xff); - } - m_link_order.sortVector(); // Look at the most empty link first - } - } - - 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; - - DEBUG_EXPR(NETWORK_COMP, MedPrio, m_routing_table[link]); - - if (msg_destinations.intersectionIsNotEmpty(m_routing_table[link])) { - - // Remember what link we're using - output_links.insertAtBottom(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.insertAtBottom(msg_destinations.AND(m_routing_table[link])); - - // Next, we update the msg_destination not to include - // those nodes that were already handled by this link - msg_destinations.removeNetDest(m_routing_table[link]); - } - } - - assert(msg_destinations.count() == 0); - //assert(output_links.size() > 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]; - enough = enough && m_out[outgoing][vnet]->areNSlotsAvailable(1); - DEBUG_MSG(NETWORK_COMP, HighPrio, "checking if node is blocked"); - DEBUG_EXPR(NETWORK_COMP, HighPrio, outgoing); - DEBUG_EXPR(NETWORK_COMP, HighPrio, vnet); - DEBUG_EXPR(NETWORK_COMP, HighPrio, enough); - } - - // There were not enough resources - if(!enough) { - g_eventQueue_ptr->scheduleEvent(this, 1); - DEBUG_MSG(NETWORK_COMP, HighPrio, "Can't deliver message to anyone since a node is blocked"); - DEBUG_EXPR(NETWORK_COMP, HighPrio, *net_msg_ptr); - break; // go to next incoming port + // For all components incoming queues + for (int vnet = highest_prio_vnet; + (vnet * decrementer) >= (decrementer * lowest_prio_vnet); + vnet -= decrementer) { + + // 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; } - 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 - unmodified_msg_ptr = *(msg_ptr.ref()); // This magic line creates a private copy of the message - } + // 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; + } - // Enqueue it - for all outgoing queues - for (int i=0; i<output_links.size(); i++) { - int outgoing = output_links[i]; - - if (i > 0) { - msg_ptr = *(unmodified_msg_ptr.ref()); // create a private copy of the unmodified message - } - - // Change the internal destination set of the message so it - // knows which destinations this link is responsible for. - net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref()); - net_msg_ptr->getInternalDestination() = output_link_destinations[i]; - - // Enqeue msg - DEBUG_NEWLINE(NETWORK_COMP,HighPrio); - DEBUG_MSG(NETWORK_COMP,HighPrio,"switch: " + int_to_string(m_switch_id) - + " enqueuing net msg from inport[" + int_to_string(incoming) + "][" - + int_to_string(vnet) +"] to outport [" + int_to_string(outgoing) - + "][" + int_to_string(vnet) +"]" - + " time: " + int_to_string(g_eventQueue_ptr->getTime()) + "."); - DEBUG_NEWLINE(NETWORK_COMP,HighPrio); - - m_out[outgoing][vnet]->enqueue(msg_ptr); + // temporary vectors to store the routing results + Vector<LinkID> output_links; + Vector<NetDest> output_link_destinations; + + // Is there a message waiting? + while (m_in[incoming][vnet]->isReady()) { + DEBUG_EXPR(NETWORK_COMP, MedPrio, incoming); + + // Peek at message + msg_ptr = m_in[incoming][vnet]->peekMsgPtr(); + net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref()); + DEBUG_EXPR(NETWORK_COMP, MedPrio, *net_msg_ptr); + + 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 + m_link_order.sortVector(); + } + } + + 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]; + DEBUG_EXPR(NETWORK_COMP, MedPrio, dst); + + if (!msg_dsts.intersectionIsNotEmpty(dst)) + continue; + + // Remember what link we're using + output_links.insertAtBottom(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.insertAtBottom(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); + //assert(output_links.size() > 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; + DEBUG_MSG(NETWORK_COMP, HighPrio, + "checking if node is blocked"); + DEBUG_EXPR(NETWORK_COMP, HighPrio, outgoing); + DEBUG_EXPR(NETWORK_COMP, HighPrio, vnet); + DEBUG_EXPR(NETWORK_COMP, HighPrio, enough); + } + + // There were not enough resources + if (!enough) { + g_eventQueue_ptr->scheduleEvent(this, 1); + DEBUG_MSG(NETWORK_COMP, HighPrio, + "Can't deliver message since a node is blocked"); + DEBUG_EXPR(NETWORK_COMP, HighPrio, *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.ref()); + } + + // Enqueue it - for all outgoing queues + for (int i=0; i<output_links.size(); i++) { + int outgoing = output_links[i]; + + if (i > 0) { + // create a private copy of the unmodified + // message + msg_ptr = *(unmodified_msg_ptr.ref()); + } + + // Change the internal destination set of the + // message so it knows which destinations this + // link is responsible for. + net_msg_ptr = safe_cast<NetworkMessage*>(msg_ptr.ref()); + net_msg_ptr->getInternalDestination() = + output_link_destinations[i]; + + // Enqeue msg + DEBUG_NEWLINE(NETWORK_COMP,HighPrio); + DEBUG_MSG(NETWORK_COMP, HighPrio, + csprintf("switch: %d enqueuing net msg from " + "inport[%d][%d] to outport [%d][%d] time: %d.", + m_switch_id, incoming, vnet, outgoing, vnet, + g_eventQueue_ptr->getTime())); + DEBUG_NEWLINE(NETWORK_COMP,HighPrio); + + m_out[outgoing][vnet]->enqueue(msg_ptr); + } + + // Dequeue msg + m_in[incoming][vnet]->pop(); + } } - - // Dequeue msg - m_in[incoming][vnet]->pop(); - } } - } } -void PerfectSwitch::printStats(std::ostream& out) const +void +PerfectSwitch::printStats(std::ostream& out) const { - out << "PerfectSwitch printStats" << endl; + out << "PerfectSwitch printStats" << endl; } -void PerfectSwitch::clearStats() +void +PerfectSwitch::clearStats() { } -void PerfectSwitch::printConfig(std::ostream& out) const +void +PerfectSwitch::printConfig(std::ostream& out) const { } -void PerfectSwitch::print(std::ostream& out) const +void +PerfectSwitch::print(std::ostream& out) const { - out << "[PerfectSwitch " << m_switch_id << "]"; + out << "[PerfectSwitch " << m_switch_id << "]"; } |