From 2f30950143cc70bc42a3c8a4111d7cf8198ec881 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Mon, 11 May 2009 10:38:43 -0700 Subject: ruby: Import ruby and slicc from GEMS We eventually plan to replace the m5 cache hierarchy with the GEMS hierarchy, but for now we will make both live alongside eachother. --- src/mem/ruby/network/simple/PerfectSwitch.cc | 319 +++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 src/mem/ruby/network/simple/PerfectSwitch.cc (limited to 'src/mem/ruby/network/simple/PerfectSwitch.cc') diff --git a/src/mem/ruby/network/simple/PerfectSwitch.cc b/src/mem/ruby/network/simple/PerfectSwitch.cc new file mode 100644 index 000000000..a88a29e83 --- /dev/null +++ b/src/mem/ruby/network/simple/PerfectSwitch.cc @@ -0,0 +1,319 @@ + +/* + * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * 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. + */ + +/* + * PerfectSwitch.C + * + * Description: See PerfectSwitch.h + * + * $Id$ + * + */ + + +#include "PerfectSwitch.hh" +#include "NetworkMessage.hh" +#include "Profiler.hh" +#include "System.hh" +#include "SimpleNetwork.hh" +#include "util.hh" +#include "MessageBuffer.hh" +#include "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); +} + +PerfectSwitch::PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr) +{ + m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS; // FIXME - pass me as a parameter? + m_switch_id = sid; + m_round_robin_start = 0; + m_network_ptr = network_ptr; + m_wakeups_wo_switch = 0; +} + +void PerfectSwitch::addInPort(const Vector& 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); + } +} + +void PerfectSwitch::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.insertAtBottom(l); + + // Add to routing table + m_out.insertAtBottom(out); + m_routing_table.insertAtBottom(routing_table_entry); + + if (g_PRINT_TOPOLOGY) { + m_out_link_vec.insertAtBottom(out); + } +} + +void PerfectSwitch::clearRoutingTables() +{ + m_routing_table.clear(); +} + +void PerfectSwitch::clearBuffers() +{ + for(int i=0; iclear(); + } + } + + for(int i=0; iclear(); + } + } +} + +void PerfectSwitch::reconfigureOutPort(const NetDest& routing_table_entry) +{ + m_routing_table.insertAtBottom(routing_table_entry); +} + +PerfectSwitch::~PerfectSwitch() +{ +} + +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; + bool schedule_wakeup = false; + 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; + } + + // 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()) { + + DEBUG_EXPR(NETWORK_COMP, MedPrio, incoming); + + // Peek at message + msg_ptr = m_in[incoming][vnet]->peekMsgPtr(); + net_msg_ptr = dynamic_cast(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 (g_adaptive_routing) { + if (m_network_ptr->isVNetOrdered(vnet)) { + // Don't adaptively route + for (int outlink=0; outlinkgetSize(); + } + 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 0); + + // Check for resources - for all outgoing queues + bool enough = true; + for (int i=0; iareNSlotsAvailable(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 + } + + 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 + } + + // Enqueue it - for all outgoing queues + for (int i=0; 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(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); + } + + // Dequeue msg + m_in[incoming][vnet]->pop(); + } + } + } +} + +void PerfectSwitch::printStats(ostream& out) const +{ + out << "PerfectSwitch printStats" << endl; +} + +void PerfectSwitch::clearStats() +{ +} + +void PerfectSwitch::printConfig(ostream& out) const +{ +} + +void PerfectSwitch::print(ostream& out) const +{ + out << "[PerfectSwitch " << m_switch_id << "]"; +} + -- cgit v1.2.3