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

Generated on Mon Jun 8 2020 15:45:12 for gem5 by doxygen 1.8.13