style: another ruby style pass

This commit is contained in:
Nathan Binkert 2010-03-31 16:56:45 -07:00
parent 60ae1d2b10
commit be10204729
46 changed files with 2244 additions and 3007 deletions

View file

@ -37,9 +37,7 @@ sticky_vars.AddVariables(
BoolVariable('NO_VECTOR_BOUNDS_CHECKS', "Don't do bounds checks", True), BoolVariable('NO_VECTOR_BOUNDS_CHECKS', "Don't do bounds checks", True),
BoolVariable('RUBY_DEBUG', "Add debugging stuff to Ruby", False), BoolVariable('RUBY_DEBUG', "Add debugging stuff to Ruby", False),
('GEMS_ROOT', "Add debugging stuff to Ruby", Dir('..').srcnode().abspath), ('GEMS_ROOT', "Add debugging stuff to Ruby", Dir('..').srcnode().abspath),
BoolVariable('RUBY_TSO_CHECKER', "Use the Ruby TSO Checker", False)
) )
export_vars += [ 'NO_VECTOR_BOUNDS_CHECKS', 'RUBY_DEBUG', 'GEMS_ROOT', export_vars += [ 'NO_VECTOR_BOUNDS_CHECKS', 'RUBY_DEBUG', 'GEMS_ROOT' ]
'RUBY_TSO_CHECKER' ]

View file

@ -41,55 +41,57 @@ Network::Network(const Params *p)
m_link_latency = p->link_latency; m_link_latency = p->link_latency;
m_control_msg_size = p->control_msg_size; m_control_msg_size = p->control_msg_size;
//
// Total nodes/controllers in network // Total nodes/controllers in network
// Must make sure this is called after the State Machine constructors // Must make sure this is called after the State Machine constructors
//
m_nodes = MachineType_base_number(MachineType_NUM); m_nodes = MachineType_base_number(MachineType_NUM);
assert(m_nodes != 0); assert(m_nodes != 0);
assert(m_virtual_networks != 0); assert(m_virtual_networks != 0);
assert(m_topology_ptr != NULL); assert(m_topology_ptr != NULL);
//
// Initialize the controller's network pointers // Initialize the controller's network pointers
//
m_topology_ptr->initNetworkPtr(this); m_topology_ptr->initNetworkPtr(this);
} }
void Network::init() void
Network::init()
{ {
m_data_msg_size = RubySystem::getBlockSizeBytes() + m_control_msg_size; m_data_msg_size = RubySystem::getBlockSizeBytes() + m_control_msg_size;
} }
int Network::MessageSizeType_to_int(MessageSizeType size_type) int
Network::MessageSizeType_to_int(MessageSizeType size_type)
{ {
switch(size_type) { switch(size_type) {
case MessageSizeType_Undefined: case MessageSizeType_Undefined:
ERROR_MSG("Can't convert Undefined MessageSizeType to integer"); ERROR_MSG("Can't convert Undefined MessageSizeType to integer");
break; break;
case MessageSizeType_Control: case MessageSizeType_Control:
case MessageSizeType_Request_Control: case MessageSizeType_Request_Control:
case MessageSizeType_Reissue_Control: case MessageSizeType_Reissue_Control:
case MessageSizeType_Response_Control: case MessageSizeType_Response_Control:
case MessageSizeType_Writeback_Control: case MessageSizeType_Writeback_Control:
case MessageSizeType_Forwarded_Control: case MessageSizeType_Forwarded_Control:
case MessageSizeType_Invalidate_Control: case MessageSizeType_Invalidate_Control:
case MessageSizeType_Unblock_Control: case MessageSizeType_Unblock_Control:
case MessageSizeType_Persistent_Control: case MessageSizeType_Persistent_Control:
case MessageSizeType_Completion_Control: case MessageSizeType_Completion_Control:
return m_control_msg_size; return m_control_msg_size;
break; case MessageSizeType_Data:
case MessageSizeType_Data: case MessageSizeType_Response_Data:
case MessageSizeType_Response_Data: case MessageSizeType_ResponseLocal_Data:
case MessageSizeType_ResponseLocal_Data: case MessageSizeType_ResponseL2hit_Data:
case MessageSizeType_ResponseL2hit_Data: case MessageSizeType_Writeback_Data:
case MessageSizeType_Writeback_Data: return m_data_msg_size;
return m_data_msg_size; default:
break; ERROR_MSG("Invalid range for type MessageSizeType");
default: break;
ERROR_MSG("Invalid range for type MessageSizeType"); }
break; return 0;
} }
return 0;
const Vector<Throttle*>*
Network::getThrottles(NodeID id) const
{
return NULL;
} }

View file

@ -27,106 +27,96 @@
*/ */
/* /*
* Network.hh * The Network class is the base class for classes that implement the
* * interconnection network between components (processor/cache
* Description: The Network class is the base class for classes that * components and memory/directory components). The interconnection
* implement the interconnection network between components * network as described here is not a physical network, but a
* (processor/cache components and memory/directory components). The * programming concept used to implement all communication between
* interconnection network as described here is not a physical * components. Thus parts of this 'network' will model the on-chip
* network, but a programming concept used to implement all * connections between cache controllers and directory controllers as
* communication between components. Thus parts of this 'network' * well as the links between chip and network switches.
* will model the on-chip connections between cache controllers and */
* directory controllers as well as the links between chip and network
* switches.
*
* $Id$
* */
#ifndef NETWORK_H #ifndef __MEM_RUBY_NETWORK_NETWORK_HH__
#define NETWORK_H #define __MEM_RUBY_NETWORK_NETWORK_HH__
#include "mem/protocol/MessageSizeType.hh"
#include "mem/ruby/common/Global.hh" #include "mem/ruby/common/Global.hh"
#include "mem/ruby/system/NodeID.hh" #include "mem/ruby/system/NodeID.hh"
#include "mem/protocol/MessageSizeType.hh"
#include "mem/ruby/system/System.hh" #include "mem/ruby/system/System.hh"
#include "sim/sim_object.hh"
#include "params/RubyNetwork.hh" #include "params/RubyNetwork.hh"
#include "sim/sim_object.hh"
class NetDest; class NetDest;
class MessageBuffer; class MessageBuffer;
class Throttle; class Throttle;
class Topology; class Topology;
class Network : public SimObject { class Network : public SimObject
public: {
// Constructors public:
typedef RubyNetworkParams Params; typedef RubyNetworkParams Params;
Network(const Params *p); Network(const Params *p);
virtual void init(); virtual ~Network() {}
// Destructor virtual void init();
virtual ~Network() {}
// Public Methods int getBufferSize() { return m_buffer_size; }
int getBufferSize() { return m_buffer_size; } int getNumberOfVirtualNetworks() { return m_virtual_networks; }
int getNumberOfVirtualNetworks() { return m_virtual_networks; } int getEndpointBandwidth() { return m_endpoint_bandwidth; }
int getEndpointBandwidth() { return m_endpoint_bandwidth; } bool getAdaptiveRouting() {return m_adaptive_routing; }
bool getAdaptiveRouting() {return m_adaptive_routing; } int getLinkLatency() { return m_link_latency; }
int getLinkLatency() { return m_link_latency; } int MessageSizeType_to_int(MessageSizeType size_type);
int MessageSizeType_to_int(MessageSizeType size_type);
// returns the queue requested for the given component
virtual MessageBuffer* getToNetQueue(NodeID id, bool ordered,
int netNumber) = 0;
virtual MessageBuffer* getFromNetQueue(NodeID id, bool ordered,
int netNumber) = 0;
virtual const Vector<Throttle*>* getThrottles(NodeID id) const;
virtual int getNumNodes() {return 1;}
// returns the queue requested for the given component virtual void makeOutLink(SwitchID src, NodeID dest,
virtual MessageBuffer* getToNetQueue(NodeID id, bool ordered, int netNumber) = 0; const NetDest& routing_table_entry, int link_latency, int link_weight,
virtual MessageBuffer* getFromNetQueue(NodeID id, bool ordered, int netNumber) = 0; int bw_multiplier, bool isReconfiguration) = 0;
virtual const Vector<Throttle*>* getThrottles(NodeID id) const { return NULL; } virtual void makeInLink(SwitchID src, NodeID dest,
const NetDest& routing_table_entry, int link_latency,
int bw_multiplier, bool isReconfiguration) = 0;
virtual void makeInternalLink(SwitchID src, NodeID dest,
const NetDest& routing_table_entry, int link_latency, int link_weight,
int bw_multiplier, bool isReconfiguration) = 0;
virtual int getNumNodes() {return 1;} virtual void reset() = 0;
virtual void makeOutLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration) = 0; virtual void printStats(ostream& out) const = 0;
virtual void makeInLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int bw_multiplier, bool isReconfiguration) = 0; virtual void clearStats() = 0;
virtual void makeInternalLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration) = 0; virtual void printConfig(ostream& out) const = 0;
virtual void print(ostream& out) const = 0;
virtual void reset() = 0; protected:
// Private copy constructor and assignment operator
Network(const Network& obj);
Network& operator=(const Network& obj);
virtual void printStats(ostream& out) const = 0; protected:
virtual void clearStats() = 0; const string m_name;
virtual void printConfig(ostream& out) const = 0; int m_nodes;
virtual void print(ostream& out) const = 0; int m_virtual_networks;
int m_buffer_size;
protected: int m_endpoint_bandwidth;
Topology* m_topology_ptr;
// Private Methods bool m_adaptive_routing;
// Private copy constructor and assignment operator int m_link_latency;
Network(const Network& obj); int m_control_msg_size;
Network& operator=(const Network& obj); int m_data_msg_size;
// Data Members (m_ prefix)
protected:
const string m_name;
int m_nodes;
int m_virtual_networks;
int m_buffer_size;
int m_endpoint_bandwidth;
Topology* m_topology_ptr;
bool m_adaptive_routing;
int m_link_latency;
int m_control_msg_size;
int m_data_msg_size;
}; };
// Output operator declaration inline ostream&
ostream& operator<<(ostream& out, const Network& obj); operator<<(ostream& out, const Network& obj)
// ******************* Definitions *******************
// Output operator definition
extern inline
ostream& operator<<(ostream& out, const Network& obj)
{ {
obj.print(out); obj.print(out);
out << flush; out << flush;
return out; return out;
} }
#endif //NETWORK_H #endif // __MEM_RUBY_NETWORK_NETWORK_HH__

View file

@ -1,66 +0,0 @@
#include "mem/ruby/network/simple/HierarchicalSwitchTopology.hh"
// hierarchical switch topology
void Topology::construct(int fan_out_degree)
{
// Make a row of switches with only one input. This extra row makes
// sure the links out of the nodes have latency and limited
// bandwidth.
// number of inter-chip switches, i.e. the last row of switches
Vector<SwitchID> last_level;
for (int i=0; i<m_nodes; i++) {
SwitchID new_switch = newSwitchID(); // internal switch id #
addLink(i, new_switch, m_network_ptr->getLinkLatency());
last_level.insertAtBottom(new_switch);
}
// Create Hierarchical Switches
// start from the bottom level and work up to root
Vector<SwitchID> next_level;
while(last_level.size() > 1) {
for (int i=0; i<last_level.size(); i++) {
if ((i % fan_out_degree) == 0) {
next_level.insertAtBottom(newSwitchID());
}
// Add this link to the last switch we created
addLink(last_level[i], next_level[next_level.size()-1], m_network_ptr->getLinkLatency());
}
// Make the current level the last level to get ready for next
// iteration
last_level = next_level;
next_level.clear();
}
SwitchID root_switch = last_level[0];
Vector<SwitchID> out_level;
for (int i=0; i<m_nodes; i++) {
out_level.insertAtBottom(m_nodes+i);
}
// Build the down network from the endpoints to the root
while(out_level.size() != 1) {
// A level of switches
for (int i=0; i<out_level.size(); i++) {
if ((i % fan_out_degree) == 0) {
if (out_level.size() > fan_out_degree) {
next_level.insertAtBottom(newSwitchID());
} else {
next_level.insertAtBottom(root_switch);
}
}
// Add this link to the last switch we created
addLink(next_level[next_level.size()-1], out_level[i], m_network_ptr->getLinkLatency());
}
// Make the current level the last level to get ready for next
// iteration
out_level = next_level;
next_level.clear();
}
}

View file

@ -1,17 +0,0 @@
#ifndef HIERARCHICALSWITCHTOPOLOGY_H
#define HIERARCHICALSWITCHTOPOLOGY_H
#include "mem/ruby/network/simple/Topology.hh"
class HierarchicalSwitchTopology : public Topology
{
public:
HierarchicalSwitchTopology(const string & name);
void init();
protected:
void construct();
};
#endif

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -27,289 +26,309 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/*
* PerfectSwitch.cc
*
* Description: See PerfectSwitch.hh
*
* $Id$
*
*/
#include "mem/ruby/network/simple/PerfectSwitch.hh"
#include "mem/ruby/slicc_interface/NetworkMessage.hh"
#include "mem/ruby/profiler/Profiler.hh"
#include "mem/ruby/system/System.hh"
#include "mem/ruby/network/simple/SimpleNetwork.hh"
#include "mem/gems_common/util.hh" #include "mem/gems_common/util.hh"
#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/protocol/Protocol.hh" #include "mem/protocol/Protocol.hh"
#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/network/simple/PerfectSwitch.hh"
#include "mem/ruby/network/simple/SimpleNetwork.hh"
#include "mem/ruby/profiler/Profiler.hh"
#include "mem/ruby/slicc_interface/NetworkMessage.hh"
#include "mem/ruby/system/System.hh"
const int PRIORITY_SWITCH_LIMIT = 128; const int PRIORITY_SWITCH_LIMIT = 128;
// Operator for helper class // Operator for helper class
bool operator<(const LinkOrder& l1, const LinkOrder& l2) { bool
return (l1.m_value < l2.m_value); operator<(const LinkOrder& l1, const LinkOrder& l2)
{
return (l1.m_value < l2.m_value);
} }
PerfectSwitch::PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr) PerfectSwitch::PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr)
{ {
m_virtual_networks = network_ptr->getNumberOfVirtualNetworks(); m_virtual_networks = network_ptr->getNumberOfVirtualNetworks();
m_switch_id = sid; m_switch_id = sid;
m_round_robin_start = 0; m_round_robin_start = 0;
m_network_ptr = network_ptr; m_network_ptr = network_ptr;
m_wakeups_wo_switch = 0; m_wakeups_wo_switch = 0;
} }
void PerfectSwitch::addInPort(const Vector<MessageBuffer*>& in) void
PerfectSwitch::addInPort(const Vector<MessageBuffer*>& in)
{ {
assert(in.size() == m_virtual_networks); assert(in.size() == m_virtual_networks);
NodeID port = m_in.size(); NodeID port = m_in.size();
m_in.insertAtBottom(in); m_in.insertAtBottom(in);
for (int j = 0; j < m_virtual_networks; j++) { for (int j = 0; j < m_virtual_networks; j++) {
m_in[port][j]->setConsumer(this); m_in[port][j]->setConsumer(this);
string desc = "[Queue from port " + NodeIDToString(m_switch_id) + " " + NodeIDToString(port) + " " + NodeIDToString(j) + " to PerfectSwitch]"; string desc = csprintf("[Queue from port %s %s %s to PerfectSwitch]",
m_in[port][j]->setDescription(desc); NodeIDToString(m_switch_id), NodeIDToString(port),
} NodeIDToString(j));
} m_in[port][j]->setDescription(desc);
void PerfectSwitch::addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routing_table_entry)
{
assert(out.size() == m_virtual_networks);
// Setup link order
LinkOrder l;
l.m_value = 0;
l.m_link = m_out.size();
m_link_order.insertAtBottom(l);
// Add to routing table
m_out.insertAtBottom(out);
m_routing_table.insertAtBottom(routing_table_entry);
}
void PerfectSwitch::clearRoutingTables()
{
m_routing_table.clear();
}
void PerfectSwitch::clearBuffers()
{
for(int i=0; i<m_in.size(); i++){
for(int vnet=0; vnet < m_virtual_networks; vnet++) {
m_in[i][vnet]->clear();
} }
}
for(int i=0; i<m_out.size(); i++){
for(int vnet=0; vnet < m_virtual_networks; vnet++) {
m_out[i][vnet]->clear();
}
}
} }
void PerfectSwitch::reconfigureOutPort(const NetDest& routing_table_entry) void
PerfectSwitch::addOutPort(const Vector<MessageBuffer*>& out,
const NetDest& routing_table_entry)
{ {
m_routing_table.insertAtBottom(routing_table_entry); assert(out.size() == m_virtual_networks);
// Setup link order
LinkOrder l;
l.m_value = 0;
l.m_link = m_out.size();
m_link_order.insertAtBottom(l);
// Add to routing table
m_out.insertAtBottom(out);
m_routing_table.insertAtBottom(routing_table_entry);
}
void
PerfectSwitch::clearRoutingTables()
{
m_routing_table.clear();
}
void
PerfectSwitch::clearBuffers()
{
for (int i = 0; i < m_in.size(); i++){
for(int vnet = 0; vnet < m_virtual_networks; vnet++) {
m_in[i][vnet]->clear();
}
}
for (int i = 0; i < m_out.size(); i++){
for(int vnet = 0; vnet < m_virtual_networks; vnet++) {
m_out[i][vnet]->clear();
}
}
}
void
PerfectSwitch::reconfigureOutPort(const NetDest& routing_table_entry)
{
m_routing_table.insertAtBottom(routing_table_entry);
} }
PerfectSwitch::~PerfectSwitch() PerfectSwitch::~PerfectSwitch()
{ {
} }
void PerfectSwitch::wakeup() void
PerfectSwitch::wakeup()
{ {
DEBUG_EXPR(NETWORK_COMP, MedPrio, m_switch_id);
DEBUG_EXPR(NETWORK_COMP, MedPrio, m_switch_id); MsgPtr msg_ptr;
MsgPtr msg_ptr; // Give the highest numbered link priority most of the time
m_wakeups_wo_switch++;
int highest_prio_vnet = m_virtual_networks-1;
int lowest_prio_vnet = 0;
int decrementer = 1;
NetworkMessage* net_msg_ptr = NULL;
// Give the highest numbered link priority most of the time // invert priorities to avoid starvation seen in the component network
m_wakeups_wo_switch++; if (m_wakeups_wo_switch > PRIORITY_SWITCH_LIMIT) {
int highest_prio_vnet = m_virtual_networks-1; m_wakeups_wo_switch = 0;
int lowest_prio_vnet = 0; highest_prio_vnet = 0;
int decrementer = 1; lowest_prio_vnet = m_virtual_networks-1;
NetworkMessage* net_msg_ptr = NULL; decrementer = -1;
}
// invert priorities to avoid starvation seen in the component network
if (m_wakeups_wo_switch > PRIORITY_SWITCH_LIMIT) {
m_wakeups_wo_switch = 0;
highest_prio_vnet = 0;
lowest_prio_vnet = m_virtual_networks-1;
decrementer = -1;
}
for (int vnet = highest_prio_vnet; (vnet*decrementer) >= (decrementer*lowest_prio_vnet); vnet -= decrementer) {
// For all components incoming queues // For all components incoming queues
int incoming = m_round_robin_start; // This is for round-robin scheduling for (int vnet = highest_prio_vnet;
m_round_robin_start++; (vnet * decrementer) >= (decrementer * lowest_prio_vnet);
if (m_round_robin_start >= m_in.size()) { vnet -= decrementer) {
m_round_robin_start = 0;
}
// for all input ports, use round robin scheduling // This is for round-robin scheduling
for (int counter = 0; counter < m_in.size(); counter++) { int incoming = m_round_robin_start;
m_round_robin_start++;
if (m_round_robin_start >= m_in.size()) {
m_round_robin_start = 0;
}
// Round robin scheduling // for all input ports, use round robin scheduling
incoming++; for (int counter = 0; counter < m_in.size(); counter++) {
if (incoming >= m_in.size()) { // Round robin scheduling
incoming = 0; incoming++;
} if (incoming >= m_in.size()) {
incoming = 0;
// temporary vectors to store the routing results
Vector<LinkID> output_links;
Vector<NetDest> output_link_destinations;
// Is there a message waiting?
while (m_in[incoming][vnet]->isReady()) {
DEBUG_EXPR(NETWORK_COMP, MedPrio, incoming);
// Peek at message
msg_ptr = m_in[incoming][vnet]->peekMsgPtr();
net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref());
DEBUG_EXPR(NETWORK_COMP, MedPrio, *net_msg_ptr);
output_links.clear();
output_link_destinations.clear();
NetDest msg_destinations = net_msg_ptr->getInternalDestination();
// Unfortunately, the token-protocol sends some
// zero-destination messages, so this assert isn't valid
// assert(msg_destinations.count() > 0);
assert(m_link_order.size() == m_routing_table.size());
assert(m_link_order.size() == m_out.size());
if (m_network_ptr->getAdaptiveRouting()) {
if (m_network_ptr->isVNetOrdered(vnet)) {
// Don't adaptively route
for (int outlink=0; outlink<m_out.size(); outlink++) {
m_link_order[outlink].m_link = outlink;
m_link_order[outlink].m_value = 0;
} }
} else {
// Find how clogged each link is // temporary vectors to store the routing results
for (int outlink=0; outlink<m_out.size(); outlink++) { Vector<LinkID> output_links;
int out_queue_length = 0; Vector<NetDest> output_link_destinations;
for (int v=0; v<m_virtual_networks; v++) {
out_queue_length += m_out[outlink][v]->getSize(); // Is there a message waiting?
} while (m_in[incoming][vnet]->isReady()) {
m_link_order[outlink].m_link = outlink; DEBUG_EXPR(NETWORK_COMP, MedPrio, incoming);
m_link_order[outlink].m_value = 0;
m_link_order[outlink].m_value |= (out_queue_length << 8); // Peek at message
m_link_order[outlink].m_value |= (random() & 0xff); msg_ptr = m_in[incoming][vnet]->peekMsgPtr();
net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref());
DEBUG_EXPR(NETWORK_COMP, MedPrio, *net_msg_ptr);
output_links.clear();
output_link_destinations.clear();
NetDest msg_dsts =
net_msg_ptr->getInternalDestination();
// Unfortunately, the token-protocol sends some
// zero-destination messages, so this assert isn't valid
// assert(msg_dsts.count() > 0);
assert(m_link_order.size() == m_routing_table.size());
assert(m_link_order.size() == m_out.size());
if (m_network_ptr->getAdaptiveRouting()) {
if (m_network_ptr->isVNetOrdered(vnet)) {
// Don't adaptively route
for (int out = 0; out < m_out.size(); out++) {
m_link_order[out].m_link = out;
m_link_order[out].m_value = 0;
}
} else {
// Find how clogged each link is
for (int out = 0; out < m_out.size(); out++) {
int out_queue_length = 0;
for (int v = 0; v < m_virtual_networks; v++) {
out_queue_length += m_out[out][v]->getSize();
}
int value =
(out_queue_length << 8) | (random() & 0xff);
m_link_order[out].m_link = out;
m_link_order[out].m_value = value;
}
// Look at the most empty link first
m_link_order.sortVector();
}
}
for (int i = 0; i < m_routing_table.size(); i++) {
// pick the next link to look at
int link = m_link_order[i].m_link;
NetDest dst = m_routing_table[link];
DEBUG_EXPR(NETWORK_COMP, MedPrio, dst);
if (!msg_dsts.intersectionIsNotEmpty(dst))
continue;
// Remember what link we're using
output_links.insertAtBottom(link);
// Need to remember which destinations need this
// message in another vector. This Set is the
// intersection of the routing_table entry and the
// current destination set. The intersection must
// not be empty, since we are inside "if"
output_link_destinations.insertAtBottom(msg_dsts.AND(dst));
// Next, we update the msg_destination not to
// include those nodes that were already handled
// by this link
msg_dsts.removeNetDest(dst);
}
assert(msg_dsts.count() == 0);
//assert(output_links.size() > 0);
// Check for resources - for all outgoing queues
bool enough = true;
for (int i = 0; i < output_links.size(); i++) {
int outgoing = output_links[i];
if (!m_out[outgoing][vnet]->areNSlotsAvailable(1))
enough = false;
DEBUG_MSG(NETWORK_COMP, HighPrio,
"checking if node is blocked");
DEBUG_EXPR(NETWORK_COMP, HighPrio, outgoing);
DEBUG_EXPR(NETWORK_COMP, HighPrio, vnet);
DEBUG_EXPR(NETWORK_COMP, HighPrio, enough);
}
// There were not enough resources
if (!enough) {
g_eventQueue_ptr->scheduleEvent(this, 1);
DEBUG_MSG(NETWORK_COMP, HighPrio,
"Can't deliver message since a node is blocked");
DEBUG_EXPR(NETWORK_COMP, HighPrio, *net_msg_ptr);
break; // go to next incoming port
}
MsgPtr unmodified_msg_ptr;
if (output_links.size() > 1) {
// If we are sending this message down more than
// one link (size>1), we need to make a copy of
// the message so each branch can have a different
// internal destination we need to create an
// unmodified MsgPtr because the MessageBuffer
// enqueue func will modify the message
// This magic line creates a private copy of the
// message
unmodified_msg_ptr = *(msg_ptr.ref());
}
// Enqueue it - for all outgoing queues
for (int i=0; i<output_links.size(); i++) {
int outgoing = output_links[i];
if (i > 0) {
// create a private copy of the unmodified
// message
msg_ptr = *(unmodified_msg_ptr.ref());
}
// Change the internal destination set of the
// message so it knows which destinations this
// link is responsible for.
net_msg_ptr = safe_cast<NetworkMessage*>(msg_ptr.ref());
net_msg_ptr->getInternalDestination() =
output_link_destinations[i];
// Enqeue msg
DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
DEBUG_MSG(NETWORK_COMP, HighPrio,
csprintf("switch: %d enqueuing net msg from "
"inport[%d][%d] to outport [%d][%d] time: %d.",
m_switch_id, incoming, vnet, outgoing, vnet,
g_eventQueue_ptr->getTime()));
DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
m_out[outgoing][vnet]->enqueue(msg_ptr);
}
// Dequeue msg
m_in[incoming][vnet]->pop();
} }
m_link_order.sortVector(); // Look at the most empty link first
}
} }
for (int i=0; i<m_routing_table.size(); i++) {
// pick the next link to look at
int link = m_link_order[i].m_link;
DEBUG_EXPR(NETWORK_COMP, MedPrio, m_routing_table[link]);
if (msg_destinations.intersectionIsNotEmpty(m_routing_table[link])) {
// Remember what link we're using
output_links.insertAtBottom(link);
// Need to remember which destinations need this message
// in another vector. This Set is the intersection of the
// routing_table entry and the current destination set.
// The intersection must not be empty, since we are inside "if"
output_link_destinations.insertAtBottom(msg_destinations.AND(m_routing_table[link]));
// Next, we update the msg_destination not to include
// those nodes that were already handled by this link
msg_destinations.removeNetDest(m_routing_table[link]);
}
}
assert(msg_destinations.count() == 0);
//assert(output_links.size() > 0);
// Check for resources - for all outgoing queues
bool enough = true;
for (int i=0; i<output_links.size(); i++) {
int outgoing = output_links[i];
enough = enough && m_out[outgoing][vnet]->areNSlotsAvailable(1);
DEBUG_MSG(NETWORK_COMP, HighPrio, "checking if node is blocked");
DEBUG_EXPR(NETWORK_COMP, HighPrio, outgoing);
DEBUG_EXPR(NETWORK_COMP, HighPrio, vnet);
DEBUG_EXPR(NETWORK_COMP, HighPrio, enough);
}
// There were not enough resources
if(!enough) {
g_eventQueue_ptr->scheduleEvent(this, 1);
DEBUG_MSG(NETWORK_COMP, HighPrio, "Can't deliver message to anyone since a node is blocked");
DEBUG_EXPR(NETWORK_COMP, HighPrio, *net_msg_ptr);
break; // go to next incoming port
}
MsgPtr unmodified_msg_ptr;
if (output_links.size() > 1) {
// If we are sending this message down more than one link
// (size>1), we need to make a copy of the message so each
// branch can have a different internal destination
// we need to create an unmodified MsgPtr because the MessageBuffer enqueue func
// will modify the message
unmodified_msg_ptr = *(msg_ptr.ref()); // This magic line creates a private copy of the message
}
// Enqueue it - for all outgoing queues
for (int i=0; i<output_links.size(); i++) {
int outgoing = output_links[i];
if (i > 0) {
msg_ptr = *(unmodified_msg_ptr.ref()); // create a private copy of the unmodified message
}
// Change the internal destination set of the message so it
// knows which destinations this link is responsible for.
net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref());
net_msg_ptr->getInternalDestination() = output_link_destinations[i];
// Enqeue msg
DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
DEBUG_MSG(NETWORK_COMP,HighPrio,"switch: " + int_to_string(m_switch_id)
+ " enqueuing net msg from inport[" + int_to_string(incoming) + "]["
+ int_to_string(vnet) +"] to outport [" + int_to_string(outgoing)
+ "][" + int_to_string(vnet) +"]"
+ " time: " + int_to_string(g_eventQueue_ptr->getTime()) + ".");
DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
m_out[outgoing][vnet]->enqueue(msg_ptr);
}
// Dequeue msg
m_in[incoming][vnet]->pop();
}
} }
}
} }
void PerfectSwitch::printStats(std::ostream& out) const void
PerfectSwitch::printStats(std::ostream& out) const
{ {
out << "PerfectSwitch printStats" << endl; out << "PerfectSwitch printStats" << endl;
} }
void PerfectSwitch::clearStats() void
PerfectSwitch::clearStats()
{ {
} }
void PerfectSwitch::printConfig(std::ostream& out) const void
PerfectSwitch::printConfig(std::ostream& out) const
{ {
} }
void PerfectSwitch::print(std::ostream& out) const void
PerfectSwitch::print(std::ostream& out) const
{ {
out << "[PerfectSwitch " << m_switch_id << "]"; out << "[PerfectSwitch " << m_switch_id << "]";
} }

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -28,93 +27,79 @@
*/ */
/* /*
* $Id$ * Perfect switch, of course it is perfect and no latency or what so
* * ever. Every cycle it is woke up and perform all the necessary
* Description: Perfect switch, of course it is perfect and no latency or what * routings that must be done. Note, this switch also has number of
* so ever. Every cycle it is woke up and perform all the * input ports/output ports and has a routing table as well.
* necessary routings that must be done. Note, this switch also
* has number of input ports/output ports and has a routing table
* as well.
*
*/ */
#ifndef PerfectSwitch_H #ifndef __MEM_RUBY_NETWORK_SIMPLE_PERFECTSWITCH_HH__
#define PerfectSwitch_H #define __MEM_RUBY_NETWORK_SIMPLE_PERFECTSWITCH_HH__
#include <iostream> #include <iostream>
#include "mem/ruby/common/Global.hh"
#include "mem/gems_common/Vector.hh" #include "mem/gems_common/Vector.hh"
#include "mem/ruby/common/Consumer.hh" #include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/system/NodeID.hh" #include "mem/ruby/system/NodeID.hh"
class MessageBuffer; class MessageBuffer;
class NetDest; class NetDest;
class SimpleNetwork; class SimpleNetwork;
class LinkOrder { struct LinkOrder
public:
int m_link;
int m_value;
};
class PerfectSwitch : public Consumer {
public:
// Constructors
// constructor specifying the number of ports
PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr);
void addInPort(const Vector<MessageBuffer*>& in);
void addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routing_table_entry);
void clearRoutingTables();
void clearBuffers();
void reconfigureOutPort(const NetDest& routing_table_entry);
int getInLinks() const { return m_in.size(); }
int getOutLinks() const { return m_out.size(); }
// Destructor
~PerfectSwitch();
// Public Methods
void wakeup();
void printStats(std::ostream& out) const;
void clearStats();
void printConfig(std::ostream& out) const;
void print(std::ostream& out) const;
private:
// Private copy constructor and assignment operator
PerfectSwitch(const PerfectSwitch& obj);
PerfectSwitch& operator=(const PerfectSwitch& obj);
// Data Members (m_ prefix)
SwitchID m_switch_id;
// vector of queues from the components
Vector<Vector<MessageBuffer*> > m_in;
Vector<Vector<MessageBuffer*> > m_out;
Vector<NetDest> m_routing_table;
Vector<LinkOrder> m_link_order;
int m_virtual_networks;
int m_round_robin_start;
int m_wakeups_wo_switch;
SimpleNetwork* m_network_ptr;
};
// Output operator declaration
std::ostream& operator<<(std::ostream& out, const PerfectSwitch& obj);
// ******************* Definitions *******************
// Output operator definition
extern inline
std::ostream& operator<<(std::ostream& out, const PerfectSwitch& obj)
{ {
obj.print(out); int m_link;
out << std::flush; int m_value;
return out; };
class PerfectSwitch : public Consumer
{
public:
PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr);
~PerfectSwitch();
void addInPort(const Vector<MessageBuffer*>& in);
void addOutPort(const Vector<MessageBuffer*>& out,
const NetDest& routing_table_entry);
void clearRoutingTables();
void clearBuffers();
void reconfigureOutPort(const NetDest& routing_table_entry);
int getInLinks() const { return m_in.size(); }
int getOutLinks() const { return m_out.size(); }
void wakeup();
void printStats(std::ostream& out) const;
void clearStats();
void printConfig(std::ostream& out) const;
void print(std::ostream& out) const;
private:
// Private copy constructor and assignment operator
PerfectSwitch(const PerfectSwitch& obj);
PerfectSwitch& operator=(const PerfectSwitch& obj);
SwitchID m_switch_id;
// vector of queues from the components
Vector<Vector<MessageBuffer*> > m_in;
Vector<Vector<MessageBuffer*> > m_out;
Vector<NetDest> m_routing_table;
Vector<LinkOrder> m_link_order;
int m_virtual_networks;
int m_round_robin_start;
int m_wakeups_wo_switch;
SimpleNetwork* m_network_ptr;
};
inline std::ostream&
operator<<(std::ostream& out, const PerfectSwitch& obj)
{
obj.print(out);
out << std::flush;
return out;
} }
#endif //PerfectSwitch_H #endif // __MEM_RUBY_NETWORK_SIMPLE_PERFECTSWITCH_HH__

View file

@ -1,17 +0,0 @@
#ifndef PTTOPTTOPOLOGY_H
#define PTTOPTTOPOLOGY_H
#include "mem/ruby/network/simple/Topology.hh"
class PtToPtTopology : public Topology
{
public:
PtToPtTopology(const string & name);
void init();
protected:
void construct();
};
#endif

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -27,248 +26,262 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/* #include "mem/gems_common/Map.hh"
* SimpleNetwork.cc #include "mem/protocol/MachineType.hh"
* #include "mem/protocol/Protocol.hh"
* Description: See SimpleNetwork.hh #include "mem/protocol/TopologyType.hh"
* #include "mem/ruby/buffers/MessageBuffer.hh"
* $Id$ #include "mem/ruby/common/NetDest.hh"
*
*/
#include "mem/ruby/network/simple/SimpleNetwork.hh" #include "mem/ruby/network/simple/SimpleNetwork.hh"
#include "mem/ruby/network/simple/Switch.hh"
#include "mem/ruby/network/simple/Topology.hh"
#include "mem/ruby/profiler/Profiler.hh" #include "mem/ruby/profiler/Profiler.hh"
#include "mem/ruby/system/System.hh" #include "mem/ruby/system/System.hh"
#include "mem/ruby/network/simple/Switch.hh"
#include "mem/ruby/common/NetDest.hh"
#include "mem/ruby/network/simple/Topology.hh"
#include "mem/protocol/TopologyType.hh"
#include "mem/protocol/MachineType.hh"
#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/protocol/Protocol.hh"
#include "mem/gems_common/Map.hh"
#if 0
// ***BIG HACK*** - This is actually code that _should_ be in Network.cc // ***BIG HACK*** - This is actually code that _should_ be in Network.cc
// Note: Moved to Princeton Network // Note: Moved to Princeton Network
// calls new to abstract away from the network // calls new to abstract away from the network
/* Network*
Network* Network::createNetwork(int nodes) Network::createNetwork(int nodes)
{ {
return new SimpleNetwork(nodes); return new SimpleNetwork(nodes);
} }
*/ #endif
SimpleNetwork::SimpleNetwork(const Params *p) SimpleNetwork::SimpleNetwork(const Params *p)
: Network(p) : Network(p)
{ {
// // Note: the parent Network Object constructor is called before the
// Note: the parent Network Object constructor is called before the // SimpleNetwork child constructor. Therefore, the member variables
// SimpleNetwork child constructor. Therefore, the member variables // used below should already be initialized.
// used below should already be initialized.
//
m_endpoint_switches.setSize(m_nodes); m_endpoint_switches.setSize(m_nodes);
m_in_use.setSize(m_virtual_networks); m_in_use.setSize(m_virtual_networks);
m_ordered.setSize(m_virtual_networks); m_ordered.setSize(m_virtual_networks);
for (int i = 0; i < m_virtual_networks; i++) { for (int i = 0; i < m_virtual_networks; i++) {
m_in_use[i] = false; m_in_use[i] = false;
m_ordered[i] = false; m_ordered[i] = false;
} }
// Allocate to and from queues // Allocate to and from queues
m_toNetQueues.setSize(m_nodes); m_toNetQueues.setSize(m_nodes);
m_fromNetQueues.setSize(m_nodes); m_fromNetQueues.setSize(m_nodes);
for (int node = 0; node < m_nodes; node++) { for (int node = 0; node < m_nodes; node++) {
m_toNetQueues[node].setSize(m_virtual_networks); m_toNetQueues[node].setSize(m_virtual_networks);
m_fromNetQueues[node].setSize(m_virtual_networks); m_fromNetQueues[node].setSize(m_virtual_networks);
for (int j = 0; j < m_virtual_networks; j++) { for (int j = 0; j < m_virtual_networks; j++) {
m_toNetQueues[node][j] = new MessageBuffer( m_toNetQueues[node][j] = new MessageBuffer(
"toNet node "+int_to_string(node)+" j "+int_to_string(j)); "toNet node "+int_to_string(node)+" j "+int_to_string(j));
m_fromNetQueues[node][j] = new MessageBuffer( m_fromNetQueues[node][j] = new MessageBuffer(
"fromNet node "+int_to_string(node)+" j "+int_to_string(j)); "fromNet node "+int_to_string(node)+" j "+int_to_string(j));
}
} }
}
} }
void SimpleNetwork::init() void
SimpleNetwork::init()
{ {
Network::init();
Network::init(); // The topology pointer should have already been initialized in
// the parent class network constructor.
assert(m_topology_ptr != NULL);
int number_of_switches = m_topology_ptr->numSwitches();
for (int i = 0; i < number_of_switches; i++) {
m_switch_ptr_vector.insertAtBottom(new Switch(i, this));
}
// // false because this isn't a reconfiguration
// The topology pointer should have already been initialized in the parent m_topology_ptr->createLinks(this, false);
// class network constructor.
//
assert(m_topology_ptr != NULL);
int number_of_switches = m_topology_ptr->numSwitches();
for (int i=0; i<number_of_switches; i++) {
m_switch_ptr_vector.insertAtBottom(new Switch(i, this));
}
m_topology_ptr->createLinks(this, false); // false because this isn't a reconfiguration
} }
void SimpleNetwork::reset() void
SimpleNetwork::reset()
{ {
for (int node = 0; node < m_nodes; node++) { for (int node = 0; node < m_nodes; node++) {
for (int j = 0; j < m_virtual_networks; j++) { for (int j = 0; j < m_virtual_networks; j++) {
m_toNetQueues[node][j]->clear(); m_toNetQueues[node][j]->clear();
m_fromNetQueues[node][j]->clear(); m_fromNetQueues[node][j]->clear();
}
} }
}
for(int i=0; i<m_switch_ptr_vector.size(); i++){ for(int i = 0; i < m_switch_ptr_vector.size(); i++){
m_switch_ptr_vector[i]->clearBuffers(); m_switch_ptr_vector[i]->clearBuffers();
} }
} }
SimpleNetwork::~SimpleNetwork() SimpleNetwork::~SimpleNetwork()
{ {
for (int i = 0; i < m_nodes; i++) { for (int i = 0; i < m_nodes; i++) {
m_toNetQueues[i].deletePointers(); m_toNetQueues[i].deletePointers();
m_fromNetQueues[i].deletePointers(); m_fromNetQueues[i].deletePointers();
} }
m_switch_ptr_vector.deletePointers(); m_switch_ptr_vector.deletePointers();
m_buffers_to_free.deletePointers(); m_buffers_to_free.deletePointers();
// delete m_topology_ptr; // delete m_topology_ptr;
} }
// From a switch to an endpoint node // From a switch to an endpoint node
void SimpleNetwork::makeOutLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration) void
SimpleNetwork::makeOutLink(SwitchID src, NodeID dest,
const NetDest& routing_table_entry, int link_latency, int link_weight,
int bw_multiplier, bool isReconfiguration)
{ {
assert(dest < m_nodes); assert(dest < m_nodes);
assert(src < m_switch_ptr_vector.size()); assert(src < m_switch_ptr_vector.size());
assert(m_switch_ptr_vector[src] != NULL); assert(m_switch_ptr_vector[src] != NULL);
if(!isReconfiguration){
m_switch_ptr_vector[src]->addOutPort(m_fromNetQueues[dest], routing_table_entry, link_latency, bw_multiplier); if (isReconfiguration) {
m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry);
return;
}
m_switch_ptr_vector[src]->addOutPort(m_fromNetQueues[dest],
routing_table_entry, link_latency, bw_multiplier);
m_endpoint_switches[dest] = m_switch_ptr_vector[src]; m_endpoint_switches[dest] = m_switch_ptr_vector[src];
} else {
m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry);
}
} }
// From an endpoint node to a switch // From an endpoint node to a switch
void SimpleNetwork::makeInLink(NodeID src, SwitchID dest, const NetDest& routing_table_entry, int link_latency, int bw_multiplier, bool isReconfiguration) void
SimpleNetwork::makeInLink(NodeID src, SwitchID dest,
const NetDest& routing_table_entry, int link_latency, int bw_multiplier,
bool isReconfiguration)
{ {
assert(src < m_nodes); assert(src < m_nodes);
if(!isReconfiguration){ if (isReconfiguration) {
// do nothing
return;
}
m_switch_ptr_vector[dest]->addInPort(m_toNetQueues[src]); m_switch_ptr_vector[dest]->addInPort(m_toNetQueues[src]);
} else {
// do nothing
}
} }
// From a switch to a switch // From a switch to a switch
void SimpleNetwork::makeInternalLink(SwitchID src, SwitchID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration) void
SimpleNetwork::makeInternalLink(SwitchID src, SwitchID dest,
const NetDest& routing_table_entry, int link_latency, int link_weight,
int bw_multiplier, bool isReconfiguration)
{ {
if(!isReconfiguration){ if (isReconfiguration) {
m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry);
return;
}
// Create a set of new MessageBuffers // Create a set of new MessageBuffers
Vector<MessageBuffer*> queues; Vector<MessageBuffer*> queues;
for (int i = 0; i < m_virtual_networks; i++) { for (int i = 0; i < m_virtual_networks; i++) {
// allocate a buffer // allocate a buffer
MessageBuffer* buffer_ptr = new MessageBuffer; MessageBuffer* buffer_ptr = new MessageBuffer;
buffer_ptr->setOrdering(true); buffer_ptr->setOrdering(true);
if (m_buffer_size > 0) { if (m_buffer_size > 0) {
buffer_ptr->setSize(m_buffer_size); buffer_ptr->setSize(m_buffer_size);
} }
queues.insertAtBottom(buffer_ptr); queues.insertAtBottom(buffer_ptr);
// remember to deallocate it // remember to deallocate it
m_buffers_to_free.insertAtBottom(buffer_ptr); m_buffers_to_free.insertAtBottom(buffer_ptr);
} }
// Connect it to the two switches // Connect it to the two switches
m_switch_ptr_vector[dest]->addInPort(queues); m_switch_ptr_vector[dest]->addInPort(queues);
m_switch_ptr_vector[src]->addOutPort(queues, routing_table_entry, link_latency, bw_multiplier); m_switch_ptr_vector[src]->addOutPort(queues, routing_table_entry,
} else { link_latency, bw_multiplier);
m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry);
}
} }
void SimpleNetwork::checkNetworkAllocation(NodeID id, bool ordered, int network_num) void
SimpleNetwork::checkNetworkAllocation(NodeID id, bool ordered, int network_num)
{ {
ASSERT(id < m_nodes); ASSERT(id < m_nodes);
ASSERT(network_num < m_virtual_networks); ASSERT(network_num < m_virtual_networks);
if (ordered) { if (ordered) {
m_ordered[network_num] = true; m_ordered[network_num] = true;
}
m_in_use[network_num] = true;
}
MessageBuffer* SimpleNetwork::getToNetQueue(NodeID id, bool ordered, int network_num)
{
checkNetworkAllocation(id, ordered, network_num);
return m_toNetQueues[id][network_num];
}
MessageBuffer* SimpleNetwork::getFromNetQueue(NodeID id, bool ordered, int network_num)
{
checkNetworkAllocation(id, ordered, network_num);
return m_fromNetQueues[id][network_num];
}
const Vector<Throttle*>* SimpleNetwork::getThrottles(NodeID id) const
{
assert(id >= 0);
assert(id < m_nodes);
assert(m_endpoint_switches[id] != NULL);
return m_endpoint_switches[id]->getThrottles();
}
void SimpleNetwork::printStats(ostream& out) const
{
out << endl;
out << "Network Stats" << endl;
out << "-------------" << endl;
out << endl;
for(int i=0; i<m_switch_ptr_vector.size(); i++) {
m_switch_ptr_vector[i]->printStats(out);
}
m_topology_ptr->printStats(out);
}
void SimpleNetwork::clearStats()
{
for(int i=0; i<m_switch_ptr_vector.size(); i++) {
m_switch_ptr_vector[i]->clearStats();
}
m_topology_ptr->clearStats();
}
void SimpleNetwork::printConfig(ostream& out) const
{
out << endl;
out << "Network Configuration" << endl;
out << "---------------------" << endl;
out << "network: SIMPLE_NETWORK" << endl;
out << "topology: " << m_topology_ptr->getName() << endl;
out << endl;
for (int i = 0; i < m_virtual_networks; i++) {
out << "virtual_net_" << i << ": ";
if (m_in_use[i]) {
out << "active, ";
if (m_ordered[i]) {
out << "ordered" << endl;
} else {
out << "unordered" << endl;
}
} else {
out << "inactive" << endl;
} }
} m_in_use[network_num] = true;
out << endl;
for(int i=0; i<m_switch_ptr_vector.size(); i++) {
m_switch_ptr_vector[i]->printConfig(out);
}
m_topology_ptr->printConfig(out);
} }
void SimpleNetwork::print(ostream& out) const MessageBuffer*
SimpleNetwork::getToNetQueue(NodeID id, bool ordered, int network_num)
{ {
out << "[SimpleNetwork]"; checkNetworkAllocation(id, ordered, network_num);
return m_toNetQueues[id][network_num];
}
MessageBuffer*
SimpleNetwork::getFromNetQueue(NodeID id, bool ordered, int network_num)
{
checkNetworkAllocation(id, ordered, network_num);
return m_fromNetQueues[id][network_num];
}
const Vector<Throttle*>*
SimpleNetwork::getThrottles(NodeID id) const
{
assert(id >= 0);
assert(id < m_nodes);
assert(m_endpoint_switches[id] != NULL);
return m_endpoint_switches[id]->getThrottles();
}
void
SimpleNetwork::printStats(ostream& out) const
{
out << endl;
out << "Network Stats" << endl;
out << "-------------" << endl;
out << endl;
for (int i = 0; i < m_switch_ptr_vector.size(); i++) {
m_switch_ptr_vector[i]->printStats(out);
}
m_topology_ptr->printStats(out);
}
void
SimpleNetwork::clearStats()
{
for (int i = 0; i < m_switch_ptr_vector.size(); i++) {
m_switch_ptr_vector[i]->clearStats();
}
m_topology_ptr->clearStats();
}
void
SimpleNetwork::printConfig(ostream& out) const
{
out << endl;
out << "Network Configuration" << endl;
out << "---------------------" << endl;
out << "network: SIMPLE_NETWORK" << endl;
out << "topology: " << m_topology_ptr->getName() << endl;
out << endl;
for (int i = 0; i < m_virtual_networks; i++) {
out << "virtual_net_" << i << ": ";
if (m_in_use[i]) {
out << "active, ";
if (m_ordered[i]) {
out << "ordered" << endl;
} else {
out << "unordered" << endl;
}
} else {
out << "inactive" << endl;
}
}
out << endl;
for(int i = 0; i < m_switch_ptr_vector.size(); i++) {
m_switch_ptr_vector[i]->printConfig(out);
}
m_topology_ptr->printConfig(out);
}
void
SimpleNetwork::print(ostream& out) const
{
out << "[SimpleNetwork]";
} }

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -28,9 +27,7 @@
*/ */
/* /*
* SimpleNetwork.hh * The SimpleNetwork class implements the interconnection
*
* Description: The SimpleNetwork class implements the interconnection
* SimpleNetwork between components (processor/cache components and * SimpleNetwork between components (processor/cache components and
* memory/directory components). The interconnection network as * memory/directory components). The interconnection network as
* described here is not a physical network, but a programming concept * described here is not a physical network, but a programming concept
@ -61,20 +58,17 @@
* abstract Network class take a enumeration parameter, and based on * abstract Network class take a enumeration parameter, and based on
* that to initial proper network. Or even better, just make the ruby * that to initial proper network. Or even better, just make the ruby
* system initializer choose the proper network to initiate. * system initializer choose the proper network to initiate.
*
* $Id$
*
*/ */
#ifndef SIMPLENETWORK_H #ifndef __MEM_RUBY_NETWORK_SIMPLE_SIMPLENETWORK_HH__
#define SIMPLENETWORK_H #define __MEM_RUBY_NETWORK_SIMPLE_SIMPLENETWORK_HH__
#include "mem/ruby/common/Global.hh"
#include "mem/gems_common/Vector.hh" #include "mem/gems_common/Vector.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/network/Network.hh" #include "mem/ruby/network/Network.hh"
#include "mem/ruby/system/NodeID.hh" #include "mem/ruby/system/NodeID.hh"
#include "sim/sim_object.hh"
#include "params/SimpleNetwork.hh" #include "params/SimpleNetwork.hh"
#include "sim/sim_object.hh"
class NetDest; class NetDest;
class MessageBuffer; class MessageBuffer;
@ -82,78 +76,74 @@ class Throttle;
class Switch; class Switch;
class Topology; class Topology;
class SimpleNetwork : public Network { class SimpleNetwork : public Network
public: {
// Constructors public:
typedef SimpleNetworkParams Params; typedef SimpleNetworkParams Params;
SimpleNetwork(const Params *p); SimpleNetwork(const Params *p);
~SimpleNetwork();
// Destructor void init();
~SimpleNetwork();
void init(); void printStats(ostream& out) const;
void clearStats();
void printConfig(ostream& out) const;
// Public Methods void reset();
void printStats(ostream& out) const;
void clearStats();
void printConfig(ostream& out) const;
void reset(); // returns the queue requested for the given component
MessageBuffer* getToNetQueue(NodeID id, bool ordered, int network_num);
MessageBuffer* getFromNetQueue(NodeID id, bool ordered, int network_num);
virtual const Vector<Throttle*>* getThrottles(NodeID id) const;
// returns the queue requested for the given component bool isVNetOrdered(int vnet) { return m_ordered[vnet]; }
MessageBuffer* getToNetQueue(NodeID id, bool ordered, int network_num); bool validVirtualNetwork(int vnet) { return m_in_use[vnet]; }
MessageBuffer* getFromNetQueue(NodeID id, bool ordered, int network_num);
virtual const Vector<Throttle*>* getThrottles(NodeID id) const;
bool isVNetOrdered(int vnet) { return m_ordered[vnet]; } int getNumNodes() {return m_nodes; }
bool validVirtualNetwork(int vnet) { return m_in_use[vnet]; }
int getNumNodes() {return m_nodes; } // Methods used by Topology to setup the network
void makeOutLink(SwitchID src, NodeID dest,
const NetDest& routing_table_entry, int link_latency, int link_weight,
int bw_multiplier, bool isReconfiguration);
void makeInLink(SwitchID src, NodeID dest,
const NetDest& routing_table_entry, int link_latency,
int bw_multiplier, bool isReconfiguration);
void makeInternalLink(SwitchID src, NodeID dest,
const NetDest& routing_table_entry, int link_latency, int link_weight,
int bw_multiplier, bool isReconfiguration);
// Methods used by Topology to setup the network void print(ostream& out) const;
void makeOutLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration);
void makeInLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int bw_multiplier, bool isReconfiguration);
void makeInternalLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration);
void print(ostream& out) const; private:
private: void checkNetworkAllocation(NodeID id, bool ordered, int network_num);
void checkNetworkAllocation(NodeID id, bool ordered, int network_num); void addLink(SwitchID src, SwitchID dest, int link_latency);
void addLink(SwitchID src, SwitchID dest, int link_latency); void makeLink(SwitchID src, SwitchID dest,
void makeLink(SwitchID src, SwitchID dest, const NetDest& routing_table_entry, int link_latency); const NetDest& routing_table_entry, int link_latency);
SwitchID createSwitch(); SwitchID createSwitch();
void makeTopology(); void makeTopology();
void linkTopology(); void linkTopology();
// Private copy constructor and assignment operator
SimpleNetwork(const SimpleNetwork& obj);
SimpleNetwork& operator=(const SimpleNetwork& obj);
// Private copy constructor and assignment operator // vector of queues from the components
SimpleNetwork(const SimpleNetwork& obj); Vector<Vector<MessageBuffer*> > m_toNetQueues;
SimpleNetwork& operator=(const SimpleNetwork& obj); Vector<Vector<MessageBuffer*> > m_fromNetQueues;
// Data Members (m_ prefix) Vector<bool> m_in_use;
Vector<bool> m_ordered;
// vector of queues from the components Vector<Switch*> m_switch_ptr_vector;
Vector<Vector<MessageBuffer*> > m_toNetQueues; Vector<MessageBuffer*> m_buffers_to_free;
Vector<Vector<MessageBuffer*> > m_fromNetQueues; Vector<Switch*> m_endpoint_switches;
Vector<bool> m_in_use;
Vector<bool> m_ordered;
Vector<Switch*> m_switch_ptr_vector;
Vector<MessageBuffer*> m_buffers_to_free;
Vector<Switch*> m_endpoint_switches;
}; };
// Output operator declaration inline ostream&
ostream& operator<<(ostream& out, const SimpleNetwork& obj); operator<<(ostream& out, const SimpleNetwork& obj)
// ******************* Definitions *******************
// Output operator definition
extern inline
ostream& operator<<(ostream& out, const SimpleNetwork& obj)
{ {
obj.print(out); obj.print(out);
out << flush; out << flush;
return out; return out;
} }
#endif //SIMPLENETWORK_H #endif // __MEM_RUBY_NETWORK_SIMPLE_SIMPLENETWORK_HH__

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -27,182 +26,194 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/*
* Switch.cc
*
* Description: See Switch.hh
*
* $Id$
*
*/
#include "mem/ruby/network/simple/Switch.hh"
#include "mem/ruby/network/simple/PerfectSwitch.hh"
#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/network/simple/Throttle.hh"
#include "mem/protocol/MessageSizeType.hh" #include "mem/protocol/MessageSizeType.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/protocol/Protocol.hh" #include "mem/protocol/Protocol.hh"
#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/network/simple/PerfectSwitch.hh"
#include "mem/ruby/network/simple/Switch.hh"
#include "mem/ruby/network/simple/Throttle.hh"
Switch::Switch(SwitchID sid, SimpleNetwork* network_ptr) Switch::Switch(SwitchID sid, SimpleNetwork* network_ptr)
{ {
m_perfect_switch_ptr = new PerfectSwitch(sid, network_ptr); m_perfect_switch_ptr = new PerfectSwitch(sid, network_ptr);
m_switch_id = sid; m_switch_id = sid;
m_throttles.setSize(0); m_throttles.setSize(0);
} }
Switch::~Switch() Switch::~Switch()
{ {
delete m_perfect_switch_ptr; delete m_perfect_switch_ptr;
// Delete throttles (one per output port) // Delete throttles (one per output port)
m_throttles.deletePointers(); m_throttles.deletePointers();
// Delete MessageBuffers // Delete MessageBuffers
m_buffers_to_free.deletePointers(); m_buffers_to_free.deletePointers();
} }
void Switch::addInPort(const Vector<MessageBuffer*>& in) void
Switch::addInPort(const Vector<MessageBuffer*>& in)
{ {
m_perfect_switch_ptr->addInPort(in); m_perfect_switch_ptr->addInPort(in);
} }
void Switch::addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routing_table_entry, int link_latency, int bw_multiplier) void
Switch::addOutPort(const Vector<MessageBuffer*>& out,
const NetDest& routing_table_entry, int link_latency, int bw_multiplier)
{ {
Throttle* throttle_ptr = NULL; Throttle* throttle_ptr = NULL;
// Create a throttle // Create a throttle
throttle_ptr = new Throttle(m_switch_id, m_throttles.size(), link_latency, bw_multiplier); throttle_ptr = new Throttle(m_switch_id, m_throttles.size(), link_latency,
m_throttles.insertAtBottom(throttle_ptr); bw_multiplier);
m_throttles.insertAtBottom(throttle_ptr);
// Create one buffer per vnet (these are intermediaryQueues) // Create one buffer per vnet (these are intermediaryQueues)
Vector<MessageBuffer*> intermediateBuffers; Vector<MessageBuffer*> intermediateBuffers;
for (int i=0; i<out.size(); i++) { for (int i = 0; i < out.size(); i++) {
MessageBuffer* buffer_ptr = new MessageBuffer; MessageBuffer* buffer_ptr = new MessageBuffer;
// Make these queues ordered // Make these queues ordered
buffer_ptr->setOrdering(true); buffer_ptr->setOrdering(true);
Network* net_ptr = RubySystem::getNetwork(); Network* net_ptr = RubySystem::getNetwork();
if(net_ptr->getBufferSize() > 0) { if (net_ptr->getBufferSize() > 0) {
buffer_ptr->setSize(net_ptr->getBufferSize()); buffer_ptr->setSize(net_ptr->getBufferSize());
}
intermediateBuffers.insertAtBottom(buffer_ptr);
m_buffers_to_free.insertAtBottom(buffer_ptr);
}
// Hook the queues to the PerfectSwitch
m_perfect_switch_ptr->addOutPort(intermediateBuffers, routing_table_entry);
// Hook the queues to the Throttle
throttle_ptr->addLinks(intermediateBuffers, out);
}
void Switch::clearRoutingTables()
{
m_perfect_switch_ptr->clearRoutingTables();
}
void Switch::clearBuffers()
{
m_perfect_switch_ptr->clearBuffers();
for (int i=0; i<m_throttles.size(); i++) {
if (m_throttles[i] != NULL) {
m_throttles[i]->clear();
}
}
}
void Switch::reconfigureOutPort(const NetDest& routing_table_entry)
{
m_perfect_switch_ptr->reconfigureOutPort(routing_table_entry);
}
const Throttle* Switch::getThrottle(LinkID link_number) const
{
assert(m_throttles[link_number] != NULL);
return m_throttles[link_number];
}
const Vector<Throttle*>* Switch::getThrottles() const
{
return &m_throttles;
}
void Switch::printStats(std::ostream& out) const
{
using namespace std;
out << "switch_" << m_switch_id << "_inlinks: " << m_perfect_switch_ptr->getInLinks() << endl;
out << "switch_" << m_switch_id << "_outlinks: " << m_perfect_switch_ptr->getOutLinks() << endl;
// Average link utilizations
double average_utilization = 0.0;
int throttle_count = 0;
for (int i=0; i<m_throttles.size(); i++) {
Throttle* throttle_ptr = m_throttles[i];
if (throttle_ptr != NULL) {
average_utilization += throttle_ptr->getUtilization();
throttle_count++;
}
}
average_utilization = (throttle_count == 0) ? 0 : average_utilization / float(throttle_count);
// Individual link utilizations
out << "links_utilized_percent_switch_" << m_switch_id << ": " << average_utilization << endl;
for (int link=0; link<m_throttles.size(); link++) {
Throttle* throttle_ptr = m_throttles[link];
if (throttle_ptr != NULL) {
out << " links_utilized_percent_switch_" << m_switch_id << "_link_" << link << ": "
<< throttle_ptr->getUtilization() << " bw: " << throttle_ptr->getLinkBandwidth()
<< " base_latency: " << throttle_ptr->getLatency() << endl;
}
}
out << endl;
// Traffic breakdown
for (int link=0; link<m_throttles.size(); link++) {
Throttle* throttle_ptr = m_throttles[link];
if (throttle_ptr != NULL) {
const Vector<Vector<int> >& message_counts = throttle_ptr->getCounters();
for (int int_type=0; int_type<MessageSizeType_NUM; int_type++) {
MessageSizeType type = MessageSizeType(int_type);
int sum = message_counts[type].sum();
if (sum != 0) {
out << " outgoing_messages_switch_" << m_switch_id << "_link_" << link << "_" << type
<< ": " << sum << " " << sum * (RubySystem::getNetwork()->MessageSizeType_to_int(type))
<< " " << message_counts[type] << " base_latency: " << throttle_ptr->getLatency() << endl;
} }
} intermediateBuffers.insertAtBottom(buffer_ptr);
} m_buffers_to_free.insertAtBottom(buffer_ptr);
} }
out << endl;
// Hook the queues to the PerfectSwitch
m_perfect_switch_ptr->addOutPort(intermediateBuffers, routing_table_entry);
// Hook the queues to the Throttle
throttle_ptr->addLinks(intermediateBuffers, out);
} }
void Switch::clearStats() void
Switch::clearRoutingTables()
{ {
m_perfect_switch_ptr->clearStats(); m_perfect_switch_ptr->clearRoutingTables();
for (int i=0; i<m_throttles.size(); i++) { }
if (m_throttles[i] != NULL) {
m_throttles[i]->clearStats(); void
Switch::clearBuffers()
{
m_perfect_switch_ptr->clearBuffers();
for (int i = 0; i < m_throttles.size(); i++) {
if (m_throttles[i] != NULL) {
m_throttles[i]->clear();
}
} }
}
} }
void Switch::printConfig(std::ostream& out) const void
Switch::reconfigureOutPort(const NetDest& routing_table_entry)
{ {
m_perfect_switch_ptr->printConfig(out); m_perfect_switch_ptr->reconfigureOutPort(routing_table_entry);
for (int i=0; i<m_throttles.size(); i++) { }
if (m_throttles[i] != NULL) {
m_throttles[i]->printConfig(out); const Throttle*
Switch::getThrottle(LinkID link_number) const
{
assert(m_throttles[link_number] != NULL);
return m_throttles[link_number];
}
const Vector<Throttle*>*
Switch::getThrottles() const
{
return &m_throttles;
}
void
Switch::printStats(std::ostream& out) const
{
using namespace std;
ccprintf(out, "switch_%d_inlinks: %d\n", m_switch_id,
m_perfect_switch_ptr->getInLinks());
ccprintf(out, "switch_%d_outlinks: %d\n", m_switch_id,
m_perfect_switch_ptr->getOutLinks());
// Average link utilizations
double average_utilization = 0.0;
int throttle_count = 0;
for (int i = 0; i < m_throttles.size(); i++) {
Throttle* throttle_ptr = m_throttles[i];
if (throttle_ptr) {
average_utilization += throttle_ptr->getUtilization();
throttle_count++;
}
} }
} average_utilization =
throttle_count == 0 ? 0 : average_utilization / throttle_count;
// Individual link utilizations
out << "links_utilized_percent_switch_" << m_switch_id << ": "
<< average_utilization << endl;
for (int link = 0; link < m_throttles.size(); link++) {
Throttle* throttle_ptr = m_throttles[link];
if (throttle_ptr != NULL) {
out << " links_utilized_percent_switch_" << m_switch_id
<< "_link_" << link << ": "
<< throttle_ptr->getUtilization() << " bw: "
<< throttle_ptr->getLinkBandwidth()
<< " base_latency: " << throttle_ptr->getLatency() << endl;
}
}
out << endl;
// Traffic breakdown
for (int link = 0; link < m_throttles.size(); link++) {
Throttle* throttle_ptr = m_throttles[link];
if (!throttle_ptr)
continue;
const Vector<Vector<int> >& message_counts =
throttle_ptr->getCounters();
for (int int_type = 0; int_type < MessageSizeType_NUM; int_type++) {
MessageSizeType type = MessageSizeType(int_type);
int sum = message_counts[type].sum();
if (sum == 0)
continue;
out << " outgoing_messages_switch_" << m_switch_id
<< "_link_" << link << "_" << type << ": " << sum << " "
<< sum * RubySystem::getNetwork()->MessageSizeType_to_int(type)
<< " " << message_counts[type] << " base_latency: "
<< throttle_ptr->getLatency() << endl;
}
}
out << endl;
} }
void Switch::print(std::ostream& out) const void
Switch::clearStats()
{ {
// FIXME printing m_perfect_switch_ptr->clearStats();
out << "[Switch]"; for (int i = 0; i < m_throttles.size(); i++) {
if (m_throttles[i] != NULL)
m_throttles[i]->clearStats();
}
}
void
Switch::printConfig(std::ostream& out) const
{
m_perfect_switch_ptr->printConfig(out);
for (int i = 0; i < m_throttles.size(); i++) {
if (m_throttles[i] != NULL)
m_throttles[i]->printConfig(out);
}
}
void
Switch::print(std::ostream& out) const
{
// FIXME printing
out << "[Switch]";
} }

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -28,26 +27,22 @@
*/ */
/* /*
* $Id$ * The actual modelled switch. It use the perfect switch and a
* * Throttle object to control and bandwidth and timing *only for the
* Description: The actual modelled switch. It use the perfect switch and a * output port*. So here we have un-realistic modelling, since the
* Throttle object to control and bandwidth and timing *only for * order of PerfectSwitch and Throttle objects get woke up affect the
* the output port*. So here we have un-realistic modelling, * message timing. A more accurate model would be having two set of
* since the order of PerfectSwitch and Throttle objects get * system states, one for this cycle, one for next cycle. And on the
* woke up affect the message timing. A more accurate model would * cycle boundary swap the two set of states.
* be having two set of system states, one for this cycle, one for
* next cycle. And on the cycle boundary swap the two set of
* states.
*
*/ */
#ifndef Switch_H #ifndef __MEM_RUBY_NETWORK_SIMPLE_SWITCH_HH__
#define Switch_H #define __MEM_RUBY_NETWORK_SIMPLE_SWITCH_HH__
#include <iostream> #include <iostream>
#include "mem/ruby/common/Global.hh"
#include "mem/gems_common/Vector.hh" #include "mem/gems_common/Vector.hh"
#include "mem/ruby/common/Global.hh"
class MessageBuffer; class MessageBuffer;
class PerfectSwitch; class PerfectSwitch;
@ -56,54 +51,46 @@ class SimpleNetwork;
class Throttle; class Throttle;
class Network; class Network;
class Switch { class Switch
public: {
// Constructors public:
Switch(SwitchID sid, SimpleNetwork* network_ptr);
~Switch();
// constructor specifying the number of ports void addInPort(const Vector<MessageBuffer*>& in);
Switch(SwitchID sid, SimpleNetwork* network_ptr); void addOutPort(const Vector<MessageBuffer*>& out,
void addInPort(const Vector<MessageBuffer*>& in); const NetDest& routing_table_entry, int link_latency,
void addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routing_table_entry, int link_latency, int bw_multiplier); int bw_multiplier);
const Throttle* getThrottle(LinkID link_number) const; const Throttle* getThrottle(LinkID link_number) const;
const Vector<Throttle*>* getThrottles() const; const Vector<Throttle*>* getThrottles() const;
void clearRoutingTables(); void clearRoutingTables();
void clearBuffers(); void clearBuffers();
void reconfigureOutPort(const NetDest& routing_table_entry); void reconfigureOutPort(const NetDest& routing_table_entry);
void printStats(std::ostream& out) const; void printStats(std::ostream& out) const;
void clearStats(); void clearStats();
void printConfig(std::ostream& out) const; void printConfig(std::ostream& out) const;
// Destructor void print(std::ostream& out) const;
~Switch();
void print(std::ostream& out) const; private:
private: // Private copy constructor and assignment operator
Switch(const Switch& obj);
Switch& operator=(const Switch& obj);
// Private copy constructor and assignment operator PerfectSwitch* m_perfect_switch_ptr;
Switch(const Switch& obj); Network* m_network_ptr;
Switch& operator=(const Switch& obj); Vector<Throttle*> m_throttles;
Vector<MessageBuffer*> m_buffers_to_free;
// Data Members (m_ prefix) SwitchID m_switch_id;
PerfectSwitch* m_perfect_switch_ptr;
Network* m_network_ptr;
Vector<Throttle*> m_throttles;
Vector<MessageBuffer*> m_buffers_to_free;
SwitchID m_switch_id;
}; };
// Output operator declaration inline std::ostream&
std::ostream& operator<<(std::ostream& out, const Switch& obj); operator<<(std::ostream& out, const Switch& obj)
// ******************* Definitions *******************
// Output operator definition
extern inline
std::ostream& operator<<(std::ostream& out, const Switch& obj)
{ {
obj.print(out); obj.print(out);
out << std::flush; out << std::flush;
return out; return out;
} }
#endif //Switch_H #endif // __MEM_RUBY_NETWORK_SIMPLE_SWITCH_HH__

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -27,19 +26,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/* #include "base/cprintf.hh"
* $Id$ #include "mem/protocol/Protocol.hh"
*
* Description: see Throttle.hh
*
*/
#include "mem/ruby/network/simple/Throttle.hh"
#include "mem/ruby/buffers/MessageBuffer.hh" #include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/network/Network.hh" #include "mem/ruby/network/Network.hh"
#include "mem/ruby/system/System.hh" #include "mem/ruby/network/simple/Throttle.hh"
#include "mem/ruby/slicc_interface/NetworkMessage.hh" #include "mem/ruby/slicc_interface/NetworkMessage.hh"
#include "mem/protocol/Protocol.hh" #include "mem/ruby/system/System.hh"
const int HIGH_RANGE = 256; const int HIGH_RANGE = 256;
const int ADJUST_INTERVAL = 50000; const int ADJUST_INTERVAL = 50000;
@ -50,200 +43,232 @@ const int PRIORITY_SWITCH_LIMIT = 128;
static int network_message_to_size(NetworkMessage* net_msg_ptr); static int network_message_to_size(NetworkMessage* net_msg_ptr);
extern std::ostream * debug_cout_ptr; extern std::ostream *debug_cout_ptr;
Throttle::Throttle(int sID, NodeID node, int link_latency, int link_bandwidth_multiplier) Throttle::Throttle(int sID, NodeID node, int link_latency,
int link_bandwidth_multiplier)
{ {
init(node, link_latency, link_bandwidth_multiplier); init(node, link_latency, link_bandwidth_multiplier);
m_sID = sID; m_sID = sID;
} }
Throttle::Throttle(NodeID node, int link_latency, int link_bandwidth_multiplier) Throttle::Throttle(NodeID node, int link_latency,
int link_bandwidth_multiplier)
{ {
init(node, link_latency, link_bandwidth_multiplier); init(node, link_latency, link_bandwidth_multiplier);
m_sID = 0; m_sID = 0;
} }
void Throttle::init(NodeID node, int link_latency, int link_bandwidth_multiplier) void
Throttle::init(NodeID node, int link_latency, int link_bandwidth_multiplier)
{ {
m_node = node; m_node = node;
m_vnets = 0; m_vnets = 0;
ASSERT(link_bandwidth_multiplier > 0); ASSERT(link_bandwidth_multiplier > 0);
m_link_bandwidth_multiplier = link_bandwidth_multiplier; m_link_bandwidth_multiplier = link_bandwidth_multiplier;
m_link_latency = link_latency; m_link_latency = link_latency;
m_wakeups_wo_switch = 0;
clearStats();
}
void Throttle::clear()
{
for (int counter = 0; counter < m_vnets; counter++) {
m_in[counter]->clear();
m_out[counter]->clear();
}
}
void Throttle::addLinks(const Vector<MessageBuffer*>& in_vec, const Vector<MessageBuffer*>& out_vec)
{
assert(in_vec.size() == out_vec.size());
for (int i=0; i<in_vec.size(); i++) {
addVirtualNetwork(in_vec[i], out_vec[i]);
}
m_message_counters.setSize(MessageSizeType_NUM);
for (int i=0; i<MessageSizeType_NUM; i++) {
m_message_counters[i].setSize(in_vec.size());
for (int j=0; j<m_message_counters[i].size(); j++) {
m_message_counters[i][j] = 0;
}
}
}
void Throttle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr)
{
m_units_remaining.insertAtBottom(0);
m_in.insertAtBottom(in_ptr);
m_out.insertAtBottom(out_ptr);
// Set consumer and description
m_in[m_vnets]->setConsumer(this);
string desc = "[Queue to Throttle " + NodeIDToString(m_sID) + " " + NodeIDToString(m_node) + "]";
m_in[m_vnets]->setDescription(desc);
m_vnets++;
}
void Throttle::wakeup()
{
// Limits the number of message sent to a limited number of bytes/cycle.
assert(getLinkBandwidth() > 0);
int bw_remaining = getLinkBandwidth();
// Give the highest numbered link priority most of the time
m_wakeups_wo_switch++;
int highest_prio_vnet = m_vnets-1;
int lowest_prio_vnet = 0;
int counter = 1;
bool schedule_wakeup = false;
// invert priorities to avoid starvation seen in the component network
if (m_wakeups_wo_switch > PRIORITY_SWITCH_LIMIT) {
m_wakeups_wo_switch = 0; m_wakeups_wo_switch = 0;
highest_prio_vnet = 0; clearStats();
lowest_prio_vnet = m_vnets-1; }
counter = -1;
}
for (int vnet = highest_prio_vnet; (vnet*counter) >= (counter*lowest_prio_vnet); vnet -= counter) { void
Throttle::clear()
{
for (int counter = 0; counter < m_vnets; counter++) {
m_in[counter]->clear();
m_out[counter]->clear();
}
}
assert(m_out[vnet] != NULL); void
assert(m_in[vnet] != NULL); Throttle::addLinks(const Vector<MessageBuffer*>& in_vec,
assert(m_units_remaining[vnet] >= 0); const Vector<MessageBuffer*>& out_vec)
{
while ((bw_remaining > 0) && ((m_in[vnet]->isReady()) || (m_units_remaining[vnet] > 0)) && m_out[vnet]->areNSlotsAvailable(1)) { assert(in_vec.size() == out_vec.size());
for (int i=0; i<in_vec.size(); i++) {
// See if we are done transferring the previous message on this virtual network addVirtualNetwork(in_vec[i], out_vec[i]);
if (m_units_remaining[vnet] == 0 && m_in[vnet]->isReady()) {
// Find the size of the message we are moving
MsgPtr msg_ptr = m_in[vnet]->peekMsgPtr();
NetworkMessage* net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref());
m_units_remaining[vnet] += network_message_to_size(net_msg_ptr);
DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
DEBUG_MSG(NETWORK_COMP,HighPrio,"throttle: " + int_to_string(m_node)
+ " my bw " + int_to_string(getLinkBandwidth())
+ " bw spent enqueueing net msg " + int_to_string(m_units_remaining[vnet])
+ " time: " + int_to_string(g_eventQueue_ptr->getTime()) + ".");
// Move the message
m_out[vnet]->enqueue(m_in[vnet]->peekMsgPtr(), m_link_latency);
m_in[vnet]->pop();
// Count the message
m_message_counters[net_msg_ptr->getMessageSize()][vnet]++;
DEBUG_MSG(NETWORK_COMP,LowPrio,*m_out[vnet]);
DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
}
// Calculate the amount of bandwidth we spent on this message
int diff = m_units_remaining[vnet] - bw_remaining;
m_units_remaining[vnet] = max(0, diff);
bw_remaining = max(0, -diff);
} }
if ((bw_remaining > 0) && ((m_in[vnet]->isReady()) || (m_units_remaining[vnet] > 0)) && !m_out[vnet]->areNSlotsAvailable(1)) { m_message_counters.setSize(MessageSizeType_NUM);
DEBUG_MSG(NETWORK_COMP,LowPrio,vnet); for (int i = 0; i < MessageSizeType_NUM; i++) {
schedule_wakeup = true; // schedule me to wakeup again because I'm waiting for my output queue to become available m_message_counters[i].setSize(in_vec.size());
for (int j = 0; j<m_message_counters[i].size(); j++) {
m_message_counters[i][j] = 0;
}
} }
}
// We should only wake up when we use the bandwidth
// assert(bw_remaining != getLinkBandwidth()); // This is only mostly true
// Record that we used some or all of the link bandwidth this cycle
double ratio = 1.0-(double(bw_remaining)/double(getLinkBandwidth()));
// If ratio = 0, we used no bandwidth, if ratio = 1, we used all
linkUtilized(ratio);
if ((bw_remaining > 0) && !schedule_wakeup) {
// We have extra bandwidth and our output buffer was available, so we must not have anything else to do until another message arrives.
DEBUG_MSG(NETWORK_COMP,LowPrio,*this);
DEBUG_MSG(NETWORK_COMP,LowPrio,"not scheduled again");
} else {
DEBUG_MSG(NETWORK_COMP,LowPrio,*this);
DEBUG_MSG(NETWORK_COMP,LowPrio,"scheduled again");
// We are out of bandwidth for this cycle, so wakeup next cycle and continue
g_eventQueue_ptr->scheduleEvent(this, 1);
}
} }
void Throttle::printStats(ostream& out) const void
Throttle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr)
{ {
out << "utilized_percent: " << getUtilization() << endl; m_units_remaining.insertAtBottom(0);
m_in.insertAtBottom(in_ptr);
m_out.insertAtBottom(out_ptr);
// Set consumer and description
m_in[m_vnets]->setConsumer(this);
string desc = "[Queue to Throttle " + NodeIDToString(m_sID) + " " +
NodeIDToString(m_node) + "]";
m_in[m_vnets]->setDescription(desc);
m_vnets++;
} }
void Throttle::clearStats() void
Throttle::wakeup()
{ {
m_ruby_start = g_eventQueue_ptr->getTime(); // Limits the number of message sent to a limited number of bytes/cycle.
m_links_utilized = 0.0; assert(getLinkBandwidth() > 0);
int bw_remaining = getLinkBandwidth();
for (int i=0; i<m_message_counters.size(); i++) { // Give the highest numbered link priority most of the time
for (int j=0; j<m_message_counters[i].size(); j++) { m_wakeups_wo_switch++;
m_message_counters[i][j] = 0; int highest_prio_vnet = m_vnets-1;
int lowest_prio_vnet = 0;
int counter = 1;
bool schedule_wakeup = false;
// invert priorities to avoid starvation seen in the component network
if (m_wakeups_wo_switch > PRIORITY_SWITCH_LIMIT) {
m_wakeups_wo_switch = 0;
highest_prio_vnet = 0;
lowest_prio_vnet = m_vnets-1;
counter = -1;
} }
}
}
void Throttle::printConfig(ostream& out) const for (int vnet = highest_prio_vnet;
{ (vnet * counter) >= (counter * lowest_prio_vnet);
vnet -= counter) {
} assert(m_out[vnet] != NULL);
assert(m_in[vnet] != NULL);
assert(m_units_remaining[vnet] >= 0);
double Throttle::getUtilization() const while (bw_remaining > 0 &&
{ (m_in[vnet]->isReady() || m_units_remaining[vnet] > 0) &&
return (100.0 * double(m_links_utilized)) / (double(g_eventQueue_ptr->getTime()-m_ruby_start)); m_out[vnet]->areNSlotsAvailable(1)) {
}
void Throttle::print(ostream& out) const // See if we are done transferring the previous message on
{ // this virtual network
out << "[Throttle: " << m_sID << " " << m_node << " bw: " << getLinkBandwidth() << "]"; if (m_units_remaining[vnet] == 0 && m_in[vnet]->isReady()) {
} // Find the size of the message we are moving
MsgPtr msg_ptr = m_in[vnet]->peekMsgPtr();
NetworkMessage* net_msg_ptr =
safe_cast<NetworkMessage*>(msg_ptr.ref());
m_units_remaining[vnet] +=
network_message_to_size(net_msg_ptr);
// Helper function DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
DEBUG_MSG(NETWORK_COMP, HighPrio,
csprintf("throttle: %d my bw %d bw spent enqueueing "
"net msg %d time: %d.",
m_node, getLinkBandwidth(), m_units_remaining[vnet],
g_eventQueue_ptr->getTime()));
static // Move the message
int network_message_to_size(NetworkMessage* net_msg_ptr) m_out[vnet]->enqueue(m_in[vnet]->peekMsgPtr(), m_link_latency);
{ m_in[vnet]->pop();
assert(net_msg_ptr != NULL);
// Artificially increase the size of broadcast messages // Count the message
if (BROADCAST_SCALING > 1) { m_message_counters[net_msg_ptr->getMessageSize()][vnet]++;
if (net_msg_ptr->getDestination().isBroadcast()) {
return (RubySystem::getNetwork()->MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER * BROADCAST_SCALING); DEBUG_MSG(NETWORK_COMP,LowPrio,*m_out[vnet]);
DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
}
// Calculate the amount of bandwidth we spent on this message
int diff = m_units_remaining[vnet] - bw_remaining;
m_units_remaining[vnet] = max(0, diff);
bw_remaining = max(0, -diff);
}
if (bw_remaining > 0 &&
(m_in[vnet]->isReady() || m_units_remaining[vnet] > 0) &&
!m_out[vnet]->areNSlotsAvailable(1)) {
DEBUG_MSG(NETWORK_COMP,LowPrio,vnet);
// schedule me to wakeup again because I'm waiting for my
// output queue to become available
schedule_wakeup = true;
}
}
// We should only wake up when we use the bandwidth
// This is only mostly true
// assert(bw_remaining != getLinkBandwidth());
// Record that we used some or all of the link bandwidth this cycle
double ratio = 1.0 - (double(bw_remaining) / double(getLinkBandwidth()));
// If ratio = 0, we used no bandwidth, if ratio = 1, we used all
linkUtilized(ratio);
if (bw_remaining > 0 && !schedule_wakeup) {
// We have extra bandwidth and our output buffer was
// available, so we must not have anything else to do until
// another message arrives.
DEBUG_MSG(NETWORK_COMP, LowPrio, *this);
DEBUG_MSG(NETWORK_COMP, LowPrio, "not scheduled again");
} else {
DEBUG_MSG(NETWORK_COMP, LowPrio, *this);
DEBUG_MSG(NETWORK_COMP, LowPrio, "scheduled again");
// We are out of bandwidth for this cycle, so wakeup next
// cycle and continue
g_eventQueue_ptr->scheduleEvent(this, 1);
} }
} }
return (RubySystem::getNetwork()->MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER);
void
Throttle::printStats(ostream& out) const
{
out << "utilized_percent: " << getUtilization() << endl;
}
void
Throttle::clearStats()
{
m_ruby_start = g_eventQueue_ptr->getTime();
m_links_utilized = 0.0;
for (int i = 0; i < m_message_counters.size(); i++) {
for (int j = 0; j < m_message_counters[i].size(); j++) {
m_message_counters[i][j] = 0;
}
}
}
void
Throttle::printConfig(ostream& out) const
{
}
double
Throttle::getUtilization() const
{
return 100.0 * double(m_links_utilized) /
double(g_eventQueue_ptr->getTime()-m_ruby_start);
}
void
Throttle::print(ostream& out) const
{
out << "[Throttle: " << m_sID << " " << m_node
<< " bw: " << getLinkBandwidth() << "]";
}
int
network_message_to_size(NetworkMessage* net_msg_ptr)
{
assert(net_msg_ptr != NULL);
int size = RubySystem::getNetwork()->
MessageSizeType_to_int(net_msg_ptr->getMessageSize());
size *= MESSAGE_SIZE_MULTIPLIER;
// Artificially increase the size of broadcast messages
if (BROADCAST_SCALING > 1 && net_msg_ptr->getDestination().isBroadcast())
size *= BROADCAST_SCALING;
return size;
} }

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -28,94 +27,92 @@
*/ */
/* /*
* $Id$ * The class to implement bandwidth and latency throttle. An instance
* * of consumer class that can be woke up. It is only used to control
* Description: The class to implement bandwidth and latency throttle. An * bandwidth at output port of a switch. And the throttle is added
* instance of consumer class that can be woke up. It is only used * *after* the output port, means the message is put in the output
* to control bandwidth at output port of a switch. And the * port of the PerfectSwitch (a intermediateBuffers) first, then go
* throttle is added *after* the output port, means the message is * through the Throttle.
* put in the output port of the PerfectSwitch (a
* intermediateBuffers) first, then go through the Throttle.
*
*/ */
#ifndef THROTTLE_H #ifndef __MEM_RUBY_NETWORK_SIMPLE_THROTTLE_HH__
#define THROTTLE_H #define __MEM_RUBY_NETWORK_SIMPLE_THROTTLE_HH__
#include "mem/ruby/common/Global.hh"
#include "mem/gems_common/Vector.hh" #include "mem/gems_common/Vector.hh"
#include "mem/ruby/common/Consumer.hh" #include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/system/NodeID.hh" #include "mem/ruby/system/NodeID.hh"
#include "mem/ruby/system/System.hh" #include "mem/ruby/system/System.hh"
#include "mem/ruby/network/Network.hh"
class MessageBuffer; class MessageBuffer;
class Throttle : public Consumer { class Throttle : public Consumer
public: {
// Constructors public:
Throttle(int sID, NodeID node, int link_latency, int link_bandwidth_multiplier); Throttle(int sID, NodeID node, int link_latency,
Throttle(NodeID node, int link_latency, int link_bandwidth_multiplier); int link_bandwidth_multiplier);
Throttle(NodeID node, int link_latency, int link_bandwidth_multiplier);
~Throttle() {}
// Destructor void addLinks(const Vector<MessageBuffer*>& in_vec,
~Throttle() {} const Vector<MessageBuffer*>& out_vec);
void wakeup();
// Public Methods void printStats(ostream& out) const;
void addLinks(const Vector<MessageBuffer*>& in_vec, const Vector<MessageBuffer*>& out_vec); void clearStats();
void wakeup(); void printConfig(ostream& out) const;
// The average utilization (a percent) since last clearStats()
double getUtilization() const;
int
getLinkBandwidth() const
{
return RubySystem::getNetwork()->getEndpointBandwidth() *
m_link_bandwidth_multiplier;
}
int getLatency() const { return m_link_latency; }
void printStats(ostream& out) const; const Vector<Vector<int> >&
void clearStats(); getCounters() const
void printConfig(ostream& out) const; {
double getUtilization() const; // The average utilization (a percent) since last clearStats() return m_message_counters;
int getLinkBandwidth() const { return RubySystem::getNetwork()->getEndpointBandwidth() * m_link_bandwidth_multiplier; } }
int getLatency() const { return m_link_latency; }
const Vector<Vector<int> >& getCounters() const { return m_message_counters; } void clear();
void clear(); void print(ostream& out) const;
void print(ostream& out) const; private:
void init(NodeID node, int link_latency, int link_bandwidth_multiplier);
void addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr);
void linkUtilized(double ratio) { m_links_utilized += ratio; }
private: // Private copy constructor and assignment operator
// Private Methods Throttle(const Throttle& obj);
void init(NodeID node, int link_latency, int link_bandwidth_multiplier); Throttle& operator=(const Throttle& obj);
void addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr);
void linkUtilized(double ratio) { m_links_utilized += ratio; }
// Private copy constructor and assignment operator Vector<MessageBuffer*> m_in;
Throttle(const Throttle& obj); Vector<MessageBuffer*> m_out;
Throttle& operator=(const Throttle& obj); Vector<Vector<int> > m_message_counters;
int m_vnets;
Vector<int> m_units_remaining;
int m_sID;
NodeID m_node;
int m_link_bandwidth_multiplier;
int m_link_latency;
int m_wakeups_wo_switch;
// Data Members (m_ prefix) // For tracking utilization
Vector<MessageBuffer*> m_in; Time m_ruby_start;
Vector<MessageBuffer*> m_out; double m_links_utilized;
Vector<Vector<int> > m_message_counters;
int m_vnets;
Vector<int> m_units_remaining;
int m_sID;
NodeID m_node;
int m_link_bandwidth_multiplier;
int m_link_latency;
int m_wakeups_wo_switch;
// For tracking utilization
Time m_ruby_start;
double m_links_utilized;
}; };
// Output operator declaration inline ostream&
ostream& operator<<(ostream& out, const Throttle& obj); operator<<(ostream& out, const Throttle& obj)
// ******************* Definitions *******************
// Output operator definition
extern inline
ostream& operator<<(ostream& out, const Throttle& obj)
{ {
obj.print(out); obj.print(out);
out << flush; out << flush;
return out; return out;
} }
#endif //THROTTLE_H #endif // __MEM_RUBY_NETWORK_SIMPLE_THROTTLE_HH__

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -27,27 +26,18 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/*
* Topology.cc
*
* Description: See Topology.hh
*
* $Id$
*
* */
#include "mem/ruby/network/simple/Topology.hh"
#include "mem/ruby/common/NetDest.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "mem/protocol/TopologyType.hh"
#include "mem/gems_common/util.hh" #include "mem/gems_common/util.hh"
#include "mem/protocol/MachineType.hh" #include "mem/protocol/MachineType.hh"
#include "mem/protocol/Protocol.hh" #include "mem/protocol/Protocol.hh"
#include "mem/protocol/TopologyType.hh"
#include "mem/ruby/common/NetDest.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/network/simple/Topology.hh"
#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "mem/ruby/system/System.hh" #include "mem/ruby/system/System.hh"
static const int INFINITE_LATENCY = 10000; // Yes, this is a big hack const int INFINITE_LATENCY = 10000; // Yes, this is a big hack
static const int DEFAULT_BW_MULTIPLIER = 1; // Just to be consistent with above :) const int DEFAULT_BW_MULTIPLIER = 1; // Just to be consistent with above :)
// Note: In this file, we use the first 2*m_nodes SwitchIDs to // Note: In this file, we use the first 2*m_nodes SwitchIDs to
// represent the input and output endpoint links. These really are // represent the input and output endpoint links. These really are
@ -57,10 +47,14 @@ static const int DEFAULT_BW_MULTIPLIER = 1; // Just to be consistent with above
// of the network. // of the network.
// Helper functions based on chapter 29 of Cormen et al. // Helper functions based on chapter 29 of Cormen et al.
static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix& inter_switches); void extend_shortest_path(Matrix& current_dist, Matrix& latencies,
static Matrix shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches); Matrix& inter_switches);
static bool link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final, const Matrix& weights, const Matrix& dist); Matrix shortest_path(const Matrix& weights, Matrix& latencies,
static NetDest shortest_path_to_node(SwitchID src, SwitchID next, const Matrix& weights, const Matrix& dist); Matrix& inter_switches);
bool link_is_shortest_path_to_node(SwitchID src, SwitchID next,
SwitchID final, const Matrix& weights, const Matrix& dist);
NetDest shortest_path_to_node(SwitchID src, SwitchID next,
const Matrix& weights, const Matrix& dist);
Topology::Topology(const Params *p) Topology::Topology(const Params *p)
: SimObject(p) : SimObject(p)
@ -71,306 +65,356 @@ Topology::Topology(const Params *p)
m_component_latencies.setSize(0); m_component_latencies.setSize(0);
m_component_inter_switches.setSize(0); m_component_inter_switches.setSize(0);
//
// Total nodes/controllers in network // Total nodes/controllers in network
// Must make sure this is called after the State Machine constructors // Must make sure this is called after the State Machine constructors
//
m_nodes = MachineType_base_number(MachineType_NUM); m_nodes = MachineType_base_number(MachineType_NUM);
assert(m_nodes > 1); assert(m_nodes > 1);
if (m_nodes != params()->ext_links.size()) { if (m_nodes != params()->ext_links.size() &&
m_nodes != params()->ext_links.size()) {
fatal("m_nodes (%d) != ext_links vector length (%d)\n", fatal("m_nodes (%d) != ext_links vector length (%d)\n",
m_nodes != params()->ext_links.size()); m_nodes != params()->ext_links.size());
} }
// // First create the links between the endpoints (i.e. controllers)
// First create the links between the endpoints (i.e. controllers) and the // and the network.
// network. for (vector<ExtLink*>::const_iterator i = params()->ext_links.begin();
// i != params()->ext_links.end(); ++i) {
for (vector<ExtLink*>::const_iterator i = params()->ext_links.begin(); const ExtLinkParams *p = (*i)->params();
i != params()->ext_links.end(); ++i) AbstractController *c = p->ext_node;
{
const ExtLinkParams *p = (*i)->params();
AbstractController *c = p->ext_node;
// Store the controller pointers for later // Store the controller pointers for later
m_controller_vector.insertAtBottom(c); m_controller_vector.insertAtBottom(c);
int ext_idx1 = int ext_idx1 =
MachineType_base_number(c->getMachineType()) + c->getVersion(); MachineType_base_number(c->getMachineType()) + c->getVersion();
int ext_idx2 = ext_idx1 + m_nodes; int ext_idx2 = ext_idx1 + m_nodes;
int int_idx = p->int_node + 2*m_nodes; int int_idx = p->int_node + 2*m_nodes;
// create the links in both directions // create the links in both directions
addLink(ext_idx1, int_idx, p->latency, p->bw_multiplier, p->weight); addLink(ext_idx1, int_idx, p->latency, p->bw_multiplier, p->weight);
addLink(int_idx, ext_idx2, p->latency, p->bw_multiplier, p->weight); addLink(int_idx, ext_idx2, p->latency, p->bw_multiplier, p->weight);
} }
for (vector<IntLink*>::const_iterator i = params()->int_links.begin(); for (vector<IntLink*>::const_iterator i = params()->int_links.begin();
i != params()->int_links.end(); ++i) i != params()->int_links.end(); ++i) {
{ const IntLinkParams *p = (*i)->params();
const IntLinkParams *p = (*i)->params(); int a = p->node_a + 2*m_nodes;
int a = p->node_a + 2*m_nodes; int b = p->node_b + 2*m_nodes;
int b = p->node_b + 2*m_nodes;
// create the links in both directions // create the links in both directions
addLink(a, b, p->latency, p->bw_multiplier, p->weight); addLink(a, b, p->latency, p->bw_multiplier, p->weight);
addLink(b, a, p->latency, p->bw_multiplier, p->weight); addLink(b, a, p->latency, p->bw_multiplier, p->weight);
} }
} }
void Topology::initNetworkPtr(Network* net_ptr) void
Topology::initNetworkPtr(Network* net_ptr)
{ {
for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) {
{
m_controller_vector[cntrl]->initNetworkPtr(net_ptr); m_controller_vector[cntrl]->initNetworkPtr(net_ptr);
} }
} }
void
void Topology::createLinks(Network *net, bool isReconfiguration) Topology::createLinks(Network *net, bool isReconfiguration)
{ {
// Find maximum switchID // Find maximum switchID
SwitchID max_switch_id = 0;
SwitchID max_switch_id = 0; for (int i = 0; i < m_links_src_vector.size(); i++) {
for (int i=0; i<m_links_src_vector.size(); i++) { max_switch_id = max(max_switch_id, m_links_src_vector[i]);
max_switch_id = max(max_switch_id, m_links_src_vector[i]); max_switch_id = max(max_switch_id, m_links_dest_vector[i]);
max_switch_id = max(max_switch_id, m_links_dest_vector[i]);
}
// Initialize weight vector
Matrix topology_weights;
Matrix topology_latency;
Matrix topology_bw_multis;
int num_switches = max_switch_id+1;
topology_weights.setSize(num_switches);
topology_latency.setSize(num_switches);
topology_bw_multis.setSize(num_switches);
m_component_latencies.setSize(num_switches); // FIXME setting the size of a member variable here is a HACK!
m_component_inter_switches.setSize(num_switches); // FIXME setting the size of a member variable here is a HACK!
for(int i=0; i<topology_weights.size(); i++) {
topology_weights[i].setSize(num_switches);
topology_latency[i].setSize(num_switches);
topology_bw_multis[i].setSize(num_switches);
m_component_latencies[i].setSize(num_switches);
m_component_inter_switches[i].setSize(num_switches); // FIXME setting the size of a member variable here is a HACK!
for(int j=0; j<topology_weights[i].size(); j++) {
topology_weights[i][j] = INFINITE_LATENCY;
topology_latency[i][j] = -1; // initialize to an invalid value
topology_bw_multis[i][j] = -1; // initialize to an invalid value
m_component_latencies[i][j] = -1; // initialize to an invalid value
m_component_inter_switches[i][j] = 0; // initially assume direct connections / no intermediate switches between components
} }
}
// Set identity weights to zero // Initialize weight vector
for(int i=0; i<topology_weights.size(); i++) { Matrix topology_weights;
topology_weights[i][i] = 0; Matrix topology_latency;
} Matrix topology_bw_multis;
int num_switches = max_switch_id+1;
topology_weights.setSize(num_switches);
topology_latency.setSize(num_switches);
topology_bw_multis.setSize(num_switches);
// Fill in the topology weights and bandwidth multipliers // FIXME setting the size of a member variable here is a HACK!
for (int i=0; i<m_links_src_vector.size(); i++) { m_component_latencies.setSize(num_switches);
topology_weights[m_links_src_vector[i]][m_links_dest_vector[i]] = m_links_weight_vector[i];
topology_latency[m_links_src_vector[i]][m_links_dest_vector[i]] = m_links_latency_vector[i];
m_component_latencies[m_links_src_vector[i]][m_links_dest_vector[i]] = m_links_latency_vector[i]; // initialize to latency vector
topology_bw_multis[m_links_src_vector[i]][m_links_dest_vector[i]] = m_bw_multiplier_vector[i];
}
// Walk topology and hookup the links // FIXME setting the size of a member variable here is a HACK!
Matrix dist = shortest_path(topology_weights, m_component_latencies, m_component_inter_switches); m_component_inter_switches.setSize(num_switches);
for(int i=0; i<topology_weights.size(); i++) {
for(int j=0; j<topology_weights[i].size(); j++) { for (int i = 0; i < topology_weights.size(); i++) {
int weight = topology_weights[i][j]; topology_weights[i].setSize(num_switches);
int bw_multiplier = topology_bw_multis[i][j]; topology_latency[i].setSize(num_switches);
int latency = topology_latency[i][j]; topology_bw_multis[i].setSize(num_switches);
if (weight > 0 && weight != INFINITE_LATENCY) { m_component_latencies[i].setSize(num_switches);
NetDest destination_set = shortest_path_to_node(i, j, topology_weights, dist);
assert(latency != -1); // FIXME setting the size of a member variable here is a HACK!
makeLink(net, i, j, destination_set, latency, weight, bw_multiplier, isReconfiguration); m_component_inter_switches[i].setSize(num_switches);
}
for (int j = 0; j < topology_weights[i].size(); j++) {
topology_weights[i][j] = INFINITE_LATENCY;
// initialize to invalid values
topology_latency[i][j] = -1;
topology_bw_multis[i][j] = -1;
m_component_latencies[i][j] = -1;
// initially assume direct connections / no intermediate
// switches between components
m_component_inter_switches[i][j] = 0;
}
}
// Set identity weights to zero
for (int i = 0; i < topology_weights.size(); i++) {
topology_weights[i][i] = 0;
}
// Fill in the topology weights and bandwidth multipliers
for (int i = 0; i < m_links_src_vector.size(); i++) {
int src = m_links_src_vector[i];
int dst = m_links_dest_vector[i];
topology_weights[src][dst] = m_links_weight_vector[i];
topology_latency[src][dst] = m_links_latency_vector[i];
m_component_latencies[src][dst] = m_links_latency_vector[i];
topology_bw_multis[src][dst] = m_bw_multiplier_vector[i];
}
// Walk topology and hookup the links
Matrix dist = shortest_path(topology_weights, m_component_latencies,
m_component_inter_switches);
for (int i = 0; i < topology_weights.size(); i++) {
for (int j = 0; j < topology_weights[i].size(); j++) {
int weight = topology_weights[i][j];
int bw_multiplier = topology_bw_multis[i][j];
int latency = topology_latency[i][j];
if (weight > 0 && weight != INFINITE_LATENCY) {
NetDest destination_set = shortest_path_to_node(i, j,
topology_weights, dist);
assert(latency != -1);
makeLink(net, i, j, destination_set, latency, weight,
bw_multiplier, isReconfiguration);
}
}
} }
}
} }
SwitchID Topology::newSwitchID() SwitchID
Topology::newSwitchID()
{ {
m_number_of_switches++; m_number_of_switches++;
return m_number_of_switches-1+m_nodes+m_nodes; return m_number_of_switches-1+m_nodes+m_nodes;
} }
void Topology::addLink(SwitchID src, SwitchID dest, int link_latency) void
Topology::addLink(SwitchID src, SwitchID dest, int link_latency)
{ {
addLink(src, dest, link_latency, DEFAULT_BW_MULTIPLIER, link_latency); addLink(src, dest, link_latency, DEFAULT_BW_MULTIPLIER, link_latency);
} }
void Topology::addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier) void
Topology::addLink(SwitchID src, SwitchID dest, int link_latency,
int bw_multiplier)
{ {
addLink(src, dest, link_latency, bw_multiplier, link_latency); addLink(src, dest, link_latency, bw_multiplier, link_latency);
} }
void Topology::addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier, int link_weight) void
Topology::addLink(SwitchID src, SwitchID dest, int link_latency,
int bw_multiplier, int link_weight)
{ {
ASSERT(src <= m_number_of_switches+m_nodes+m_nodes); ASSERT(src <= m_number_of_switches+m_nodes+m_nodes);
ASSERT(dest <= m_number_of_switches+m_nodes+m_nodes); ASSERT(dest <= m_number_of_switches+m_nodes+m_nodes);
m_links_src_vector.insertAtBottom(src); m_links_src_vector.insertAtBottom(src);
m_links_dest_vector.insertAtBottom(dest); m_links_dest_vector.insertAtBottom(dest);
m_links_latency_vector.insertAtBottom(link_latency); m_links_latency_vector.insertAtBottom(link_latency);
m_links_weight_vector.insertAtBottom(link_weight); m_links_weight_vector.insertAtBottom(link_weight);
m_bw_multiplier_vector.insertAtBottom(bw_multiplier); m_bw_multiplier_vector.insertAtBottom(bw_multiplier);
} }
void Topology::makeLink(Network *net, SwitchID src, SwitchID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration) void
Topology::makeLink(Network *net, SwitchID src, SwitchID dest,
const NetDest& routing_table_entry, int link_latency, int link_weight,
int bw_multiplier, bool isReconfiguration)
{ {
// Make sure we're not trying to connect two end-point nodes directly together // Make sure we're not trying to connect two end-point nodes
assert((src >= 2*m_nodes) || (dest >= 2*m_nodes)); // directly together
assert(src >= 2 * m_nodes || dest >= 2 * m_nodes);
if (src < m_nodes) { if (src < m_nodes) {
net->makeInLink(src, dest-(2*m_nodes), routing_table_entry, link_latency, bw_multiplier, isReconfiguration); net->makeInLink(src, dest-(2*m_nodes), routing_table_entry,
} else if (dest < 2*m_nodes) { link_latency, bw_multiplier, isReconfiguration);
assert(dest >= m_nodes); } else if (dest < 2*m_nodes) {
NodeID node = dest-m_nodes; assert(dest >= m_nodes);
net->makeOutLink(src-(2*m_nodes), node, routing_table_entry, link_latency, link_weight, bw_multiplier, isReconfiguration); NodeID node = dest-m_nodes;
} else { net->makeOutLink(src-(2*m_nodes), node, routing_table_entry,
assert((src >= 2*m_nodes) && (dest >= 2*m_nodes)); link_latency, link_weight, bw_multiplier, isReconfiguration);
net->makeInternalLink(src-(2*m_nodes), dest-(2*m_nodes), routing_table_entry, link_latency, link_weight, bw_multiplier, isReconfiguration); } else {
} assert((src >= 2*m_nodes) && (dest >= 2*m_nodes));
net->makeInternalLink(src-(2*m_nodes), dest-(2*m_nodes),
routing_table_entry, link_latency, link_weight, bw_multiplier,
isReconfiguration);
}
} }
void Topology::printStats(std::ostream& out) const void
Topology::printStats(std::ostream& out) const
{ {
for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) { for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) {
m_controller_vector[cntrl]->printStats(out); m_controller_vector[cntrl]->printStats(out);
} }
} }
void Topology::clearStats() void
Topology::clearStats()
{ {
for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) { for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) {
m_controller_vector[cntrl]->clearStats(); m_controller_vector[cntrl]->clearStats();
} }
} }
void Topology::printConfig(std::ostream& out) const void
Topology::printConfig(std::ostream& out) const
{ {
using namespace std; using namespace std;
if (m_print_config == false) return; if (m_print_config == false)
return;
assert(m_component_latencies.size() > 0); assert(m_component_latencies.size() > 0);
out << "--- Begin Topology Print ---" << endl; out << "--- Begin Topology Print ---" << endl
out << endl; << endl
out << "Topology print ONLY indicates the _NETWORK_ latency between two machines" << endl; << "Topology print ONLY indicates the _NETWORK_ latency between two "
out << "It does NOT include the latency within the machines" << endl; << "machines" << endl
out << endl; << "It does NOT include the latency within the machines" << endl
for (int m=0; m<MachineType_NUM; m++) { << endl;
for (int i=0; i<MachineType_base_count((MachineType)m); i++) {
MachineID cur_mach = {(MachineType)m, i}; for (int m = 0; m < MachineType_NUM; m++) {
out << cur_mach << " Network Latencies" << endl; int i_end = MachineType_base_count((MachineType)m);
for (int n=0; n<MachineType_NUM; n++) { for (int i = 0; i < i_end; i++) {
for (int j=0; j<MachineType_base_count((MachineType)n); j++) { MachineID cur_mach = {(MachineType)m, i};
MachineID dest_mach = {(MachineType)n, j}; out << cur_mach << " Network Latencies" << endl;
if (cur_mach != dest_mach) { for (int n = 0; n < MachineType_NUM; n++) {
int link_latency = m_component_latencies[MachineType_base_number((MachineType)m)+i][MachineType_base_number(MachineType_NUM)+MachineType_base_number((MachineType)n)+j]; int j_end = MachineType_base_count((MachineType)n);
int intermediate_switches = m_component_inter_switches[MachineType_base_number((MachineType)m)+i][MachineType_base_number(MachineType_NUM)+MachineType_base_number((MachineType)n)+j]; for (int j = 0; j < j_end; j++) {
out << " " << cur_mach << " -> " << dest_mach << " net_lat: " MachineID dest_mach = {(MachineType)n, j};
<< link_latency+intermediate_switches << endl; // NOTE switches are assumed to have single cycle latency if (cur_mach == dest_mach)
} continue;
int src = MachineType_base_number((MachineType)m) + i;
int dst = MachineType_base_number(MachineType_NUM) +
MachineType_base_number((MachineType)n) + j;
int link_latency = m_component_latencies[src][dst];
int intermediate_switches =
m_component_inter_switches[src][dst];
// NOTE switches are assumed to have single
// cycle latency
out << " " << cur_mach << " -> " << dest_mach
<< " net_lat: "
<< link_latency + intermediate_switches << endl;
}
}
out << endl;
} }
}
out << endl;
} }
}
out << "--- End Topology Print ---" << endl; out << "--- End Topology Print ---" << endl;
} }
/**************************************************************************/
// The following all-pairs shortest path algorithm is based on the // The following all-pairs shortest path algorithm is based on the
// discussion from Cormen et al., Chapter 26.1. // discussion from Cormen et al., Chapter 26.1.
void
static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix& inter_switches) extend_shortest_path(Matrix& current_dist, Matrix& latencies,
Matrix& inter_switches)
{ {
bool change = true; bool change = true;
int nodes = current_dist.size(); int nodes = current_dist.size();
while (change) { while (change) {
change = false; change = false;
for (int i=0; i<nodes; i++) { for (int i = 0; i < nodes; i++) {
for (int j=0; j<nodes; j++) { for (int j = 0; j < nodes; j++) {
int minimum = current_dist[i][j]; int minimum = current_dist[i][j];
int previous_minimum = minimum; int previous_minimum = minimum;
int intermediate_switch = -1; int intermediate_switch = -1;
for (int k=0; k<nodes; k++) { for (int k = 0; k < nodes; k++) {
minimum = min(minimum, current_dist[i][k] + current_dist[k][j]); minimum = min(minimum,
if (previous_minimum != minimum) { current_dist[i][k] + current_dist[k][j]);
intermediate_switch = k; if (previous_minimum != minimum) {
inter_switches[i][j] = inter_switches[i][k] + inter_switches[k][j] + 1; intermediate_switch = k;
} inter_switches[i][j] =
previous_minimum = minimum; inter_switches[i][k] +
inter_switches[k][j] + 1;
}
previous_minimum = minimum;
}
if (current_dist[i][j] != minimum) {
change = true;
current_dist[i][j] = minimum;
assert(intermediate_switch >= 0);
assert(intermediate_switch < latencies[i].size());
latencies[i][j] = latencies[i][intermediate_switch] +
latencies[intermediate_switch][j];
}
}
} }
if (current_dist[i][j] != minimum) { }
change = true; }
current_dist[i][j] = minimum;
assert(intermediate_switch >= 0); Matrix
assert(intermediate_switch < latencies[i].size()); shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches)
latencies[i][j] = latencies[i][intermediate_switch] + latencies[intermediate_switch][j]; {
Matrix dist = weights;
extend_shortest_path(dist, latencies, inter_switches);
return dist;
}
bool
link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final,
const Matrix& weights, const Matrix& dist)
{
return weights[src][next] + dist[next][final] == dist[src][final];
}
NetDest
shortest_path_to_node(SwitchID src, SwitchID next, const Matrix& weights,
const Matrix& dist)
{
NetDest result;
int d = 0;
int machines;
int max_machines;
machines = MachineType_NUM;
max_machines = MachineType_base_number(MachineType_NUM);
for (int m = 0; m < machines; m++) {
for (int i = 0; i < MachineType_base_count((MachineType)m); i++) {
// we use "d+max_machines" below since the "destination"
// switches for the machines are numbered
// [MachineType_base_number(MachineType_NUM)...
// 2*MachineType_base_number(MachineType_NUM)-1] for the
// component network
if (link_is_shortest_path_to_node(src, next, d + max_machines,
weights, dist)) {
MachineID mach = {(MachineType)m, i};
result.add(mach);
}
d++;
} }
}
} }
}
}
static Matrix shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches) DEBUG_MSG(NETWORK_COMP, MedPrio, "returning shortest path");
{ DEBUG_EXPR(NETWORK_COMP, MedPrio, (src-(2*max_machines)));
Matrix dist = weights; DEBUG_EXPR(NETWORK_COMP, MedPrio, (next-(2*max_machines)));
extend_shortest_path(dist, latencies, inter_switches); DEBUG_EXPR(NETWORK_COMP, MedPrio, src);
return dist; DEBUG_EXPR(NETWORK_COMP, MedPrio, next);
} DEBUG_EXPR(NETWORK_COMP, MedPrio, result);
DEBUG_NEWLINE(NETWORK_COMP, MedPrio);
static bool link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final, return result;
const Matrix& weights, const Matrix& dist)
{
return (weights[src][next] + dist[next][final] == dist[src][final]);
}
static NetDest shortest_path_to_node(SwitchID src, SwitchID next,
const Matrix& weights, const Matrix& dist)
{
NetDest result;
int d = 0;
int machines;
int max_machines;
machines = MachineType_NUM;
max_machines = MachineType_base_number(MachineType_NUM);
for (int m=0; m<machines; m++) {
for (int i=0; i<MachineType_base_count((MachineType)m); i++) {
// we use "d+max_machines" below since the "destination" switches for the machines are numbered
// [MachineType_base_number(MachineType_NUM)...2*MachineType_base_number(MachineType_NUM)-1]
// for the component network
if (link_is_shortest_path_to_node(src, next,
d+max_machines,
weights, dist)) {
MachineID mach = {(MachineType)m, i};
result.add(mach);
}
d++;
}
}
DEBUG_MSG(NETWORK_COMP, MedPrio, "returning shortest path");
DEBUG_EXPR(NETWORK_COMP, MedPrio, (src-(2*max_machines)));
DEBUG_EXPR(NETWORK_COMP, MedPrio, (next-(2*max_machines)));
DEBUG_EXPR(NETWORK_COMP, MedPrio, src);
DEBUG_EXPR(NETWORK_COMP, MedPrio, next);
DEBUG_EXPR(NETWORK_COMP, MedPrio, result);
DEBUG_NEWLINE(NETWORK_COMP, MedPrio);
return result;
} }
Topology * Topology *

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -28,133 +27,121 @@
*/ */
/* /*
* Topology.hh * The topology here is configurable; it can be a hierachical (default
* * one) or a 2D torus or a 2D torus with half switches killed. I think
* Description: The topology here is configurable; it can be a hierachical * all input port has a one-input-one-output switch connected just to
* (default one) or a 2D torus or a 2D torus with half switches * control and bandwidth, since we don't control bandwidth on input
* killed. I think all input port has a * ports. Basically, the class has a vector of nodes and edges. First
* one-input-one-output switch connected just to control and * 2*m_nodes elements in the node vector are input and output
* bandwidth, since we don't control bandwidth on input ports. * ports. Edges are represented in two vectors of src and dest
* Basically, the class has a vector of nodes and edges. First * nodes. All edges have latency.
* 2*m_nodes elements in the node vector are input and output */
* ports. Edges are represented in two vectors of src and dest
* nodes. All edges have latency.
*
* $Id$
*
* */
#ifndef TOPOLOGY_H #ifndef __MEM_RUBY_NETWORK_SIMPLE_TOPOLOGY_HH__
#define TOPOLOGY_H #define __MEM_RUBY_NETWORK_SIMPLE_TOPOLOGY_HH__
#include <iostream> #include <iostream>
#include <string> #include <string>
#include "mem/ruby/common/Global.hh"
#include "mem/gems_common/Vector.hh" #include "mem/gems_common/Vector.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/system/NodeID.hh" #include "mem/ruby/system/NodeID.hh"
#include "sim/sim_object.hh"
#include "params/Topology.hh"
#include "params/Link.hh"
#include "params/ExtLink.hh" #include "params/ExtLink.hh"
#include "params/IntLink.hh" #include "params/IntLink.hh"
#include "params/Link.hh"
#include "params/Topology.hh"
#include "sim/sim_object.hh"
class Network; class Network;
class NetDest; class NetDest;
typedef Vector < Vector <int> > Matrix; typedef Vector<Vector<int> > Matrix;
class Link : public SimObject { class Link : public SimObject
{
public: public:
typedef LinkParams Params; typedef LinkParams Params;
Link(const Params *p) : SimObject(p) {} Link(const Params *p) : SimObject(p) {}
const Params *params() const { return (const Params *)_params; } const Params *params() const { return (const Params *)_params; }
}; };
class ExtLink : public Link
class ExtLink : public Link { {
public: public:
typedef ExtLinkParams Params; typedef ExtLinkParams Params;
ExtLink(const Params *p) : Link(p) {} ExtLink(const Params *p) : Link(p) {}
const Params *params() const { return (const Params *)_params; } const Params *params() const { return (const Params *)_params; }
}; };
class IntLink : public Link
class IntLink : public Link { {
public: public:
typedef IntLinkParams Params; typedef IntLinkParams Params;
IntLink(const Params *p) : Link(p) {} IntLink(const Params *p) : Link(p) {}
const Params *params() const { return (const Params *)_params; } const Params *params() const { return (const Params *)_params; }
}; };
class Topology : public SimObject
class Topology : public SimObject { {
public: public:
// Constructors
typedef TopologyParams Params; typedef TopologyParams Params;
Topology(const Params *p); Topology(const Params *p);
virtual ~Topology() {}
const Params *params() const { return (const Params *)_params; } const Params *params() const { return (const Params *)_params; }
// Destructor int numSwitches() const { return m_number_of_switches; }
virtual ~Topology() {} void createLinks(Network *net, bool isReconfiguration);
// Public Methods void initNetworkPtr(Network* net_ptr);
int numSwitches() const { return m_number_of_switches; }
void createLinks(Network *net, bool isReconfiguration);
void initNetworkPtr(Network* net_ptr); const std::string getName() { return m_name; }
void printStats(std::ostream& out) const;
void clearStats();
void printConfig(std::ostream& out) const;
void print(std::ostream& out) const { out << "[Topology]"; }
const std::string getName() { return m_name; } protected:
void printStats(std::ostream& out) const; SwitchID newSwitchID();
void clearStats(); void addLink(SwitchID src, SwitchID dest, int link_latency);
void printConfig(std::ostream& out) const; void addLink(SwitchID src, SwitchID dest, int link_latency,
void print(std::ostream& out) const { out << "[Topology]"; } int bw_multiplier);
void addLink(SwitchID src, SwitchID dest, int link_latency,
int bw_multiplier, int link_weight);
void makeLink(Network *net, SwitchID src, SwitchID dest,
const NetDest& routing_table_entry, int link_latency, int weight,
int bw_multiplier, bool isReconfiguration);
protected: //void makeSwitchesPerChip(Vector<Vector< SwitchID> > &nodePairs,
// Private Methods // Vector<int> &latencies, Vector<int> &bw_multis, int numberOfChips);
SwitchID newSwitchID();
void addLink(SwitchID src, SwitchID dest, int link_latency);
void addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier);
void addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier, int link_weight);
void makeLink(Network *net, SwitchID src, SwitchID dest, const NetDest& routing_table_entry, int link_latency, int weight, int bw_multiplier, bool isReconfiguration);
// void makeSwitchesPerChip(Vector< Vector < SwitchID > > &nodePairs, Vector<int> &latencies, Vector<int> &bw_multis, int numberOfChips); std::string getDesignStr();
// Private copy constructor and assignment operator
Topology(const Topology& obj);
Topology& operator=(const Topology& obj);
std::string getDesignStr(); std::string m_name;
// Private copy constructor and assignment operator bool m_print_config;
Topology(const Topology& obj); NodeID m_nodes;
Topology& operator=(const Topology& obj); int m_number_of_switches;
// Data Members (m_ prefix) Vector<AbstractController*> m_controller_vector;
std::string m_name;
bool m_print_config;
NodeID m_nodes;
int m_number_of_switches;
Vector<AbstractController*> m_controller_vector; Vector<SwitchID> m_links_src_vector;
Vector<SwitchID> m_links_dest_vector;
Vector<int> m_links_latency_vector;
Vector<int> m_links_weight_vector;
Vector<int> m_bw_multiplier_vector;
Vector<SwitchID> m_links_src_vector; Matrix m_component_latencies;
Vector<SwitchID> m_links_dest_vector; Matrix m_component_inter_switches;
Vector<int> m_links_latency_vector;
Vector<int> m_links_weight_vector;
Vector<int> m_bw_multiplier_vector;
Matrix m_component_latencies;
Matrix m_component_inter_switches;
}; };
// Output operator declaration inline std::ostream&
std::ostream& operator<<(std::ostream& out, const Topology& obj); operator<<(std::ostream& out, const Topology& obj)
// ******************* Definitions *******************
// Output operator definition
extern inline
std::ostream& operator<<(std::ostream& out, const Topology& obj)
{ {
obj.print(out); obj.print(out);
out << std::flush; out << std::flush;
return out; return out;
} }
#endif #endif // __MEM_RUBY_NETWORK_SIMPLE_TOPOLOGY_HH__

View file

@ -1,84 +0,0 @@
// 2D torus topology
void Torus2DTopology::construct()
{
Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file
Vector<int> latencies; // link latencies for each link extracted
Vector<int> bw_multis; // bw multipliers for each link extracted
Vector < SwitchID > nodes; // temporary buffer
nodes.setSize(2);
// number of inter-chip switches
int numberOfTorusSwitches = m_nodes/MachineType_base_level(MachineType_NUM);
// one switch per machine node grouping
Vector<SwitchID> torusSwitches;
for(int i=0; i<numberOfTorusSwitches; i++){
SwitchID new_switch = newSwitchID();
torusSwitches.insertAtBottom(new_switch);
}
makeSwitchesPerChip(nodePairs, latencies, bw_multis, numberOfTorusSwitches);
int lengthOfSide = (int)sqrt((double)numberOfTorusSwitches);
// Now connect the inter-chip torus links
int latency = m_network_ptr->getLinkLatency(); // external link latency
int bw_multiplier = 1; // external link bw multiplier of the global bandwidth
for(int i=0; i<numberOfTorusSwitches; i++){
nodes[0] = torusSwitches[i]; // current switch
// left
if(nodes[0]%lengthOfSide == 0){ // determine left neighbor
nodes[1] = nodes[0] - 1 + lengthOfSide;
} else {
nodes[1] = nodes[0] - 1;
}
nodePairs.insertAtBottom(nodes);
latencies.insertAtBottom(latency);
bw_multis.insertAtBottom(bw_multiplier);
// right
if((nodes[0] + 1)%lengthOfSide == 0){ // determine right neighbor
nodes[1] = nodes[0] + 1 - lengthOfSide;
} else {
nodes[1] = nodes[0] + 1;
}
nodePairs.insertAtBottom(nodes);
latencies.insertAtBottom(latency);
bw_multis.insertAtBottom(bw_multiplier);
// top
if(nodes[0] - lengthOfSide < 2*m_nodes){ // determine if node is on the top
nodes[1] = nodes[0] - lengthOfSide + (lengthOfSide*lengthOfSide);
} else {
nodes[1] = nodes[0] - lengthOfSide;
}
nodePairs.insertAtBottom(nodes);
latencies.insertAtBottom(latency);
bw_multis.insertAtBottom(bw_multiplier);
// bottom
if(nodes[0] + lengthOfSide >= 2*m_nodes+numberOfTorusSwitches){ // determine if node is on the bottom
// sorin: bad bug if this is a > instead of a >=
nodes[1] = nodes[0] + lengthOfSide - (lengthOfSide*lengthOfSide);
} else {
nodes[1] = nodes[0] + lengthOfSide;
}
nodePairs.insertAtBottom(nodes);
latencies.insertAtBottom(latency);
bw_multis.insertAtBottom(bw_multiplier);
}
// add links
ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size())
for (int k = 0; k < nodePairs.size(); k++) {
ASSERT(nodePairs[k].size() == 2);
addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k]);
}
}

View file

@ -1,17 +0,0 @@
#ifndef TORUS2DTOPOLOGY_H
#define TORUS2DTOPOLOGY_H
#include "mem/ruby/network/simple/Topology.hh"
class Torus2DTopology : public Topology
{
public:
Torus2DTopology(const string & name);
void init();
protected:
void construct();
};
#endif

View file

@ -29,28 +29,22 @@
from m5.params import * from m5.params import *
from m5.objects import * from m5.objects import *
#
# Makes a generic mesh assuming an equal number of cache and directory cntrls # Makes a generic mesh assuming an equal number of cache and directory cntrls
#
def makeTopology(nodes, options): def makeTopology(nodes, options):
num_routers = options.num_cpus num_routers = options.num_cpus
num_rows = options.mesh_rows num_rows = options.mesh_rows
#
# There must be an evenly divisible number of cntrls to routers # There must be an evenly divisible number of cntrls to routers
# Also, obviously the number or rows must be <= the number of routers # Also, obviously the number or rows must be <= the number of routers
#
cntrls_per_router, remainder = divmod(len(nodes), num_routers) cntrls_per_router, remainder = divmod(len(nodes), num_routers)
assert(num_rows <= num_routers) assert(num_rows <= num_routers)
num_columns = int(num_routers / num_rows) num_columns = int(num_routers / num_rows)
assert(num_columns * num_rows == num_routers) assert(num_columns * num_rows == num_routers)
#
# Add all but the remainder nodes to the list of nodes to be uniformly # Add all but the remainder nodes to the list of nodes to be uniformly
# distributed across the network. # distributed across the network.
#
network_nodes = [] network_nodes = []
remainder_nodes = [] remainder_nodes = []
for node_index in xrange(len(nodes)): for node_index in xrange(len(nodes)):
@ -59,27 +53,22 @@ def makeTopology(nodes, options):
else: else:
remainder_nodes.append(nodes[node_index]) remainder_nodes.append(nodes[node_index])
#
# Connect each node to the appropriate router # Connect each node to the appropriate router
#
ext_links = [] ext_links = []
for (i, n) in enumerate(network_nodes): for (i, n) in enumerate(network_nodes):
cntrl_level, router_id = divmod(i, num_routers) cntrl_level, router_id = divmod(i, num_routers)
assert(cntrl_level < cntrls_per_router) assert(cntrl_level < cntrls_per_router)
ext_links.append(ExtLink(ext_node=n, int_node=router_id)) ext_links.append(ExtLink(ext_node=n, int_node=router_id))
# # Connect the remainding nodes to router 0. These should only be
# Connect the remainding nodes to router 0. These should only be DMA nodes. # DMA nodes.
#
for (i, node) in enumerate(remainder_nodes): for (i, node) in enumerate(remainder_nodes):
assert(node.type == 'DMA_Controller') assert(node.type == 'DMA_Controller')
assert(i < remainder) assert(i < remainder)
ext_links.append(ExtLink(ext_node=node, int_node=0)) ext_links.append(ExtLink(ext_node=node, int_node=0))
#
# Create the mesh links. First row (east-west) links then column # Create the mesh links. First row (east-west) links then column
# (north-south) links # (north-south) links
#
int_links = [] int_links = []
for row in xrange(num_rows): for row in xrange(num_rows):
for col in xrange(num_columns): for col in xrange(num_columns):

View file

@ -29,20 +29,16 @@
from m5.params import * from m5.params import *
from m5.objects import * from m5.objects import *
# # This file contains a special network creation function. This
# This file contains a special network creation function. This networks is not # networks is not general and will only work with specific system
# general and will only work with specific system configurations. The network # configurations. The network specified is similar to GEMS old file
# specified is similar to GEMS old file specified network. # specified network.
#
def makeTopology(nodes, options): def makeTopology(nodes, options):
num_routers = options.num_cpus num_routers = options.num_cpus
num_rows = options.mesh_rows num_rows = options.mesh_rows
#
# First determine which nodes are cache cntrls vs. dirs vs. dma # First determine which nodes are cache cntrls vs. dirs vs. dma
#
cache_nodes = [] cache_nodes = []
dir_nodes = [] dir_nodes = []
dma_nodes = [] dma_nodes = []
@ -55,11 +51,10 @@ def makeTopology(nodes, options):
elif node.type == 'DMA_Controller': elif node.type == 'DMA_Controller':
dma_nodes.append(node) dma_nodes.append(node)
# # Obviously the number or rows must be <= the number of routers
# Obviously the number or rows must be <= the number of routers and evenly # and evenly divisible. Also the number of caches must be a
# divisible. Also the number of caches must be a multiple of the number of # multiple of the number of routers and the number of directories
# routers and the number of directories must be four. # must be four.
#
assert(num_rows <= num_routers) assert(num_rows <= num_routers)
num_columns = int(num_routers / num_rows) num_columns = int(num_routers / num_rows)
assert(num_columns * num_rows == num_routers) assert(num_columns * num_rows == num_routers)
@ -67,37 +62,31 @@ def makeTopology(nodes, options):
assert(remainder == 0) assert(remainder == 0)
assert(len(dir_nodes) == 4) assert(len(dir_nodes) == 4)
#
# Connect each cache controller to the appropriate router # Connect each cache controller to the appropriate router
#
ext_links = [] ext_links = []
for (i, n) in enumerate(cache_nodes): for (i, n) in enumerate(cache_nodes):
cntrl_level, router_id = divmod(i, num_routers) cntrl_level, router_id = divmod(i, num_routers)
assert(cntrl_level < caches_per_router) assert(cntrl_level < caches_per_router)
ext_links.append(ExtLink(ext_node=n, int_node=router_id)) ext_links.append(ExtLink(ext_node=n, int_node=router_id))
#
# Connect the dir nodes to the corners. # Connect the dir nodes to the corners.
#
ext_links.append(ExtLink(ext_node=dir_nodes[0], int_node=0)) ext_links.append(ExtLink(ext_node=dir_nodes[0], int_node=0))
ext_links.append(ExtLink(ext_node=dir_nodes[1], int_node=(num_columns - 1))) ext_links.append(ExtLink(ext_node=dir_nodes[1],
int_node=(num_columns - 1)))
ext_links.append(ExtLink(ext_node=dir_nodes[2], ext_links.append(ExtLink(ext_node=dir_nodes[2],
int_node=(num_routers - num_columns))) int_node=(num_routers - num_columns)))
ext_links.append(ExtLink(ext_node=dir_nodes[3], int_node=(num_routers - 1))) ext_links.append(ExtLink(ext_node=dir_nodes[3],
int_node=(num_routers - 1)))
#
# Connect the dma nodes to router 0. These should only be DMA nodes. # Connect the dma nodes to router 0. These should only be DMA nodes.
#
for (i, node) in enumerate(dma_nodes): for (i, node) in enumerate(dma_nodes):
assert(node.type == 'DMA_Controller') assert(node.type == 'DMA_Controller')
ext_links.append(ExtLink(ext_node=node, int_node=0)) ext_links.append(ExtLink(ext_node=node, int_node=0))
#
# Create the mesh links. First row (east-west) links then column # Create the mesh links. First row (east-west) links then column
# (north-south) links # (north-south) links
#
int_links = [] int_links = []
for row in xrange(num_rows): for row in xrange(num_rows):
for col in xrange(num_columns): for col in xrange(num_columns):

View file

@ -1,3 +1,5 @@
# -*- mode:python -*-
# Copyright (c) 2010 Advanced Micro Devices, Inc. # Copyright (c) 2010 Advanced Micro Devices, Inc.
# All rights reserved. # All rights reserved.
# #

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -27,53 +26,50 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/* #include "gzstream.hh"
* $Id$
*
*/
#include "mem/gems_common/PrioHeap.hh"
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
#include "mem/ruby/recorder/CacheRecorder.hh" #include "mem/ruby/recorder/CacheRecorder.hh"
#include "mem/ruby/recorder/TraceRecord.hh" #include "mem/ruby/recorder/TraceRecord.hh"
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
#include "mem/gems_common/PrioHeap.hh"
#include "gzstream.hh"
CacheRecorder::CacheRecorder() CacheRecorder::CacheRecorder()
{ {
m_records_ptr = new PrioHeap<TraceRecord>; m_records_ptr = new PrioHeap<TraceRecord>;
} }
CacheRecorder::~CacheRecorder() CacheRecorder::~CacheRecorder()
{ {
delete m_records_ptr; delete m_records_ptr;
} }
void CacheRecorder::addRecord(Sequencer* sequencer, void
const Address& data_addr, CacheRecorder::addRecord(Sequencer* sequencer, const Address& data_addr,
const Address& pc_addr, const Address& pc_addr, RubyRequestType type, Time time)
RubyRequestType type,
Time time)
{ {
m_records_ptr->insert(TraceRecord(sequencer, data_addr, pc_addr, type, time)); m_records_ptr->
insert(TraceRecord(sequencer, data_addr, pc_addr, type, time));
} }
int CacheRecorder::dumpRecords(string filename) int
CacheRecorder::dumpRecords(string filename)
{ {
ogzstream out(filename.c_str()); ogzstream out(filename.c_str());
if (out.fail()) { if (out.fail()) {
cout << "Error: error opening file '" << filename << "'" << endl; cout << "Error: error opening file '" << filename << "'" << endl;
return 0; return 0;
} }
int counter = 0; int counter = 0;
while (m_records_ptr->size() != 0) { while (m_records_ptr->size() != 0) {
TraceRecord record = m_records_ptr->extractMin(); TraceRecord record = m_records_ptr->extractMin();
record.output(out); record.output(out);
counter++; counter++;
} }
return counter; return counter;
} }
void CacheRecorder::print(ostream& out) const void
CacheRecorder::print(ostream& out) const
{ {
} }

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -28,15 +27,12 @@
*/ */
/* /*
* $Id$ * Recording cache requests made to a ruby cache at certain ruby
* * time. Also dump the requests to a gziped file.
* Description: Recording cache requests made to a ruby cache at certain
* ruby time. Also dump the requests to a gziped file.
*
*/ */
#ifndef CACHERECORDER_H #ifndef __MEM_RUBY_RECORDER_CACHERECORDER_HH__
#define CACHERECORDER_H #define __MEM_RUBY_RECORDER_CACHERECORDER_HH__
#include <iostream> #include <iostream>
#include <string> #include <string>
@ -51,46 +47,32 @@ class Address;
class TraceRecord; class TraceRecord;
class Sequencer; class Sequencer;
class CacheRecorder { class CacheRecorder
public: {
// Constructors public:
CacheRecorder(); CacheRecorder();
~CacheRecorder();
// Destructor void addRecord(Sequencer* sequencer, const Address& data_addr,
~CacheRecorder(); const Address& pc_addr, RubyRequestType type, Time time);
int dumpRecords(std::string filename);
// Public Methods void print(std::ostream& out) const;
void addRecord(Sequencer* sequencer,
const Address& data_addr,
const Address& pc_addr,
RubyRequestType type,
Time time);
int dumpRecords(std::string filename);
void print(std::ostream& out) const; private:
private: // Private copy constructor and assignment operator
// Private Methods CacheRecorder(const CacheRecorder& obj);
CacheRecorder& operator=(const CacheRecorder& obj);
// Private copy constructor and assignment operator PrioHeap<TraceRecord>* m_records_ptr;
CacheRecorder(const CacheRecorder& obj);
CacheRecorder& operator=(const CacheRecorder& obj);
// Data Members (m_ prefix)
PrioHeap<TraceRecord>* m_records_ptr;
}; };
// Output operator declaration inline std::ostream&
std::ostream& operator<<(std::ostream& out, const CacheRecorder& obj); operator<<(std::ostream& out, const CacheRecorder& obj)
// ******************* Definitions *******************
// Output operator definition
extern inline
std::ostream& operator<<(std::ostream& out, const CacheRecorder& obj)
{ {
obj.print(out); obj.print(out);
out << std::flush; out << std::flush;
return out; return out;
} }
#endif //CACHERECORDER_H #endif // __MEM_RUBY_RECORDER_CACHERECORDER_HH__

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -27,125 +26,114 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/* #include "mem/protocol/CacheMsg.hh"
* $Id$
*
*/
#include "mem/ruby/recorder/TraceRecord.hh" #include "mem/ruby/recorder/TraceRecord.hh"
#include "mem/ruby/system/Sequencer.hh" #include "mem/ruby/system/Sequencer.hh"
#include "mem/ruby/system/System.hh" #include "mem/ruby/system/System.hh"
#include "mem/protocol/CacheMsg.hh"
#include "sim/sim_object.hh" #include "sim/sim_object.hh"
TraceRecord::TraceRecord(Sequencer* _sequencer, TraceRecord::TraceRecord(Sequencer* _sequencer, const Address& data_addr,
const Address& data_addr, const Address& pc_addr, RubyRequestType type, Time time)
const Address& pc_addr,
RubyRequestType type,
Time time)
{ {
m_sequencer_ptr = _sequencer; m_sequencer_ptr = _sequencer;
m_data_address = data_addr; m_data_address = data_addr;
m_pc_address = pc_addr; m_pc_address = pc_addr;
m_time = time; m_time = time;
m_type = type; m_type = type;
// Don't differentiate between store misses and atomic requests in // Don't differentiate between store misses and atomic requests in
// the trace // the trace
if (m_type == RubyRequestType_Locked_Read) { if (m_type == RubyRequestType_Locked_Read) {
m_type = RubyRequestType_ST; m_type = RubyRequestType_ST;
} } else if (m_type == RubyRequestType_Locked_Write) {
else if (m_type == RubyRequestType_Locked_Write) { m_type = RubyRequestType_ST;
m_type = RubyRequestType_ST; }
}
} }
// Public copy constructor and assignment operator
TraceRecord::TraceRecord(const TraceRecord& obj) TraceRecord::TraceRecord(const TraceRecord& obj)
{ {
*this = obj; // Call assignment operator // Call assignment operator
*this = obj;
} }
TraceRecord& TraceRecord::operator=(const TraceRecord& obj) TraceRecord&
TraceRecord::operator=(const TraceRecord& obj)
{ {
m_sequencer_ptr = obj.m_sequencer_ptr; m_sequencer_ptr = obj.m_sequencer_ptr;
m_time = obj.m_time; m_time = obj.m_time;
m_data_address = obj.m_data_address; m_data_address = obj.m_data_address;
m_pc_address = obj.m_pc_address; m_pc_address = obj.m_pc_address;
m_type = obj.m_type; m_type = obj.m_type;
return *this; return *this;
} }
void TraceRecord::issueRequest() const void
TraceRecord::issueRequest() const
{ {
assert(m_sequencer_ptr != NULL); assert(m_sequencer_ptr != NULL);
RubyRequest request(m_data_address.getAddress(), RubyRequest request(m_data_address.getAddress(), NULL,
NULL, RubySystem::getBlockSizeBytes(), m_pc_address.getAddress(),
RubySystem::getBlockSizeBytes(), m_type, RubyAccessMode_User, NULL);
m_pc_address.getAddress(),
m_type,
RubyAccessMode_User,
NULL);
// Clear out the sequencer // Clear out the sequencer
while (!m_sequencer_ptr->empty()) { while (!m_sequencer_ptr->empty()) {
g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 100); g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 100);
} }
m_sequencer_ptr->makeRequest(request); m_sequencer_ptr->makeRequest(request);
// Clear out the sequencer // Clear out the sequencer
while (!m_sequencer_ptr->empty()) { while (!m_sequencer_ptr->empty()) {
g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 100); g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 100);
} }
} }
void TraceRecord::print(ostream& out) const void
TraceRecord::print(ostream& out) const
{ {
out << "[TraceRecord: Node, " << m_sequencer_ptr->name() << ", " out << "[TraceRecord: Node, " << m_sequencer_ptr->name() << ", "
<< m_data_address << ", " << m_pc_address << ", " << m_data_address << ", " << m_pc_address << ", "
<< m_type << ", Time: " << m_time << "]"; << m_type << ", Time: " << m_time << "]";
} }
void TraceRecord::output(ostream& out) const void
TraceRecord::output(ostream& out) const
{ {
out << m_sequencer_ptr->name() << " "; out << m_sequencer_ptr->name() << " ";
m_data_address.output(out); m_data_address.output(out);
out << " "; out << " ";
m_pc_address.output(out); m_pc_address.output(out);
out << " "; out << " ";
out << m_type; out << m_type;
out << endl; out << endl;
} }
bool TraceRecord::input(istream& in) bool
TraceRecord::input(istream& in)
{ {
string sequencer_name; string sequencer_name;
in >> sequencer_name; in >> sequencer_name;
// // The SimObject find function is slow and iterates through the
// The SimObject find function is slow and iterates through the // simObjectList to find the sequencer pointer. Therefore, expect
// simObjectList to find the sequencer pointer. Therefore, expect trace // trace playback to be slow.
// playback to be slow. m_sequencer_ptr = (Sequencer*)SimObject::find(sequencer_name.c_str());
//
m_sequencer_ptr = (Sequencer*)SimObject::find(sequencer_name.c_str());
m_data_address.input(in); m_data_address.input(in);
m_pc_address.input(in); m_pc_address.input(in);
string type; if (in.eof())
if (!in.eof()) { return false;
string type;
in >> type; in >> type;
m_type = string_to_RubyRequestType(type); m_type = string_to_RubyRequestType(type);
// Ignore the rest of the line // Ignore the rest of the line
char c = '\0'; char c = '\0';
while ((!in.eof()) && (c != '\n')) { while ((!in.eof()) && (c != '\n')) {
in.get(c); in.get(c);
} }
return true; return true;
} else {
return false;
}
} }

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -28,84 +27,69 @@
*/ */
/* /*
* $Id$ * A entry in the cache request record. It is aware of the ruby time
* * and can issue the request back to the cache.
* Description: A entry in the cache request record. It is aware of
* the ruby time and can issue the request back to the
* cache.
*
*/ */
#ifndef TRACERECORD_H #ifndef __MEM_RUBY_RECORDER_TRACERECORD_HH__
#define TRACERECORD_H #define __MEM_RUBY_RECORDER_TRACERECORD_HH__
#include "mem/ruby/libruby_internal.hh"
#include "mem/ruby/system/Sequencer.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/common/Address.hh" #include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/libruby_internal.hh"
#include "mem/ruby/system/NodeID.hh" #include "mem/ruby/system/NodeID.hh"
#include "mem/ruby/system/Sequencer.hh"
class CacheMsg; class CacheMsg;
class TraceRecord { class TraceRecord
public: {
// Constructors public:
TraceRecord(Sequencer* _sequencer, TraceRecord(Sequencer* _sequencer, const Address& data_addr,
const Address& data_addr, const Address& pc_addr, RubyRequestType type, Time time);
const Address& pc_addr,
RubyRequestType type,
Time time);
TraceRecord() { TraceRecord()
m_sequencer_ptr = NULL; {
m_time = 0; m_sequencer_ptr = NULL;
m_type = RubyRequestType_NULL; m_time = 0;
} m_type = RubyRequestType_NULL;
}
// Destructor TraceRecord(const TraceRecord& obj);
// ~TraceRecord(); TraceRecord& operator=(const TraceRecord& obj);
// Public copy constructor and assignment operator bool
TraceRecord(const TraceRecord& obj); node_less_then_eq(const TraceRecord& rec) const
TraceRecord& operator=(const TraceRecord& obj); {
return this->m_time <= rec.m_time;
}
// Public Methods void issueRequest() const;
bool node_less_then_eq(const TraceRecord& rec) const { return (this->m_time <= rec.m_time); }
void issueRequest() const;
void print(ostream& out) const; void print(ostream& out) const;
void output(ostream& out) const; void output(ostream& out) const;
bool input(istream& in); bool input(istream& in);
private:
// Private Methods
// Data Members (m_ prefix) private:
Sequencer* m_sequencer_ptr; Sequencer* m_sequencer_ptr;
Time m_time; Time m_time;
Address m_data_address; Address m_data_address;
Address m_pc_address; Address m_pc_address;
RubyRequestType m_type; RubyRequestType m_type;
}; };
inline extern bool node_less_then_eq(const TraceRecord& n1, const TraceRecord& n2); inline bool
node_less_then_eq(const TraceRecord& n1, const TraceRecord& n2)
// Output operator declaration
ostream& operator<<(ostream& out, const TraceRecord& obj);
// ******************* Definitions *******************
inline extern
bool node_less_then_eq(const TraceRecord& n1, const TraceRecord& n2)
{ {
return n1.node_less_then_eq(n2); return n1.node_less_then_eq(n2);
} }
// Output operator definition inline std::ostream&
extern inline operator<<(ostream& out, const TraceRecord& obj)
ostream& operator<<(ostream& out, const TraceRecord& obj)
{ {
obj.print(out); obj.print(out);
out << flush; out << std::flush;
return out; return out;
} }
#endif //TRACERECORD_H #endif // __MEM_RUBY_RECORDER_TRACERECORD_HH__

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -27,131 +26,107 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/* #include "base/cprintf.hh"
* $Id$
*
*/
#include "mem/ruby/recorder/Tracer.hh"
#include "mem/ruby/recorder/TraceRecord.hh"
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
#include "mem/gems_common/PrioHeap.hh" #include "mem/gems_common/PrioHeap.hh"
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
#include "mem/ruby/recorder/TraceRecord.hh"
#include "mem/ruby/recorder/Tracer.hh"
#include "mem/ruby/system/System.hh" #include "mem/ruby/system/System.hh"
//added by SS
Tracer::Tracer(const Params *p) Tracer::Tracer(const Params *p)
: SimObject(p) : SimObject(p)
{ {
m_enabled = false;
m_warmup_length = p->warmup_length;
assert(m_warmup_length > 0);
RubySystem::m_tracer_ptr = this;
}
//commented by SS
//Tracer::Tracer()
//{
// m_enabled = false;
//}
Tracer::~Tracer()
{
}
void Tracer::init()
{
}
void Tracer::startTrace(std::string filename)
{
if (m_enabled) {
stopTrace();
}
if (filename != "") {
m_trace_file.open(filename.c_str());
if (m_trace_file.fail()) {
cout << "Error: error opening file '" << filename << "'" << endl;
cout << "Trace not enabled." << endl;
return;
}
cout << "Request trace enabled to output file '" << filename << "'" << endl;
m_enabled = true;
}
}
void Tracer::stopTrace()
{
if (m_enabled == true) {
m_trace_file.close();
cout << "Request trace file closed." << endl;
m_enabled = false; m_enabled = false;
} m_warmup_length = p->warmup_length;
assert(m_warmup_length > 0);
RubySystem::m_tracer_ptr = this;
} }
void Tracer::traceRequest(Sequencer* sequencer, void
const Address& data_addr, Tracer::startTrace(std::string filename)
const Address& pc_addr,
RubyRequestType type,
Time time)
{ {
assert(m_enabled == true); if (m_enabled)
TraceRecord tr(sequencer, data_addr, pc_addr, type, time); stopTrace();
tr.output(m_trace_file);
if (filename != "") {
m_trace_file.open(filename.c_str());
if (m_trace_file.fail()) {
cprintf("Error: error opening file '%s'\n", filename);
cprintf("Trace not enabled.\n");
return;
}
cprintf("Request trace enabled to output file '%s'\n", filename);
m_enabled = true;
}
} }
// Class method void
int Tracer::playbackTrace(std::string filename) Tracer::stopTrace()
{ {
igzstream in(filename.c_str()); if (m_enabled) {
if (in.fail()) { m_trace_file.close();
cout << "Error: error opening file '" << filename << "'" << endl; cout << "Request trace file closed." << endl;
return 0; m_enabled = false;
} }
}
time_t start_time = time(NULL); void
Tracer::traceRequest(Sequencer* sequencer, const Address& data_addr,
const Address& pc_addr, RubyRequestType type, Time time)
{
assert(m_enabled);
TraceRecord tr(sequencer, data_addr, pc_addr, type, time);
tr.output(m_trace_file);
}
TraceRecord record; int
int counter = 0; Tracer::playbackTrace(std::string filename)
// Read in the next TraceRecord {
bool ok = record.input(in); igzstream in(filename.c_str());
while (ok) { if (in.fail()) {
// Put it in the right cache cprintf("Error: error opening file '%s'\n", filename);
record.issueRequest(); return 0;
counter++; }
time_t start_time = time(NULL);
TraceRecord record;
int counter = 0;
// Read in the next TraceRecord // Read in the next TraceRecord
ok = record.input(in); bool ok = record.input(in);
while (ok) {
// Put it in the right cache
record.issueRequest();
counter++;
// Clear the statistics after warmup // Read in the next TraceRecord
/* if (counter == m_warmup_length) { ok = record.input(in);
cout << "Clearing stats after warmup of length " << m_warmup_length << endl;
g_system_ptr->clearStats(); // Clear the statistics after warmup
} if (counter == m_warmup_length) {
*/ cprintf("Clearing stats after warmup of length %s\n",
if (counter == m_warmup_length) { m_warmup_length);
cout << "Clearing stats after warmup of length " << m_warmup_length << endl; g_system_ptr->clearStats();
g_system_ptr->clearStats(); }
} }
} // Flush the prefetches through the system
// FIXME - should be smarter
g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 1000);
// Flush the prefetches through the system time_t stop_time = time(NULL);
g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 1000); // FIXME - should be smarter double seconds = difftime(stop_time, start_time);
double minutes = seconds / 60.0;
cout << "playbackTrace: " << minutes << " minutes" << endl;
time_t stop_time = time(NULL); return counter;
double seconds = difftime(stop_time, start_time);
double minutes = seconds / 60.0;
cout << "playbackTrace: " << minutes << " minutes" << endl;
return counter;
} }
void Tracer::print(std::ostream& out) const void
Tracer::print(std::ostream& out) const
{ {
} }
Tracer * Tracer *
RubyTracerParams::create() RubyTracerParams::create()
{ {

View file

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved. * All rights reserved.
@ -28,87 +27,64 @@
*/ */
/* /*
* $Id$ * Controller class of the tracer. Can stop/start/playback the ruby
* * cache requests trace.
* Description: Controller class of the tracer. Can stop/start/playback
* the ruby cache requests trace.
*
*/ */
#ifndef TRACER_H #ifndef __MEM_RUBY_RECORDER_TRACER_HH__
#define TRACER_H #define __MEM_RUBY_RECORDER_TRACER_HH__
#include <iostream> #include <iostream>
#include <string> #include <string>
#include "mem/ruby/libruby_internal.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/system/NodeID.hh"
#include "mem/protocol/CacheRequestType.hh"
#include "sim/sim_object.hh"
#include "params/RubyTracer.hh"
#include "gzstream.hh" #include "gzstream.hh"
#include "mem/protocol/CacheRequestType.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/libruby_internal.hh"
#include "mem/ruby/system/NodeID.hh"
#include "params/RubyTracer.hh"
#include "sim/sim_object.hh"
template <class TYPE> class PrioHeap; template <class TYPE> class PrioHeap;
class Address; class Address;
class TraceRecord; class TraceRecord;
class Sequencer; class Sequencer;
class Tracer : public SimObject { class Tracer : public SimObject
public: {
// Constructors public:
// Tracer();
typedef RubyTracerParams Params; typedef RubyTracerParams Params;
Tracer(const Params *p); Tracer(const Params *p);
// Destructor void startTrace(std::string filename);
~Tracer(); void stopTrace();
bool traceEnabled() { return m_enabled; }
void traceRequest(Sequencer* sequencer, const Address& data_addr,
const Address& pc_addr, RubyRequestType type, Time time);
// Public Methods void print(std::ostream& out) const;
void startTrace(std::string filename);
void stopTrace();
bool traceEnabled() { return m_enabled; }
void traceRequest(Sequencer* sequencer,
const Address& data_addr,
const Address& pc_addr,
RubyRequestType type,
Time time);
void print(std::ostream& out) const; int playbackTrace(std::string filename);
// Public Class Methods private:
int playbackTrace(std::string filename); // Private copy constructor and assignment operator
void init(); Tracer(const Tracer& obj);
private: Tracer& operator=(const Tracer& obj);
// Private Methods
// Private copy constructor and assignment operator ogzstream m_trace_file;
Tracer(const Tracer& obj); bool m_enabled;
Tracer& operator=(const Tracer& obj);
// Data Members (m_ prefix) //added by SS
ogzstream m_trace_file; int m_warmup_length;
bool m_enabled;
//added by SS
int m_warmup_length;
}; };
// Output operator declaration inline std::ostream&
std::ostream& operator<<(std::ostream& out, const Tracer& obj); operator<<(std::ostream& out, const Tracer& obj)
// ******************* Definitions *******************
// Output operator definition
extern inline
std::ostream& operator<<(std::ostream& out, const Tracer& obj)
{ {
obj.print(out); obj.print(out);
out << std::flush; out << std::flush;
return out; return out;
} }
#endif //TRACER_H #endif // __MEM_RUBY_RECORDER_TRACER_HH__

View file

@ -1,103 +0,0 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// this code was modified to fit into Rochs
#ifndef _HFA_H_
#define _HFA_H_
using namespace std;
/*
* Global include file for entire project.
* Should be included first in all ".cc" project files
*/
/*------------------------------------------------------------------------*/
/* Includes */
/*------------------------------------------------------------------------*/
#include "mem/ruby/common/Global.hh"
#include <string>
#include <map>
#include <set>
#include <list>
#include <fstream>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> // va_start(), va_end()
#include <strings.h> // declaration of bzero()
#include <sys/time.h> // gettimeofday() includes
#include <errno.h>
#include <unistd.h>
/*------------------------------------------------------------------------*/
/* Type Includes */
/*------------------------------------------------------------------------*/
#include "mem/ruby/storebuffer/hfatypes.hh"
/*------------------------------------------------------------------------*/
/* Forward class declaration(s) */
/*------------------------------------------------------------------------*/
class wait_list_t;
class waiter_t;
class free_list_t;
class pipestate_t;
class pipepool_t;
/** Maximum size of a load or store that may occur to/from the memory system.
* (in 64-bit quantities). Currently this is set to 8 * 64-bits = 64-bytes.
*/
const uint32 MEMOP_MAX_SIZE = 8;
/** 64-bit int memory masks */
#define MEM_BYTE_MASK 0x00000000000000ffULL
#define MEM_HALF_MASK 0x000000000000ffffULL
#define MEM_WORD_MASK 0x00000000ffffffffULL
#define MEM_EXTD_MASK 0xffffffffffffffffULL
#define MEM_QUAD_MASK 0xffffffffffffffffULL
#define ISEQ_MASK 0x0000ffffffffffffULL
/*------------------------------------------------------------------------*/
/* Configuration Parameters */
/*------------------------------------------------------------------------*/
#define SIM_HALT assert(0);
#include <assert.h>
#endif /* _HFA_H_ */

View file

@ -1,80 +0,0 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _HFATYPES_H_
#define _HFATYPES_H_
/*
* Global include file for entire project.
* Should be included first in all ".cc" project files
*/
/*------------------------------------------------------------------------*/
/* Includes */
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
/* SimIcs Includes */
/*------------------------------------------------------------------------*/
/* import C functions */
/*------------------------------------------------------------------------*/
/* Forward class declaration(s) */
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
/* Macro declarations */
/*------------------------------------------------------------------------*/
// definitions of MAX / MIN (if needed)
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
/* Statistics tracking definition */
#define STAT_INC(A) (A)++
/*------------------------------------------------------------------------*/
/* Enumerations */
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
/* Project Includes */
/*------------------------------------------------------------------------*/
typedef unsigned char byte_t; /* byte - 8 bits */
typedef unsigned short half_t; /* half - 16 bits */
typedef unsigned int word_t; /* word - 32 bits */
typedef uint64 tick_t; /* time - 64 bit */
#endif /* _HFATYPES_H_ */

View file

@ -1,67 +0,0 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "mem/ruby/libruby.hh"
#include "writebuffer.hh"
#include <iostream>
writebuffer_status_t handleStore (writebuffer_t * writebuffer, const RubyRequest & request) {
assert(request.type == RubyRequestType_ST);
if (writebuffer->writeBufferFull()){
return WB_FULL;
}
else if (writebuffer->writeBufferFlushing()) {
return WB_FLUSHING;
}
else {
writebuffer->addToWriteBuffer(request);
return WB_OK;
}
}
uint64_t handleLoad(writebuffer_t * writebuffer, const RubyRequest & request) {
assert(request.type == RubyRequestType_LD);
return writebuffer->handleLoad(request);
}
uint64_t handleAtomic(writebuffer_t * writebuffer, const RubyRequest & request) {
// flush the store buffer
writebuffer->flushWriteBuffer();
// let writebuffer issue atomic
//return writebuffer->issueAtomic(request);
}
void flushSTB(writebuffer_t * writebuffer) {
// in in-order can't get a request to flushSTB if already flushing
// on out of order, have to check if already flushing
writebuffer->flushWriteBuffer();
}
void registerHitCallback(writebuffer_t * writebuffer, void (*hit_callback)(int64_t access_id)) {
writebuffer->registerHitCallback(hit_callback);
}

View file

@ -1,46 +0,0 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef STB_H
#define STB_H
#include "mem/ruby/libruby.hh"
#include "writebuffer.hh"
#include <iostream>
writebuffer_status_t handleStore (writebuffer_t * writebuffer, const RubyRequest & request);
uint64_t handleLoad(writebuffer_t * writebuffer, const RubyRequest & request);
uint64_t handleAtomic(writebuffer_t * writebuffer, const RubyRequest & request);
void flushSTB(writebuffer_t * writebuffer);
void registerHitCallback(writebuffer_t * writebuffer, void (*hit_callback)(int64_t access_id));
#endif

View file

@ -27,49 +27,59 @@
*/ */
#include <iostream> #include <iostream>
#include "mem/ruby/storebuffer/stb_interface.hh" #include "mem/ruby/storebuffer/stb_interface.hh"
StoreBuffer * createNewSTB(uint32 id, uint32 block_bits, int storebuffer_size) { StoreBuffer *
StoreBuffer * stb = new StoreBuffer(id, block_bits, storebuffer_size); createNewSTB(uint32 id, uint32 block_bits, int storebuffer_size)
return stb; {
StoreBuffer *stb = new StoreBuffer(id, block_bits, storebuffer_size);
return stb;
} }
storebuffer_status_t handleStore (StoreBuffer * storebuffer, const RubyRequest & request) { storebuffer_status_t
assert(request.type == RubyRequestType_ST); handleStore(StoreBuffer *storebuffer, const RubyRequest &request)
if (storebuffer->storeBufferFull()){ {
return WB_FULL; assert(request.type == RubyRequestType_ST);
} if (storebuffer->storeBufferFull()){
else if (storebuffer->storeBufferFlushing()) { return WB_FULL;
return WB_FLUSHING; } else if (storebuffer->storeBufferFlushing()) {
} return WB_FLUSHING;
else { } else {
storebuffer->addToStoreBuffer(request); storebuffer->addToStoreBuffer(request);
return WB_OK; return WB_OK;
} }
} }
uint64_t handleLoad(StoreBuffer * storebuffer, const RubyRequest & request) { uint64_t
assert(request.type == RubyRequestType_LD); handleLoad(StoreBuffer *storebuffer, const RubyRequest &request)
return storebuffer->handleLoad(request); {
assert(request.type == RubyRequestType_LD);
return storebuffer->handleLoad(request);
} }
#if 0 #if 0
uint64_t handleAtomic(StoreBuffer * storebuffer, const RubyRequest & request) { uint64_t
// flush the store buffer handleAtomic(StoreBuffer *storebuffer, const RubyRequest &request)
storebuffer->flushStoreBuffer(); {
// let storebuffer issue atomic // flush the store buffer
//return storebuffer->issueAtomic(request); storebuffer->flushStoreBuffer();
// let storebuffer issue atomic
// return storebuffer->issueAtomic(request);
} }
#endif #endif
void flushSTB(StoreBuffer * storebuffer) { void
// in in-order can't get a request to flushSTB if already flushing flushSTB(StoreBuffer *storebuffer)
// on out of order, have to check if already flushing {
storebuffer->flushStoreBuffer(); // in in-order can't get a request to flushSTB if already flushing
// on out of order, have to check if already flushing
storebuffer->flushStoreBuffer();
} }
void registerHitCallback(StoreBuffer * storebuffer, void (*hit_callback)(int64_t access_id)) { void
storebuffer->registerHitCallback(hit_callback); registerHitCallback(StoreBuffer *storebuffer,
void (*hit_callback)(int64_t access_id))
{
storebuffer->registerHitCallback(hit_callback);
} }

View file

@ -27,16 +27,12 @@
*/ */
#include "mem/ruby/storebuffer/storebuffer.hh" #include "mem/ruby/storebuffer/storebuffer.hh"
#include <iostream>
StoreBuffer * createNewSTB (uint32 id, uint32 block_bits, int storebuffer_size); StoreBuffer *createNewSTB(uint32 id, uint32 block_bits, int storebuffer_size);
storebuffer_status_t handleStore(StoreBuffer *storebuffer,
storebuffer_status_t handleStore (StoreBuffer * storebuffer, const RubyRequest & request); const RubyRequest &request);
uint64_t handleLoad(StoreBuffer *storebuffer, const RubyRequest &request);
uint64_t handleLoad(StoreBuffer * storebuffer, const RubyRequest & request); uint64_t handleAtomic(StoreBuffer *storebuffer, const RubyRequest &request);
void flushSTB(StoreBuffer *storebuffer);
uint64_t handleAtomic(StoreBuffer * storebuffer, const RubyRequest & request); void registerHitCallback(StoreBuffer *storebuffer,
void (*hit_callback)(int64_t access_id));
void flushSTB(StoreBuffer * storebuffer);
void registerHitCallback(StoreBuffer * storebuffer, void (*hit_callback)(int64_t access_id));

View file

@ -26,240 +26,216 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/*------------------------------------------------------------------------*/
/* Includes */
/*------------------------------------------------------------------------*/
#include <map> #include <map>
#include "mem/ruby/storebuffer/hfa.hh"
#include "mem/ruby/storebuffer/storebuffer.hh"
#include "mem/ruby/common/Global.hh" #include "mem/ruby/common/Global.hh"
#include "mem/ruby/storebuffer/storebuffer.hh"
#if RUBY_TSO_CHECKER using namespace std;
#include "TsoChecker.hh"
#endif
#define SYSTEM_EXIT ASSERT(0) #define SYSTEM_EXIT ASSERT(0)
// global map of request id_s to map them back to storebuffer pointers // global map of request id_s to map them back to storebuffer pointers
map <uint64_t, StoreBuffer *> request_map; map<uint64_t, StoreBuffer *> request_map;
#if RUBY_TSO_CHECKER void
Tso::TsoChecker * g_tsoChecker; hit(int64_t id)
#endif {
if (request_map.find(id) == request_map.end()) {
void hit(int64_t id) { ERROR_OUT("Request ID not found in the map");
if (request_map.find(id) == request_map.end()) { DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id);
ERROR_OUT("Request ID not found in the map"); ASSERT(0);
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id); } else {
ASSERT(0); request_map[id]->complete(id);
} request_map.erase(id);
else { }
request_map[id]->complete(id);
request_map.erase(id);
}
} }
StoreBuffer::StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size)
{
iseq = 0;
tso_iseq = 0;
char name [] = "Sequencer_";
char port_name [13];
sprintf(port_name, "%s%d", name, id);
m_port = libruby_get_port(port_name, hit);
m_hit_callback = NULL;
ASSERT(storebuffer_size >= 0);
m_storebuffer_size = storebuffer_size;
m_id = id;
m_block_size = 1 << block_bits;
m_block_mask = ~(m_block_size - 1);
m_buffer_size = 0;
m_use_storebuffer = false;
m_storebuffer_full = false;
m_storebuffer_flushing = false;
m_stalled_issue = true;
if (m_storebuffer_size > 0){
m_use_storebuffer = true;
}
//***************************************************************************************** #ifdef DEBUG_WRITE_BUFFER
StoreBuffer::StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size) { DEBUG_OUT("*******storebuffer_t::Using Write Buffer? %d\n",
#if RUBY_TSO_CHECKER m_use_storebuffer);
if (id == 0) {
g_tsoChecker = new Tso::TsoChecker();
g_tsoChecker->init(64);
}
#endif
iseq = 0;
tso_iseq = 0;
char name [] = "Sequencer_";
char port_name [13];
sprintf(port_name, "%s%d", name, id);
m_port = libruby_get_port(port_name, hit);
m_hit_callback = NULL;
ASSERT(storebuffer_size >= 0);
m_storebuffer_size = storebuffer_size;
m_id = id;
m_block_size = 1 << block_bits;
m_block_mask = ~(m_block_size - 1);
m_buffer_size = 0;
m_use_storebuffer = false;
m_storebuffer_full = false;
m_storebuffer_flushing = false;
m_stalled_issue = true;
if(m_storebuffer_size > 0){
m_use_storebuffer = true;
}
#ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("*******storebuffer_t::Using Write Buffer? %d\n",m_use_storebuffer);
#endif
}
//******************************************************************************************
StoreBuffer::~StoreBuffer(){
#if RUBY_TSO_CHECKER
if (m_id == 0) {
delete g_tsoChecker;
}
#endif #endif
} }
//***************************************************************************************************** StoreBuffer::~StoreBuffer()
void StoreBuffer::registerHitCallback(void (*hit_callback)(int64_t request_id)) { {
assert(m_hit_callback == NULL); // can't assign hit_callback twice }
m_hit_callback = hit_callback;
void
StoreBuffer::registerHitCallback(void (*hit_callback)(int64_t request_id))
{
assert(m_hit_callback == NULL); // can't assign hit_callback twice
m_hit_callback = hit_callback;
} }
//***************************************************************************************************** void
void StoreBuffer::addToStoreBuffer(struct RubyRequest request){ StoreBuffer::addToStoreBuffer(RubyRequest request)
if(m_use_storebuffer){ {
#ifdef DEBUG_WRITE_BUFFER if (!m_use_storebuffer) {
DEBUG_OUT("\n***StoreBuffer: addToStoreBuffer BEGIN, contents:\n"); // make request to libruby
DEBUG_OUT("\n"); uint64_t id = libruby_issue_request(m_port, request);
#endif if (request_map.find(id) != request_map.end()) {
ERROR_OUT("Request ID is already in the map");
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id);
ASSERT(0);
} else {
request_map.insert(make_pair(id, this));
outstanding_requests.insert(make_pair(id, request));
}
return;
}
#ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("\t INSERTING new request\n");
#endif
#ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("\n***StoreBuffer: addToStoreBuffer BEGIN, contents:\n");
DEBUG_OUT("\n");
DEBUG_OUT("\t INSERTING new request\n");
#endif
buffer.push_front(SBEntry(request, NULL)); buffer.push_front(SBEntry(request, NULL));
m_buffer_size++; m_buffer_size++;
if (m_buffer_size >= m_storebuffer_size) { if (m_buffer_size >= m_storebuffer_size) {
m_storebuffer_full = true; m_storebuffer_full = true;
} } else if (m_stalled_issue) {
else if (m_stalled_issue) { m_stalled_issue = false;
m_stalled_issue = false; issueNextStore();
issueNextStore();
} }
iseq++; iseq++;
#ifdef DEBUG_WRITE_BUFFER #ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("***StoreBuffer: addToStoreBuffer END, contents:\n"); DEBUG_OUT("***StoreBuffer: addToStoreBuffer END, contents:\n");
DEBUG_OUT("\n"); DEBUG_OUT("\n");
#endif #endif
} //end if(m_use_storebuffer)
else {
// make request to libruby
uint64_t id = libruby_issue_request(m_port, request);
if (request_map.find(id) != request_map.end()) {
ERROR_OUT("Request ID is already in the map");
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id);
ASSERT(0);
}
else {
request_map.insert(make_pair(id, this));
outstanding_requests.insert(make_pair(id, request));
}
}
} }
//***************************************************************************************************** // Return value of -2 indicates that the load request was satisfied by
// Return value of -2 indicates that the load request was satisfied by the store buffer // the store buffer
// Return value of -3 indicates a partial match, so the load has to retry until NO_MATCH // Return value of -3 indicates a partial match, so the load has to
// Alternatively we could satisfy the partial match, but tso gets complicated and more races // retry until NO_MATCH
//***************************************************************************************************** // Alternatively we could satisfy the partial match, but tso gets
int64_t StoreBuffer::handleLoad(struct RubyRequest request) { // complicated and more races
if (m_use_storebuffer) { int64_t
StoreBuffer::handleLoad(RubyRequest request)
{
if (!m_use_storebuffer) {
// make a request to ruby
return libruby_issue_request(m_port, request);
}
load_match match = checkForLoadHit(request); load_match match = checkForLoadHit(request);
if (match == FULL_MATCH) { if (match == FULL_MATCH) {
// fill data // fill data
returnMatchedData(request); returnMatchedData(request);
iseq++; iseq++;
return -2; return -2;
} else if (match == NO_MATCH) {
// make request to libruby and return the id
uint64_t id = libruby_issue_request(m_port, request);
if (request_map.find(id) != request_map.end()) {
ERROR_OUT("Request ID is already in the map");
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id);
ASSERT(0);
} else {
request_map.insert(make_pair(id, this));
outstanding_requests.insert(make_pair(id, request));
}
iseq++;
return id;
} else { // partial match
return -3;
} }
else if (match == NO_MATCH) {
// make request to libruby and return the id
uint64_t id = libruby_issue_request(m_port, request);
if (request_map.find(id) != request_map.end()) {
ERROR_OUT("Request ID is already in the map");
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id);
ASSERT(0);
}
else {
request_map.insert(make_pair(id, this));
outstanding_requests.insert(make_pair(id, request));
}
iseq++;
return id;
}
else { // partial match
return -3;
}
}
else {
// make a request to ruby
return libruby_issue_request(m_port, request);
}
} }
//*****************************************************************************************************
// This function will fill the data array if any match is found // This function will fill the data array if any match is found
//***************************************************************************************************** load_match
load_match StoreBuffer::checkForLoadHit(struct RubyRequest request) { StoreBuffer::checkForLoadHit(RubyRequest request)
if (m_use_storebuffer) { {
if (!m_use_storebuffer) {
// this function should never be called if we are not using a
// store buffer
ERROR_OUT("checkForLoadHit called while write buffer is not in use");
ASSERT(0);
}
physical_address_t physical_address = request.paddr; physical_address_t physical_address = request.paddr;
int len = request.len; int len = request.len;
uint8_t * data = new uint8_t[64]; uint8_t * data = new uint8_t[64];
memset(data, 0, 64); memset(data, 0, 64);
for (int i = physical_address%64; i < len; i++) { for (int i = physical_address % 64; i < len; i++)
data[i] = 1; data[i] = 1;
}
bool found = false; bool found = false;
physical_address_t lineaddr = physical_address & m_block_mask; physical_address_t lineaddr = physical_address & m_block_mask;
// iterate over the buffer looking for hits // iterate over the buffer looking for hits
for (deque<struct SBEntry>::iterator it = buffer.begin(); it != buffer.end(); it++) { deque<SBEntry>::iterator it = buffer.begin();
if ((it->m_request.paddr & m_block_mask) == lineaddr) { for (; it != buffer.end(); it++) {
RubyRequest &req = it->m_request;
if ((req.paddr & m_block_mask) != lineaddr)
continue;
found = true; found = true;
for (int i = it->m_request.paddr%64; i < it->m_request.len; i++) { for (int i = req.paddr % 64; i < req.len; i++)
data[i] = 0; data[i] = 0;
}
}
} }
// if any matching entry is found, determine if all the requested bytes have been matched // if any matching entry is found, determine if all the
// requested bytes have been matched
if (found) { if (found) {
ASSERT(m_buffer_size > 0); ASSERT(m_buffer_size > 0);
int unmatched_bytes = 0; int unmatched_bytes = 0;
for (int i = physical_address%64; i < len; i++) { for (int i = physical_address%64; i < len; i++) {
unmatched_bytes = unmatched_bytes + data[i]; unmatched_bytes = unmatched_bytes + data[i];
} }
if (unmatched_bytes == 0) { if (unmatched_bytes == 0) {
delete data;
return FULL_MATCH;
} else {
delete data;
return PARTIAL_MATCH;
}
} else {
delete data; delete data;
return FULL_MATCH; return NO_MATCH;
}
else {
delete data;
return PARTIAL_MATCH;
}
} }
else {
delete data;
return NO_MATCH;
}
} // end of if (m_use_storebuffer)
else {
// this function should never be called if we are not using a store buffer
ERROR_OUT("checkForLoadHit called while write buffer is not in use");
ASSERT(0);
}
} }
void
//*************************************************************************************************** StoreBuffer::returnMatchedData(RubyRequest request)
void StoreBuffer::returnMatchedData(struct RubyRequest request) { {
if (m_use_storebuffer) { if (!m_use_storebuffer) {
ERROR_OUT("returnMatchedData called while write buffer is not in use");
ASSERT(0);
}
uint8_t * data = new uint8_t[64]; uint8_t * data = new uint8_t[64];
memset(data, 0, 64); memset(data, 0, 64);
@ -272,114 +248,75 @@ void StoreBuffer::returnMatchedData(struct RubyRequest request) {
ASSERT(checkForLoadHit(request) != NO_MATCH); ASSERT(checkForLoadHit(request) != NO_MATCH);
physical_address_t lineaddr = physical_address & m_block_mask; physical_address_t lineaddr = physical_address & m_block_mask;
bool found = false; bool found = false;
#if RUBY_TSO_CHECKER deque<SBEntry>::iterator satisfying_store;
Tso::TsoCheckerCmd * cmd; deque<SBEntry>::iterator it = buffer.begin();
#endif for (; it != buffer.end(); it++) {
deque<struct SBEntry>::iterator satisfying_store; if ((it->m_request.paddr & m_block_mask) == lineaddr) {
for (deque<struct SBEntry>::iterator it = buffer.begin(); it != buffer.end(); it++) { if (!found) {
if ((it->m_request.paddr & m_block_mask) == lineaddr) { found = true;
if (!found) { }
found = true; uint8_t * dataPtr = it->m_request.data;
#if RUBY_TSO_CHECKER int offset = it->m_request.paddr%64;
satisfying_store = it; for (int i = offset; i < it->m_request.len; i++) {
cmd = new Tso::TsoCheckerCmd(m_id, // this thread id if (!written[i]) { // don't overwrite data with earlier data
iseq, // instruction sequence data[i] = dataPtr[i-offset];
ITYPE_LOAD, // is a store written[i] = 1;
MEM_LOAD_DATA, // commit }
request.paddr, // the address }
NULL, // and data
request.len, // and len
DSRC_STB, // shouldn't matter
libruby_get_time(), // macc: for store macc and time are the same and it
0, // gobs
0);
#endif
} }
uint8_t * dataPtr = it->m_request.data;
int offset = it->m_request.paddr%64;
for (int i = offset; i < it->m_request.len; i++) {
if (!written[i]) { // don't overwrite data with earlier data
data[i] = dataPtr[i-offset];
written[i] = 1;
}
}
}
} }
int i = physical_address%64; int i = physical_address%64;
for (int j = 0; (i < physical_address%64 + len) && (j < len); i++, j++) { for (int j = 0; (i < physical_address%64 + len) && (j < len); i++, j++) {
if (written[i]) { if (written[i]) {
request.data[j] = data[i]; request.data[j] = data[i];
} }
} }
#if RUBY_TSO_CHECKER
uint64_t tso_data = 0;
memcpy(&tso_data, request.data, request.len);
cmd->setData(tso_data);
Tso::TsoCheckerCmd * adjust_cmd = satisfying_store->m_next_ptr;
if (adjust_cmd == NULL) {
adjust_cmd = cmd;
}
else {
while (adjust_cmd->getNext() != NULL) {
adjust_cmd = adjust_cmd->getNext();
}
adjust_cmd->setNext(cmd);
}
#endif
delete data; delete data;
delete written; delete written;
}
else {
ERROR_OUT("returnMatchedData called while write buffer is not in use");
ASSERT(0);
}
} }
void
StoreBuffer::flushStoreBuffer()
{
if (!m_use_storebuffer) {
// do nothing
return;
}
//****************************************************************************************** #ifdef DEBUG_WRITE_BUFFER
void StoreBuffer::flushStoreBuffer(){ DEBUG_OUT("\n***StoreBuffer: flushStoreBuffer BEGIN, contents:\n");
if (m_use_storebuffer) { DEBUG_OUT("\n");
#ifdef DEBUG_WRITE_BUFFER #endif
DEBUG_OUT("\n***StoreBuffer: flushStoreBuffer BEGIN, contents:\n");
DEBUG_OUT("\n");
#endif
if(m_buffer_size > 0) { m_storebuffer_flushing = (m_buffer_size > 0);
m_storebuffer_flushing = true; // indicate that we are flushing
}
else {
m_storebuffer_flushing = false;
return;
}
}
else {
// do nothing
return;
}
} }
//**************************************************************************************** void
void StoreBuffer::issueNextStore() { StoreBuffer::issueNextStore()
SBEntry request = buffer.back(); {
uint64_t id = libruby_issue_request(m_port, request.m_request); SBEntry request = buffer.back();
if (request_map.find(id) != request_map.end()) { uint64_t id = libruby_issue_request(m_port, request.m_request);
assert(0); if (request_map.find(id) != request_map.end()) {
} assert(0);
else { } else {
request_map.insert(make_pair(id, this)); request_map.insert(make_pair(id, this));
outstanding_requests.insert(make_pair(id, request.m_request)); outstanding_requests.insert(make_pair(id, request.m_request));
} }
} }
//**************************************************************************************** void
void StoreBuffer::complete(uint64_t id) { StoreBuffer::complete(uint64_t id)
if (m_use_storebuffer) { {
if (!m_use_storebuffer) {
m_hit_callback(id);
return;
}
ASSERT(outstanding_requests.find(id) != outstanding_requests.end()); ASSERT(outstanding_requests.find(id) != outstanding_requests.end());
physical_address_t physical_address = outstanding_requests.find(id)->second.paddr; physical_address_t physical_address =
outstanding_requests.find(id)->second.paddr;
RubyRequestType type = outstanding_requests.find(id)->second.type; RubyRequestType type = outstanding_requests.find(id)->second.type;
#ifdef DEBUG_WRITE_BUFFER #ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("\n***StoreBuffer: complete BEGIN, contents:\n"); DEBUG_OUT("\n***StoreBuffer: complete BEGIN, contents:\n");
@ -387,184 +324,59 @@ void StoreBuffer::complete(uint64_t id) {
#endif #endif
if (type == RubyRequestType_ST) { if (type == RubyRequestType_ST) {
physical_address_t lineaddr = physical_address & m_block_mask; physical_address_t lineaddr = physical_address & m_block_mask;
//Note fastpath hits are handled like regular requests - they must remove the WB entry! // Note fastpath hits are handled like regular requests - they
if ( lineaddr != physical_address ) { // must remove the WB entry!
ERROR_OUT("error: StoreBuffer: ruby returns pa 0x%0llx which is not a cache line: 0x%0llx\n", physical_address, lineaddr ); if (lineaddr != physical_address) {
} ERROR_OUT("error: StoreBuffer: ruby returns pa 0x%0llx "
"which is not a cache line: 0x%0llx\n",
physical_address, lineaddr);
}
SBEntry from_buffer = buffer.back(); SBEntry from_buffer = buffer.back();
if (((from_buffer.m_request.paddr & m_block_mask) == lineaddr) && (from_buffer.m_request.type == type)) { if ((from_buffer.m_request.paddr & m_block_mask) == lineaddr &&
buffer.pop_back(); from_buffer.m_request.type == type) {
m_buffer_size--; buffer.pop_back();
ASSERT(m_buffer_size >= 0); m_buffer_size--;
ASSERT(m_buffer_size >= 0);
#if RUBY_TSO_CHECKER // schedule the next request
int len = outstanding_requests.find(id)->second.len; if (m_buffer_size > 0) {
uint64_t data = 0; issueNextStore();
memcpy(&data, from_buffer.m_request.data, 4); } else if (m_buffer_size == 0) {
m_storebuffer_flushing = false;
cerr << m_id << " INSERTING STORE" << endl << flush; m_stalled_issue = true;
// add to the tsoChecker
g_tsoChecker->input(m_id, // this thread id
(id & ISEQ_MASK), // instruction sequence
ITYPE_STORE, // is a store
MEM_STORE_COMMIT, // commit
physical_address, // the address
data, // and data
len, // and len
DSRC_STB, // shouldn't matter
libruby_get_time(), // macc
libruby_get_time(), // gobs
libruby_get_time()); // time
tso_iseq++;
// also add the loads that are satisfied by this store
if (from_buffer.m_next_ptr != NULL) {
from_buffer.m_next_ptr->setGobs(libruby_get_time());
g_tsoChecker->input(*(from_buffer.m_next_ptr));
cerr << m_id << " INSERTING LOAD for STORE: " << from_buffer.m_next_ptr->getIseq() << endl << flush;
tso_iseq++;
Tso::TsoCheckerCmd * to_input = from_buffer.m_next_ptr->getNext();
while (to_input != NULL) {
if (to_input->getGobs() == 0) {
to_input->setGobs(libruby_get_time());
} }
cerr << m_id << " INSERTING LOAD iseq for STORE: " << to_input->getIseq() << endl << flush;
g_tsoChecker->input(*to_input);
tso_iseq++;
to_input = to_input->getNext();
}
}
#endif
// schedule the next request
if (m_buffer_size > 0) {
issueNextStore();
}
else if (m_buffer_size == 0) {
m_storebuffer_flushing = false;
m_stalled_issue = true;
}
m_storebuffer_full = false; m_storebuffer_full = false;
} else {
} ERROR_OUT("[%d] error: StoreBuffer: at complete, address 0x%0llx "
else { "not found.\n", m_id, lineaddr);
ERROR_OUT("[%d] error: StoreBuffer: at complete, address 0x%0llx not found.\n", m_id, lineaddr); ERROR_OUT("StoreBuffer:: complete FAILS\n");
ERROR_OUT("StoreBuffer:: complete FAILS\n"); ASSERT(0);
ASSERT(0); }
}
#ifdef DEBUG_WRITE_BUFFER #ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("***StoreBuffer: complete END, contents:\n"); DEBUG_OUT("***StoreBuffer: complete END, contents:\n");
DEBUG_OUT("\n"); DEBUG_OUT("\n");
#endif #endif
} // end if (type == ST) } else if (type == RubyRequestType_LD) {
else if (type == RubyRequestType_LD) { m_hit_callback(id);
#if RUBY_TSO_CHECKER
RubyRequest request = outstanding_requests.find(id)->second;
uint64_t data = 0;
memcpy(&data, request.data, request.len);
// add to the tsoChecker if in order, otherwise, find a place to put ourselves
if ((id & ISEQ_MASK) == tso_iseq) {
tso_iseq++;
cerr << m_id << " INSERTING LOAD" << endl << flush;
g_tsoChecker->input(m_id, // this thread id
(id & ISEQ_MASK), // instruction sequence
ITYPE_LOAD, // is a store
MEM_LOAD_DATA, // commit
request.paddr, // the address
data, // and data
request.len, // and len
DSRC_L2_MEMORY, // shouldn't matter DSRC_L1
libruby_get_time(), // macc: for store macc and time are the same and it
libruby_get_time(), // macc
libruby_get_time()); // time
}
else {
Tso::TsoCheckerCmd * cmd;
cmd = new Tso::TsoCheckerCmd(m_id, // this thread id
(id & ISEQ_MASK), // instruction sequence
ITYPE_LOAD, // is a store
MEM_LOAD_DATA, // commit
request.paddr, // the address
data, // and data
request.len, // and len
DSRC_L2_MEMORY, // shouldn't matter DSRC_L1
libruby_get_time(), // macc: for store macc and time are the same and it
libruby_get_time(), // macc
libruby_get_time()); // time
insertTsoLL(cmd);
}
#endif
m_hit_callback(id);
} }
// LD, ST or FETCH hit callback // LD, ST or FETCH hit callback
outstanding_requests.erase(id); outstanding_requests.erase(id);
} // end if(m_use_storebuffer)
else {
m_hit_callback(id);
}
} }
#if RUBY_TSO_CHECKER void
void StoreBuffer::insertTsoLL(Tso::TsoCheckerCmd * cmd) { StoreBuffer::print()
uint64_t count = cmd->getIseq();
Tso::TsoCheckerCmd * current = NULL;
Tso::TsoCheckerCmd * previous = NULL;
deque<struct SBEntry>::reverse_iterator iter;
bool found = false;
for (iter = buffer.rbegin(); iter != buffer.rend(); ++ iter) {
if (iter->m_next_ptr != NULL) {
current = iter->m_next_ptr->getNext(); // initalize both to the beginning of the linked list
previous = current;
while (current != NULL) {
if (current->getIseq() > count) {
found = true;
break;
}
previous = current;
current = current->getNext();
}
}
// break out if found a match, iterator should still point to the right SBEntry
if (found) {
break;
}
}
// will insert at the end if not found
if (!found) {
buffer.front().m_next_ptr = cmd;
}
else if (current == previous) {
cerr << "INSERTING " << count << " BEFORE: " << iter->m_next_ptr->getIseq();
Tso::TsoCheckerCmd * temp = iter->m_next_ptr;
iter->m_next_ptr = cmd;
cmd->setNext(temp);
}
else {
cerr << "INSERTING " << count << " BETWEEN: " << previous->getIseq() << " AND " << current->getIseq();
cmd->setNext(current);
previous->setNext(cmd);
}
}
#endif
//***************************************************************************************************
void StoreBuffer::print( void )
{ {
DEBUG_OUT("[%d] StoreBuffer: Total entries: %d Outstanding: %d\n", m_id, m_buffer_size); DEBUG_OUT("[%d] StoreBuffer: Total entries: %d Outstanding: %d\n",
m_id, m_buffer_size);
if(m_use_storebuffer){ if (!m_use_storebuffer)
} DEBUG_OUT("\t WRITE BUFFER NOT USED\n");
else{
DEBUG_OUT("\t WRITE BUFFER NOT USED\n");
}
} }

View file

@ -26,23 +26,18 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef _STOREBUFFER_H_ #ifndef __MEM_RUBY_STOREBUFFER_STOREBUFFER_HH__
#define _STOREBUFFER_H_ #define __MEM_RUBY_STOREBUFFER_STOREBUFFER_HH__
#include <map>
#include <deque> #include <deque>
#include <map>
#include "config/ruby_tso_checker.hh" #include "mem/ruby/common/TypeDefines.hh"
#include "mem/ruby/storebuffer/hfa.hh"
#include "mem/ruby/libruby.hh" #include "mem/ruby/libruby.hh"
#if RUBY_TSO_CHECKER
#include "TsoCheckerCmd.hh"
#endif
/** /**
* Status for write buffer accesses. The Write buffer can hit in fastpath, be full, or * Status for write buffer accesses. The Write buffer can hit in
* successfully enqueue the store request * fastpath, be full, or successfully enqueue the store request
*/ */
enum storebuffer_status_t { WB_FULL, WB_OK, WB_FLUSHING }; enum storebuffer_status_t { WB_FULL, WB_OK, WB_FLUSHING };
@ -51,114 +46,106 @@ enum storebuffer_status_t { WB_FULL, WB_OK, WB_FLUSHING };
*/ */
enum load_match { NO_MATCH, PARTIAL_MATCH, FULL_MATCH }; enum load_match { NO_MATCH, PARTIAL_MATCH, FULL_MATCH };
struct SBEntry { struct SBEntry
struct RubyRequest m_request; {
#if RUBY_TSO_CHECKER RubyRequest m_request;
Tso::TsoCheckerCmd * m_next_ptr;
#endif SBEntry(RubyRequest request, void * ptr)
SBEntry(struct RubyRequest request, void * ptr) : m_request(request)
: m_request(request)
{ {
#if RUBY_TSO_CHECKER
m_next_ptr = (Tso::TsoCheckerCmd*) ptr;
#endif
} }
}; };
class StoreBuffer { class StoreBuffer
public: {
///Constructor public:
/// Note that the size of the Write Buffer is determined by the WRITE_BUFFER_SIZE config parameter /// Note that the size of the Write Buffer is determined by the
StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size); /// WRITE_BUFFER_SIZE config parameter
StoreBuffer(uint32_t id, uint32_t block_bits, int storebuffer_size);
/// Register hitcallback back to CPU ~StoreBuffer();
void registerHitCallback(void (*hit_callback)(int64_t request_id));
/// Destructor /// Register hitcallback back to CPU
~StoreBuffer(); void registerHitCallback(void (*hit_callback)(int64_t request_id));
///Adds a store entry to the write buffer ///Adds a store entry to the write buffer
void addToStoreBuffer(struct RubyRequest request); void addToStoreBuffer(RubyRequest request);
///Flushes the entire write buffer ///Flushes the entire write buffer
void flushStoreBuffer(); void flushStoreBuffer();
///A pseq object calls this when Ruby completes our request ///A pseq object calls this when Ruby completes our request
void complete(uint64_t); void complete(uint64_t);
/// Returns ID. If ID == -2, HIT, else it's an ID to wait on /// Returns ID. If ID == -2, HIT, else it's an ID to wait on
int64_t handleLoad(struct RubyRequest request); int64_t handleLoad(RubyRequest request);
/// Used by all load insts to check whether it hits to any entry in the WB. If so, the WB is flushed /// Used by all load insts to check whether it hits to any entry
load_match checkForLoadHit(struct RubyRequest request); /// in the WB. If so, the WB is flushed
load_match checkForLoadHit(RubyRequest request);
/// Used to fill the load in case of FULL_MATCH /// Used to fill the load in case of FULL_MATCH
void returnMatchedData(struct RubyRequest request); void returnMatchedData(RubyRequest request);
/// Issue next store in line /// Issue next store in line
void issueNextStore(); void issueNextStore();
/// prints out the contents of the Write Buffer /// prints out the contents of the Write Buffer
void print(); void print();
#if RUBY_TSO_CHECKER /// Returns flag indicating whether we are using the write buffer
/// if load completes before store, insert correctly to be issued to TSOChecker bool useStoreBuffer() { return m_use_storebuffer; }
void insertTsoLL(Tso::TsoCheckerCmd * cmd);
#endif
/// Returns flag indicating whether we are using the write buffer bool storeBufferFull() { return m_storebuffer_full; }
bool useStoreBuffer() { return m_use_storebuffer; }
bool storeBufferFull() { return m_storebuffer_full; } bool storeBufferFlushing() { return m_storebuffer_flushing; }
bool storeBufferFlushing() { return m_storebuffer_flushing; } private:
/// id of this write buffer (one per sequencer object)
uint32_t m_id;
private: /// number of bytes in cacheline
/// id of this write buffer (one per sequencer object) uint32_t m_block_size;
uint32 m_id;
/// number of bytes in cacheline /// the size of the write buffer
uint32 m_block_size; uint32_t m_storebuffer_size;
/// the size of the write buffer /// mask to strip off non-cache line bits
uint32 m_storebuffer_size; pa_t m_block_mask;
/// mask to strip off non-cache line bits /// list of store requests in the write buffer
pa_t m_block_mask; std::deque<SBEntry> buffer;
/// list of store requests in the write buffer /// the current length of the write buffer
deque <struct SBEntry> buffer; uint32_t m_buffer_size;
/// the current length of the write buffer /// whether we want to simulate the write buffer or not:
uint32 m_buffer_size; bool m_use_storebuffer;
/// whether we want to simulate the write buffer or not: /// indicates whether the write buffer is full or not
bool m_use_storebuffer; bool m_storebuffer_full;
/// indicates whether the write buffer is full or not /// indicates that we are currently flushing the write buffer
bool m_storebuffer_full; bool m_storebuffer_flushing;
/// indicates that we are currently flushing the write buffer /// indicates that automatic issue is stalled and the next store
bool m_storebuffer_flushing; /// to be added should issue itself
bool m_stalled_issue;
/// indicates that automatic issue is stalled and the next store to be added should issue itself /// RubyPort to make requests to
bool m_stalled_issue; RubyPortHandle m_port;
/// RubyPort to make requests to /// HitCallback to CPU
RubyPortHandle m_port; void (*m_hit_callback)(int64_t);
/// HitCallback to CPU /// Map the request id to rubyrequest
void (*m_hit_callback)(int64_t); std::map<uint64_t, RubyRequest> outstanding_requests;
/// Map the request id to rubyrequest /// current instruction counter
map<uint64_t, struct RubyRequest> outstanding_requests; uint64_t iseq;
/// current instruction counter /// input into tso counter
uint64_t iseq; uint64_t tso_iseq;
/// input into tso counter
uint64_t tso_iseq;
}; };
#endif #endif // __MEM_RUBY_STOREBUFFER_STOREBUFFER_HH__