Throttle.cc revision 10074
19243SN/A/* 211846Swendy.elsasser@arm.com * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 39243SN/A * All rights reserved. 49243SN/A * 59243SN/A * Redistribution and use in source and binary forms, with or without 69243SN/A * modification, are permitted provided that the following conditions are 79243SN/A * met: redistributions of source code must retain the above copyright 89243SN/A * notice, this list of conditions and the following disclaimer; 99243SN/A * redistributions in binary form must reproduce the above copyright 109243SN/A * notice, this list of conditions and the following disclaimer in the 119243SN/A * documentation and/or other materials provided with the distribution; 129243SN/A * neither the name of the copyright holders nor the names of its 139243SN/A * contributors may be used to endorse or promote products derived from 149831SN/A * this software without specific prior written permission. 159831SN/A * 169831SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 179243SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 189243SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 199243SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 209243SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 219243SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 229243SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239243SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249243SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259243SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 269243SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279243SN/A */ 289243SN/A 299243SN/A#include <cassert> 309243SN/A 319243SN/A#include "base/cast.hh" 329243SN/A#include "base/cprintf.hh" 339243SN/A#include "debug/RubyNetwork.hh" 349243SN/A#include "mem/ruby/buffers/MessageBuffer.hh" 359243SN/A#include "mem/ruby/network/simple/Throttle.hh" 369243SN/A#include "mem/ruby/network/Network.hh" 379243SN/A#include "mem/ruby/slicc_interface/NetworkMessage.hh" 389243SN/A#include "mem/ruby/system/System.hh" 399243SN/A 409243SN/Ausing namespace std; 419243SN/A 429967SN/Aconst int HIGH_RANGE = 256; 4310618SOmar.Naji@arm.comconst int ADJUST_INTERVAL = 50000; 4411678Swendy.elsasser@arm.comconst int MESSAGE_SIZE_MULTIPLIER = 1000; 459243SN/A//const int BROADCAST_SCALING = 4; // Have a 16p system act like a 64p systems 469243SN/Aconst int BROADCAST_SCALING = 1; 4711793Sbrandon.potter@amd.comconst int PRIORITY_SWITCH_LIMIT = 128; 4811793Sbrandon.potter@amd.com 4910146Sandreas.hansson@arm.comstatic int network_message_to_size(NetworkMessage* net_msg_ptr); 509356SN/A 5110146Sandreas.hansson@arm.comThrottle::Throttle(int sID, NodeID node, Cycles link_latency, 5210247Sandreas.hansson@arm.com int link_bandwidth_multiplier, int endpoint_bandwidth, 5310208Sandreas.hansson@arm.com ClockedObject *em) 549352SN/A : Consumer(em) 559814SN/A{ 569243SN/A init(node, link_latency, link_bandwidth_multiplier, endpoint_bandwidth); 579243SN/A m_sID = sID; 5810432SOmar.Naji@arm.com} 599243SN/A 6010146Sandreas.hansson@arm.comThrottle::Throttle(NodeID node, Cycles link_latency, 619243SN/A int link_bandwidth_multiplier, int endpoint_bandwidth, 6210619Sandreas.hansson@arm.com ClockedObject *em) 639243SN/A : Consumer(em) 6410211Sandreas.hansson@arm.com{ 6511678Swendy.elsasser@arm.com init(node, link_latency, link_bandwidth_multiplier, endpoint_bandwidth); 6610618SOmar.Naji@arm.com m_sID = 0; 6710489SOmar.Naji@arm.com} 689831SN/A 699831SN/Avoid 709831SN/AThrottle::init(NodeID node, Cycles link_latency, 719831SN/A int link_bandwidth_multiplier, int endpoint_bandwidth) 729831SN/A{ 7310140SN/A m_node = node; 7410646Sandreas.hansson@arm.com m_vnets = 0; 759243SN/A 7610394Swendy.elsasser@arm.com assert(link_bandwidth_multiplier > 0); 7710394Swendy.elsasser@arm.com m_link_bandwidth_multiplier = link_bandwidth_multiplier; 789566SN/A m_link_latency = link_latency; 799243SN/A m_endpoint_bandwidth = endpoint_bandwidth; 809243SN/A 8110140SN/A m_wakeups_wo_switch = 0; 8210140SN/A 8310147Sandreas.hansson@arm.com m_link_utilization_proxy = 0; 8410147Sandreas.hansson@arm.com} 8510393Swendy.elsasser@arm.com 8610394Swendy.elsasser@arm.comvoid 8710394Swendy.elsasser@arm.comThrottle::addLinks(const std::vector<MessageBuffer*>& in_vec, 8811673SOmar.Naji@arm.com const std::vector<MessageBuffer*>& out_vec) 8911673SOmar.Naji@arm.com{ 909243SN/A assert(in_vec.size() == out_vec.size()); 919243SN/A for (int i=0; i<in_vec.size(); i++) { 9210141SN/A addVirtualNetwork(in_vec[i], out_vec[i]); 939726SN/A } 949726SN/A} 9510618SOmar.Naji@arm.com 9610618SOmar.Naji@arm.comvoid 979243SN/AThrottle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr) 9810620Sandreas.hansson@arm.com{ 9910620Sandreas.hansson@arm.com m_units_remaining.push_back(0); 10010620Sandreas.hansson@arm.com m_in.push_back(in_ptr); 10110620Sandreas.hansson@arm.com m_out.push_back(out_ptr); 10210620Sandreas.hansson@arm.com 10310889Sandreas.hansson@arm.com // Set consumer and description 10410889Sandreas.hansson@arm.com m_in[m_vnets]->setConsumer(this); 10510889Sandreas.hansson@arm.com 10610618SOmar.Naji@arm.com string desc = "[Queue to Throttle " + to_string(m_sID) + " " + 10712081Sspwilson2@wisc.edu to_string(m_node) + "]"; 10810618SOmar.Naji@arm.com m_in[m_vnets]->setDescription(desc); 10910246Sandreas.hansson@arm.com m_vnets++; 11010246Sandreas.hansson@arm.com} 11110140SN/A 11210140SN/Avoid 11310140SN/AThrottle::wakeup() 11410140SN/A{ 11510140SN/A // Limits the number of message sent to a limited number of bytes/cycle. 1169243SN/A assert(getLinkBandwidth() > 0); 1179243SN/A int bw_remaining = getLinkBandwidth(); 1189567SN/A 1199243SN/A // Give the highest numbered link priority most of the time 12010489SOmar.Naji@arm.com m_wakeups_wo_switch++; 12110489SOmar.Naji@arm.com int highest_prio_vnet = m_vnets-1; 12210489SOmar.Naji@arm.com int lowest_prio_vnet = 0; 12310489SOmar.Naji@arm.com int counter = 1; 12410489SOmar.Naji@arm.com bool schedule_wakeup = false; 12510489SOmar.Naji@arm.com 12610489SOmar.Naji@arm.com // invert priorities to avoid starvation seen in the component network 12710489SOmar.Naji@arm.com if (m_wakeups_wo_switch > PRIORITY_SWITCH_LIMIT) { 12810489SOmar.Naji@arm.com m_wakeups_wo_switch = 0; 12910489SOmar.Naji@arm.com highest_prio_vnet = 0; 1309243SN/A lowest_prio_vnet = m_vnets-1; 1319243SN/A counter = -1; 1329831SN/A } 1339831SN/A 1349831SN/A for (int vnet = highest_prio_vnet; 1359831SN/A (vnet * counter) >= (counter * lowest_prio_vnet); 1369831SN/A vnet -= counter) { 1379243SN/A 13810207Sandreas.hansson@arm.com assert(m_out[vnet] != NULL); 13910207Sandreas.hansson@arm.com assert(m_in[vnet] != NULL); 14010207Sandreas.hansson@arm.com assert(m_units_remaining[vnet] >= 0); 14110207Sandreas.hansson@arm.com 14210207Sandreas.hansson@arm.com while (bw_remaining > 0 && 14310394Swendy.elsasser@arm.com (m_in[vnet]->isReady() || m_units_remaining[vnet] > 0) && 14410394Swendy.elsasser@arm.com m_out[vnet]->areNSlotsAvailable(1)) { 14510394Swendy.elsasser@arm.com 14610394Swendy.elsasser@arm.com // See if we are done transferring the previous message on 14710394Swendy.elsasser@arm.com // this virtual network 14810394Swendy.elsasser@arm.com if (m_units_remaining[vnet] == 0 && m_in[vnet]->isReady()) { 14910394Swendy.elsasser@arm.com // Find the size of the message we are moving 15010394Swendy.elsasser@arm.com MsgPtr msg_ptr = m_in[vnet]->peekMsgPtr(); 15110394Swendy.elsasser@arm.com NetworkMessage* net_msg_ptr = 15210394Swendy.elsasser@arm.com safe_cast<NetworkMessage*>(msg_ptr.get()); 15310394Swendy.elsasser@arm.com m_units_remaining[vnet] += 15410394Swendy.elsasser@arm.com network_message_to_size(net_msg_ptr); 15510394Swendy.elsasser@arm.com 15610394Swendy.elsasser@arm.com DPRINTF(RubyNetwork, "throttle: %d my bw %d bw spent " 15710394Swendy.elsasser@arm.com "enqueueing net msg %d time: %lld.\n", 15810394Swendy.elsasser@arm.com m_node, getLinkBandwidth(), m_units_remaining[vnet], 15910394Swendy.elsasser@arm.com g_system_ptr->curCycle()); 16010394Swendy.elsasser@arm.com 16110394Swendy.elsasser@arm.com // Move the message 16210394Swendy.elsasser@arm.com m_out[vnet]->enqueue(m_in[vnet]->peekMsgPtr(), m_link_latency); 16310394Swendy.elsasser@arm.com m_in[vnet]->dequeue(); 16410394Swendy.elsasser@arm.com 16510561SOmar.Naji@arm.com // Count the message 16610561SOmar.Naji@arm.com m_msg_counts[net_msg_ptr->getMessageSize()][vnet]++; 16710394Swendy.elsasser@arm.com 16810394Swendy.elsasser@arm.com DPRINTF(RubyNetwork, "%s\n", *m_out[vnet]); 16910394Swendy.elsasser@arm.com } 17010394Swendy.elsasser@arm.com 17110394Swendy.elsasser@arm.com // Calculate the amount of bandwidth we spent on this message 17210394Swendy.elsasser@arm.com int diff = m_units_remaining[vnet] - bw_remaining; 1739243SN/A m_units_remaining[vnet] = max(0, diff); 1749243SN/A bw_remaining = max(0, -diff); 1759243SN/A } 17610146Sandreas.hansson@arm.com 17710140SN/A if (bw_remaining > 0 && 17810466Sandreas.hansson@arm.com (m_in[vnet]->isReady() || m_units_remaining[vnet] > 0) && 17910466Sandreas.hansson@arm.com !m_out[vnet]->areNSlotsAvailable(1)) { 18010466Sandreas.hansson@arm.com DPRINTF(RubyNetwork, "vnet: %d", vnet); 18110146Sandreas.hansson@arm.com // schedule me to wakeup again because I'm waiting for my 18210140SN/A // output queue to become available 18310140SN/A schedule_wakeup = true; 18410140SN/A } 18510646Sandreas.hansson@arm.com } 18610646Sandreas.hansson@arm.com 18710646Sandreas.hansson@arm.com // We should only wake up when we use the bandwidth 18810646Sandreas.hansson@arm.com // This is only mostly true 18910646Sandreas.hansson@arm.com // assert(bw_remaining != getLinkBandwidth()); 19010646Sandreas.hansson@arm.com 19110646Sandreas.hansson@arm.com // Record that we used some or all of the link bandwidth this cycle 19210646Sandreas.hansson@arm.com double ratio = 1.0 - (double(bw_remaining) / double(getLinkBandwidth())); 19310646Sandreas.hansson@arm.com 19410646Sandreas.hansson@arm.com // If ratio = 0, we used no bandwidth, if ratio = 1, we used all 19510646Sandreas.hansson@arm.com m_link_utilization_proxy += ratio; 19610646Sandreas.hansson@arm.com 19710646Sandreas.hansson@arm.com if (bw_remaining > 0 && !schedule_wakeup) { 19810646Sandreas.hansson@arm.com // We have extra bandwidth and our output buffer was 19910646Sandreas.hansson@arm.com // available, so we must not have anything else to do until 20010646Sandreas.hansson@arm.com // another message arrives. 20110646Sandreas.hansson@arm.com DPRINTF(RubyNetwork, "%s not scheduled again\n", *this); 20210646Sandreas.hansson@arm.com } else { 20310646Sandreas.hansson@arm.com DPRINTF(RubyNetwork, "%s scheduled again\n", *this); 20410646Sandreas.hansson@arm.com 20510646Sandreas.hansson@arm.com // We are out of bandwidth for this cycle, so wakeup next 20610646Sandreas.hansson@arm.com // cycle and continue 20710646Sandreas.hansson@arm.com scheduleEvent(Cycles(1)); 20810646Sandreas.hansson@arm.com } 20910646Sandreas.hansson@arm.com} 21010646Sandreas.hansson@arm.com 21110646Sandreas.hansson@arm.comvoid 21210646Sandreas.hansson@arm.comThrottle::regStats(string parent) 21310646Sandreas.hansson@arm.com{ 21410646Sandreas.hansson@arm.com m_link_utilization 21510646Sandreas.hansson@arm.com .name(parent + csprintf(".throttle%i", m_node) + ".link_utilization"); 21610646Sandreas.hansson@arm.com 21710646Sandreas.hansson@arm.com for (MessageSizeType type = MessageSizeType_FIRST; 21810646Sandreas.hansson@arm.com type < MessageSizeType_NUM; ++type) { 21910646Sandreas.hansson@arm.com m_msg_counts[(unsigned int)type] 22010646Sandreas.hansson@arm.com .init(m_vnets) 22110646Sandreas.hansson@arm.com .name(parent + csprintf(".throttle%i", m_node) + ".msg_count." + 22210646Sandreas.hansson@arm.com MessageSizeType_to_string(type)) 22310646Sandreas.hansson@arm.com .flags(Stats::nozero) 22410646Sandreas.hansson@arm.com ; 22510140SN/A m_msg_bytes[(unsigned int) type] 22610140SN/A .name(parent + csprintf(".throttle%i", m_node) + ".msg_bytes." + 22710140SN/A MessageSizeType_to_string(type)) 22810146Sandreas.hansson@arm.com .flags(Stats::nozero) 2299243SN/A ; 23010619Sandreas.hansson@arm.com 23110619Sandreas.hansson@arm.com m_msg_bytes[(unsigned int) type] = m_msg_counts[type] * Stats::constant( 23210618SOmar.Naji@arm.com Network::MessageSizeType_to_int(type)); 23310619Sandreas.hansson@arm.com } 23410619Sandreas.hansson@arm.com} 23510619Sandreas.hansson@arm.com 23610619Sandreas.hansson@arm.comvoid 23710619Sandreas.hansson@arm.comThrottle::clearStats() 23810619Sandreas.hansson@arm.com{ 23910619Sandreas.hansson@arm.com m_link_utilization_proxy = 0; 24010619Sandreas.hansson@arm.com} 24110619Sandreas.hansson@arm.com 24210619Sandreas.hansson@arm.comvoid 24310619Sandreas.hansson@arm.comThrottle::collateStats() 24410619Sandreas.hansson@arm.com{ 24510619Sandreas.hansson@arm.com m_link_utilization = 100.0 * m_link_utilization_proxy 24610619Sandreas.hansson@arm.com / (double(g_system_ptr->curCycle() - g_ruby_start)); 24710619Sandreas.hansson@arm.com} 24810618SOmar.Naji@arm.com 2499243SN/Avoid 2509243SN/AThrottle::print(ostream& out) const 2519243SN/A{ 25210146Sandreas.hansson@arm.com ccprintf(out, "[%i bw: %i]", m_node, getLinkBandwidth()); 2539243SN/A} 2549243SN/A 2559243SN/Aint 25611334Sandreas.hansson@arm.comnetwork_message_to_size(NetworkMessage* net_msg_ptr) 25711334Sandreas.hansson@arm.com{ 25811334Sandreas.hansson@arm.com assert(net_msg_ptr != NULL); 2599243SN/A 2609243SN/A int size = Network::MessageSizeType_to_int(net_msg_ptr->getMessageSize()); 2619243SN/A size *= MESSAGE_SIZE_MULTIPLIER; 2629243SN/A 26311334Sandreas.hansson@arm.com // Artificially increase the size of broadcast messages 2649243SN/A if (BROADCAST_SCALING > 1 && net_msg_ptr->getDestination().isBroadcast()) 2659243SN/A size *= BROADCAST_SCALING; 2669243SN/A 2679243SN/A return size; 2689243SN/A} 2699243SN/A