NetworkInterface.cc revision 11797
111666Stushar@ece.gatech.edu/* 211666Stushar@ece.gatech.edu * Copyright (c) 2008 Princeton University 311666Stushar@ece.gatech.edu * Copyright (c) 2016 Georgia Institute of Technology 411666Stushar@ece.gatech.edu * All rights reserved. 511666Stushar@ece.gatech.edu * 611666Stushar@ece.gatech.edu * Redistribution and use in source and binary forms, with or without 711666Stushar@ece.gatech.edu * modification, are permitted provided that the following conditions are 811666Stushar@ece.gatech.edu * met: redistributions of source code must retain the above copyright 911666Stushar@ece.gatech.edu * notice, this list of conditions and the following disclaimer; 1011666Stushar@ece.gatech.edu * redistributions in binary form must reproduce the above copyright 1111666Stushar@ece.gatech.edu * notice, this list of conditions and the following disclaimer in the 1211666Stushar@ece.gatech.edu * documentation and/or other materials provided with the distribution; 1311666Stushar@ece.gatech.edu * neither the name of the copyright holders nor the names of its 1411666Stushar@ece.gatech.edu * contributors may be used to endorse or promote products derived from 1511666Stushar@ece.gatech.edu * this software without specific prior written permission. 1611666Stushar@ece.gatech.edu * 1711666Stushar@ece.gatech.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1811666Stushar@ece.gatech.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1911666Stushar@ece.gatech.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2011666Stushar@ece.gatech.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2111666Stushar@ece.gatech.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2211666Stushar@ece.gatech.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2311666Stushar@ece.gatech.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2411666Stushar@ece.gatech.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2511666Stushar@ece.gatech.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2611666Stushar@ece.gatech.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2711666Stushar@ece.gatech.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2811666Stushar@ece.gatech.edu * 2911666Stushar@ece.gatech.edu * Authors: Niket Agarwal 3011666Stushar@ece.gatech.edu * Tushar Krishna 3111666Stushar@ece.gatech.edu */ 3211666Stushar@ece.gatech.edu 3311666Stushar@ece.gatech.edu 3411666Stushar@ece.gatech.edu#include "mem/ruby/network/garnet2.0/NetworkInterface.hh" 3511666Stushar@ece.gatech.edu 3611666Stushar@ece.gatech.edu#include <cassert> 3711666Stushar@ece.gatech.edu#include <cmath> 3811666Stushar@ece.gatech.edu 3911666Stushar@ece.gatech.edu#include "base/cast.hh" 4011666Stushar@ece.gatech.edu#include "base/stl_helpers.hh" 4111666Stushar@ece.gatech.edu#include "debug/RubyNetwork.hh" 4211666Stushar@ece.gatech.edu#include "mem/ruby/network/MessageBuffer.hh" 4311666Stushar@ece.gatech.edu#include "mem/ruby/network/garnet2.0/Credit.hh" 4411666Stushar@ece.gatech.edu#include "mem/ruby/network/garnet2.0/flitBuffer.hh" 4511666Stushar@ece.gatech.edu#include "mem/ruby/slicc_interface/Message.hh" 4611666Stushar@ece.gatech.edu 4711666Stushar@ece.gatech.eduusing namespace std; 4811666Stushar@ece.gatech.eduusing m5::stl_helpers::deletePointers; 4911666Stushar@ece.gatech.edu 5011666Stushar@ece.gatech.eduNetworkInterface::NetworkInterface(const Params *p) 5111666Stushar@ece.gatech.edu : ClockedObject(p), Consumer(this), m_id(p->id), 5211666Stushar@ece.gatech.edu m_virtual_networks(p->virt_nets), m_vc_per_vnet(p->vcs_per_vnet), 5311762Sjieming.yin@amd.com m_num_vcs(m_vc_per_vnet * m_virtual_networks), 5411762Sjieming.yin@amd.com m_deadlock_threshold(p->garnet_deadlock_threshold), 5511762Sjieming.yin@amd.com vc_busy_counter(m_virtual_networks, 0) 5611666Stushar@ece.gatech.edu{ 5711666Stushar@ece.gatech.edu m_router_id = -1; 5811666Stushar@ece.gatech.edu m_vc_round_robin = 0; 5911666Stushar@ece.gatech.edu m_ni_out_vcs.resize(m_num_vcs); 6011666Stushar@ece.gatech.edu m_ni_out_vcs_enqueue_time.resize(m_num_vcs); 6111666Stushar@ece.gatech.edu outCreditQueue = new flitBuffer(); 6211666Stushar@ece.gatech.edu 6311666Stushar@ece.gatech.edu // instantiating the NI flit buffers 6411666Stushar@ece.gatech.edu for (int i = 0; i < m_num_vcs; i++) { 6511666Stushar@ece.gatech.edu m_ni_out_vcs[i] = new flitBuffer(); 6611666Stushar@ece.gatech.edu m_ni_out_vcs_enqueue_time[i] = Cycles(INFINITE_); 6711666Stushar@ece.gatech.edu } 6811666Stushar@ece.gatech.edu 6911666Stushar@ece.gatech.edu m_vc_allocator.resize(m_virtual_networks); // 1 allocator per vnet 7011666Stushar@ece.gatech.edu for (int i = 0; i < m_virtual_networks; i++) { 7111666Stushar@ece.gatech.edu m_vc_allocator[i] = 0; 7211666Stushar@ece.gatech.edu } 7311797Smatthew.poremba@amd.com 7411797Smatthew.poremba@amd.com m_stall_count.resize(m_virtual_networks); 7511666Stushar@ece.gatech.edu} 7611666Stushar@ece.gatech.edu 7711666Stushar@ece.gatech.eduvoid 7811666Stushar@ece.gatech.eduNetworkInterface::init() 7911666Stushar@ece.gatech.edu{ 8011666Stushar@ece.gatech.edu for (int i = 0; i < m_num_vcs; i++) { 8111666Stushar@ece.gatech.edu m_out_vc_state.push_back(new OutVcState(i, m_net_ptr)); 8211666Stushar@ece.gatech.edu } 8311666Stushar@ece.gatech.edu} 8411666Stushar@ece.gatech.edu 8511666Stushar@ece.gatech.eduNetworkInterface::~NetworkInterface() 8611666Stushar@ece.gatech.edu{ 8711666Stushar@ece.gatech.edu deletePointers(m_out_vc_state); 8811666Stushar@ece.gatech.edu deletePointers(m_ni_out_vcs); 8911666Stushar@ece.gatech.edu delete outCreditQueue; 9011666Stushar@ece.gatech.edu delete outFlitQueue; 9111666Stushar@ece.gatech.edu} 9211666Stushar@ece.gatech.edu 9311666Stushar@ece.gatech.eduvoid 9411666Stushar@ece.gatech.eduNetworkInterface::addInPort(NetworkLink *in_link, 9511666Stushar@ece.gatech.edu CreditLink *credit_link) 9611666Stushar@ece.gatech.edu{ 9711666Stushar@ece.gatech.edu inNetLink = in_link; 9811666Stushar@ece.gatech.edu in_link->setLinkConsumer(this); 9911666Stushar@ece.gatech.edu outCreditLink = credit_link; 10011666Stushar@ece.gatech.edu credit_link->setSourceQueue(outCreditQueue); 10111666Stushar@ece.gatech.edu} 10211666Stushar@ece.gatech.edu 10311666Stushar@ece.gatech.eduvoid 10411666Stushar@ece.gatech.eduNetworkInterface::addOutPort(NetworkLink *out_link, 10511666Stushar@ece.gatech.edu CreditLink *credit_link, 10611666Stushar@ece.gatech.edu SwitchID router_id) 10711666Stushar@ece.gatech.edu{ 10811666Stushar@ece.gatech.edu inCreditLink = credit_link; 10911666Stushar@ece.gatech.edu credit_link->setLinkConsumer(this); 11011666Stushar@ece.gatech.edu 11111666Stushar@ece.gatech.edu outNetLink = out_link; 11211666Stushar@ece.gatech.edu outFlitQueue = new flitBuffer(); 11311666Stushar@ece.gatech.edu out_link->setSourceQueue(outFlitQueue); 11411666Stushar@ece.gatech.edu 11511666Stushar@ece.gatech.edu m_router_id = router_id; 11611666Stushar@ece.gatech.edu} 11711666Stushar@ece.gatech.edu 11811666Stushar@ece.gatech.eduvoid 11911666Stushar@ece.gatech.eduNetworkInterface::addNode(vector<MessageBuffer *>& in, 12011666Stushar@ece.gatech.edu vector<MessageBuffer *>& out) 12111666Stushar@ece.gatech.edu{ 12211666Stushar@ece.gatech.edu inNode_ptr = in; 12311666Stushar@ece.gatech.edu outNode_ptr = out; 12411666Stushar@ece.gatech.edu 12511666Stushar@ece.gatech.edu for (auto& it : in) { 12611666Stushar@ece.gatech.edu if (it != nullptr) { 12711666Stushar@ece.gatech.edu it->setConsumer(this); 12811666Stushar@ece.gatech.edu } 12911666Stushar@ece.gatech.edu } 13011666Stushar@ece.gatech.edu} 13111666Stushar@ece.gatech.edu 13211797Smatthew.poremba@amd.comvoid 13311797Smatthew.poremba@amd.comNetworkInterface::dequeueCallback() 13411797Smatthew.poremba@amd.com{ 13511797Smatthew.poremba@amd.com // An output MessageBuffer has dequeued something this cycle and there 13611797Smatthew.poremba@amd.com // is now space to enqueue a stalled message. However, we cannot wake 13711797Smatthew.poremba@amd.com // on the same cycle as the dequeue. Schedule a wake at the soonest 13811797Smatthew.poremba@amd.com // possible time (next cycle). 13911797Smatthew.poremba@amd.com scheduleEventAbsolute(clockEdge(Cycles(1))); 14011797Smatthew.poremba@amd.com} 14111797Smatthew.poremba@amd.com 14211797Smatthew.poremba@amd.comvoid 14311797Smatthew.poremba@amd.comNetworkInterface::incrementStats(flit *t_flit) 14411797Smatthew.poremba@amd.com{ 14511797Smatthew.poremba@amd.com int vnet = t_flit->get_vnet(); 14611797Smatthew.poremba@amd.com 14711797Smatthew.poremba@amd.com // Latency 14811797Smatthew.poremba@amd.com m_net_ptr->increment_received_flits(vnet); 14911797Smatthew.poremba@amd.com Cycles network_delay = 15011797Smatthew.poremba@amd.com t_flit->get_dequeue_time() - t_flit->get_enqueue_time() - Cycles(1); 15111797Smatthew.poremba@amd.com Cycles src_queueing_delay = t_flit->get_src_delay(); 15211797Smatthew.poremba@amd.com Cycles dest_queueing_delay = (curCycle() - t_flit->get_dequeue_time()); 15311797Smatthew.poremba@amd.com Cycles queueing_delay = src_queueing_delay + dest_queueing_delay; 15411797Smatthew.poremba@amd.com 15511797Smatthew.poremba@amd.com m_net_ptr->increment_flit_network_latency(network_delay, vnet); 15611797Smatthew.poremba@amd.com m_net_ptr->increment_flit_queueing_latency(queueing_delay, vnet); 15711797Smatthew.poremba@amd.com 15811797Smatthew.poremba@amd.com if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) { 15911797Smatthew.poremba@amd.com m_net_ptr->increment_received_packets(vnet); 16011797Smatthew.poremba@amd.com m_net_ptr->increment_packet_network_latency(network_delay, vnet); 16111797Smatthew.poremba@amd.com m_net_ptr->increment_packet_queueing_latency(queueing_delay, vnet); 16211797Smatthew.poremba@amd.com } 16311797Smatthew.poremba@amd.com 16411797Smatthew.poremba@amd.com // Hops 16511797Smatthew.poremba@amd.com m_net_ptr->increment_total_hops(t_flit->get_route().hops_traversed); 16611797Smatthew.poremba@amd.com} 16711666Stushar@ece.gatech.edu 16811666Stushar@ece.gatech.edu/* 16911666Stushar@ece.gatech.edu * The NI wakeup checks whether there are any ready messages in the protocol 17011666Stushar@ece.gatech.edu * buffer. If yes, it picks that up, flitisizes it into a number of flits and 17111666Stushar@ece.gatech.edu * puts it into an output buffer and schedules the output link. On a wakeup 17211666Stushar@ece.gatech.edu * it also checks whether there are flits in the input link. If yes, it picks 17311666Stushar@ece.gatech.edu * them up and if the flit is a tail, the NI inserts the corresponding message 17411666Stushar@ece.gatech.edu * into the protocol buffer. It also checks for credits being sent by the 17511666Stushar@ece.gatech.edu * downstream router. 17611666Stushar@ece.gatech.edu */ 17711666Stushar@ece.gatech.edu 17811666Stushar@ece.gatech.eduvoid 17911666Stushar@ece.gatech.eduNetworkInterface::wakeup() 18011666Stushar@ece.gatech.edu{ 18111666Stushar@ece.gatech.edu DPRINTF(RubyNetwork, "Network Interface %d connected to router %d " 18211666Stushar@ece.gatech.edu "woke up at time: %lld\n", m_id, m_router_id, curCycle()); 18311666Stushar@ece.gatech.edu 18411666Stushar@ece.gatech.edu MsgPtr msg_ptr; 18511666Stushar@ece.gatech.edu Tick curTime = clockEdge(); 18611666Stushar@ece.gatech.edu 18711666Stushar@ece.gatech.edu // Checking for messages coming from the protocol 18811666Stushar@ece.gatech.edu // can pick up a message/cycle for each virtual net 18911666Stushar@ece.gatech.edu for (int vnet = 0; vnet < inNode_ptr.size(); ++vnet) { 19011666Stushar@ece.gatech.edu MessageBuffer *b = inNode_ptr[vnet]; 19111666Stushar@ece.gatech.edu if (b == nullptr) { 19211666Stushar@ece.gatech.edu continue; 19311666Stushar@ece.gatech.edu } 19411666Stushar@ece.gatech.edu 19511666Stushar@ece.gatech.edu if (b->isReady(curTime)) { // Is there a message waiting 19611666Stushar@ece.gatech.edu msg_ptr = b->peekMsgPtr(); 19711666Stushar@ece.gatech.edu if (flitisizeMessage(msg_ptr, vnet)) { 19811666Stushar@ece.gatech.edu b->dequeue(curTime); 19911666Stushar@ece.gatech.edu } 20011666Stushar@ece.gatech.edu } 20111666Stushar@ece.gatech.edu } 20211666Stushar@ece.gatech.edu 20311666Stushar@ece.gatech.edu scheduleOutputLink(); 20411666Stushar@ece.gatech.edu checkReschedule(); 20511666Stushar@ece.gatech.edu 20611797Smatthew.poremba@amd.com // Check if there are flits stalling a virtual channel. Track if a 20711797Smatthew.poremba@amd.com // message is enqueued to restrict ejection to one message per cycle. 20811797Smatthew.poremba@amd.com bool messageEnqueuedThisCycle = checkStallQueue(); 20911797Smatthew.poremba@amd.com 21011666Stushar@ece.gatech.edu /*********** Check the incoming flit link **********/ 21111666Stushar@ece.gatech.edu if (inNetLink->isReady(curCycle())) { 21211666Stushar@ece.gatech.edu flit *t_flit = inNetLink->consumeLink(); 21311797Smatthew.poremba@amd.com int vnet = t_flit->get_vnet(); 21411797Smatthew.poremba@amd.com t_flit->set_dequeue_time(curCycle()); 21511797Smatthew.poremba@amd.com 21611797Smatthew.poremba@amd.com // If a tail flit is received, enqueue into the protocol buffers if 21711797Smatthew.poremba@amd.com // space is available. Otherwise, exchange non-tail flits for credits. 21811666Stushar@ece.gatech.edu if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) { 21911797Smatthew.poremba@amd.com if (!messageEnqueuedThisCycle && 22011797Smatthew.poremba@amd.com outNode_ptr[vnet]->areNSlotsAvailable(1, curTime)) { 22111797Smatthew.poremba@amd.com // Space is available. Enqueue to protocol buffer. 22211797Smatthew.poremba@amd.com outNode_ptr[vnet]->enqueue(t_flit->get_msg_ptr(), curTime, 22311797Smatthew.poremba@amd.com cyclesToTicks(Cycles(1))); 22411666Stushar@ece.gatech.edu 22511797Smatthew.poremba@amd.com // Simply send a credit back since we are not buffering 22611797Smatthew.poremba@amd.com // this flit in the NI 22711797Smatthew.poremba@amd.com sendCredit(t_flit, true); 22811797Smatthew.poremba@amd.com 22911797Smatthew.poremba@amd.com // Update stats and delete flit pointer 23011797Smatthew.poremba@amd.com incrementStats(t_flit); 23111797Smatthew.poremba@amd.com delete t_flit; 23211797Smatthew.poremba@amd.com } else { 23311797Smatthew.poremba@amd.com // No space available- Place tail flit in stall queue and set 23411797Smatthew.poremba@amd.com // up a callback for when protocol buffer is dequeued. Stat 23511797Smatthew.poremba@amd.com // update and flit pointer deletion will occur upon unstall. 23611797Smatthew.poremba@amd.com m_stall_queue.push_back(t_flit); 23711797Smatthew.poremba@amd.com m_stall_count[vnet]++; 23811797Smatthew.poremba@amd.com 23911797Smatthew.poremba@amd.com auto cb = std::bind(&NetworkInterface::dequeueCallback, this); 24011797Smatthew.poremba@amd.com outNode_ptr[vnet]->registerDequeueCallback(cb); 24111797Smatthew.poremba@amd.com } 24211797Smatthew.poremba@amd.com } else { 24311797Smatthew.poremba@amd.com // Non-tail flit. Send back a credit but not VC free signal. 24411797Smatthew.poremba@amd.com sendCredit(t_flit, false); 24511797Smatthew.poremba@amd.com 24611797Smatthew.poremba@amd.com // Update stats and delete flit pointer. 24711797Smatthew.poremba@amd.com incrementStats(t_flit); 24811797Smatthew.poremba@amd.com delete t_flit; 24911666Stushar@ece.gatech.edu } 25011666Stushar@ece.gatech.edu } 25111666Stushar@ece.gatech.edu 25211666Stushar@ece.gatech.edu /****************** Check the incoming credit link *******/ 25311666Stushar@ece.gatech.edu 25411666Stushar@ece.gatech.edu if (inCreditLink->isReady(curCycle())) { 25511666Stushar@ece.gatech.edu Credit *t_credit = (Credit*) inCreditLink->consumeLink(); 25611666Stushar@ece.gatech.edu m_out_vc_state[t_credit->get_vc()]->increment_credit(); 25711666Stushar@ece.gatech.edu if (t_credit->is_free_signal()) { 25811666Stushar@ece.gatech.edu m_out_vc_state[t_credit->get_vc()]->setState(IDLE_, curCycle()); 25911666Stushar@ece.gatech.edu } 26011666Stushar@ece.gatech.edu delete t_credit; 26111666Stushar@ece.gatech.edu } 26211797Smatthew.poremba@amd.com 26311797Smatthew.poremba@amd.com 26411797Smatthew.poremba@amd.com // It is possible to enqueue multiple outgoing credit flits if a message 26511797Smatthew.poremba@amd.com // was unstalled in the same cycle as a new message arrives. In this 26611797Smatthew.poremba@amd.com // case, we should schedule another wakeup to ensure the credit is sent 26711797Smatthew.poremba@amd.com // back. 26811797Smatthew.poremba@amd.com if (outCreditQueue->getSize() > 0) { 26911797Smatthew.poremba@amd.com outCreditLink->scheduleEventAbsolute(clockEdge(Cycles(1))); 27011797Smatthew.poremba@amd.com } 27111666Stushar@ece.gatech.edu} 27211666Stushar@ece.gatech.edu 27311797Smatthew.poremba@amd.comvoid 27411797Smatthew.poremba@amd.comNetworkInterface::sendCredit(flit *t_flit, bool is_free) 27511797Smatthew.poremba@amd.com{ 27611797Smatthew.poremba@amd.com Credit *credit_flit = new Credit(t_flit->get_vc(), is_free, curCycle()); 27711797Smatthew.poremba@amd.com outCreditQueue->insert(credit_flit); 27811797Smatthew.poremba@amd.com} 27911797Smatthew.poremba@amd.com 28011797Smatthew.poremba@amd.combool 28111797Smatthew.poremba@amd.comNetworkInterface::checkStallQueue() 28211797Smatthew.poremba@amd.com{ 28311797Smatthew.poremba@amd.com bool messageEnqueuedThisCycle = false; 28411797Smatthew.poremba@amd.com Tick curTime = clockEdge(); 28511797Smatthew.poremba@amd.com 28611797Smatthew.poremba@amd.com if (!m_stall_queue.empty()) { 28711797Smatthew.poremba@amd.com for (auto stallIter = m_stall_queue.begin(); 28811797Smatthew.poremba@amd.com stallIter != m_stall_queue.end(); ) { 28911797Smatthew.poremba@amd.com flit *stallFlit = *stallIter; 29011797Smatthew.poremba@amd.com int vnet = stallFlit->get_vnet(); 29111797Smatthew.poremba@amd.com 29211797Smatthew.poremba@amd.com // If we can now eject to the protocol buffer, send back credits 29311797Smatthew.poremba@amd.com if (outNode_ptr[vnet]->areNSlotsAvailable(1, curTime)) { 29411797Smatthew.poremba@amd.com outNode_ptr[vnet]->enqueue(stallFlit->get_msg_ptr(), curTime, 29511797Smatthew.poremba@amd.com cyclesToTicks(Cycles(1))); 29611797Smatthew.poremba@amd.com 29711797Smatthew.poremba@amd.com // Send back a credit with free signal now that the VC is no 29811797Smatthew.poremba@amd.com // longer stalled. 29911797Smatthew.poremba@amd.com sendCredit(stallFlit, true); 30011797Smatthew.poremba@amd.com 30111797Smatthew.poremba@amd.com // Update Stats 30211797Smatthew.poremba@amd.com incrementStats(stallFlit); 30311797Smatthew.poremba@amd.com 30411797Smatthew.poremba@amd.com // Flit can now safely be deleted and removed from stall queue 30511797Smatthew.poremba@amd.com delete stallFlit; 30611797Smatthew.poremba@amd.com m_stall_queue.erase(stallIter); 30711797Smatthew.poremba@amd.com m_stall_count[vnet]--; 30811797Smatthew.poremba@amd.com 30911797Smatthew.poremba@amd.com // If there are no more stalled messages for this vnet, the 31011797Smatthew.poremba@amd.com // callback on it's MessageBuffer is not needed. 31111797Smatthew.poremba@amd.com if (m_stall_count[vnet] == 0) 31211797Smatthew.poremba@amd.com outNode_ptr[vnet]->unregisterDequeueCallback(); 31311797Smatthew.poremba@amd.com 31411797Smatthew.poremba@amd.com messageEnqueuedThisCycle = true; 31511797Smatthew.poremba@amd.com break; 31611797Smatthew.poremba@amd.com } else { 31711797Smatthew.poremba@amd.com ++stallIter; 31811797Smatthew.poremba@amd.com } 31911797Smatthew.poremba@amd.com } 32011797Smatthew.poremba@amd.com } 32111797Smatthew.poremba@amd.com 32211797Smatthew.poremba@amd.com return messageEnqueuedThisCycle; 32311797Smatthew.poremba@amd.com} 32411666Stushar@ece.gatech.edu 32511666Stushar@ece.gatech.edu// Embed the protocol message into flits 32611666Stushar@ece.gatech.edubool 32711666Stushar@ece.gatech.eduNetworkInterface::flitisizeMessage(MsgPtr msg_ptr, int vnet) 32811666Stushar@ece.gatech.edu{ 32911666Stushar@ece.gatech.edu Message *net_msg_ptr = msg_ptr.get(); 33011666Stushar@ece.gatech.edu NetDest net_msg_dest = net_msg_ptr->getDestination(); 33111666Stushar@ece.gatech.edu 33211666Stushar@ece.gatech.edu // gets all the destinations associated with this message. 33311666Stushar@ece.gatech.edu vector<NodeID> dest_nodes = net_msg_dest.getAllDest(); 33411666Stushar@ece.gatech.edu 33511666Stushar@ece.gatech.edu // Number of flits is dependent on the link bandwidth available. 33611666Stushar@ece.gatech.edu // This is expressed in terms of bytes/cycle or the flit size 33711666Stushar@ece.gatech.edu int num_flits = (int) ceil((double) m_net_ptr->MessageSizeType_to_int( 33811666Stushar@ece.gatech.edu net_msg_ptr->getMessageSize())/m_net_ptr->getNiFlitSize()); 33911666Stushar@ece.gatech.edu 34011666Stushar@ece.gatech.edu // loop to convert all multicast messages into unicast messages 34111666Stushar@ece.gatech.edu for (int ctr = 0; ctr < dest_nodes.size(); ctr++) { 34211666Stushar@ece.gatech.edu 34311666Stushar@ece.gatech.edu // this will return a free output virtual channel 34411666Stushar@ece.gatech.edu int vc = calculateVC(vnet); 34511666Stushar@ece.gatech.edu 34611666Stushar@ece.gatech.edu if (vc == -1) { 34711666Stushar@ece.gatech.edu return false ; 34811666Stushar@ece.gatech.edu } 34911666Stushar@ece.gatech.edu MsgPtr new_msg_ptr = msg_ptr->clone(); 35011666Stushar@ece.gatech.edu NodeID destID = dest_nodes[ctr]; 35111666Stushar@ece.gatech.edu 35211666Stushar@ece.gatech.edu Message *new_net_msg_ptr = new_msg_ptr.get(); 35311666Stushar@ece.gatech.edu if (dest_nodes.size() > 1) { 35411666Stushar@ece.gatech.edu NetDest personal_dest; 35511666Stushar@ece.gatech.edu for (int m = 0; m < (int) MachineType_NUM; m++) { 35611666Stushar@ece.gatech.edu if ((destID >= MachineType_base_number((MachineType) m)) && 35711666Stushar@ece.gatech.edu destID < MachineType_base_number((MachineType) (m+1))) { 35811666Stushar@ece.gatech.edu // calculating the NetDest associated with this destID 35911666Stushar@ece.gatech.edu personal_dest.clear(); 36011666Stushar@ece.gatech.edu personal_dest.add((MachineID) {(MachineType) m, (destID - 36111666Stushar@ece.gatech.edu MachineType_base_number((MachineType) m))}); 36211666Stushar@ece.gatech.edu new_net_msg_ptr->getDestination() = personal_dest; 36311666Stushar@ece.gatech.edu break; 36411666Stushar@ece.gatech.edu } 36511666Stushar@ece.gatech.edu } 36611666Stushar@ece.gatech.edu net_msg_dest.removeNetDest(personal_dest); 36711666Stushar@ece.gatech.edu // removing the destination from the original message to reflect 36811666Stushar@ece.gatech.edu // that a message with this particular destination has been 36911666Stushar@ece.gatech.edu // flitisized and an output vc is acquired 37011666Stushar@ece.gatech.edu net_msg_ptr->getDestination().removeNetDest(personal_dest); 37111666Stushar@ece.gatech.edu } 37211666Stushar@ece.gatech.edu 37311666Stushar@ece.gatech.edu // Embed Route into the flits 37411666Stushar@ece.gatech.edu // NetDest format is used by the routing table 37511666Stushar@ece.gatech.edu // Custom routing algorithms just need destID 37611666Stushar@ece.gatech.edu RouteInfo route; 37711666Stushar@ece.gatech.edu route.vnet = vnet; 37811666Stushar@ece.gatech.edu route.net_dest = new_net_msg_ptr->getDestination(); 37911666Stushar@ece.gatech.edu route.src_ni = m_id; 38011666Stushar@ece.gatech.edu route.src_router = m_router_id; 38111666Stushar@ece.gatech.edu route.dest_ni = destID; 38211666Stushar@ece.gatech.edu route.dest_router = m_net_ptr->get_router_id(destID); 38311666Stushar@ece.gatech.edu 38411666Stushar@ece.gatech.edu // initialize hops_traversed to -1 38511666Stushar@ece.gatech.edu // so that the first router increments it to 0 38611666Stushar@ece.gatech.edu route.hops_traversed = -1; 38711666Stushar@ece.gatech.edu 38811666Stushar@ece.gatech.edu m_net_ptr->increment_injected_packets(vnet); 38911666Stushar@ece.gatech.edu for (int i = 0; i < num_flits; i++) { 39011666Stushar@ece.gatech.edu m_net_ptr->increment_injected_flits(vnet); 39111666Stushar@ece.gatech.edu flit *fl = new flit(i, vc, vnet, route, num_flits, new_msg_ptr, 39211666Stushar@ece.gatech.edu curCycle()); 39311666Stushar@ece.gatech.edu 39411666Stushar@ece.gatech.edu fl->set_src_delay(curCycle() - ticksToCycles(msg_ptr->getTime())); 39511666Stushar@ece.gatech.edu m_ni_out_vcs[vc]->insert(fl); 39611666Stushar@ece.gatech.edu } 39711666Stushar@ece.gatech.edu 39811666Stushar@ece.gatech.edu m_ni_out_vcs_enqueue_time[vc] = curCycle(); 39911666Stushar@ece.gatech.edu m_out_vc_state[vc]->setState(ACTIVE_, curCycle()); 40011666Stushar@ece.gatech.edu } 40111666Stushar@ece.gatech.edu return true ; 40211666Stushar@ece.gatech.edu} 40311666Stushar@ece.gatech.edu 40411666Stushar@ece.gatech.edu// Looking for a free output vc 40511666Stushar@ece.gatech.eduint 40611666Stushar@ece.gatech.eduNetworkInterface::calculateVC(int vnet) 40711666Stushar@ece.gatech.edu{ 40811666Stushar@ece.gatech.edu for (int i = 0; i < m_vc_per_vnet; i++) { 40911666Stushar@ece.gatech.edu int delta = m_vc_allocator[vnet]; 41011666Stushar@ece.gatech.edu m_vc_allocator[vnet]++; 41111666Stushar@ece.gatech.edu if (m_vc_allocator[vnet] == m_vc_per_vnet) 41211666Stushar@ece.gatech.edu m_vc_allocator[vnet] = 0; 41311666Stushar@ece.gatech.edu 41411666Stushar@ece.gatech.edu if (m_out_vc_state[(vnet*m_vc_per_vnet) + delta]->isInState( 41511666Stushar@ece.gatech.edu IDLE_, curCycle())) { 41611762Sjieming.yin@amd.com vc_busy_counter[vnet] = 0; 41711666Stushar@ece.gatech.edu return ((vnet*m_vc_per_vnet) + delta); 41811666Stushar@ece.gatech.edu } 41911666Stushar@ece.gatech.edu } 42011762Sjieming.yin@amd.com 42111762Sjieming.yin@amd.com vc_busy_counter[vnet] += 1; 42211762Sjieming.yin@amd.com panic_if(vc_busy_counter[vnet] > m_deadlock_threshold, 42311762Sjieming.yin@amd.com "%s: Possible network deadlock in vnet: %d at time: %llu \n", 42411762Sjieming.yin@amd.com name(), vnet, curTick()); 42511762Sjieming.yin@amd.com 42611666Stushar@ece.gatech.edu return -1; 42711666Stushar@ece.gatech.edu} 42811666Stushar@ece.gatech.edu 42911666Stushar@ece.gatech.edu 43011666Stushar@ece.gatech.edu/** This function looks at the NI buffers 43111666Stushar@ece.gatech.edu * if some buffer has flits which are ready to traverse the link in the next 43211666Stushar@ece.gatech.edu * cycle, and the downstream output vc associated with this flit has buffers 43311666Stushar@ece.gatech.edu * left, the link is scheduled for the next cycle 43411666Stushar@ece.gatech.edu */ 43511666Stushar@ece.gatech.edu 43611666Stushar@ece.gatech.eduvoid 43711666Stushar@ece.gatech.eduNetworkInterface::scheduleOutputLink() 43811666Stushar@ece.gatech.edu{ 43911666Stushar@ece.gatech.edu int vc = m_vc_round_robin; 44011666Stushar@ece.gatech.edu m_vc_round_robin++; 44111666Stushar@ece.gatech.edu if (m_vc_round_robin == m_num_vcs) 44211666Stushar@ece.gatech.edu m_vc_round_robin = 0; 44311666Stushar@ece.gatech.edu 44411666Stushar@ece.gatech.edu for (int i = 0; i < m_num_vcs; i++) { 44511666Stushar@ece.gatech.edu vc++; 44611666Stushar@ece.gatech.edu if (vc == m_num_vcs) 44711666Stushar@ece.gatech.edu vc = 0; 44811666Stushar@ece.gatech.edu 44911666Stushar@ece.gatech.edu // model buffer backpressure 45011666Stushar@ece.gatech.edu if (m_ni_out_vcs[vc]->isReady(curCycle()) && 45111666Stushar@ece.gatech.edu m_out_vc_state[vc]->has_credit()) { 45211666Stushar@ece.gatech.edu 45311666Stushar@ece.gatech.edu bool is_candidate_vc = true; 45411666Stushar@ece.gatech.edu int t_vnet = get_vnet(vc); 45511666Stushar@ece.gatech.edu int vc_base = t_vnet * m_vc_per_vnet; 45611666Stushar@ece.gatech.edu 45711666Stushar@ece.gatech.edu if (m_net_ptr->isVNetOrdered(t_vnet)) { 45811666Stushar@ece.gatech.edu for (int vc_offset = 0; vc_offset < m_vc_per_vnet; 45911666Stushar@ece.gatech.edu vc_offset++) { 46011666Stushar@ece.gatech.edu int t_vc = vc_base + vc_offset; 46111666Stushar@ece.gatech.edu if (m_ni_out_vcs[t_vc]->isReady(curCycle())) { 46211666Stushar@ece.gatech.edu if (m_ni_out_vcs_enqueue_time[t_vc] < 46311666Stushar@ece.gatech.edu m_ni_out_vcs_enqueue_time[vc]) { 46411666Stushar@ece.gatech.edu is_candidate_vc = false; 46511666Stushar@ece.gatech.edu break; 46611666Stushar@ece.gatech.edu } 46711666Stushar@ece.gatech.edu } 46811666Stushar@ece.gatech.edu } 46911666Stushar@ece.gatech.edu } 47011666Stushar@ece.gatech.edu if (!is_candidate_vc) 47111666Stushar@ece.gatech.edu continue; 47211666Stushar@ece.gatech.edu 47311666Stushar@ece.gatech.edu m_out_vc_state[vc]->decrement_credit(); 47411666Stushar@ece.gatech.edu // Just removing the flit 47511666Stushar@ece.gatech.edu flit *t_flit = m_ni_out_vcs[vc]->getTopFlit(); 47611666Stushar@ece.gatech.edu t_flit->set_time(curCycle() + Cycles(1)); 47711666Stushar@ece.gatech.edu outFlitQueue->insert(t_flit); 47811666Stushar@ece.gatech.edu // schedule the out link 47911666Stushar@ece.gatech.edu outNetLink->scheduleEventAbsolute(clockEdge(Cycles(1))); 48011666Stushar@ece.gatech.edu 48111666Stushar@ece.gatech.edu if (t_flit->get_type() == TAIL_ || 48211666Stushar@ece.gatech.edu t_flit->get_type() == HEAD_TAIL_) { 48311666Stushar@ece.gatech.edu m_ni_out_vcs_enqueue_time[vc] = Cycles(INFINITE_); 48411666Stushar@ece.gatech.edu } 48511666Stushar@ece.gatech.edu return; 48611666Stushar@ece.gatech.edu } 48711666Stushar@ece.gatech.edu } 48811666Stushar@ece.gatech.edu} 48911666Stushar@ece.gatech.edu 49011666Stushar@ece.gatech.eduint 49111666Stushar@ece.gatech.eduNetworkInterface::get_vnet(int vc) 49211666Stushar@ece.gatech.edu{ 49311666Stushar@ece.gatech.edu for (int i = 0; i < m_virtual_networks; i++) { 49411666Stushar@ece.gatech.edu if (vc >= (i*m_vc_per_vnet) && vc < ((i+1)*m_vc_per_vnet)) { 49511666Stushar@ece.gatech.edu return i; 49611666Stushar@ece.gatech.edu } 49711666Stushar@ece.gatech.edu } 49811666Stushar@ece.gatech.edu fatal("Could not determine vc"); 49911666Stushar@ece.gatech.edu} 50011666Stushar@ece.gatech.edu 50111666Stushar@ece.gatech.edu 50211666Stushar@ece.gatech.edu// Wakeup the NI in the next cycle if there are waiting 50311666Stushar@ece.gatech.edu// messages in the protocol buffer, or waiting flits in the 50411666Stushar@ece.gatech.edu// output VC buffer 50511666Stushar@ece.gatech.eduvoid 50611666Stushar@ece.gatech.eduNetworkInterface::checkReschedule() 50711666Stushar@ece.gatech.edu{ 50811666Stushar@ece.gatech.edu for (const auto& it : inNode_ptr) { 50911666Stushar@ece.gatech.edu if (it == nullptr) { 51011666Stushar@ece.gatech.edu continue; 51111666Stushar@ece.gatech.edu } 51211666Stushar@ece.gatech.edu 51311666Stushar@ece.gatech.edu while (it->isReady(clockEdge())) { // Is there a message waiting 51411666Stushar@ece.gatech.edu scheduleEvent(Cycles(1)); 51511666Stushar@ece.gatech.edu return; 51611666Stushar@ece.gatech.edu } 51711666Stushar@ece.gatech.edu } 51811666Stushar@ece.gatech.edu 51911666Stushar@ece.gatech.edu for (int vc = 0; vc < m_num_vcs; vc++) { 52011666Stushar@ece.gatech.edu if (m_ni_out_vcs[vc]->isReady(curCycle() + Cycles(1))) { 52111666Stushar@ece.gatech.edu scheduleEvent(Cycles(1)); 52211666Stushar@ece.gatech.edu return; 52311666Stushar@ece.gatech.edu } 52411666Stushar@ece.gatech.edu } 52511666Stushar@ece.gatech.edu} 52611666Stushar@ece.gatech.edu 52711666Stushar@ece.gatech.eduvoid 52811666Stushar@ece.gatech.eduNetworkInterface::print(std::ostream& out) const 52911666Stushar@ece.gatech.edu{ 53011666Stushar@ece.gatech.edu out << "[Network Interface]"; 53111666Stushar@ece.gatech.edu} 53211666Stushar@ece.gatech.edu 53311666Stushar@ece.gatech.eduuint32_t 53411666Stushar@ece.gatech.eduNetworkInterface::functionalWrite(Packet *pkt) 53511666Stushar@ece.gatech.edu{ 53611666Stushar@ece.gatech.edu uint32_t num_functional_writes = 0; 53711666Stushar@ece.gatech.edu for (unsigned int i = 0; i < m_num_vcs; ++i) { 53811666Stushar@ece.gatech.edu num_functional_writes += m_ni_out_vcs[i]->functionalWrite(pkt); 53911666Stushar@ece.gatech.edu } 54011666Stushar@ece.gatech.edu 54111666Stushar@ece.gatech.edu num_functional_writes += outFlitQueue->functionalWrite(pkt); 54211666Stushar@ece.gatech.edu return num_functional_writes; 54311666Stushar@ece.gatech.edu} 54411666Stushar@ece.gatech.edu 54511666Stushar@ece.gatech.eduNetworkInterface * 54611666Stushar@ece.gatech.eduGarnetNetworkInterfaceParams::create() 54711666Stushar@ece.gatech.edu{ 54811666Stushar@ece.gatech.edu return new NetworkInterface(this); 54911666Stushar@ece.gatech.edu} 550