Throttle.cc revision 6154
1955SN/A
2955SN/A/*
311408Sandreas.sandberg@arm.com * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
49812Sandreas.hansson@arm.com * All rights reserved.
59812Sandreas.hansson@arm.com *
69812Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
79812Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
89812Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
99812Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
109812Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
119812Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
129812Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
139812Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
149812Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
157816Ssteve.reinhardt@amd.com * this software without specific prior written permission.
165871Snate@binkert.org *
171762SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28955SN/A */
29955SN/A
30955SN/A/*
31955SN/A * $Id$
32955SN/A *
33955SN/A * Description: see Throttle.h
34955SN/A *
35955SN/A */
36955SN/A
37955SN/A#include "mem/ruby/network/simple/Throttle.hh"
38955SN/A#include "mem/ruby/buffers/MessageBuffer.hh"
39955SN/A#include "mem/ruby/network/Network.hh"
40955SN/A#include "mem/ruby/system/System.hh"
41955SN/A#include "mem/ruby/slicc_interface/NetworkMessage.hh"
422665Ssaidi@eecs.umich.edu#include "mem/protocol/Protocol.hh"
432665Ssaidi@eecs.umich.edu
445863Snate@binkert.orgconst int HIGH_RANGE = 256;
45955SN/Aconst int ADJUST_INTERVAL = 50000;
46955SN/Aconst int MESSAGE_SIZE_MULTIPLIER = 1000;
47955SN/A//const int BROADCAST_SCALING = 4; // Have a 16p system act like a 64p systems
48955SN/Aconst int BROADCAST_SCALING = 1;
49955SN/Aconst int PRIORITY_SWITCH_LIMIT = 128;
508878Ssteve.reinhardt@amd.com
512632Sstever@eecs.umich.edustatic int network_message_to_size(NetworkMessage* net_msg_ptr);
528878Ssteve.reinhardt@amd.com
532632Sstever@eecs.umich.eduextern std::ostream * debug_cout_ptr;
54955SN/A
558878Ssteve.reinhardt@amd.comThrottle::Throttle(int sID, NodeID node, int link_latency, int link_bandwidth_multiplier)
562632Sstever@eecs.umich.edu{
572761Sstever@eecs.umich.edu  init(node, link_latency, link_bandwidth_multiplier);
582632Sstever@eecs.umich.edu  m_sID = sID;
592632Sstever@eecs.umich.edu}
602632Sstever@eecs.umich.edu
612761Sstever@eecs.umich.eduThrottle::Throttle(NodeID node, int link_latency, int link_bandwidth_multiplier)
622761Sstever@eecs.umich.edu{
632761Sstever@eecs.umich.edu  init(node, link_latency, link_bandwidth_multiplier);
648878Ssteve.reinhardt@amd.com  m_sID = 0;
658878Ssteve.reinhardt@amd.com}
662761Sstever@eecs.umich.edu
672761Sstever@eecs.umich.eduvoid Throttle::init(NodeID node, int link_latency, int link_bandwidth_multiplier)
682761Sstever@eecs.umich.edu{
692761Sstever@eecs.umich.edu  m_node = node;
702761Sstever@eecs.umich.edu  m_vnets = 0;
718878Ssteve.reinhardt@amd.com
728878Ssteve.reinhardt@amd.com  ASSERT(link_bandwidth_multiplier > 0);
732632Sstever@eecs.umich.edu  m_link_bandwidth_multiplier = link_bandwidth_multiplier;
742632Sstever@eecs.umich.edu  m_link_latency = link_latency;
758878Ssteve.reinhardt@amd.com
768878Ssteve.reinhardt@amd.com  m_bash_counter = HIGH_RANGE;
772632Sstever@eecs.umich.edu  m_bandwidth_since_sample = 0;
78955SN/A  m_last_bandwidth_sample = 0;
79955SN/A  m_wakeups_wo_switch = 0;
80955SN/A  clearStats();
815863Snate@binkert.org}
825863Snate@binkert.org
835863Snate@binkert.orgvoid Throttle::clear()
845863Snate@binkert.org{
855863Snate@binkert.org  for (int counter = 0; counter < m_vnets; counter++) {
865863Snate@binkert.org    m_in[counter]->clear();
875863Snate@binkert.org    m_out[counter]->clear();
885863Snate@binkert.org  }
895863Snate@binkert.org}
905863Snate@binkert.org
915863Snate@binkert.orgvoid Throttle::addLinks(const Vector<MessageBuffer*>& in_vec, const Vector<MessageBuffer*>& out_vec)
928878Ssteve.reinhardt@amd.com{
935863Snate@binkert.org  assert(in_vec.size() == out_vec.size());
945863Snate@binkert.org  for (int i=0; i<in_vec.size(); i++) {
955863Snate@binkert.org    addVirtualNetwork(in_vec[i], out_vec[i]);
969812Sandreas.hansson@arm.com  }
979812Sandreas.hansson@arm.com
985863Snate@binkert.org  m_message_counters.setSize(MessageSizeType_NUM);
999812Sandreas.hansson@arm.com  for (int i=0; i<MessageSizeType_NUM; i++) {
1005863Snate@binkert.org    m_message_counters[i].setSize(in_vec.size());
1015863Snate@binkert.org    for (int j=0; j<m_message_counters[i].size(); j++) {
1025863Snate@binkert.org      m_message_counters[i][j] = 0;
1039812Sandreas.hansson@arm.com    }
1049812Sandreas.hansson@arm.com  }
1055863Snate@binkert.org
1065863Snate@binkert.org  if (g_PRINT_TOPOLOGY) {
1078878Ssteve.reinhardt@amd.com    m_out_link_vec.insertAtBottom(out_vec);
1085863Snate@binkert.org  }
1095863Snate@binkert.org}
1105863Snate@binkert.org
1116654Snate@binkert.orgvoid Throttle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr)
11210196SCurtis.Dunham@arm.com{
113955SN/A  m_units_remaining.insertAtBottom(0);
1145396Ssaidi@eecs.umich.edu  m_in.insertAtBottom(in_ptr);
11511401Sandreas.sandberg@arm.com  m_out.insertAtBottom(out_ptr);
1165863Snate@binkert.org
1175863Snate@binkert.org  // Set consumer and description
1184202Sbinkertn@umich.edu  m_in[m_vnets]->setConsumer(this);
1195863Snate@binkert.org  string desc = "[Queue to Throttle " + NodeIDToString(m_sID) + " " + NodeIDToString(m_node) + "]";
1205863Snate@binkert.org  m_in[m_vnets]->setDescription(desc);
1215863Snate@binkert.org  m_vnets++;
1225863Snate@binkert.org}
123955SN/A
1246654Snate@binkert.orgvoid Throttle::wakeup()
1255273Sstever@gmail.com{
1265871Snate@binkert.org  // Limits the number of message sent to a limited number of bytes/cycle.
1275273Sstever@gmail.com  assert(getLinkBandwidth() > 0);
1286655Snate@binkert.org  int bw_remaining = getLinkBandwidth();
1298878Ssteve.reinhardt@amd.com
1306655Snate@binkert.org  // Give the highest numbered link priority most of the time
1316655Snate@binkert.org  m_wakeups_wo_switch++;
1329219Spower.jg@gmail.com  int highest_prio_vnet = m_vnets-1;
1336655Snate@binkert.org  int lowest_prio_vnet = 0;
1345871Snate@binkert.org  int counter = 1;
1356654Snate@binkert.org  bool schedule_wakeup = false;
1368947Sandreas.hansson@arm.com
1375396Ssaidi@eecs.umich.edu  // invert priorities to avoid starvation seen in the component network
1388120Sgblack@eecs.umich.edu  if (m_wakeups_wo_switch > PRIORITY_SWITCH_LIMIT) {
1398120Sgblack@eecs.umich.edu    m_wakeups_wo_switch = 0;
1408120Sgblack@eecs.umich.edu    highest_prio_vnet = 0;
1418120Sgblack@eecs.umich.edu    lowest_prio_vnet = m_vnets-1;
1428120Sgblack@eecs.umich.edu    counter = -1;
1438120Sgblack@eecs.umich.edu  }
1448120Sgblack@eecs.umich.edu
1458120Sgblack@eecs.umich.edu  for (int vnet = highest_prio_vnet; (vnet*counter) >= (counter*lowest_prio_vnet); vnet -= counter) {
1468879Ssteve.reinhardt@amd.com
1478879Ssteve.reinhardt@amd.com    assert(m_out[vnet] != NULL);
1488879Ssteve.reinhardt@amd.com    assert(m_in[vnet] != NULL);
1498879Ssteve.reinhardt@amd.com    assert(m_units_remaining[vnet] >= 0);
1508879Ssteve.reinhardt@amd.com
1518879Ssteve.reinhardt@amd.com    while ((bw_remaining > 0) && ((m_in[vnet]->isReady()) || (m_units_remaining[vnet] > 0)) && m_out[vnet]->areNSlotsAvailable(1)) {
1528879Ssteve.reinhardt@amd.com
1538879Ssteve.reinhardt@amd.com      // See if we are done transferring the previous message on this virtual network
1548879Ssteve.reinhardt@amd.com      if (m_units_remaining[vnet] == 0 && m_in[vnet]->isReady()) {
1558879Ssteve.reinhardt@amd.com
1568879Ssteve.reinhardt@amd.com        // Find the size of the message we are moving
1578879Ssteve.reinhardt@amd.com        MsgPtr msg_ptr = m_in[vnet]->peekMsgPtr();
1588879Ssteve.reinhardt@amd.com        NetworkMessage* net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref());
1598120Sgblack@eecs.umich.edu        m_units_remaining[vnet] += network_message_to_size(net_msg_ptr);
1608120Sgblack@eecs.umich.edu
1618120Sgblack@eecs.umich.edu        DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
1628120Sgblack@eecs.umich.edu        DEBUG_MSG(NETWORK_COMP,HighPrio,"throttle: " + int_to_string(m_node)
1638120Sgblack@eecs.umich.edu                  + " my bw " + int_to_string(getLinkBandwidth())
1648120Sgblack@eecs.umich.edu                  + " bw spent enqueueing net msg " + int_to_string(m_units_remaining[vnet])
1658120Sgblack@eecs.umich.edu                  + " time: " + int_to_string(g_eventQueue_ptr->getTime()) + ".");
1668120Sgblack@eecs.umich.edu
1678120Sgblack@eecs.umich.edu        // Move the message
1688120Sgblack@eecs.umich.edu        m_out[vnet]->enqueue(m_in[vnet]->peekMsgPtr(), m_link_latency);
1698120Sgblack@eecs.umich.edu        m_in[vnet]->pop();
1708120Sgblack@eecs.umich.edu
1718120Sgblack@eecs.umich.edu        // Count the message
1728120Sgblack@eecs.umich.edu        m_message_counters[net_msg_ptr->getMessageSize()][vnet]++;
1738879Ssteve.reinhardt@amd.com
1748879Ssteve.reinhardt@amd.com        DEBUG_MSG(NETWORK_COMP,LowPrio,*m_out[vnet]);
1758879Ssteve.reinhardt@amd.com        DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
1768879Ssteve.reinhardt@amd.com      }
17710458Sandreas.hansson@arm.com
17810458Sandreas.hansson@arm.com      // Calculate the amount of bandwidth we spent on this message
17910458Sandreas.hansson@arm.com      int diff = m_units_remaining[vnet] - bw_remaining;
1808879Ssteve.reinhardt@amd.com      m_units_remaining[vnet] = max(0, diff);
1818879Ssteve.reinhardt@amd.com      bw_remaining = max(0, -diff);
1828879Ssteve.reinhardt@amd.com    }
1838879Ssteve.reinhardt@amd.com
1849227Sandreas.hansson@arm.com    if ((bw_remaining > 0) && ((m_in[vnet]->isReady()) || (m_units_remaining[vnet] > 0)) && !m_out[vnet]->areNSlotsAvailable(1)) {
1859227Sandreas.hansson@arm.com      DEBUG_MSG(NETWORK_COMP,LowPrio,vnet);
1868879Ssteve.reinhardt@amd.com      schedule_wakeup = true; // schedule me to wakeup again because I'm waiting for my output queue to become available
1878879Ssteve.reinhardt@amd.com    }
1888879Ssteve.reinhardt@amd.com  }
1898879Ssteve.reinhardt@amd.com
19010453SAndrew.Bardsley@arm.com  // We should only wake up when we use the bandwidth
19110453SAndrew.Bardsley@arm.com  //  assert(bw_remaining != getLinkBandwidth());  // This is only mostly true
19210453SAndrew.Bardsley@arm.com
19310456SCurtis.Dunham@arm.com  // Record that we used some or all of the link bandwidth this cycle
19410456SCurtis.Dunham@arm.com  double ratio = 1.0-(double(bw_remaining)/double(getLinkBandwidth()));
19510456SCurtis.Dunham@arm.com  // If ratio = 0, we used no bandwidth, if ratio = 1, we used all
19610457Sandreas.hansson@arm.com  linkUtilized(ratio);
19710457Sandreas.hansson@arm.com
19811342Sandreas.hansson@arm.com  // Sample the link bandwidth utilization over a number of cycles
19911342Sandreas.hansson@arm.com  int bw_used = getLinkBandwidth()-bw_remaining;
2008120Sgblack@eecs.umich.edu  m_bandwidth_since_sample += bw_used;
2018947Sandreas.hansson@arm.com
2027816Ssteve.reinhardt@amd.com  // FIXME - comment out the bash specific code for faster performance
2035871Snate@binkert.org  // Start Bash code
2045871Snate@binkert.org  // Update the predictor
2056121Snate@binkert.org  Time current_time = g_eventQueue_ptr->getTime();
2065871Snate@binkert.org  while ((current_time - m_last_bandwidth_sample) > ADJUST_INTERVAL) {
2075871Snate@binkert.org    double utilization = m_bandwidth_since_sample/double(ADJUST_INTERVAL * getLinkBandwidth());
2089926Sstan.czerniawski@arm.com
2099926Sstan.czerniawski@arm.com    if (utilization > g_bash_bandwidth_adaptive_threshold) {
2109119Sandreas.hansson@arm.com      // Used more bandwidth
21110068Sandreas.hansson@arm.com      m_bash_counter++;
21210068Sandreas.hansson@arm.com    } else {
213955SN/A      // Used less bandwidth
2149416SAndreas.Sandberg@ARM.com      m_bash_counter--;
21511342Sandreas.hansson@arm.com    }
21611212Sjoseph.gross@amd.com
21711212Sjoseph.gross@amd.com    // Make sure we don't overflow
21811212Sjoseph.gross@amd.com    m_bash_counter = min(HIGH_RANGE, m_bash_counter);
21911212Sjoseph.gross@amd.com    m_bash_counter = max(0, m_bash_counter);
22011212Sjoseph.gross@amd.com
2219416SAndreas.Sandberg@ARM.com    // Reset samples
2229416SAndreas.Sandberg@ARM.com    m_last_bandwidth_sample += ADJUST_INTERVAL;
2235871Snate@binkert.org    m_bandwidth_since_sample = 0;
22410584Sandreas.hansson@arm.com  }
2259416SAndreas.Sandberg@ARM.com  // End Bash code
2269416SAndreas.Sandberg@ARM.com
2275871Snate@binkert.org  if ((bw_remaining > 0) && !schedule_wakeup) {
228955SN/A    // We have extra bandwidth and our output buffer was available, so we must not have anything else to do until another message arrives.
22910671Sandreas.hansson@arm.com    DEBUG_MSG(NETWORK_COMP,LowPrio,*this);
23010671Sandreas.hansson@arm.com    DEBUG_MSG(NETWORK_COMP,LowPrio,"not scheduled again");
23110671Sandreas.hansson@arm.com  } else {
23210671Sandreas.hansson@arm.com    DEBUG_MSG(NETWORK_COMP,LowPrio,*this);
2338881Smarc.orr@gmail.com    DEBUG_MSG(NETWORK_COMP,LowPrio,"scheduled again");
2346121Snate@binkert.org    // We are out of bandwidth for this cycle, so wakeup next cycle and continue
2356121Snate@binkert.org    g_eventQueue_ptr->scheduleEvent(this, 1);
2361533SN/A  }
2379239Sandreas.hansson@arm.com}
2389239Sandreas.hansson@arm.com
2399239Sandreas.hansson@arm.combool Throttle::broadcastBandwidthAvailable(int rand) const
2409239Sandreas.hansson@arm.com{
2419239Sandreas.hansson@arm.com  bool result =  !(m_bash_counter > ((HIGH_RANGE/4) + (rand % (HIGH_RANGE/2))));
2429239Sandreas.hansson@arm.com  return result;
2439239Sandreas.hansson@arm.com}
2449239Sandreas.hansson@arm.com
2459239Sandreas.hansson@arm.comvoid Throttle::printStats(ostream& out) const
2469239Sandreas.hansson@arm.com{
2479239Sandreas.hansson@arm.com  out << "utilized_percent: " << getUtilization() << endl;
2489239Sandreas.hansson@arm.com}
2496655Snate@binkert.org
2506655Snate@binkert.orgvoid Throttle::clearStats()
2516655Snate@binkert.org{
2526655Snate@binkert.org  m_ruby_start = g_eventQueue_ptr->getTime();
2535871Snate@binkert.org  m_links_utilized = 0.0;
2545871Snate@binkert.org
2555863Snate@binkert.org  for (int i=0; i<m_message_counters.size(); i++) {
2565871Snate@binkert.org    for (int j=0; j<m_message_counters[i].size(); j++) {
2578878Ssteve.reinhardt@amd.com      m_message_counters[i][j] = 0;
2585871Snate@binkert.org    }
2595871Snate@binkert.org  }
2605871Snate@binkert.org}
2615863Snate@binkert.org
2626121Snate@binkert.orgvoid Throttle::printConfig(ostream& out) const
2635863Snate@binkert.org{
26411408Sandreas.sandberg@arm.com
26511408Sandreas.sandberg@arm.com}
2668336Ssteve.reinhardt@amd.com
26711469SCurtis.Dunham@arm.comdouble Throttle::getUtilization() const
26811469SCurtis.Dunham@arm.com{
2698336Ssteve.reinhardt@amd.com  return (100.0 * double(m_links_utilized)) / (double(g_eventQueue_ptr->getTime()-m_ruby_start));
2704678Snate@binkert.org}
27111887Sandreas.sandberg@arm.com
27211887Sandreas.sandberg@arm.comvoid Throttle::print(ostream& out) const
27311887Sandreas.sandberg@arm.com{
27411887Sandreas.sandberg@arm.com  out << "[Throttle: " << m_sID << " " << m_node << " bw: " << getLinkBandwidth() << "]";
27511887Sandreas.sandberg@arm.com}
27611887Sandreas.sandberg@arm.com
27711887Sandreas.sandberg@arm.com// Helper function
27811887Sandreas.sandberg@arm.com
27911887Sandreas.sandberg@arm.comstatic
28011887Sandreas.sandberg@arm.comint network_message_to_size(NetworkMessage* net_msg_ptr)
28111887Sandreas.sandberg@arm.com{
28211408Sandreas.sandberg@arm.com  assert(net_msg_ptr != NULL);
28311401Sandreas.sandberg@arm.com
28411401Sandreas.sandberg@arm.com  // Artificially increase the size of broadcast messages
28511401Sandreas.sandberg@arm.com  if (BROADCAST_SCALING > 1) {
28611401Sandreas.sandberg@arm.com    if (net_msg_ptr->getDestination().isBroadcast()) {
28711401Sandreas.sandberg@arm.com      return (MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER * BROADCAST_SCALING);
28811401Sandreas.sandberg@arm.com    }
2898336Ssteve.reinhardt@amd.com  }
2908336Ssteve.reinhardt@amd.com  return (MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER);
2918336Ssteve.reinhardt@amd.com}
2924678Snate@binkert.org