gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NetworkInterface.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008 Princeton University
3  * Copyright (c) 2016 Georgia Institute of Technology
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met: redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer;
10  * redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution;
13  * neither the name of the copyright holders nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * Authors: Niket Agarwal
30  * Tushar Krishna
31  */
32 
33 
35 
36 #include <cassert>
37 #include <cmath>
38 
39 #include "base/cast.hh"
40 #include "base/stl_helpers.hh"
41 #include "debug/RubyNetwork.hh"
46 
47 using namespace std;
49 
51  : ClockedObject(p), Consumer(this), m_id(p->id),
52  m_virtual_networks(p->virt_nets), m_vc_per_vnet(p->vcs_per_vnet),
53  m_num_vcs(m_vc_per_vnet * m_virtual_networks),
54  m_deadlock_threshold(p->garnet_deadlock_threshold),
55  vc_busy_counter(m_virtual_networks, 0)
56 {
57  m_router_id = -1;
58  m_vc_round_robin = 0;
59  m_ni_out_vcs.resize(m_num_vcs);
61  outCreditQueue = new flitBuffer();
62 
63  // instantiating the NI flit buffers
64  for (int i = 0; i < m_num_vcs; i++) {
65  m_ni_out_vcs[i] = new flitBuffer();
67  }
68 
69  m_vc_allocator.resize(m_virtual_networks); // 1 allocator per vnet
70  for (int i = 0; i < m_virtual_networks; i++) {
71  m_vc_allocator[i] = 0;
72  }
73 
74  m_stall_count.resize(m_virtual_networks);
75 }
76 
77 void
79 {
80  for (int i = 0; i < m_num_vcs; i++) {
81  m_out_vc_state.push_back(new OutVcState(i, m_net_ptr));
82  }
83 }
84 
86 {
89  delete outCreditQueue;
90  delete outFlitQueue;
91 }
92 
93 void
95  CreditLink *credit_link)
96 {
97  inNetLink = in_link;
98  in_link->setLinkConsumer(this);
99  outCreditLink = credit_link;
100  credit_link->setSourceQueue(outCreditQueue);
101 }
102 
103 void
105  CreditLink *credit_link,
106  SwitchID router_id)
107 {
108  inCreditLink = credit_link;
109  credit_link->setLinkConsumer(this);
110 
111  outNetLink = out_link;
112  outFlitQueue = new flitBuffer();
113  out_link->setSourceQueue(outFlitQueue);
114 
115  m_router_id = router_id;
116 }
117 
118 void
121 {
122  inNode_ptr = in;
123  outNode_ptr = out;
124 
125  for (auto& it : in) {
126  if (it != nullptr) {
127  it->setConsumer(this);
128  }
129  }
130 }
131 
132 void
134 {
135  // An output MessageBuffer has dequeued something this cycle and there
136  // is now space to enqueue a stalled message. However, we cannot wake
137  // on the same cycle as the dequeue. Schedule a wake at the soonest
138  // possible time (next cycle).
140 }
141 
142 void
144 {
145  int vnet = t_flit->get_vnet();
146 
147  // Latency
149  Cycles network_delay =
150  t_flit->get_dequeue_time() - t_flit->get_enqueue_time() - Cycles(1);
151  Cycles src_queueing_delay = t_flit->get_src_delay();
152  Cycles dest_queueing_delay = (curCycle() - t_flit->get_dequeue_time());
153  Cycles queueing_delay = src_queueing_delay + dest_queueing_delay;
154 
155  m_net_ptr->increment_flit_network_latency(network_delay, vnet);
156  m_net_ptr->increment_flit_queueing_latency(queueing_delay, vnet);
157 
158  if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) {
160  m_net_ptr->increment_packet_network_latency(network_delay, vnet);
161  m_net_ptr->increment_packet_queueing_latency(queueing_delay, vnet);
162  }
163 
164  // Hops
166 }
167 
168 /*
169  * The NI wakeup checks whether there are any ready messages in the protocol
170  * buffer. If yes, it picks that up, flitisizes it into a number of flits and
171  * puts it into an output buffer and schedules the output link. On a wakeup
172  * it also checks whether there are flits in the input link. If yes, it picks
173  * them up and if the flit is a tail, the NI inserts the corresponding message
174  * into the protocol buffer. It also checks for credits being sent by the
175  * downstream router.
176  */
177 
178 void
180 {
181  DPRINTF(RubyNetwork, "Network Interface %d connected to router %d "
182  "woke up at time: %lld\n", m_id, m_router_id, curCycle());
183 
184  MsgPtr msg_ptr;
185  Tick curTime = clockEdge();
186 
187  // Checking for messages coming from the protocol
188  // can pick up a message/cycle for each virtual net
189  for (int vnet = 0; vnet < inNode_ptr.size(); ++vnet) {
190  MessageBuffer *b = inNode_ptr[vnet];
191  if (b == nullptr) {
192  continue;
193  }
194 
195  if (b->isReady(curTime)) { // Is there a message waiting
196  msg_ptr = b->peekMsgPtr();
197  if (flitisizeMessage(msg_ptr, vnet)) {
198  b->dequeue(curTime);
199  }
200  }
201  }
202 
204  checkReschedule();
205 
206  // Check if there are flits stalling a virtual channel. Track if a
207  // message is enqueued to restrict ejection to one message per cycle.
208  bool messageEnqueuedThisCycle = checkStallQueue();
209 
210  /*********** Check the incoming flit link **********/
211  if (inNetLink->isReady(curCycle())) {
212  flit *t_flit = inNetLink->consumeLink();
213  int vnet = t_flit->get_vnet();
214  t_flit->set_dequeue_time(curCycle());
215 
216  // If a tail flit is received, enqueue into the protocol buffers if
217  // space is available. Otherwise, exchange non-tail flits for credits.
218  if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) {
219  if (!messageEnqueuedThisCycle &&
220  outNode_ptr[vnet]->areNSlotsAvailable(1, curTime)) {
221  // Space is available. Enqueue to protocol buffer.
222  outNode_ptr[vnet]->enqueue(t_flit->get_msg_ptr(), curTime,
223  cyclesToTicks(Cycles(1)));
224 
225  // Simply send a credit back since we are not buffering
226  // this flit in the NI
227  sendCredit(t_flit, true);
228 
229  // Update stats and delete flit pointer
230  incrementStats(t_flit);
231  delete t_flit;
232  } else {
233  // No space available- Place tail flit in stall queue and set
234  // up a callback for when protocol buffer is dequeued. Stat
235  // update and flit pointer deletion will occur upon unstall.
236  m_stall_queue.push_back(t_flit);
237  m_stall_count[vnet]++;
238 
239  auto cb = std::bind(&NetworkInterface::dequeueCallback, this);
240  outNode_ptr[vnet]->registerDequeueCallback(cb);
241  }
242  } else {
243  // Non-tail flit. Send back a credit but not VC free signal.
244  sendCredit(t_flit, false);
245 
246  // Update stats and delete flit pointer.
247  incrementStats(t_flit);
248  delete t_flit;
249  }
250  }
251 
252  /****************** Check the incoming credit link *******/
253 
254  if (inCreditLink->isReady(curCycle())) {
255  Credit *t_credit = (Credit*) inCreditLink->consumeLink();
256  m_out_vc_state[t_credit->get_vc()]->increment_credit();
257  if (t_credit->is_free_signal()) {
258  m_out_vc_state[t_credit->get_vc()]->setState(IDLE_, curCycle());
259  }
260  delete t_credit;
261  }
262 
263 
264  // It is possible to enqueue multiple outgoing credit flits if a message
265  // was unstalled in the same cycle as a new message arrives. In this
266  // case, we should schedule another wakeup to ensure the credit is sent
267  // back.
268  if (outCreditQueue->getSize() > 0) {
270  }
271 }
272 
273 void
274 NetworkInterface::sendCredit(flit *t_flit, bool is_free)
275 {
276  Credit *credit_flit = new Credit(t_flit->get_vc(), is_free, curCycle());
277  outCreditQueue->insert(credit_flit);
278 }
279 
280 bool
282 {
283  bool messageEnqueuedThisCycle = false;
284  Tick curTime = clockEdge();
285 
286  if (!m_stall_queue.empty()) {
287  for (auto stallIter = m_stall_queue.begin();
288  stallIter != m_stall_queue.end(); ) {
289  flit *stallFlit = *stallIter;
290  int vnet = stallFlit->get_vnet();
291 
292  // If we can now eject to the protocol buffer, send back credits
293  if (outNode_ptr[vnet]->areNSlotsAvailable(1, curTime)) {
294  outNode_ptr[vnet]->enqueue(stallFlit->get_msg_ptr(), curTime,
295  cyclesToTicks(Cycles(1)));
296 
297  // Send back a credit with free signal now that the VC is no
298  // longer stalled.
299  sendCredit(stallFlit, true);
300 
301  // Update Stats
302  incrementStats(stallFlit);
303 
304  // Flit can now safely be deleted and removed from stall queue
305  delete stallFlit;
306  m_stall_queue.erase(stallIter);
307  m_stall_count[vnet]--;
308 
309  // If there are no more stalled messages for this vnet, the
310  // callback on it's MessageBuffer is not needed.
311  if (m_stall_count[vnet] == 0)
312  outNode_ptr[vnet]->unregisterDequeueCallback();
313 
314  messageEnqueuedThisCycle = true;
315  break;
316  } else {
317  ++stallIter;
318  }
319  }
320  }
321 
322  return messageEnqueuedThisCycle;
323 }
324 
325 // Embed the protocol message into flits
326 bool
328 {
329  Message *net_msg_ptr = msg_ptr.get();
330  NetDest net_msg_dest = net_msg_ptr->getDestination();
331 
332  // gets all the destinations associated with this message.
333  vector<NodeID> dest_nodes = net_msg_dest.getAllDest();
334 
335  // Number of flits is dependent on the link bandwidth available.
336  // This is expressed in terms of bytes/cycle or the flit size
337  int num_flits = (int) ceil((double) m_net_ptr->MessageSizeType_to_int(
338  net_msg_ptr->getMessageSize())/m_net_ptr->getNiFlitSize());
339 
340  // loop to convert all multicast messages into unicast messages
341  for (int ctr = 0; ctr < dest_nodes.size(); ctr++) {
342 
343  // this will return a free output virtual channel
344  int vc = calculateVC(vnet);
345 
346  if (vc == -1) {
347  return false ;
348  }
349  MsgPtr new_msg_ptr = msg_ptr->clone();
350  NodeID destID = dest_nodes[ctr];
351 
352  Message *new_net_msg_ptr = new_msg_ptr.get();
353  if (dest_nodes.size() > 1) {
354  NetDest personal_dest;
355  for (int m = 0; m < (int) MachineType_NUM; m++) {
356  if ((destID >= MachineType_base_number((MachineType) m)) &&
357  destID < MachineType_base_number((MachineType) (m+1))) {
358  // calculating the NetDest associated with this destID
359  personal_dest.clear();
360  personal_dest.add((MachineID) {(MachineType) m, (destID -
361  MachineType_base_number((MachineType) m))});
362  new_net_msg_ptr->getDestination() = personal_dest;
363  break;
364  }
365  }
366  net_msg_dest.removeNetDest(personal_dest);
367  // removing the destination from the original message to reflect
368  // that a message with this particular destination has been
369  // flitisized and an output vc is acquired
370  net_msg_ptr->getDestination().removeNetDest(personal_dest);
371  }
372 
373  // Embed Route into the flits
374  // NetDest format is used by the routing table
375  // Custom routing algorithms just need destID
376  RouteInfo route;
377  route.vnet = vnet;
378  route.net_dest = new_net_msg_ptr->getDestination();
379  route.src_ni = m_id;
380  route.src_router = m_router_id;
381  route.dest_ni = destID;
382  route.dest_router = m_net_ptr->get_router_id(destID);
383 
384  // initialize hops_traversed to -1
385  // so that the first router increments it to 0
386  route.hops_traversed = -1;
387 
389  for (int i = 0; i < num_flits; i++) {
391  flit *fl = new flit(i, vc, vnet, route, num_flits, new_msg_ptr,
392  curCycle());
393 
394  fl->set_src_delay(curCycle() - ticksToCycles(msg_ptr->getTime()));
395  m_ni_out_vcs[vc]->insert(fl);
396  }
397 
399  m_out_vc_state[vc]->setState(ACTIVE_, curCycle());
400  }
401  return true ;
402 }
403 
404 // Looking for a free output vc
405 int
407 {
408  for (int i = 0; i < m_vc_per_vnet; i++) {
409  int delta = m_vc_allocator[vnet];
410  m_vc_allocator[vnet]++;
411  if (m_vc_allocator[vnet] == m_vc_per_vnet)
412  m_vc_allocator[vnet] = 0;
413 
414  if (m_out_vc_state[(vnet*m_vc_per_vnet) + delta]->isInState(
415  IDLE_, curCycle())) {
416  vc_busy_counter[vnet] = 0;
417  return ((vnet*m_vc_per_vnet) + delta);
418  }
419  }
420 
421  vc_busy_counter[vnet] += 1;
423  "%s: Possible network deadlock in vnet: %d at time: %llu \n",
424  name(), vnet, curTick());
425 
426  return -1;
427 }
428 
429 
436 void
438 {
439  int vc = m_vc_round_robin;
442  m_vc_round_robin = 0;
443 
444  for (int i = 0; i < m_num_vcs; i++) {
445  vc++;
446  if (vc == m_num_vcs)
447  vc = 0;
448 
449  // model buffer backpressure
450  if (m_ni_out_vcs[vc]->isReady(curCycle()) &&
451  m_out_vc_state[vc]->has_credit()) {
452 
453  bool is_candidate_vc = true;
454  int t_vnet = get_vnet(vc);
455  int vc_base = t_vnet * m_vc_per_vnet;
456 
457  if (m_net_ptr->isVNetOrdered(t_vnet)) {
458  for (int vc_offset = 0; vc_offset < m_vc_per_vnet;
459  vc_offset++) {
460  int t_vc = vc_base + vc_offset;
461  if (m_ni_out_vcs[t_vc]->isReady(curCycle())) {
462  if (m_ni_out_vcs_enqueue_time[t_vc] <
464  is_candidate_vc = false;
465  break;
466  }
467  }
468  }
469  }
470  if (!is_candidate_vc)
471  continue;
472 
473  m_out_vc_state[vc]->decrement_credit();
474  // Just removing the flit
475  flit *t_flit = m_ni_out_vcs[vc]->getTopFlit();
476  t_flit->set_time(curCycle() + Cycles(1));
477  outFlitQueue->insert(t_flit);
478  // schedule the out link
480 
481  if (t_flit->get_type() == TAIL_ ||
482  t_flit->get_type() == HEAD_TAIL_) {
484  }
485  return;
486  }
487  }
488 }
489 
490 int
492 {
493  for (int i = 0; i < m_virtual_networks; i++) {
494  if (vc >= (i*m_vc_per_vnet) && vc < ((i+1)*m_vc_per_vnet)) {
495  return i;
496  }
497  }
498  fatal("Could not determine vc");
499 }
500 
501 
502 // Wakeup the NI in the next cycle if there are waiting
503 // messages in the protocol buffer, or waiting flits in the
504 // output VC buffer
505 void
507 {
508  for (const auto& it : inNode_ptr) {
509  if (it == nullptr) {
510  continue;
511  }
512 
513  while (it->isReady(clockEdge())) { // Is there a message waiting
514  scheduleEvent(Cycles(1));
515  return;
516  }
517  }
518 
519  for (int vc = 0; vc < m_num_vcs; vc++) {
520  if (m_ni_out_vcs[vc]->isReady(curCycle() + Cycles(1))) {
521  scheduleEvent(Cycles(1));
522  return;
523  }
524  }
525 }
526 
527 void
528 NetworkInterface::print(std::ostream& out) const
529 {
530  out << "[Network Interface]";
531 }
532 
533 uint32_t
535 {
536  uint32_t num_functional_writes = 0;
537  for (unsigned int i = 0; i < m_num_vcs; ++i) {
538  num_functional_writes += m_ni_out_vcs[i]->functionalWrite(pkt);
539  }
540 
541  num_functional_writes += outFlitQueue->functionalWrite(pkt);
542  return num_functional_writes;
543 }
544 
546 GarnetNetworkInterfaceParams::create()
547 {
548  return new NetworkInterface(this);
549 }
void set_dequeue_time(Cycles time)
Definition: flit.hh:70
std::vector< int > m_stall_count
virtual const MessageSizeType & getMessageSize() const
Definition: Message.hh:64
bool isVNetOrdered(int vnet) const
#define DPRINTF(x,...)
Definition: trace.hh:212
void incrementStats(flit *t_flit)
std::vector< Cycles > m_ni_out_vcs_enqueue_time
void set_time(Cycles time)
Definition: flit.hh:66
virtual const NetDest & getDestination() const
Definition: Message.hh:96
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:83
int get_vc()
Definition: flit.hh:58
std::shared_ptr< Message > MsgPtr
Definition: Message.hh:40
void increment_injected_flits(int vnet)
Bitfield< 7 > i
Definition: miscregs.hh:1378
void sendCredit(flit *t_flit, bool is_free)
Bitfield< 0 > m
Definition: miscregs.hh:1577
void clear()
Definition: NetDest.cc:79
GarnetNetworkInterfaceParams Params
Cycles ticksToCycles(Tick t) const
void addOutPort(NetworkLink *out_link, CreditLink *credit_link, SwitchID router_id)
void scheduleEvent(Cycles timeDelta)
Definition: Consumer.cc:34
Tick cyclesToTicks(Cycles c) const
panic_if(!root,"Invalid expression\n")
int calculateVC(int vnet)
std::vector< flitBuffer * > m_ni_out_vcs
void scheduleOutputLink()
This function looks at the NI buffers if some buffer has flits which are ready to traverse the link i...
std::vector< int > vc_busy_counter
void increment_total_hops(int hops)
std::deque< flit * > m_stall_queue
void add(MachineID newElement)
Definition: NetDest.cc:39
NetworkLink * outNetLink
void addInPort(NetworkLink *in_link, CreditLink *credit_link)
void scheduleEventAbsolute(Tick timeAbs)
Definition: Consumer.cc:40
NetworkInterface(const Params *p)
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Bitfield< 7 > b
Definition: miscregs.hh:1564
unsigned int NodeID
Definition: TypeDefines.hh:34
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
const MsgPtr & peekMsgPtr() const
unsigned int SwitchID
Definition: TypeDefines.hh:35
Tick curTick()
The current simulated tick.
Definition: core.hh:47
Definition: flit.hh:44
std::vector< OutVcState * > m_out_vc_state
flitBuffer * outFlitQueue
uint64_t Tick
Tick count type.
Definition: types.hh:63
void increment_packet_queueing_latency(Cycles latency, int vnet)
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
void set_src_delay(Cycles delay)
Definition: flit.hh:69
flitBuffer * outCreditQueue
#define INFINITE_
Definition: CommonTypes.hh:63
Tick dequeue(Tick current_time, bool decrement_messages=true)
Updates the delay cycles of the message at the head of the queue, removes it from the queue and retur...
#define fatal(...)
Definition: misc.hh:163
uint32_t functionalWrite(Packet *)
void increment_injected_packets(int vnet)
int dest_router
Definition: CommonTypes.hh:59
NetworkLink * inNetLink
void deletePointers(C< T, A > &container)
Definition: stl_helpers.hh:77
Cycles get_src_delay()
Definition: flit.hh:63
Cycles get_dequeue_time()
Definition: flit.hh:54
bool flitisizeMessage(MsgPtr msg_ptr, int vnet)
void removeNetDest(const NetDest &netDest)
Definition: NetDest.cc:70
Definition: Credit.hh:48
uint32_t getNiFlitSize() const
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:245
CreditLink * inCreditLink
void increment_packet_network_latency(Cycles latency, int vnet)
void print(std::ostream &out) const
int get_router_id(int ni)
void addNode(std::vector< MessageBuffer * > &inNode, std::vector< MessageBuffer * > &outNode)
static uint32_t MessageSizeType_to_int(MessageSizeType size_type)
Definition: Network.cc:110
int get_vnet()
Definition: flit.hh:57
std::vector< int > m_vc_allocator
Cycles get_enqueue_time()
Definition: flit.hh:53
bool isReady(Tick current_time) const
MsgPtr & get_msg_ptr()
Definition: flit.hh:60
CreditLink * outCreditLink
void increment_received_packets(int vnet)
void increment_flit_queueing_latency(Cycles latency, int vnet)
virtual const std::string name() const
Definition: sim_object.hh:117
std::vector< MessageBuffer * > outNode_ptr
std::vector< MessageBuffer * > inNode_ptr
NetDest net_dest
Definition: CommonTypes.hh:53
bool is_free_signal()
Definition: Credit.hh:54
void increment_flit_network_latency(Cycles latency, int vnet)
flit_type get_type()
Definition: flit.hh:61
const int m_virtual_networks
std::vector< NodeID > getAllDest()
Definition: NetDest.cc:106
int getSize() const
Definition: flitBuffer.hh:55
GarnetNetwork * m_net_ptr
int hops_traversed
Definition: CommonTypes.hh:60
Bitfield< 11 > id
Definition: miscregs.hh:124
Bitfield< 0 > p
void insert(flit *flt)
Definition: flitBuffer.hh:73
RouteInfo get_route()
Definition: flit.hh:59
uint32_t functionalWrite(Packet *pkt)
Definition: flitBuffer.cc:82
void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
int src_router
Definition: CommonTypes.hh:57
void increment_received_flits(int vnet)

Generated on Fri Jun 9 2017 13:03:49 for gem5 by doxygen 1.8.6