Throttle.cc revision 9863:9483739f83ee
11897Sstever@eecs.umich.edu/* 24130Ssaidi@eecs.umich.edu * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 31897Sstever@eecs.umich.edu * All rights reserved. 41897Sstever@eecs.umich.edu * 51897Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 61897Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are 71897Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright 81897Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 91897Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 101897Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 111897Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution; 121897Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its 131897Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from 141897Sstever@eecs.umich.edu * this software without specific prior written permission. 151897Sstever@eecs.umich.edu * 161897Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171897Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181897Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191897Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201897Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211897Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221897Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231897Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241897Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251897Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261897Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 271897Sstever@eecs.umich.edu */ 281897Sstever@eecs.umich.edu 291897Sstever@eecs.umich.edu#include <cassert> 301897Sstever@eecs.umich.edu 311897Sstever@eecs.umich.edu#include "base/cast.hh" 321897Sstever@eecs.umich.edu#include "base/cprintf.hh" 331897Sstever@eecs.umich.edu#include "debug/RubyNetwork.hh" 344961Ssaidi@eecs.umich.edu#include "mem/ruby/buffers/MessageBuffer.hh" 351897Sstever@eecs.umich.edu#include "mem/ruby/network/simple/Throttle.hh" 361897Sstever@eecs.umich.edu#include "mem/ruby/network/Network.hh" 371897Sstever@eecs.umich.edu#include "mem/ruby/slicc_interface/NetworkMessage.hh" 381897Sstever@eecs.umich.edu#include "mem/ruby/system/System.hh" 397047Snate@binkert.org 408319Ssteve.reinhardt@amd.comusing namespace std; 417047Snate@binkert.org 428319Ssteve.reinhardt@amd.comconst int HIGH_RANGE = 256; 4311706Sandreas.hansson@arm.comconst int ADJUST_INTERVAL = 50000; 448811Sandreas.hansson@arm.comconst int MESSAGE_SIZE_MULTIPLIER = 1000; 459850Sandreas.hansson@arm.com//const int BROADCAST_SCALING = 4; // Have a 16p system act like a 64p systems 4611706Sandreas.hansson@arm.comconst int BROADCAST_SCALING = 1; 4711706Sandreas.hansson@arm.comconst int PRIORITY_SWITCH_LIMIT = 128; 4811706Sandreas.hansson@arm.com 4911706Sandreas.hansson@arm.comstatic int network_message_to_size(NetworkMessage* net_msg_ptr); 508811Sandreas.hansson@arm.com 518811Sandreas.hansson@arm.comThrottle::Throttle(int sID, NodeID node, Cycles link_latency, 5210007Snilay@cs.wisc.edu int link_bandwidth_multiplier, int endpoint_bandwidth, 5311308Santhony.gutierrez@amd.com ClockedObject *em) 5411308Santhony.gutierrez@amd.com : Consumer(em) 557047Snate@binkert.org{ 568811Sandreas.hansson@arm.com init(node, link_latency, link_bandwidth_multiplier, endpoint_bandwidth); 578811Sandreas.hansson@arm.com m_sID = sID; 588811Sandreas.hansson@arm.com} 598319Ssteve.reinhardt@amd.com 608319Ssteve.reinhardt@amd.comThrottle::Throttle(NodeID node, Cycles link_latency, 618319Ssteve.reinhardt@amd.com int link_bandwidth_multiplier, int endpoint_bandwidth, 628319Ssteve.reinhardt@amd.com ClockedObject *em) 638319Ssteve.reinhardt@amd.com : Consumer(em) 648319Ssteve.reinhardt@amd.com{ 658319Ssteve.reinhardt@amd.com init(node, link_latency, link_bandwidth_multiplier, endpoint_bandwidth); 667047Snate@binkert.org m_sID = 0; 678319Ssteve.reinhardt@amd.com} 688319Ssteve.reinhardt@amd.com 697047Snate@binkert.orgvoid 707047Snate@binkert.orgThrottle::init(NodeID node, Cycles link_latency, 718319Ssteve.reinhardt@amd.com int link_bandwidth_multiplier, int endpoint_bandwidth) 728319Ssteve.reinhardt@amd.com{ 738319Ssteve.reinhardt@amd.com m_node = node; 747047Snate@binkert.org m_vnets = 0; 757047Snate@binkert.org 767047Snate@binkert.org assert(link_bandwidth_multiplier > 0); 771897Sstever@eecs.umich.edu m_link_bandwidth_multiplier = link_bandwidth_multiplier; 781897Sstever@eecs.umich.edu m_link_latency = link_latency; 791897Sstever@eecs.umich.edu m_endpoint_bandwidth = endpoint_bandwidth; 801897Sstever@eecs.umich.edu 818319Ssteve.reinhardt@amd.com m_wakeups_wo_switch = 0; 828319Ssteve.reinhardt@amd.com 838319Ssteve.reinhardt@amd.com m_msg_counts.resize(MessageSizeType_NUM); 848319Ssteve.reinhardt@amd.com m_msg_bytes.resize(MessageSizeType_NUM); 858319Ssteve.reinhardt@amd.com 868319Ssteve.reinhardt@amd.com m_link_utilization_proxy = 0; 878319Ssteve.reinhardt@amd.com} 881897Sstever@eecs.umich.edu 898319Ssteve.reinhardt@amd.comvoid 908811Sandreas.hansson@arm.comThrottle::addLinks(const std::vector<MessageBuffer*>& in_vec, 918319Ssteve.reinhardt@amd.com const std::vector<MessageBuffer*>& out_vec) 928319Ssteve.reinhardt@amd.com{ 931897Sstever@eecs.umich.edu assert(in_vec.size() == out_vec.size()); 947047Snate@binkert.org for (int i=0; i<in_vec.size(); i++) { 957047Snate@binkert.org addVirtualNetwork(in_vec[i], out_vec[i]); 961897Sstever@eecs.umich.edu } 971897Sstever@eecs.umich.edu} 984961Ssaidi@eecs.umich.edu 994961Ssaidi@eecs.umich.eduvoid 1004961Ssaidi@eecs.umich.eduThrottle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr) 1014961Ssaidi@eecs.umich.edu{ 1024961Ssaidi@eecs.umich.edu m_units_remaining.push_back(0); 1034961Ssaidi@eecs.umich.edu m_in.push_back(in_ptr); 1044961Ssaidi@eecs.umich.edu m_out.push_back(out_ptr); 1054961Ssaidi@eecs.umich.edu 1064961Ssaidi@eecs.umich.edu // Set consumer and description 1074961Ssaidi@eecs.umich.edu m_in[m_vnets]->setConsumer(this); 1084961Ssaidi@eecs.umich.edu 1094961Ssaidi@eecs.umich.edu string desc = "[Queue to Throttle " + to_string(m_sID) + " " + 1104961Ssaidi@eecs.umich.edu to_string(m_node) + "]"; 1114961Ssaidi@eecs.umich.edu m_in[m_vnets]->setDescription(desc); 1121897Sstever@eecs.umich.edu m_vnets++; 1138319Ssteve.reinhardt@amd.com} 1141897Sstever@eecs.umich.edu 1158319Ssteve.reinhardt@amd.comvoid 1168319Ssteve.reinhardt@amd.comThrottle::wakeup() 1178816Sgblack@eecs.umich.edu{ 1188319Ssteve.reinhardt@amd.com // Limits the number of message sent to a limited number of bytes/cycle. 1198319Ssteve.reinhardt@amd.com assert(getLinkBandwidth() > 0); 1208319Ssteve.reinhardt@amd.com int bw_remaining = getLinkBandwidth(); 1218811Sandreas.hansson@arm.com 1224961Ssaidi@eecs.umich.edu // Give the highest numbered link priority most of the time 1238319Ssteve.reinhardt@amd.com m_wakeups_wo_switch++; 1248811Sandreas.hansson@arm.com int highest_prio_vnet = m_vnets-1; 1258814Sgblack@eecs.umich.edu int lowest_prio_vnet = 0; 1268319Ssteve.reinhardt@amd.com int counter = 1; 1278811Sandreas.hansson@arm.com bool schedule_wakeup = false; 1288811Sandreas.hansson@arm.com 1298811Sandreas.hansson@arm.com // invert priorities to avoid starvation seen in the component network 1308811Sandreas.hansson@arm.com if (m_wakeups_wo_switch > PRIORITY_SWITCH_LIMIT) { 1318811Sandreas.hansson@arm.com m_wakeups_wo_switch = 0; 1328811Sandreas.hansson@arm.com highest_prio_vnet = 0; 1338811Sandreas.hansson@arm.com lowest_prio_vnet = m_vnets-1; 1348811Sandreas.hansson@arm.com counter = -1; 1358811Sandreas.hansson@arm.com } 1361897Sstever@eecs.umich.edu 1377047Snate@binkert.org for (int vnet = highest_prio_vnet; 1387047Snate@binkert.org (vnet * counter) >= (counter * lowest_prio_vnet); 1397047Snate@binkert.org vnet -= counter) { 1407047Snate@binkert.org 1417047Snate@binkert.org assert(m_out[vnet] != NULL); 1427047Snate@binkert.org assert(m_in[vnet] != NULL); 1437047Snate@binkert.org assert(m_units_remaining[vnet] >= 0); 1447047Snate@binkert.org 1457047Snate@binkert.org while (bw_remaining > 0 && 1467047Snate@binkert.org (m_in[vnet]->isReady() || m_units_remaining[vnet] > 0) && 1477047Snate@binkert.org m_out[vnet]->areNSlotsAvailable(1)) { 1487047Snate@binkert.org 1497047Snate@binkert.org // See if we are done transferring the previous message on 1507047Snate@binkert.org // this virtual network 1514961Ssaidi@eecs.umich.edu if (m_units_remaining[vnet] == 0 && m_in[vnet]->isReady()) { 1524961Ssaidi@eecs.umich.edu // Find the size of the message we are moving 1537047Snate@binkert.org MsgPtr msg_ptr = m_in[vnet]->peekMsgPtr(); 1547047Snate@binkert.org NetworkMessage* net_msg_ptr = 1554961Ssaidi@eecs.umich.edu safe_cast<NetworkMessage*>(msg_ptr.get()); 1565247Sstever@gmail.com m_units_remaining[vnet] += 1575247Sstever@gmail.com network_message_to_size(net_msg_ptr); 1588319Ssteve.reinhardt@amd.com 1598319Ssteve.reinhardt@amd.com DPRINTF(RubyNetwork, "throttle: %d my bw %d bw spent " 1603725Sstever@eecs.umich.edu "enqueueing net msg %d time: %lld.\n", 1619843Ssteve.reinhardt@amd.com m_node, getLinkBandwidth(), m_units_remaining[vnet], 1629843Ssteve.reinhardt@amd.com g_system_ptr->curCycle()); 1639843Ssteve.reinhardt@amd.com 1649843Ssteve.reinhardt@amd.com // Move the message 1659843Ssteve.reinhardt@amd.com m_out[vnet]->enqueue(m_in[vnet]->peekMsgPtr(), m_link_latency); 1669843Ssteve.reinhardt@amd.com m_in[vnet]->pop(); 1678120Sgblack@eecs.umich.edu 1687047Snate@binkert.org // Count the message 1697047Snate@binkert.org m_msg_counts[net_msg_ptr->getMessageSize()][vnet]++; 1707047Snate@binkert.org 1717047Snate@binkert.org DPRINTF(RubyNetwork, "%s\n", *m_out[vnet]); 1727047Snate@binkert.org } 173 174 // Calculate the amount of bandwidth we spent on this message 175 int diff = m_units_remaining[vnet] - bw_remaining; 176 m_units_remaining[vnet] = max(0, diff); 177 bw_remaining = max(0, -diff); 178 } 179 180 if (bw_remaining > 0 && 181 (m_in[vnet]->isReady() || m_units_remaining[vnet] > 0) && 182 !m_out[vnet]->areNSlotsAvailable(1)) { 183 DPRINTF(RubyNetwork, "vnet: %d", vnet); 184 // schedule me to wakeup again because I'm waiting for my 185 // output queue to become available 186 schedule_wakeup = true; 187 } 188 } 189 190 // We should only wake up when we use the bandwidth 191 // This is only mostly true 192 // assert(bw_remaining != getLinkBandwidth()); 193 194 // Record that we used some or all of the link bandwidth this cycle 195 double ratio = 1.0 - (double(bw_remaining) / double(getLinkBandwidth())); 196 197 // If ratio = 0, we used no bandwidth, if ratio = 1, we used all 198 m_link_utilization_proxy += ratio; 199 200 if (bw_remaining > 0 && !schedule_wakeup) { 201 // We have extra bandwidth and our output buffer was 202 // available, so we must not have anything else to do until 203 // another message arrives. 204 DPRINTF(RubyNetwork, "%s not scheduled again\n", *this); 205 } else { 206 DPRINTF(RubyNetwork, "%s scheduled again\n", *this); 207 208 // We are out of bandwidth for this cycle, so wakeup next 209 // cycle and continue 210 scheduleEvent(Cycles(1)); 211 } 212} 213 214void 215Throttle::regStats(string parent) 216{ 217 m_link_utilization 218 .name(parent + csprintf(".throttle%i", m_node) + ".link_utilization"); 219 220 for (MessageSizeType type = MessageSizeType_FIRST; 221 type < MessageSizeType_NUM; ++type) { 222 m_msg_counts[(unsigned int)type] 223 .init(m_vnets) 224 .name(parent + csprintf(".throttle%i", m_node) + ".msg_count." + 225 MessageSizeType_to_string(type)) 226 .flags(Stats::nozero) 227 ; 228 m_msg_bytes[(unsigned int) type] 229 .name(parent + csprintf(".throttle%i", m_node) + ".msg_bytes." + 230 MessageSizeType_to_string(type)) 231 .flags(Stats::nozero) 232 ; 233 234 m_msg_bytes[(unsigned int) type] = m_msg_counts[type] * Stats::constant( 235 Network::MessageSizeType_to_int(type)); 236 } 237} 238 239void 240Throttle::clearStats() 241{ 242 m_link_utilization_proxy = 0; 243} 244 245void 246Throttle::collateStats() 247{ 248 m_link_utilization = 100.0 * m_link_utilization_proxy 249 / (double(g_system_ptr->curCycle() - g_ruby_start)); 250} 251 252void 253Throttle::print(ostream& out) const 254{ 255 ccprintf(out, "[%i bw: %i]", m_node, getLinkBandwidth()); 256} 257 258int 259network_message_to_size(NetworkMessage* net_msg_ptr) 260{ 261 assert(net_msg_ptr != NULL); 262 263 int size = Network::MessageSizeType_to_int(net_msg_ptr->getMessageSize()); 264 size *= MESSAGE_SIZE_MULTIPLIER; 265 266 // Artificially increase the size of broadcast messages 267 if (BROADCAST_SCALING > 1 && net_msg_ptr->getDestination().isBroadcast()) 268 size *= BROADCAST_SCALING; 269 270 return size; 271} 272