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

Generated on Wed Sep 30 2020 14:02:13 for gem5 by doxygen 1.8.17