gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Throttle.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
30 
31 #include <cassert>
32 
33 #include "base/cast.hh"
34 #include "base/cprintf.hh"
35 #include "debug/RubyNetwork.hh"
41 
42 using namespace std;
43 
44 const int MESSAGE_SIZE_MULTIPLIER = 1000;
45 //const int BROADCAST_SCALING = 4; // Have a 16p system act like a 64p systems
46 const int BROADCAST_SCALING = 1;
47 const int PRIORITY_SWITCH_LIMIT = 128;
48 
49 static int network_message_to_size(Message* net_msg_ptr);
50 
51 Throttle::Throttle(int sID, RubySystem *rs, NodeID node, Cycles link_latency,
52  int link_bandwidth_multiplier, int endpoint_bandwidth,
53  Switch *em)
54  : Consumer(em), m_switch_id(sID), m_switch(em), m_node(node),
55  m_ruby_system(rs)
56 {
57  m_vnets = 0;
58 
59  assert(link_bandwidth_multiplier > 0);
60  m_link_bandwidth_multiplier = link_bandwidth_multiplier;
61 
62  m_link_latency = link_latency;
63  m_endpoint_bandwidth = endpoint_bandwidth;
64 
67 }
68 
69 void
71  const vector<MessageBuffer*>& out_vec)
72 {
73  assert(in_vec.size() == out_vec.size());
74 
75  for (int vnet = 0; vnet < in_vec.size(); ++vnet) {
76  MessageBuffer *in_ptr = in_vec[vnet];
77  MessageBuffer *out_ptr = out_vec[vnet];
78 
79  m_vnets++;
80  m_units_remaining.push_back(0);
81  m_in.push_back(in_ptr);
82  m_out.push_back(out_ptr);
83 
84  // Set consumer and description
85  in_ptr->setConsumer(this);
86  string desc = "[Queue to Throttle " + to_string(m_switch_id) + " " +
87  to_string(m_node) + "]";
88  }
89 }
90 
91 void
92 Throttle::operateVnet(int vnet, int &bw_remaining, bool &schedule_wakeup,
93  MessageBuffer *in, MessageBuffer *out)
94 {
95  if (out == nullptr || in == nullptr) {
96  return;
97  }
98 
99  assert(m_units_remaining[vnet] >= 0);
100  Tick current_time = m_switch->clockEdge();
101 
102  while (bw_remaining > 0 && (in->isReady(current_time) ||
103  m_units_remaining[vnet] > 0) &&
104  out->areNSlotsAvailable(1, current_time)) {
105  // See if we are done transferring the previous message on
106  // this virtual network
107  if (m_units_remaining[vnet] == 0 && in->isReady(current_time)) {
108  // Find the size of the message we are moving
109  MsgPtr msg_ptr = in->peekMsgPtr();
110  Message *net_msg_ptr = msg_ptr.get();
111  m_units_remaining[vnet] +=
112  network_message_to_size(net_msg_ptr);
113 
114  DPRINTF(RubyNetwork, "throttle: %d my bw %d bw spent "
115  "enqueueing net msg %d time: %lld.\n",
118 
119  // Move the message
120  in->dequeue(current_time);
121  out->enqueue(msg_ptr, current_time,
123 
124  // Count the message
125  m_msg_counts[net_msg_ptr->getMessageSize()][vnet]++;
126  DPRINTF(RubyNetwork, "%s\n", *out);
127  }
128 
129  // Calculate the amount of bandwidth we spent on this message
130  int diff = m_units_remaining[vnet] - bw_remaining;
131  m_units_remaining[vnet] = max(0, diff);
132  bw_remaining = max(0, -diff);
133  }
134 
135  if (bw_remaining > 0 && (in->isReady(current_time) ||
136  m_units_remaining[vnet] > 0) &&
137  !out->areNSlotsAvailable(1, current_time)) {
138  DPRINTF(RubyNetwork, "vnet: %d", vnet);
139 
140  // schedule me to wakeup again because I'm waiting for my
141  // output queue to become available
142  schedule_wakeup = true;
143  }
144 }
145 
146 void
148 {
149  // Limits the number of message sent to a limited number of bytes/cycle.
150  assert(getLinkBandwidth() > 0);
151  int bw_remaining = getLinkBandwidth();
152 
154  bool schedule_wakeup = false;
155 
156  // variable for deciding the direction in which to iterate
157  bool iteration_direction = false;
158 
159 
160  // invert priorities to avoid starvation seen in the component network
163  iteration_direction = true;
164  }
165 
166  if (iteration_direction) {
167  for (int vnet = 0; vnet < m_vnets; ++vnet) {
168  operateVnet(vnet, bw_remaining, schedule_wakeup,
169  m_in[vnet], m_out[vnet]);
170  }
171  } else {
172  for (int vnet = m_vnets-1; vnet >= 0; --vnet) {
173  operateVnet(vnet, bw_remaining, schedule_wakeup,
174  m_in[vnet], m_out[vnet]);
175  }
176  }
177 
178  // We should only wake up when we use the bandwidth
179  // This is only mostly true
180  // assert(bw_remaining != getLinkBandwidth());
181 
182  // Record that we used some or all of the link bandwidth this cycle
183  double ratio = 1.0 - (double(bw_remaining) / double(getLinkBandwidth()));
184 
185  // If ratio = 0, we used no bandwidth, if ratio = 1, we used all
186  m_link_utilization_proxy += ratio;
187 
188  if (bw_remaining > 0 && !schedule_wakeup) {
189  // We have extra bandwidth and our output buffer was
190  // available, so we must not have anything else to do until
191  // another message arrives.
192  DPRINTF(RubyNetwork, "%s not scheduled again\n", *this);
193  } else {
194  DPRINTF(RubyNetwork, "%s scheduled again\n", *this);
195 
196  // We are out of bandwidth for this cycle, so wakeup next
197  // cycle and continue
198  scheduleEvent(Cycles(1));
199  }
200 }
201 
202 void
203 Throttle::regStats(string parent)
204 {
206  .name(parent + csprintf(".throttle%i", m_node) + ".link_utilization");
207 
208  for (MessageSizeType type = MessageSizeType_FIRST;
209  type < MessageSizeType_NUM; ++type) {
210  m_msg_counts[(unsigned int)type]
212  .name(parent + csprintf(".throttle%i", m_node) + ".msg_count." +
213  MessageSizeType_to_string(type))
214  .flags(Stats::nozero)
215  ;
216  m_msg_bytes[(unsigned int) type]
217  .name(parent + csprintf(".throttle%i", m_node) + ".msg_bytes." +
218  MessageSizeType_to_string(type))
219  .flags(Stats::nozero)
220  ;
221 
222  m_msg_bytes[(unsigned int) type] = m_msg_counts[type] * Stats::constant(
224  }
225 }
226 
227 void
229 {
231 }
232 
233 void
235 {
236  double time_delta = double(m_ruby_system->curCycle() -
238 
239  m_link_utilization = 100.0 * m_link_utilization_proxy / time_delta;
240 }
241 
242 void
243 Throttle::print(ostream& out) const
244 {
245  ccprintf(out, "[%i bw: %i]", m_node, getLinkBandwidth());
246 }
247 
248 int
250 {
251  assert(net_msg_ptr != NULL);
252 
254  size *= MESSAGE_SIZE_MULTIPLIER;
255 
256  // Artificially increase the size of broadcast messages
257  if (BROADCAST_SCALING > 1 && net_msg_ptr->getDestination().isBroadcast())
258  size *= BROADCAST_SCALING;
259 
260  return size;
261 }
void ccprintf(cp::Print &print)
Definition: cprintf.hh:130
virtual const MessageSizeType & getMessageSize() const
Definition: Message.hh:64
#define DPRINTF(x,...)
Definition: trace.hh:212
std::vector< MessageBuffer * > m_out
Definition: Throttle.hh:94
NodeID m_node
Definition: Throttle.hh:100
virtual const NetDest & getDestination() const
Definition: Message.hh:96
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:83
void addLinks(const std::vector< MessageBuffer * > &in_vec, const std::vector< MessageBuffer * > &out_vec)
Definition: Throttle.cc:70
std::shared_ptr< Message > MsgPtr
Definition: Message.hh:40
std::vector< MessageBuffer * > m_in
Definition: Throttle.hh:93
Stats::Formula m_msg_bytes[MessageSizeType_NUM]
Definition: Throttle.hh:111
void scheduleEvent(Cycles timeDelta)
Definition: Consumer.cc:34
Tick cyclesToTicks(Cycles c) const
static uint32_t getNumberOfVirtualNetworks()
Definition: Network.hh:69
void init(NodeID node, Cycles link_latency, int link_bandwidth_multiplier, int endpoint_bandwidth)
std::string name()
Definition: Throttle.hh:60
Bitfield< 2 > em
Definition: misc.hh:603
bool isBroadcast() const
Definition: NetDest.cc:168
std::vector< int > m_units_remaining
Definition: Throttle.hh:96
int m_endpoint_bandwidth
Definition: Throttle.hh:105
int getLinkBandwidth() const
Definition: Throttle.hh:73
RubySystem * m_ruby_system
Definition: Throttle.hh:106
const int m_switch_id
Definition: Throttle.hh:98
void print(std::ostream &out) const
Definition: Throttle.cc:243
Cycles m_link_latency
Definition: Throttle.hh:103
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Stats::Scalar m_link_utilization
Definition: Throttle.hh:109
Definition: Switch.hh:57
unsigned int NodeID
Definition: TypeDefines.hh:34
Throttle(int sID, RubySystem *rs, NodeID node, Cycles link_latency, int link_bandwidth_multiplier, int endpoint_bandwidth, Switch *em)
Definition: Throttle.cc:51
bool areNSlotsAvailable(unsigned int n, Tick curTime)
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...
const MsgPtr & peekMsgPtr() const
double m_link_utilization_proxy
Definition: Throttle.hh:113
int m_link_bandwidth_multiplier
Definition: Throttle.hh:102
Cycles getStartCycle()
Definition: RubySystem.hh:81
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
const int MESSAGE_SIZE_MULTIPLIER
Definition: Throttle.cc:44
uint64_t Tick
Tick count type.
Definition: types.hh:63
unsigned int m_vnets
Definition: Throttle.hh:95
void setConsumer(Consumer *consumer)
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...
Temp constant(T val)
Definition: statistics.hh:3211
const int BROADCAST_SCALING
Definition: Throttle.cc:46
Stats::Vector m_msg_counts[MessageSizeType_NUM]
Definition: Throttle.hh:110
Switch * m_switch
Definition: Throttle.hh:99
static uint32_t MessageSizeType_to_int(MessageSizeType size_type)
Definition: Network.cc:110
const int PRIORITY_SWITCH_LIMIT
Definition: Throttle.cc:47
Derived & name(const std::string &name)
Set the name and marks this stat to print at the end of simulation.
Definition: statistics.hh:254
bool isReady(Tick current_time) const
type
Definition: misc.hh:728
int size()
Definition: pagetable.hh:146
void wakeup()
Definition: Throttle.cc:147
static int network_message_to_size(Message *net_msg_ptr)
Definition: Throttle.cc:249
const FlagsType nozero
Don't print if this is zero.
Definition: info.hh:57
Bitfield< 9, 8 > rs
Definition: miscregs.hh:1560
void enqueue(MsgPtr message, Tick curTime, Tick delta)
void collateStats()
Definition: Throttle.cc:234
void regStats(std::string name)
Definition: Throttle.cc:203
int m_wakeups_wo_switch
Definition: Throttle.hh:104
void clearStats()
Definition: Throttle.cc:228
void operateVnet(int vnet, int &bw_remainin, bool &schedule_wakeup, MessageBuffer *in, MessageBuffer *out)
Definition: Throttle.cc:92

Generated on Fri Jun 9 2017 13:03:50 for gem5 by doxygen 1.8.6