gem5  v22.1.0.0
PerfectSwitch.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020-2021 ARM Limited
3  * All rights reserved.
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are
19  * met: redistributions of source code must retain the above copyright
20  * notice, this list of conditions and the following disclaimer;
21  * redistributions in binary form must reproduce the above copyright
22  * notice, this list of conditions and the following disclaimer in the
23  * documentation and/or other materials provided with the distribution;
24  * neither the name of the copyright holders nor the names of its
25  * contributors may be used to endorse or promote products derived from
26  * this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  */
40 
42 
43 #include <algorithm>
44 
45 #include "base/cast.hh"
46 #include "base/cprintf.hh"
47 #include "base/random.hh"
48 #include "debug/RubyNetwork.hh"
53 
54 namespace gem5
55 {
56 
57 namespace ruby
58 {
59 
60 const int PRIORITY_SWITCH_LIMIT = 128;
61 
62 PerfectSwitch::PerfectSwitch(SwitchID sid, Switch *sw, uint32_t virt_nets)
63  : Consumer(sw, Switch::PERFECTSWITCH_EV_PRI),
64  m_switch_id(sid), m_switch(sw)
65 {
67  m_virtual_networks = virt_nets;
68 }
69 
70 void
72 {
73  m_network_ptr = network_ptr;
74 
75  for (int i = 0;i < m_virtual_networks;++i) {
76  m_pending_message_count.push_back(0);
77  }
78 }
79 
80 void
82 {
83  NodeID port = m_in.size();
84  m_in.push_back(in);
85 
86  for (int i = 0; i < in.size(); ++i) {
87  if (in[i] != nullptr) {
88  in[i]->setConsumer(this);
89  in[i]->setIncomingLink(port);
90  in[i]->setVnet(i);
91  updatePriorityGroups(i, in[i]);
92  }
93  }
94 }
95 
96 void
98 {
99  while (m_in_prio.size() <= vnet) {
100  m_in_prio.emplace_back();
101  m_in_prio_groups.emplace_back();
102  }
103 
104  m_in_prio[vnet].push_back(in_buf);
105 
106  std::sort(m_in_prio[vnet].begin(), m_in_prio[vnet].end(),
107  [](const MessageBuffer* i, const MessageBuffer* j)
108  { return i->routingPriority() < j->routingPriority(); });
109 
110  // reset groups
111  m_in_prio_groups[vnet].clear();
112  int cur_prio = m_in_prio[vnet].front()->routingPriority();
113  m_in_prio_groups[vnet].emplace_back();
114  for (auto buf : m_in_prio[vnet]) {
115  if (buf->routingPriority() != cur_prio)
116  m_in_prio_groups[vnet].emplace_back();
117  m_in_prio_groups[vnet].back().push_back(buf);
118  }
119 }
120 
121 void
123  const NetDest& routing_table_entry,
124  const PortDirection &dst_inport,
125  Tick routing_latency,
126  int link_weight)
127 {
128  // Add to routing unit
130  out,
131  routing_table_entry,
132  dst_inport,
133  link_weight);
134  m_out.push_back({routing_latency, out});
135 }
136 
138 {
139 }
140 
142 PerfectSwitch::inBuffer(int in_port, int vnet) const
143 {
144  if (m_in[in_port].size() <= vnet) {
145  return nullptr;
146  }
147  else {
148  return m_in[in_port][vnet];
149  }
150 }
151 
152 void
154 {
155  if (m_pending_message_count[vnet] == 0)
156  return;
157 
158  for (auto &in : m_in_prio_groups[vnet]) {
159  // first check the port with the oldest message
160  unsigned start_in_port = 0;
161  Tick lowest_tick = MaxTick;
162  for (int i = 0; i < in.size(); ++i) {
163  MessageBuffer *buffer = in[i];
164  if (buffer) {
165  Tick ready_time = buffer->readyTime();
166  if (ready_time < lowest_tick){
167  lowest_tick = ready_time;
168  start_in_port = i;
169  }
170  }
171  }
172  DPRINTF(RubyNetwork, "vnet %d: %d pending msgs. "
173  "Checking port %d first\n",
174  vnet, m_pending_message_count[vnet], start_in_port);
175  // check all ports starting with the one with the oldest message
176  for (int i = 0; i < in.size(); ++i) {
177  int in_port = (i + start_in_port) % in.size();
178  MessageBuffer *buffer = in[in_port];
179  if (buffer)
180  operateMessageBuffer(buffer, vnet);
181  }
182  }
183 }
184 
185 void
187 {
188  MsgPtr msg_ptr;
189  Message *net_msg_ptr = NULL;
190 
191  // temporary vectors to store the routing results
192  static thread_local std::vector<BaseRoutingUnit::RouteInfo> output_links;
193 
194  Tick current_time = m_switch->clockEdge();
195 
196  while (buffer->isReady(current_time)) {
197  DPRINTF(RubyNetwork, "incoming: %d\n", buffer->getIncomingLink());
198 
199  // Peek at message
200  msg_ptr = buffer->peekMsgPtr();
201  net_msg_ptr = msg_ptr.get();
202  DPRINTF(RubyNetwork, "Message: %s\n", (*net_msg_ptr));
203 
204 
205  output_links.clear();
206  m_switch->getRoutingUnit().route(*net_msg_ptr, vnet,
208  output_links);
209 
210  // Check for resources - for all outgoing queues
211  bool enough = true;
212  for (int i = 0; i < output_links.size(); i++) {
213  int outgoing = output_links[i].m_link_id;
214  OutputPort &out_port = m_out[outgoing];
215 
216  if (!out_port.buffers[vnet]->areNSlotsAvailable(1, current_time))
217  enough = false;
218 
219  DPRINTF(RubyNetwork, "Checking if node is blocked ..."
220  "outgoing: %d, vnet: %d, enough: %d\n",
221  outgoing, vnet, enough);
222  }
223 
224  // There were not enough resources
225  if (!enough) {
226  scheduleEvent(Cycles(1));
227  DPRINTF(RubyNetwork, "Can't deliver message since a node "
228  "is blocked\n");
229  DPRINTF(RubyNetwork, "Message: %s\n", (*net_msg_ptr));
230  break; // go to next incoming port
231  }
232 
233  MsgPtr unmodified_msg_ptr;
234 
235  if (output_links.size() > 1) {
236  // If we are sending this message down more than one link
237  // (size>1), we need to make a copy of the message so each
238  // branch can have a different internal destination we need
239  // to create an unmodified MsgPtr because the MessageBuffer
240  // enqueue func will modify the message
241 
242  // This magic line creates a private copy of the message
243  unmodified_msg_ptr = msg_ptr->clone();
244  }
245 
246  // Dequeue msg
247  buffer->dequeue(current_time);
248  m_pending_message_count[vnet]--;
249 
250  // Enqueue it - for all outgoing queues
251  for (int i=0; i<output_links.size(); i++) {
252  int outgoing = output_links[i].m_link_id;
253  OutputPort &out_port = m_out[outgoing];
254 
255  if (i > 0) {
256  // create a private copy of the unmodified message
257  msg_ptr = unmodified_msg_ptr->clone();
258  }
259 
260  // Change the internal destination set of the message so it
261  // knows which destinations this link is responsible for.
262  net_msg_ptr = msg_ptr.get();
263  net_msg_ptr->getDestination() = output_links[i].m_destinations;
264 
265  // Enqeue msg
266  DPRINTF(RubyNetwork, "Enqueuing net msg from "
267  "inport[%d][%d] to outport [%d][%d].\n",
268  buffer->getIncomingLink(), vnet, outgoing, vnet);
269 
270  out_port.buffers[vnet]->enqueue(msg_ptr, current_time,
271  out_port.latency);
272  }
273  }
274 }
275 
276 void
278 {
279  // Give the highest numbered link priority most of the time
281  int highest_prio_vnet = m_virtual_networks-1;
282  int lowest_prio_vnet = 0;
283  int decrementer = 1;
284 
285  // invert priorities to avoid starvation seen in the component network
288  highest_prio_vnet = 0;
289  lowest_prio_vnet = m_virtual_networks-1;
290  decrementer = -1;
291  }
292 
293  // For all components incoming queues
294  for (int vnet = highest_prio_vnet;
295  (vnet * decrementer) >= (decrementer * lowest_prio_vnet);
296  vnet -= decrementer) {
297  operateVnet(vnet);
298  }
299 }
300 
301 void
303 {
304  m_pending_message_count[info]++;
305 }
306 
307 void
309 {
310 }
311 void
313 {
314 }
315 
316 
317 void
318 PerfectSwitch::print(std::ostream& out) const
319 {
320  out << "[PerfectSwitch " << m_switch_id << "]";
321 }
322 
323 } // namespace ruby
324 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
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...
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
virtual void addOutPort(LinkID link_id, const std::vector< MessageBuffer * > &m_out_buffer, const NetDest &routing_table_entry, const PortDirection &direction, int link_weight)=0
virtual void route(const Message &msg, int vnet, bool deterministic, std::vector< RouteInfo > &out_links)=0
void scheduleEvent(Cycles timeDelta)
Definition: Consumer.cc:56
bool isReady(Tick current_time) const
const MsgPtr & peekMsgPtr() const
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...
virtual const NetDest & getDestination() const
Definition: Message.hh:114
void init(SimpleNetwork *)
void addOutPort(const std::vector< MessageBuffer * > &out, const NetDest &routing_table_entry, const PortDirection &dst_inport, Tick routing_latency, int link_weight)
std::vector< std::vector< MessageBuffer * > > m_in_prio
std::vector< std::vector< MessageBuffer * > > m_in
void storeEventInfo(int info)
std::vector< int > m_pending_message_count
std::vector< OutputPort > m_out
std::vector< std::vector< std::vector< MessageBuffer * > > > m_in_prio_groups
SimpleNetwork * m_network_ptr
PerfectSwitch(SwitchID sid, Switch *, uint32_t)
void print(std::ostream &out) const
MessageBuffer * inBuffer(int in_port, int vnet) const
void updatePriorityGroups(int vnet, MessageBuffer *buf)
void addInPort(const std::vector< MessageBuffer * > &in)
void operateMessageBuffer(MessageBuffer *b, int vnet)
bool isVNetOrdered(int vnet) const
BaseRoutingUnit & getRoutingUnit()
Definition: Switch.hh:112
STL vector class.
Definition: stl.hh:37
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 24 > j
Definition: misc_types.hh:57
Bitfield< 53, 52 > sw
Definition: pagetable.hh:55
std::shared_ptr< Message > MsgPtr
Definition: Message.hh:59
unsigned int SwitchID
Definition: TypeDefines.hh:43
std::string PortDirection
Definition: TypeDefines.hh:44
unsigned int NodeID
Definition: TypeDefines.hh:42
const int PRIORITY_SWITCH_LIMIT
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
uint64_t Tick
Tick count type.
Definition: types.hh:58
const Tick MaxTick
Definition: types.hh:60
std::vector< MessageBuffer * > buffers

Generated on Wed Dec 21 2022 10:22:38 for gem5 by doxygen 1.9.1