gem5 [DEVELOP-FOR-25.1]
Loading...
Searching...
No Matches
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
55namespace gem5
56{
57
58namespace ruby
59{
60
61const int MESSAGE_SIZE_MULTIPLIER = 1000;
62//const int BROADCAST_SCALING = 4; // Have a 16p system act like a 64p systems
63const int BROADCAST_SCALING = 1;
64const int PRIORITY_SWITCH_LIMIT = 128;
65
66static int network_message_to_size(Message* net_msg_ptr);
67
68Throttle::Throttle(int sID, RubySystem *rs, NodeID node, Cycles link_latency,
69 int endpoint_bandwidth, Switch *em, std::string link_name)
70 : Consumer(em, Switch::THROTTLE_EV_PRI),
71 m_switch_id(sID), m_switch(em), m_node(node),
75{
76 m_vnets = 0;
77
78 m_link_latency = link_latency;
79 m_endpoint_bandwidth = endpoint_bandwidth;
80
82}
83
84Throttle::Throttle(int sID, RubySystem *rs, NodeID node, Cycles link_latency,
85 int link_bandwidth_multiplier, int endpoint_bandwidth,
86 Switch *em, std::string link_name)
87 : Throttle(sID, rs, node, link_latency, endpoint_bandwidth, em, link_name)
88{
89 gem5_assert(link_bandwidth_multiplier > 0, "Throttle::Throttle");
90 m_link_bandwidth_multiplier.push_back(link_bandwidth_multiplier);
91}
92
93Throttle::Throttle(int sID, RubySystem *rs, NodeID node, Cycles link_latency,
94 const std::vector<int> &vnet_channels,
95 const std::vector<int> &vnet_bandwidth_multiplier,
96 int endpoint_bandwidth, Switch *em, std::string link_name)
97 : Throttle(sID, rs, node, link_latency, endpoint_bandwidth, em, link_name)
98{
99 m_physical_vnets = true;
100 for (auto link_bandwidth_multiplier : vnet_bandwidth_multiplier){
101 gem5_assert(link_bandwidth_multiplier > 0, "Throttle::Throttle");
102 m_link_bandwidth_multiplier.push_back(link_bandwidth_multiplier);
103 }
104 for (auto channels : vnet_channels){
105 gem5_assert(channels > 0, "Throttle::Throttle");
106 m_vnet_channels.push_back(channels);
107 }
109 "Throttle::Throttle");
110}
111
112void
114 const std::vector<MessageBuffer*>& out_vec)
115{
116 assert(in_vec.size() == out_vec.size());
117
118 for (int vnet = 0; vnet < in_vec.size(); ++vnet) {
119 MessageBuffer *in_ptr = in_vec[vnet];
120 MessageBuffer *out_ptr = out_vec[vnet];
121
122 m_units_remaining.emplace_back(getChannelCnt(vnet),0);
123 m_in.push_back(in_ptr);
124 m_out.push_back(out_ptr);
125
126 // Set consumer and description
127 in_ptr->setConsumer(this);
128 std::string desc = "[Queue to Throttle " +
129 std::to_string(m_switch_id) + " " + std::to_string(m_node) + "]";
130 }
131
132 m_vnets = in_vec.size();
133
136 : (m_link_bandwidth_multiplier.size() == 1),
137 "Throttle::addLinks");
138}
139
140int
142{
143 int bw = m_physical_vnets ?
146 gem5_assert(bw > 0, "Throttle::getLinkBandwidth");
147 return m_endpoint_bandwidth * bw;
148}
149
150int
152{
153 int sum = getLinkBandwidth(0) * getChannelCnt(0);
154 if (m_physical_vnets) {
155 for (unsigned i = 1; i < m_vnets; ++i)
157 }
158 return sum;
159}
160
161int
163{
164 return m_physical_vnets ? m_vnet_channels[vnet] : 1;
165}
166
167void
168Throttle::operateVnet(int vnet, int channel, int &total_bw_remaining,
169 bool &bw_saturated, bool &output_blocked,
171{
172 if (out == nullptr || in == nullptr) {
173 return;
174 }
175
176 int &units_remaining = m_units_remaining[vnet][channel];
177
178 gem5_assert(units_remaining >= 0, "Throttle::operateVnet");
179 Tick current_time = m_switch->clockEdge();
180
181 int bw_remaining = m_physical_vnets ?
182 getLinkBandwidth(vnet) : total_bw_remaining;
183
184 auto hasPendingWork = [&]{ return in->isReady(current_time) ||
185 units_remaining > 0; };
186 while ((bw_remaining > 0) && hasPendingWork() &&
187 out->areNSlotsAvailable(1, current_time)) {
188 // See if we are done transferring the previous message on
189 // this virtual network
190 if (units_remaining == 0 && in->isReady(current_time)) {
191 // Find the size of the message we are moving
192 MsgPtr msg_ptr = in->peekMsgPtr();
193 Message *net_msg_ptr = msg_ptr.get();
194 Tick msg_enqueue_time = msg_ptr->getLastEnqueueTime();
195 units_remaining = network_message_to_size(net_msg_ptr);
196
197 DPRINTF(RubyNetwork, "throttle: %d my bw %d bw spent "
198 "enqueueing net msg %d time: %lld.\n",
199 m_node, getLinkBandwidth(vnet), units_remaining,
200 m_ruby_system->curCycle());
201
202 // Move the message
203 in->dequeue(current_time);
204 out->enqueue(msg_ptr, current_time,
205 m_switch->cyclesToTicks(m_link_latency),
206 m_ruby_system->getRandomization(),
207 m_ruby_system->getWarmupEnabled());
208
209 // Count the message
210 (*(throttleStats.
211 msg_counts[net_msg_ptr->getMessageSize()]))[vnet]++;
212 throttleStats.total_msg_count += 1;
213 uint32_t total_size =
215 throttleStats.total_msg_bytes += total_size;
216 total_size -=
217 Network::MessageSizeType_to_int(MessageSizeType_Control);
218 throttleStats.total_data_msg_bytes += total_size;
219 throttleStats.total_msg_wait_time +=
220 current_time - msg_enqueue_time;
221 DPRINTF(RubyNetwork, "%s\n", *out);
222 }
223
224 // Calculate the amount of bandwidth we spent on this message
225 int spent = std::min(units_remaining, bw_remaining);
226 units_remaining -= spent;
227 bw_remaining -= spent;
228 total_bw_remaining -= spent;
229 }
230
231 gem5_assert(units_remaining >= 0, "Throttle::operateVnet");
232 gem5_assert(bw_remaining >= 0, "Throttle::operateVnet");
233 gem5_assert(total_bw_remaining >= 0, "Throttle::operateVnet");
234
235 // Notify caller if
236 // - we ran out of bandwith and still have stuff to do
237 // - we had something to do but output queue was unavailable
238 if (hasPendingWork()) {
239 gem5_assert((bw_remaining == 0) ||
240 !out->areNSlotsAvailable(1, current_time),
241 "Throttle::operateVnet");
242 bw_saturated = bw_saturated || (bw_remaining == 0);
243 output_blocked = output_blocked ||
244 !out->areNSlotsAvailable(1, current_time);
245 }
246}
247
248void
250{
251 // Limits the number of message sent to a limited number of bytes/cycle.
252 assert(getTotalLinkBandwidth() > 0);
253 int bw_remaining = getTotalLinkBandwidth();
254
256 bool bw_saturated = false;
257 bool output_blocked = false;
258
259 // variable for deciding the direction in which to iterate
260 bool iteration_direction = false;
261
262
263 // invert priorities to avoid starvation seen in the component network
266 iteration_direction = true;
267 }
268
269 if (iteration_direction) {
270 for (int vnet = 0; vnet < m_vnets; ++vnet) {
271 for (int channel = 0; channel < getChannelCnt(vnet); ++channel) {
272 operateVnet(vnet, channel, bw_remaining,
273 bw_saturated, output_blocked,
274 m_in[vnet], m_out[vnet]);
275 }
276 }
277 } else {
278 for (int vnet = m_vnets-1; vnet >= 0; --vnet) {
279 for (int channel = 0; channel < getChannelCnt(vnet); ++channel) {
280 operateVnet(vnet, channel, bw_remaining,
281 bw_saturated, output_blocked,
282 m_in[vnet], m_out[vnet]);
283 }
284 }
285 }
286
287 // We should only wake up when we use the bandwidth
288 // This is only mostly true
289 // assert(bw_remaining != getLinkBandwidth());
290
291 // Record that we used some or all of the link bandwidth this cycle
292 double ratio = 1.0 - (double(bw_remaining) /
293 double(getTotalLinkBandwidth()));
294
295 // If ratio = 0, we used no bandwidth, if ratio = 1, we used all
296 throttleStats.acc_link_utilization += ratio;
297
298 if (bw_saturated) throttleStats.total_bw_sat_cy += 1;
299 if (output_blocked) throttleStats.total_stall_cy += 1;
300
301 if (bw_saturated || output_blocked) {
302 // We are out of bandwidth for this cycle, so wakeup next
303 // cycle and continue
304 DPRINTF(RubyNetwork, "%s scheduled again\n", *this);
306 }
307}
308
309void
310Throttle::print(std::ostream& out) const
311{
312 ccprintf(out, "[%i bw:", m_node);
313 if (m_physical_vnets) {
314 for (unsigned i = 0; i < m_vnets; ++i)
315 ccprintf(out, " vnet%d=%i", i, getLinkBandwidth(i));
316 } else {
317 ccprintf(out, " %i", getTotalLinkBandwidth());
318 }
319 ccprintf(out, "]");
320}
321
322int
324{
325 assert(net_msg_ptr != NULL);
326
327 int size = Network::MessageSizeType_to_int(net_msg_ptr->getMessageSize());
329
330 // Artificially increase the size of broadcast messages
331 if (BROADCAST_SCALING > 1 && net_msg_ptr->getDestination().isBroadcast())
332 size *= BROADCAST_SCALING;
333
334 return size;
335}
336
339 Switch *parent, const NodeID &nodeID, std::string link_name
340) : statistics::Group(parent, csprintf("throttle%02i", nodeID).c_str()),
342 csprintf("Accumulated link utilization %s",link_name).c_str()),
344 "Average link utilization"),
346 "Total number of messages forwarded by this switch"),
348 "Total number of bytes forwarded by this switch"),
350 "Total number of data bytes forwarded by this switch"),
352 "Total time spend forwarding messages"),
353 ADD_STAT(total_stall_cy, statistics::units::Cycle::get(),
354 "Total time spent blocked on any output link"),
356 "Total time bandwidth was saturated on any output link"),
358 "Average time a message took to be forwarded"),
359 ADD_STAT(avg_bandwidth, statistics::units::Ratio::get(),
360 "Average bandwidth (GB/s)"),
362 "Average useful (only data) bandwidth (GB/s)")
363{
365 (simTicks / parent->clockPeriod());
366
368
369 avg_bandwidth.precision(2);
371 statistics::constant(1024*1024*1024);
372
373 avg_useful_bandwidth.precision(2);
375 statistics::constant(1024*1024*1024);
376
377 for (MessageSizeType type = MessageSizeType_FIRST;
378 type < MessageSizeType_NUM; ++type) {
379 msg_counts[(unsigned int)type] =
380 new statistics::Vector(this,
381 csprintf("msg_count.%s", MessageSizeType_to_string(type)).c_str());
382 msg_counts[(unsigned int)type]
384 .flags(statistics::nozero)
385 ;
386
387 msg_bytes[(unsigned int) type] =
388 new statistics::Formula(this,
389 csprintf("msg_bytes.%s", MessageSizeType_to_string(type)).c_str());
390 msg_bytes[(unsigned int) type]
391 ->flags(statistics::nozero)
392 ;
393
394 *(msg_bytes[(unsigned int) type]) =
397 }
398}
399
400} // namespace ruby
401} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
Tick clockPeriod() const
Cycles is a wrapper class for representing cycle counts, i.e.
Definition types.hh:79
Consumer(ClockedObject *em, Event::Priority ev_prio=Event::Default_Pri)
Definition Consumer.cc:49
void scheduleEvent(Cycles timeDelta)
Definition Consumer.cc:56
ClockedObject * em
Definition Consumer.hh:93
void setConsumer(Consumer *consumer)
bool areNSlotsAvailable(unsigned int n, Tick curTime)
bool isReady(Tick current_time) 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...
const MsgPtr & peekMsgPtr() const
void enqueue(MsgPtr message, Tick curTime, Tick delta, bool ruby_is_random, bool ruby_warmup, bool bypassStrictFIFO=false)
virtual const NetDest & getDestination() const
Definition Message.hh:115
virtual const MessageSizeType & getMessageSize() const
Definition Message.hh:79
bool isBroadcast() const
Definition NetDest.cc:200
static uint32_t getNumberOfVirtualNetworks()
Definition Network.hh:91
static uint32_t MessageSizeType_to_int(MessageSizeType size_type)
Definition Network.cc:166
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:168
std::vector< std::vector< int > > m_units_remaining
Definition Throttle.hh:122
void print(std::ostream &out) const
Definition Throttle.cc:310
const int m_switch_id
Definition Throttle.hh:124
int getTotalLinkBandwidth() const
Definition Throttle.cc:151
std::string link_name
Definition Throttle.hh:136
Throttle(int sID, RubySystem *rs, NodeID node, Cycles link_latency, int endpoint_bandwidth, Switch *em, std::string link_name)
Definition Throttle.cc:68
RubySystem * m_ruby_system
Definition Throttle.hh:134
gem5::ruby::Throttle::ThrottleStats throttleStats
std::vector< MessageBuffer * > m_out
Definition Throttle.hh:120
int getLinkBandwidth(int vnet) const
Definition Throttle.cc:141
void addLinks(const std::vector< MessageBuffer * > &in_vec, const std::vector< MessageBuffer * > &out_vec)
Definition Throttle.cc:113
std::vector< int > m_link_bandwidth_multiplier
Definition Throttle.hh:129
int getChannelCnt(int vnet) const
Definition Throttle.cc:162
A formula for statistics that is calculated when printed.
A vector of scalar stats.
STL vector class.
Definition stl.hh:37
#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:349
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 9, 8 > rs
Bitfield< 18 > sum
Definition misc.hh:1346
std::shared_ptr< Message > MsgPtr
Definition Message.hh:60
unsigned int NodeID
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:323
Units for Stats.
Definition units.hh:113
const FlagsType init
This Stat is Initialized.
Definition info.hh:55
const FlagsType nozero
Don't print if this is zero.
Definition info.hh:67
Temp constant(T val)
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
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
statistics::Scalar total_msg_bytes
Definition Throttle.hh:150
statistics::Formula avg_msg_wait_time
Definition Throttle.hh:155
statistics::Formula link_utilization
Definition Throttle.hh:145
statistics::Formula * msg_bytes[MessageSizeType_NUM]
Definition Throttle.hh:147
statistics::Scalar total_msg_wait_time
Definition Throttle.hh:152
statistics::Scalar total_data_msg_bytes
Definition Throttle.hh:151
statistics::Scalar acc_link_utilization
Definition Throttle.hh:144
ThrottleStats(Switch *parent, const NodeID &nodeID, std::string link_name)
Definition Throttle.cc:338
statistics::Formula avg_useful_bandwidth
Definition Throttle.hh:157
statistics::Scalar total_msg_count
Definition Throttle.hh:149
statistics::Formula avg_bandwidth
Definition Throttle.hh:156
statistics::Vector * msg_counts[MessageSizeType_NUM]
Definition Throttle.hh:146
statistics::Scalar total_stall_cy
Definition Throttle.hh:153
statistics::Scalar total_bw_sat_cy
Definition Throttle.hh:154

Generated on Mon Oct 27 2025 04:13:03 for gem5 by doxygen 1.14.0