gem5  v22.1.0.0
Throttle.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 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 <cassert>
44 
45 #include "base/cast.hh"
46 #include "base/cprintf.hh"
47 #include "debug/RubyNetwork.hh"
53 #include "sim/stats.hh"
54 
55 namespace gem5
56 {
57 
58 namespace ruby
59 {
60 
61 const int MESSAGE_SIZE_MULTIPLIER = 1000;
62 //const int BROADCAST_SCALING = 4; // Have a 16p system act like a 64p systems
63 const int BROADCAST_SCALING = 1;
64 const int PRIORITY_SWITCH_LIMIT = 128;
65 
66 static int network_message_to_size(Message* net_msg_ptr);
67 
68 Throttle::Throttle(int sID, RubySystem *rs, NodeID node, Cycles link_latency,
69  int endpoint_bandwidth, Switch *em)
70  : Consumer(em, Switch::THROTTLE_EV_PRI),
71  m_switch_id(sID), m_switch(em), m_node(node),
72  m_physical_vnets(false), m_ruby_system(rs),
73  throttleStats(em, node)
74 {
75  m_vnets = 0;
76 
77  m_link_latency = link_latency;
78  m_endpoint_bandwidth = endpoint_bandwidth;
79 
81 }
82 
83 Throttle::Throttle(int sID, RubySystem *rs, NodeID node, Cycles link_latency,
84  int link_bandwidth_multiplier, int endpoint_bandwidth,
85  Switch *em)
86  : Throttle(sID, rs, node, link_latency, endpoint_bandwidth, em)
87 {
88  gem5_assert(link_bandwidth_multiplier > 0);
89  m_link_bandwidth_multiplier.push_back(link_bandwidth_multiplier);
90 }
91 
92 Throttle::Throttle(int sID, RubySystem *rs, NodeID node, Cycles link_latency,
93  const std::vector<int> &vnet_channels,
94  const std::vector<int> &vnet_bandwidth_multiplier,
95  int endpoint_bandwidth, Switch *em)
96  : Throttle(sID, rs, node, link_latency, endpoint_bandwidth, em)
97 {
98  m_physical_vnets = true;
99  for (auto link_bandwidth_multiplier : vnet_bandwidth_multiplier){
100  gem5_assert(link_bandwidth_multiplier > 0);
101  m_link_bandwidth_multiplier.push_back(link_bandwidth_multiplier);
102  }
103  for (auto channels : vnet_channels){
104  gem5_assert(channels > 0);
105  m_vnet_channels.push_back(channels);
106  }
108 }
109 
110 void
112  const std::vector<MessageBuffer*>& out_vec)
113 {
114  assert(in_vec.size() == out_vec.size());
115 
116  for (int vnet = 0; vnet < in_vec.size(); ++vnet) {
117  MessageBuffer *in_ptr = in_vec[vnet];
118  MessageBuffer *out_ptr = out_vec[vnet];
119 
120  m_units_remaining.emplace_back(getChannelCnt(vnet),0);
121  m_in.push_back(in_ptr);
122  m_out.push_back(out_ptr);
123 
124  // Set consumer and description
125  in_ptr->setConsumer(this);
126  std::string desc = "[Queue to Throttle " +
128  }
129 
130  m_vnets = in_vec.size();
131 
134  (m_link_bandwidth_multiplier.size() == 1));
135 }
136 
137 int
139 {
140  int bw = m_physical_vnets ?
143  gem5_assert(bw > 0);
144  return m_endpoint_bandwidth * bw;
145 }
146 
147 int
149 {
150  int sum = getLinkBandwidth(0) * getChannelCnt(0);
151  if (m_physical_vnets) {
152  for (unsigned i = 1; i < m_vnets; ++i)
154  }
155  return sum;
156 }
157 
158 int
159 Throttle::getChannelCnt(int vnet) const
160 {
161  return m_physical_vnets ? m_vnet_channels[vnet] : 1;
162 }
163 
164 void
165 Throttle::operateVnet(int vnet, int channel, int &total_bw_remaining,
166  bool &bw_saturated, bool &output_blocked,
167  MessageBuffer *in, MessageBuffer *out)
168 {
169  if (out == nullptr || in == nullptr) {
170  return;
171  }
172 
173  int &units_remaining = m_units_remaining[vnet][channel];
174 
175  gem5_assert(units_remaining >= 0);
176  Tick current_time = m_switch->clockEdge();
177 
178  int bw_remaining = m_physical_vnets ?
179  getLinkBandwidth(vnet) : total_bw_remaining;
180 
181  auto hasPendingWork = [&]{ return in->isReady(current_time) ||
182  units_remaining > 0; };
183  while ((bw_remaining > 0) && hasPendingWork() &&
184  out->areNSlotsAvailable(1, current_time)) {
185  // See if we are done transferring the previous message on
186  // this virtual network
187  if (units_remaining == 0 && in->isReady(current_time)) {
188  // Find the size of the message we are moving
189  MsgPtr msg_ptr = in->peekMsgPtr();
190  Message *net_msg_ptr = msg_ptr.get();
191  Tick msg_enqueue_time = msg_ptr->getLastEnqueueTime();
192  units_remaining = network_message_to_size(net_msg_ptr);
193 
194  DPRINTF(RubyNetwork, "throttle: %d my bw %d bw spent "
195  "enqueueing net msg %d time: %lld.\n",
196  m_node, getLinkBandwidth(vnet), units_remaining,
198 
199  // Move the message
200  in->dequeue(current_time);
201  out->enqueue(msg_ptr, current_time,
203 
204  // Count the message
205  (*(throttleStats.
206  msg_counts[net_msg_ptr->getMessageSize()]))[vnet]++;
208  uint32_t total_size =
210  throttleStats.total_msg_bytes += total_size;
211  total_size -=
212  Network::MessageSizeType_to_int(MessageSizeType_Control);
213  throttleStats.total_data_msg_bytes += total_size;
215  current_time - msg_enqueue_time;
216  DPRINTF(RubyNetwork, "%s\n", *out);
217  }
218 
219  // Calculate the amount of bandwidth we spent on this message
220  int spent = std::min(units_remaining, bw_remaining);
221  units_remaining -= spent;
222  bw_remaining -= spent;
223  total_bw_remaining -= spent;
224  }
225 
226  gem5_assert(units_remaining >= 0);
227  gem5_assert(bw_remaining >= 0);
228  gem5_assert(total_bw_remaining >= 0);
229 
230  // Notify caller if
231  // - we ran out of bandwith and still have stuff to do
232  // - we had something to do but output queue was unavailable
233  if (hasPendingWork()) {
234  gem5_assert((bw_remaining == 0) ||
235  !out->areNSlotsAvailable(1, current_time));
236  bw_saturated = bw_saturated || (bw_remaining == 0);
237  output_blocked = output_blocked ||
238  !out->areNSlotsAvailable(1, current_time);
239  }
240 }
241 
242 void
244 {
245  // Limits the number of message sent to a limited number of bytes/cycle.
246  assert(getTotalLinkBandwidth() > 0);
247  int bw_remaining = getTotalLinkBandwidth();
248 
250  bool bw_saturated = false;
251  bool output_blocked = false;
252 
253  // variable for deciding the direction in which to iterate
254  bool iteration_direction = false;
255 
256 
257  // invert priorities to avoid starvation seen in the component network
260  iteration_direction = true;
261  }
262 
263  if (iteration_direction) {
264  for (int vnet = 0; vnet < m_vnets; ++vnet) {
265  for (int channel = 0; channel < getChannelCnt(vnet); ++channel) {
266  operateVnet(vnet, channel, bw_remaining,
267  bw_saturated, output_blocked,
268  m_in[vnet], m_out[vnet]);
269  }
270  }
271  } else {
272  for (int vnet = m_vnets-1; vnet >= 0; --vnet) {
273  for (int channel = 0; channel < getChannelCnt(vnet); ++channel) {
274  operateVnet(vnet, channel, bw_remaining,
275  bw_saturated, output_blocked,
276  m_in[vnet], m_out[vnet]);
277  }
278  }
279  }
280 
281  // We should only wake up when we use the bandwidth
282  // This is only mostly true
283  // assert(bw_remaining != getLinkBandwidth());
284 
285  // Record that we used some or all of the link bandwidth this cycle
286  double ratio = 1.0 - (double(bw_remaining) /
287  double(getTotalLinkBandwidth()));
288 
289  // If ratio = 0, we used no bandwidth, if ratio = 1, we used all
291 
292  if (bw_saturated) throttleStats.total_bw_sat_cy += 1;
293  if (output_blocked) throttleStats.total_stall_cy += 1;
294 
295  if (bw_saturated || output_blocked) {
296  // We are out of bandwidth for this cycle, so wakeup next
297  // cycle and continue
298  DPRINTF(RubyNetwork, "%s scheduled again\n", *this);
299  scheduleEvent(Cycles(1));
300  }
301 }
302 
303 void
304 Throttle::print(std::ostream& out) const
305 {
306  ccprintf(out, "[%i bw:", m_node);
307  if (m_physical_vnets) {
308  for (unsigned i = 0; i < m_vnets; ++i)
309  ccprintf(out, " vnet%d=%i", i, getLinkBandwidth(i));
310  } else {
311  ccprintf(out, " %i", getTotalLinkBandwidth());
312  }
313  ccprintf(out, "]");
314 }
315 
316 int
318 {
319  assert(net_msg_ptr != NULL);
320 
321  int size = Network::MessageSizeType_to_int(net_msg_ptr->getMessageSize());
322  size *= MESSAGE_SIZE_MULTIPLIER;
323 
324  // Artificially increase the size of broadcast messages
325  if (BROADCAST_SCALING > 1 && net_msg_ptr->getDestination().isBroadcast())
326  size *= BROADCAST_SCALING;
327 
328  return size;
329 }
330 
332 ThrottleStats::ThrottleStats(Switch *parent, const NodeID &nodeID)
333  : statistics::Group(parent, csprintf("throttle%02i", nodeID).c_str()),
334  ADD_STAT(acc_link_utilization, statistics::units::Count::get(),
335  "Accumulated link utilization"),
336  ADD_STAT(link_utilization, statistics::units::Ratio::get(),
337  "Average link utilization"),
338  ADD_STAT(total_msg_count, statistics::units::Count::get(),
339  "Total number of messages forwarded by this switch"),
340  ADD_STAT(total_msg_bytes, statistics::units::Byte::get(),
341  "Total number of bytes forwarded by this switch"),
342  ADD_STAT(total_data_msg_bytes, statistics::units::Byte::get(),
343  "Total number of data bytes forwarded by this switch"),
344  ADD_STAT(total_msg_wait_time, statistics::units::Tick::get(),
345  "Total time spend forwarding messages"),
346  ADD_STAT(total_stall_cy, statistics::units::Cycle::get(),
347  "Total time spent blocked on any output link"),
348  ADD_STAT(total_bw_sat_cy, statistics::units::Cycle::get(),
349  "Total time bandwidth was saturated on any output link"),
350  ADD_STAT(avg_msg_wait_time, statistics::units::Ratio::get(),
351  "Average time a message took to be forwarded"),
352  ADD_STAT(avg_bandwidth, statistics::units::Ratio::get(),
353  "Average bandwidth (GB/s)"),
354  ADD_STAT(avg_useful_bandwidth, statistics::units::Ratio::get(),
355  "Average usefull (only data) bandwidth (GB/s)")
356 {
358  (simTicks / parent->clockPeriod());
359 
361 
364  statistics::constant(1024*1024*1024);
365 
368  statistics::constant(1024*1024*1024);
369 
370  for (MessageSizeType type = MessageSizeType_FIRST;
371  type < MessageSizeType_NUM; ++type) {
372  msg_counts[(unsigned int)type] =
373  new statistics::Vector(this,
374  csprintf("msg_count.%s", MessageSizeType_to_string(type)).c_str());
375  msg_counts[(unsigned int)type]
378  ;
379 
380  msg_bytes[(unsigned int) type] =
381  new statistics::Formula(this,
382  csprintf("msg_bytes.%s", MessageSizeType_to_string(type)).c_str());
383  msg_bytes[(unsigned int) type]
385  ;
386 
387  *(msg_bytes[(unsigned int) type]) =
390  }
391 }
392 
393 } // namespace ruby
394 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
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...
Tick cyclesToTicks(Cycles c) const
Tick clockPeriod() const
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
void scheduleEvent(Cycles timeDelta)
Definition: Consumer.cc:56
void setConsumer(Consumer *consumer)
bool areNSlotsAvailable(unsigned int n, Tick curTime)
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...
void enqueue(MsgPtr message, Tick curTime, Tick delta)
virtual const NetDest & getDestination() const
Definition: Message.hh:114
Tick getLastEnqueueTime() const
Definition: Message.hh:107
virtual const MessageSizeType & getMessageSize() const
Definition: Message.hh:78
bool isBroadcast() const
Definition: NetDest.cc:174
static uint32_t getNumberOfVirtualNetworks()
Definition: Network.hh:90
static uint32_t MessageSizeType_to_int(MessageSizeType size_type)
Definition: Network.cc:164
std::vector< int > m_vnet_channels
Definition: Throttle.hh:130
std::vector< MessageBuffer * > m_in
Definition: Throttle.hh:119
unsigned int m_vnets
Definition: Throttle.hh:121
void operateVnet(int vnet, int channel, int &total_bw_remaining, bool &bw_saturated, bool &output_blocked, MessageBuffer *in, MessageBuffer *out)
Definition: Throttle.cc:165
std::vector< std::vector< int > > m_units_remaining
Definition: Throttle.hh:122
void print(std::ostream &out) const
Definition: Throttle.cc:304
const int m_switch_id
Definition: Throttle.hh:124
int getTotalLinkBandwidth() const
Definition: Throttle.cc:148
RubySystem * m_ruby_system
Definition: Throttle.hh:134
gem5::ruby::Throttle::ThrottleStats throttleStats
Throttle(int sID, RubySystem *rs, NodeID node, Cycles link_latency, int endpoint_bandwidth, Switch *em)
Definition: Throttle.cc:68
std::vector< MessageBuffer * > m_out
Definition: Throttle.hh:120
int getLinkBandwidth(int vnet) const
Definition: Throttle.cc:138
void addLinks(const std::vector< MessageBuffer * > &in_vec, const std::vector< MessageBuffer * > &out_vec)
Definition: Throttle.cc:111
std::vector< int > m_link_bandwidth_multiplier
Definition: Throttle.hh:129
void init(NodeID node, Cycles link_latency, int link_bandwidth_multiplier, int endpoint_bandwidth)
int getChannelCnt(int vnet) const
Definition: Throttle.cc:159
Derived & precision(int _precision)
Set the precision and marks this stat to print at the end of simulation.
Definition: statistics.hh:346
A formula for statistics that is calculated when printed.
Definition: statistics.hh:2540
Statistics container.
Definition: group.hh:94
A vector of scalar stats.
Definition: statistics.hh:2007
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
#define gem5_assert(cond,...)
The assert macro will function like a normal assert, but will use panic instead of straight abort().
Definition: logging.hh:318
uint8_t flags
Definition: helpers.cc:66
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 9, 8 > rs
Definition: misc_types.hh:383
Bitfield< 18 > sum
Definition: misc.hh:560
Bitfield< 2 > em
Definition: misc.hh:607
std::shared_ptr< Message > MsgPtr
Definition: Message.hh:59
unsigned int NodeID
Definition: TypeDefines.hh:42
const int PRIORITY_SWITCH_LIMIT
const int MESSAGE_SIZE_MULTIPLIER
Definition: Throttle.cc:61
const int BROADCAST_SCALING
Definition: Throttle.cc:63
static int network_message_to_size(Message *net_msg_ptr)
Definition: Throttle.cc:317
const FlagsType nozero
Don't print if this is zero.
Definition: info.hh:68
Temp constant(T val)
Definition: statistics.hh:2865
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
uint64_t Tick
Tick count type.
Definition: types.hh:58
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
statistics::Value & simTicks
Definition: stats.cc:46
statistics::Formula & simSeconds
Definition: stats.cc:45
void ccprintf(cp::Print &print)
Definition: cprintf.hh:130
const std::string to_string(sc_enc enc)
Definition: sc_fxdefs.cc:60
statistics::Scalar total_msg_bytes
Definition: Throttle.hh:147
statistics::Formula avg_msg_wait_time
Definition: Throttle.hh:152
statistics::Formula link_utilization
Definition: Throttle.hh:142
statistics::Formula * msg_bytes[MessageSizeType_NUM]
Definition: Throttle.hh:144
statistics::Scalar total_msg_wait_time
Definition: Throttle.hh:149
statistics::Scalar total_data_msg_bytes
Definition: Throttle.hh:148
statistics::Scalar acc_link_utilization
Definition: Throttle.hh:141
ThrottleStats(Switch *parent, const NodeID &nodeID)
Definition: Throttle.cc:332
statistics::Formula avg_useful_bandwidth
Definition: Throttle.hh:154
statistics::Scalar total_msg_count
Definition: Throttle.hh:146
statistics::Formula avg_bandwidth
Definition: Throttle.hh:153
statistics::Vector * msg_counts[MessageSizeType_NUM]
Definition: Throttle.hh:143
statistics::Scalar total_stall_cy
Definition: Throttle.hh:150
statistics::Scalar total_bw_sat_cy
Definition: Throttle.hh:151

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