gem5  v20.0.0.2
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
SwitchAllocator.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 "debug/RubyNetwork.hh"
39 
41  : Consumer(router)
42 {
43  m_router = router;
46 
49 }
50 
51 void
53 {
60 
61  for (int i = 0; i < m_num_inports; i++) {
62  m_round_robin_invc[i] = 0;
63  }
64 
65  for (int i = 0; i < m_num_outports; i++) {
66  m_port_requests[i].resize(m_num_inports);
67  m_vc_winners[i].resize(m_num_inports);
68 
70 
71  for (int j = 0; j < m_num_inports; j++) {
72  m_port_requests[i][j] = false; // [outport][inport]
73  }
74  }
75 }
76 
77 /*
78  * The wakeup function of the SwitchAllocator performs a 2-stage
79  * seperable switch allocation. At the end of the 2nd stage, a free
80  * output VC is assigned to the winning flits of each output port.
81  * There is no separate VCAllocator stage like the one in garnet1.0.
82  * At the end of this function, the router is rescheduled to wakeup
83  * next cycle for peforming SA for any flits ready next cycle.
84  */
85 
86 void
88 {
89  arbitrate_inports(); // First stage of allocation
90  arbitrate_outports(); // Second stage of allocation
91 
94 }
95 
96 /*
97  * SA-I (or SA-i) loops through all input VCs at every input port,
98  * and selects one in a round robin manner.
99  * - For HEAD/HEAD_TAIL flits only selects an input VC whose output port
100  * has at least one free output VC.
101  * - For BODY/TAIL flits, only selects an input VC that has credits
102  * in its output VC.
103  * Places a request for the output port from this input VC.
104  */
105 
106 void
108 {
109  // Select a VC from each input in a round robin manner
110  // Independent arbiter at each input port
111  for (int inport = 0; inport < m_num_inports; inport++) {
112  int invc = m_round_robin_invc[inport];
113 
114  for (int invc_iter = 0; invc_iter < m_num_vcs; invc_iter++) {
115  auto input_unit = m_router->getInputUnit(inport);
116 
117  if (input_unit->need_stage(invc, SA_, m_router->curCycle())) {
118  // This flit is in SA stage
119 
120  int outport = input_unit->get_outport(invc);
121  int outvc = input_unit->get_outvc(invc);
122 
123  // check if the flit in this InputVC is allowed to be sent
124  // send_allowed conditions described in that function.
125  bool make_request =
126  send_allowed(inport, invc, outport, outvc);
127 
128  if (make_request) {
130  m_port_requests[outport][inport] = true;
131  m_vc_winners[outport][inport]= invc;
132 
133  // Update Round Robin pointer to the next VC
134  m_round_robin_invc[inport] = invc + 1;
135  if (m_round_robin_invc[inport] >= m_num_vcs)
136  m_round_robin_invc[inport] = 0;
137 
138  break; // got one vc winner for this port
139  }
140  }
141 
142  invc++;
143  if (invc >= m_num_vcs)
144  invc = 0;
145  }
146  }
147 }
148 
149 /*
150  * SA-II (or SA-o) loops through all output ports,
151  * and selects one input VC (that placed a request during SA-I)
152  * as the winner for this output port in a round robin manner.
153  * - For HEAD/HEAD_TAIL flits, performs simplified outvc allocation.
154  * (i.e., select a free VC from the output port).
155  * - For BODY/TAIL flits, decrement a credit in the output vc.
156  * The winning flit is read out from the input VC and sent to the
157  * CrossbarSwitch.
158  * An increment_credit signal is sent from the InputUnit
159  * to the upstream router. For HEAD_TAIL/TAIL flits, is_free_signal in the
160  * credit is set to true.
161  */
162 
163 void
165 {
166  // Now there are a set of input vc requests for output vcs.
167  // Again do round robin arbitration on these requests
168  // Independent arbiter at each output port
169  for (int outport = 0; outport < m_num_outports; outport++) {
170  int inport = m_round_robin_inport[outport];
171 
172  for (int inport_iter = 0; inport_iter < m_num_inports;
173  inport_iter++) {
174 
175  // inport has a request this cycle for outport
176  if (m_port_requests[outport][inport]) {
177  auto output_unit = m_router->getOutputUnit(outport);
178  auto input_unit = m_router->getInputUnit(inport);
179 
180  // grant this outport to this inport
181  int invc = m_vc_winners[outport][inport];
182 
183  int outvc = input_unit->get_outvc(invc);
184  if (outvc == -1) {
185  // VC Allocation - select any free VC from outport
186  outvc = vc_allocate(outport, inport, invc);
187  }
188 
189  // remove flit from Input VC
190  flit *t_flit = input_unit->getTopFlit(invc);
191 
192  DPRINTF(RubyNetwork, "SwitchAllocator at Router %d "
193  "granted outvc %d at outport %d "
194  "to invc %d at inport %d to flit %s at "
195  "time: %lld\n",
196  m_router->get_id(), outvc,
198  output_unit->get_direction()),
199  invc,
201  input_unit->get_direction()),
202  *t_flit,
203  m_router->curCycle());
204 
205 
206  // Update outport field in the flit since this is
207  // used by CrossbarSwitch code to send it out of
208  // correct outport.
209  // Note: post route compute in InputUnit,
210  // outport is updated in VC, but not in flit
211  t_flit->set_outport(outport);
212 
213  // set outvc (i.e., invc for next hop) in flit
214  // (This was updated in VC by vc_allocate, but not in flit)
215  t_flit->set_vc(outvc);
216 
217  // decrement credit in outvc
218  output_unit->decrement_credit(outvc);
219 
220  // flit ready for Switch Traversal
221  t_flit->advance_stage(ST_, m_router->curCycle());
222  m_router->grant_switch(inport, t_flit);
224 
225  if ((t_flit->get_type() == TAIL_) ||
226  t_flit->get_type() == HEAD_TAIL_) {
227 
228  // This Input VC should now be empty
229  assert(!(input_unit->isReady(invc, m_router->curCycle())));
230 
231  // Free this VC
232  input_unit->set_vc_idle(invc, m_router->curCycle());
233 
234  // Send a credit back
235  // along with the information that this VC is now idle
236  input_unit->increment_credit(invc, true,
237  m_router->curCycle());
238  } else {
239  // Send a credit back
240  // but do not indicate that the VC is idle
241  input_unit->increment_credit(invc, false,
242  m_router->curCycle());
243  }
244 
245  // remove this request
246  m_port_requests[outport][inport] = false;
247 
248  // Update Round Robin pointer
249  m_round_robin_inport[outport] = inport + 1;
250  if (m_round_robin_inport[outport] >= m_num_inports)
251  m_round_robin_inport[outport] = 0;
252 
253  break; // got a input winner for this outport
254  }
255 
256  inport++;
257  if (inport >= m_num_inports)
258  inport = 0;
259  }
260  }
261 }
262 
263 /*
264  * A flit can be sent only if
265  * (1) there is at least one free output VC at the
266  * output port (for HEAD/HEAD_TAIL),
267  * or
268  * (2) if there is at least one credit (i.e., buffer slot)
269  * within the VC for BODY/TAIL flits of multi-flit packets.
270  * and
271  * (3) pt-to-pt ordering is not violated in ordered vnets, i.e.,
272  * there should be no other flit in this input port
273  * within an ordered vnet
274  * that arrived before this flit and is requesting the same output port.
275  */
276 
277 bool
278 SwitchAllocator::send_allowed(int inport, int invc, int outport, int outvc)
279 {
280  // Check if outvc needed
281  // Check if credit needed (for multi-flit packet)
282  // Check if ordering violated (in ordered vnet)
283 
284  int vnet = get_vnet(invc);
285  bool has_outvc = (outvc != -1);
286  bool has_credit = false;
287 
288  auto output_unit = m_router->getOutputUnit(outport);
289  if (!has_outvc) {
290 
291  // needs outvc
292  // this is only true for HEAD and HEAD_TAIL flits.
293 
294  if (output_unit->has_free_vc(vnet)) {
295 
296  has_outvc = true;
297 
298  // each VC has at least one buffer,
299  // so no need for additional credit check
300  has_credit = true;
301  }
302  } else {
303  has_credit = output_unit->has_credit(outvc);
304  }
305 
306  // cannot send if no outvc or no credit.
307  if (!has_outvc || !has_credit)
308  return false;
309 
310 
311  // protocol ordering check
312  if ((m_router->get_net_ptr())->isVNetOrdered(vnet)) {
313  auto input_unit = m_router->getInputUnit(inport);
314 
315  // enqueue time of this flit
316  Cycles t_enqueue_time = input_unit->get_enqueue_time(invc);
317 
318  // check if any other flit is ready for SA and for same output port
319  // and was enqueued before this flit
320  int vc_base = vnet*m_vc_per_vnet;
321  for (int vc_offset = 0; vc_offset < m_vc_per_vnet; vc_offset++) {
322  int temp_vc = vc_base + vc_offset;
323  if (input_unit->need_stage(temp_vc, SA_, m_router->curCycle()) &&
324  (input_unit->get_outport(temp_vc) == outport) &&
325  (input_unit->get_enqueue_time(temp_vc) < t_enqueue_time)) {
326  return false;
327  }
328  }
329  }
330 
331  return true;
332 }
333 
334 // Assign a free VC to the winner of the output port.
335 int
336 SwitchAllocator::vc_allocate(int outport, int inport, int invc)
337 {
338  // Select a free VC from the output port
339  int outvc =
340  m_router->getOutputUnit(outport)->select_free_vc(get_vnet(invc));
341 
342  // has to get a valid VC since it checked before performing SA
343  assert(outvc != -1);
344  m_router->getInputUnit(inport)->grant_outvc(invc, outvc);
345  return outvc;
346 }
347 
348 // Wakeup the router next cycle to perform SA again
349 // if there are flits ready.
350 void
352 {
353  Cycles nextCycle = m_router->curCycle() + Cycles(1);
354 
355  for (int i = 0; i < m_num_inports; i++) {
356  for (int j = 0; j < m_num_vcs; j++) {
357  if (m_router->getInputUnit(i)->need_stage(j, SA_, nextCycle)) {
359  return;
360  }
361  }
362  }
363 }
364 
365 int
367 {
368  int vnet = invc/m_vc_per_vnet;
369  assert(vnet < m_router->get_num_vnets());
370  return vnet;
371 }
372 
373 
374 // Clear the request vector within the allocator at end of SA-II.
375 // Was populated by SA-I.
376 void
378 {
379  for (int i = 0; i < m_num_outports; i++) {
380  for (int j = 0; j < m_num_inports; j++) {
381  m_port_requests[i][j] = false;
382  }
383  }
384 }
385 
386 void
388 {
391 }
#define DPRINTF(x,...)
Definition: trace.hh:222
void set_outport(int port)
Definition: flit.hh:62
double m_input_arbiter_activity
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:81
Bitfield< 7 > i
std::vector< std::vector< bool > > m_port_requests
bool need_stage(int vc, flit_stage stage, Cycles time)
Definition: InputUnit.hh:114
void grant_switch(int inport, flit *t_flit)
Definition: Router.cc:146
std::vector< std::vector< int > > m_vc_winners
int get_outport(int invc)
Definition: InputUnit.hh:82
std::string getPortDirectionName(PortDirection direction)
Definition: Router.cc:159
int get_id()
Definition: Router.hh:80
OutputUnit * getOutputUnit(unsigned port)
Definition: Router.hh:97
void schedule_wakeup(Cycles time)
Definition: Router.cc:152
Definition: flit.hh:41
int get_vnet(int invc)
bool has_credit(int out_vc)
Definition: OutputUnit.cc:75
int get_num_outports()
Definition: Router.hh:79
GarnetNetwork * get_net_ptr()
Definition: Router.hh:87
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
void set_vc(int vc)
Definition: flit.hh:64
int get_vc_per_vnet()
Definition: Router.hh:77
double m_output_arbiter_activity
bool send_allowed(int inport, int invc, int outport, int outvc)
Bitfield< 24 > j
Definition: Router.hh:56
int vc_allocate(int outport, int inport, int invc)
SwitchAllocator(Router *router)
void grant_outvc(int vc, int outvc)
Definition: InputUnit.hh:76
std::vector< int > m_round_robin_inport
int get_num_vcs()
Definition: Router.hh:75
int get_num_inports()
Definition: Router.hh:78
void advance_stage(flit_stage t_stage, Cycles newTime)
Definition: flit.hh:80
flit_type get_type()
Definition: flit.hh:58
std::vector< int > m_round_robin_invc
InputUnit * getInputUnit(unsigned port)
Definition: Router.hh:90
int select_free_vc(int vnet)
Definition: OutputUnit.cc:97

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