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,28 +41,26 @@ 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:
@ -79,17 +77,21 @@ int Network::MessageSizeType_to_int(MessageSizeType size_type)
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;
break;
default: default:
ERROR_MSG("Invalid range for type MessageSizeType"); ERROR_MSG("Invalid range for type MessageSizeType");
break; break;
} }
return 0; return 0;
} }
const Vector<Throttle*>*
Network::getThrottles(NodeID id) const
{
return NULL;
}

View file

@ -27,47 +27,40 @@
*/ */
/* /*
* 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();
// Destructor
virtual ~Network() {} virtual ~Network() {}
// Public Methods virtual void init();
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; }
@ -75,17 +68,23 @@ public:
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 // returns the queue requested for the given component
virtual MessageBuffer* getToNetQueue(NodeID id, bool ordered, int netNumber) = 0; virtual MessageBuffer* getToNetQueue(NodeID id, bool ordered,
virtual MessageBuffer* getFromNetQueue(NodeID id, bool ordered, int netNumber) = 0; int netNumber) = 0;
virtual const Vector<Throttle*>* getThrottles(NodeID id) const { return NULL; } virtual MessageBuffer* getFromNetQueue(NodeID id, bool ordered,
int netNumber) = 0;
virtual const Vector<Throttle*>* getThrottles(NodeID id) const;
virtual int getNumNodes() {return 1;} virtual int getNumNodes() {return 1;}
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 makeOutLink(SwitchID src, NodeID dest,
virtual void makeInLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int bw_multiplier, bool isReconfiguration) = 0; const NetDest& routing_table_entry, int link_latency, int link_weight,
virtual void makeInternalLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration) = 0; int bw_multiplier, bool isReconfiguration) = 0;
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 void reset() = 0; virtual void reset() = 0;
@ -94,15 +93,12 @@ public:
virtual void printConfig(ostream& out) const = 0; virtual void printConfig(ostream& out) const = 0;
virtual void print(ostream& out) const = 0; virtual void print(ostream& out) const = 0;
protected: protected:
// Private Methods
// Private copy constructor and assignment operator // Private copy constructor and assignment operator
Network(const Network& obj); Network(const Network& obj);
Network& operator=(const Network& obj); Network& operator=(const Network& obj);
// Data Members (m_ prefix) protected:
protected:
const string m_name; const string m_name;
int m_nodes; int m_nodes;
int m_virtual_networks; int m_virtual_networks;
@ -115,18 +111,12 @@ protected:
int m_data_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,29 +26,21 @@
* 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
operator<(const LinkOrder& l1, const LinkOrder& l2)
{
return (l1.m_value < l2.m_value); return (l1.m_value < l2.m_value);
} }
@ -62,19 +53,24 @@ PerfectSwitch::PerfectSwitch(SwitchID sid, SimpleNetwork* 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]",
NodeIDToString(m_switch_id), NodeIDToString(port),
NodeIDToString(j));
m_in[port][j]->setDescription(desc); m_in[port][j]->setDescription(desc);
} }
} }
void PerfectSwitch::addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routing_table_entry) void
PerfectSwitch::addOutPort(const Vector<MessageBuffer*>& out,
const NetDest& routing_table_entry)
{ {
assert(out.size() == m_virtual_networks); assert(out.size() == m_virtual_networks);
@ -87,30 +83,32 @@ void PerfectSwitch::addOutPort(const Vector<MessageBuffer*>& out, const NetDest&
// Add to routing table // Add to routing table
m_out.insertAtBottom(out); m_out.insertAtBottom(out);
m_routing_table.insertAtBottom(routing_table_entry); m_routing_table.insertAtBottom(routing_table_entry);
} }
void PerfectSwitch::clearRoutingTables() void
PerfectSwitch::clearRoutingTables()
{ {
m_routing_table.clear(); m_routing_table.clear();
} }
void PerfectSwitch::clearBuffers() void
PerfectSwitch::clearBuffers()
{ {
for(int i=0; i<m_in.size(); i++){ for (int i = 0; i < m_in.size(); i++){
for(int vnet=0; vnet < m_virtual_networks; vnet++) { for(int vnet = 0; vnet < m_virtual_networks; vnet++) {
m_in[i][vnet]->clear(); m_in[i][vnet]->clear();
} }
} }
for(int i=0; i<m_out.size(); i++){ for (int i = 0; i < m_out.size(); i++){
for(int vnet=0; vnet < m_virtual_networks; vnet++) { for(int vnet = 0; vnet < m_virtual_networks; vnet++) {
m_out[i][vnet]->clear(); m_out[i][vnet]->clear();
} }
} }
} }
void PerfectSwitch::reconfigureOutPort(const NetDest& routing_table_entry) void
PerfectSwitch::reconfigureOutPort(const NetDest& routing_table_entry)
{ {
m_routing_table.insertAtBottom(routing_table_entry); m_routing_table.insertAtBottom(routing_table_entry);
} }
@ -119,9 +117,9 @@ 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;
@ -141,10 +139,13 @@ void PerfectSwitch::wakeup()
decrementer = -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;
(vnet * decrementer) >= (decrementer * lowest_prio_vnet);
vnet -= decrementer) {
// This is for round-robin scheduling
int incoming = m_round_robin_start;
m_round_robin_start++; m_round_robin_start++;
if (m_round_robin_start >= m_in.size()) { if (m_round_robin_start >= m_in.size()) {
m_round_robin_start = 0; m_round_robin_start = 0;
@ -152,7 +153,6 @@ void PerfectSwitch::wakeup()
// for all input ports, use round robin scheduling // for all input ports, use round robin scheduling
for (int counter = 0; counter < m_in.size(); counter++) { for (int counter = 0; counter < m_in.size(); counter++) {
// Round robin scheduling // Round robin scheduling
incoming++; incoming++;
if (incoming >= m_in.size()) { if (incoming >= m_in.size()) {
@ -165,7 +165,6 @@ void PerfectSwitch::wakeup()
// Is there a message waiting? // Is there a message waiting?
while (m_in[incoming][vnet]->isReady()) { while (m_in[incoming][vnet]->isReady()) {
DEBUG_EXPR(NETWORK_COMP, MedPrio, incoming); DEBUG_EXPR(NETWORK_COMP, MedPrio, incoming);
// Peek at message // Peek at message
@ -175,11 +174,12 @@ void PerfectSwitch::wakeup()
output_links.clear(); output_links.clear();
output_link_destinations.clear(); output_link_destinations.clear();
NetDest msg_destinations = net_msg_ptr->getInternalDestination(); NetDest msg_dsts =
net_msg_ptr->getInternalDestination();
// Unfortunately, the token-protocol sends some // Unfortunately, the token-protocol sends some
// zero-destination messages, so this assert isn't valid // zero-destination messages, so this assert isn't valid
// assert(msg_destinations.count() > 0); // assert(msg_dsts.count() > 0);
assert(m_link_order.size() == m_routing_table.size()); assert(m_link_order.size() == m_routing_table.size());
assert(m_link_order.size() == m_out.size()); assert(m_link_order.size() == m_out.size());
@ -187,67 +187,74 @@ void PerfectSwitch::wakeup()
if (m_network_ptr->getAdaptiveRouting()) { if (m_network_ptr->getAdaptiveRouting()) {
if (m_network_ptr->isVNetOrdered(vnet)) { if (m_network_ptr->isVNetOrdered(vnet)) {
// Don't adaptively route // Don't adaptively route
for (int outlink=0; outlink<m_out.size(); outlink++) { for (int out = 0; out < m_out.size(); out++) {
m_link_order[outlink].m_link = outlink; m_link_order[out].m_link = out;
m_link_order[outlink].m_value = 0; m_link_order[out].m_value = 0;
} }
} else { } else {
// Find how clogged each link is // Find how clogged each link is
for (int outlink=0; outlink<m_out.size(); outlink++) { for (int out = 0; out < m_out.size(); out++) {
int out_queue_length = 0; int out_queue_length = 0;
for (int v=0; v<m_virtual_networks; v++) { for (int v = 0; v < m_virtual_networks; v++) {
out_queue_length += m_out[outlink][v]->getSize(); out_queue_length += m_out[out][v]->getSize();
} }
m_link_order[outlink].m_link = outlink; int value =
m_link_order[outlink].m_value = 0; (out_queue_length << 8) | (random() & 0xff);
m_link_order[outlink].m_value |= (out_queue_length << 8); m_link_order[out].m_link = out;
m_link_order[outlink].m_value |= (random() & 0xff); m_link_order[out].m_value = value;
} }
m_link_order.sortVector(); // Look at the most empty link first
// Look at the most empty link first
m_link_order.sortVector();
} }
} }
for (int i=0; i<m_routing_table.size(); i++) { for (int i = 0; i < m_routing_table.size(); i++) {
// pick the next link to look at // pick the next link to look at
int link = m_link_order[i].m_link; int link = m_link_order[i].m_link;
NetDest dst = m_routing_table[link];
DEBUG_EXPR(NETWORK_COMP, MedPrio, dst);
DEBUG_EXPR(NETWORK_COMP, MedPrio, m_routing_table[link]); if (!msg_dsts.intersectionIsNotEmpty(dst))
continue;
if (msg_destinations.intersectionIsNotEmpty(m_routing_table[link])) {
// Remember what link we're using // Remember what link we're using
output_links.insertAtBottom(link); output_links.insertAtBottom(link);
// Need to remember which destinations need this message // Need to remember which destinations need this
// in another vector. This Set is the intersection of the // message in another vector. This Set is the
// routing_table entry and the current destination set. // intersection of the routing_table entry and the
// The intersection must not be empty, since we are inside "if" // current destination set. The intersection must
output_link_destinations.insertAtBottom(msg_destinations.AND(m_routing_table[link])); // 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 // Next, we update the msg_destination not to
// those nodes that were already handled by this link // include those nodes that were already handled
msg_destinations.removeNetDest(m_routing_table[link]); // by this link
} msg_dsts.removeNetDest(dst);
} }
assert(msg_destinations.count() == 0); assert(msg_dsts.count() == 0);
//assert(output_links.size() > 0); //assert(output_links.size() > 0);
// Check for resources - for all outgoing queues // Check for resources - for all outgoing queues
bool enough = true; bool enough = true;
for (int i=0; i<output_links.size(); i++) { for (int i = 0; i < output_links.size(); i++) {
int outgoing = output_links[i]; int outgoing = output_links[i];
enough = enough && m_out[outgoing][vnet]->areNSlotsAvailable(1); if (!m_out[outgoing][vnet]->areNSlotsAvailable(1))
DEBUG_MSG(NETWORK_COMP, HighPrio, "checking if node is blocked"); enough = false;
DEBUG_MSG(NETWORK_COMP, HighPrio,
"checking if node is blocked");
DEBUG_EXPR(NETWORK_COMP, HighPrio, outgoing); DEBUG_EXPR(NETWORK_COMP, HighPrio, outgoing);
DEBUG_EXPR(NETWORK_COMP, HighPrio, vnet); DEBUG_EXPR(NETWORK_COMP, HighPrio, vnet);
DEBUG_EXPR(NETWORK_COMP, HighPrio, enough); DEBUG_EXPR(NETWORK_COMP, HighPrio, enough);
} }
// There were not enough resources // There were not enough resources
if(!enough) { if (!enough) {
g_eventQueue_ptr->scheduleEvent(this, 1); g_eventQueue_ptr->scheduleEvent(this, 1);
DEBUG_MSG(NETWORK_COMP, HighPrio, "Can't deliver message to anyone since a node is blocked"); DEBUG_MSG(NETWORK_COMP, HighPrio,
"Can't deliver message since a node is blocked");
DEBUG_EXPR(NETWORK_COMP, HighPrio, *net_msg_ptr); DEBUG_EXPR(NETWORK_COMP, HighPrio, *net_msg_ptr);
break; // go to next incoming port break; // go to next incoming port
} }
@ -255,12 +262,16 @@ void PerfectSwitch::wakeup()
MsgPtr unmodified_msg_ptr; MsgPtr unmodified_msg_ptr;
if (output_links.size() > 1) { if (output_links.size() > 1) {
// If we are sending this message down more than one link // If we are sending this message down more than
// (size>1), we need to make a copy of the message so each // one link (size>1), we need to make a copy of
// branch can have a different internal destination // the message so each branch can have a different
// we need to create an unmodified MsgPtr because the MessageBuffer enqueue func // internal destination we need to create an
// will modify the message // unmodified MsgPtr because the MessageBuffer
unmodified_msg_ptr = *(msg_ptr.ref()); // This magic line creates a private copy of the message // 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 // Enqueue it - for all outgoing queues
@ -268,21 +279,25 @@ void PerfectSwitch::wakeup()
int outgoing = output_links[i]; int outgoing = output_links[i];
if (i > 0) { if (i > 0) {
msg_ptr = *(unmodified_msg_ptr.ref()); // create a private copy of the unmodified message // create a private copy of the unmodified
// message
msg_ptr = *(unmodified_msg_ptr.ref());
} }
// Change the internal destination set of the message so it // Change the internal destination set of the
// knows which destinations this link is responsible for. // message so it knows which destinations this
net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref()); // link is responsible for.
net_msg_ptr->getInternalDestination() = output_link_destinations[i]; net_msg_ptr = safe_cast<NetworkMessage*>(msg_ptr.ref());
net_msg_ptr->getInternalDestination() =
output_link_destinations[i];
// Enqeue msg // Enqeue msg
DEBUG_NEWLINE(NETWORK_COMP,HighPrio); DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
DEBUG_MSG(NETWORK_COMP,HighPrio,"switch: " + int_to_string(m_switch_id) DEBUG_MSG(NETWORK_COMP, HighPrio,
+ " enqueuing net msg from inport[" + int_to_string(incoming) + "][" csprintf("switch: %d enqueuing net msg from "
+ int_to_string(vnet) +"] to outport [" + int_to_string(outgoing) "inport[%d][%d] to outport [%d][%d] time: %d.",
+ "][" + int_to_string(vnet) +"]" m_switch_id, incoming, vnet, outgoing, vnet,
+ " time: " + int_to_string(g_eventQueue_ptr->getTime()) + "."); g_eventQueue_ptr->getTime()));
DEBUG_NEWLINE(NETWORK_COMP,HighPrio); DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
m_out[outgoing][vnet]->enqueue(msg_ptr); m_out[outgoing][vnet]->enqueue(msg_ptr);
@ -295,20 +310,24 @@ void PerfectSwitch::wakeup()
} }
} }
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,54 +27,47 @@
*/ */
/* /*
* $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_link;
int m_value; int m_value;
}; };
class PerfectSwitch : public Consumer { class PerfectSwitch : public Consumer
public: {
// Constructors public:
// constructor specifying the number of ports
PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr); PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr);
~PerfectSwitch();
void addInPort(const Vector<MessageBuffer*>& in); void addInPort(const Vector<MessageBuffer*>& in);
void addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routing_table_entry); void addOutPort(const Vector<MessageBuffer*>& out,
const NetDest& routing_table_entry);
void clearRoutingTables(); void clearRoutingTables();
void clearBuffers(); void clearBuffers();
void reconfigureOutPort(const NetDest& routing_table_entry); void reconfigureOutPort(const NetDest& routing_table_entry);
int getInLinks() const { return m_in.size(); } int getInLinks() const { return m_in.size(); }
int getOutLinks() const { return m_out.size(); } int getOutLinks() const { return m_out.size(); }
// Destructor
~PerfectSwitch();
// Public Methods
void wakeup(); void wakeup();
void printStats(std::ostream& out) const; void printStats(std::ostream& out) const;
@ -83,13 +75,12 @@ public:
void printConfig(std::ostream& out) const; void printConfig(std::ostream& out) const;
void print(std::ostream& out) const; void print(std::ostream& out) const;
private:
private:
// Private copy constructor and assignment operator // Private copy constructor and assignment operator
PerfectSwitch(const PerfectSwitch& obj); PerfectSwitch(const PerfectSwitch& obj);
PerfectSwitch& operator=(const PerfectSwitch& obj); PerfectSwitch& operator=(const PerfectSwitch& obj);
// Data Members (m_ prefix)
SwitchID m_switch_id; SwitchID m_switch_id;
// vector of queues from the components // vector of queues from the components
@ -103,18 +94,12 @@ private:
SimpleNetwork* m_network_ptr; SimpleNetwork* m_network_ptr;
}; };
// Output operator declaration inline std::ostream&
std::ostream& operator<<(std::ostream& out, const PerfectSwitch& obj); 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); obj.print(out);
out << std::flush; out << std::flush;
return out; 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,46 +26,36 @@
* 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);
@ -92,24 +81,25 @@ SimpleNetwork::SimpleNetwork(const Params *p)
} }
} }
void SimpleNetwork::init() void
SimpleNetwork::init()
{ {
Network::init(); Network::init();
// // The topology pointer should have already been initialized in
// The topology pointer should have already been initialized in the parent // the parent class network constructor.
// class network constructor.
//
assert(m_topology_ptr != NULL); assert(m_topology_ptr != NULL);
int number_of_switches = m_topology_ptr->numSwitches(); int number_of_switches = m_topology_ptr->numSwitches();
for (int i=0; i<number_of_switches; i++) { for (int i = 0; i < number_of_switches; i++) {
m_switch_ptr_vector.insertAtBottom(new Switch(i, this)); m_switch_ptr_vector.insertAtBottom(new Switch(i, this));
} }
m_topology_ptr->createLinks(this, false); // false because this isn't a reconfiguration
// false because this isn't a reconfiguration
m_topology_ptr->createLinks(this, false);
} }
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++) {
@ -118,7 +108,7 @@ void SimpleNetwork::reset()
} }
} }
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();
} }
} }
@ -135,34 +125,51 @@ SimpleNetwork::~SimpleNetwork()
} }
// 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_endpoint_switches[dest] = m_switch_ptr_vector[src];
} else {
m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry); 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];
} }
// 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) {
m_switch_ptr_vector[dest]->addInPort(m_toNetQueues[src]);
} else {
// do nothing // do nothing
return;
} }
m_switch_ptr_vector[dest]->addInPort(m_toNetQueues[src]);
} }
// 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++) {
@ -176,16 +183,14 @@ void SimpleNetwork::makeInternalLink(SwitchID src, SwitchID dest, const NetDest&
// 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);
@ -196,19 +201,22 @@ void SimpleNetwork::checkNetworkAllocation(NodeID id, bool ordered, int network_
m_in_use[network_num] = true; m_in_use[network_num] = true;
} }
MessageBuffer* SimpleNetwork::getToNetQueue(NodeID id, bool ordered, int network_num) MessageBuffer*
SimpleNetwork::getToNetQueue(NodeID id, bool ordered, int network_num)
{ {
checkNetworkAllocation(id, ordered, network_num); checkNetworkAllocation(id, ordered, network_num);
return m_toNetQueues[id][network_num]; return m_toNetQueues[id][network_num];
} }
MessageBuffer* SimpleNetwork::getFromNetQueue(NodeID id, bool ordered, int network_num) MessageBuffer*
SimpleNetwork::getFromNetQueue(NodeID id, bool ordered, int network_num)
{ {
checkNetworkAllocation(id, ordered, network_num); checkNetworkAllocation(id, ordered, network_num);
return m_fromNetQueues[id][network_num]; return m_fromNetQueues[id][network_num];
} }
const Vector<Throttle*>* SimpleNetwork::getThrottles(NodeID id) const const Vector<Throttle*>*
SimpleNetwork::getThrottles(NodeID id) const
{ {
assert(id >= 0); assert(id >= 0);
assert(id < m_nodes); assert(id < m_nodes);
@ -216,27 +224,30 @@ const Vector<Throttle*>* SimpleNetwork::getThrottles(NodeID id) const
return m_endpoint_switches[id]->getThrottles(); return m_endpoint_switches[id]->getThrottles();
} }
void SimpleNetwork::printStats(ostream& out) const void
SimpleNetwork::printStats(ostream& out) const
{ {
out << endl; out << endl;
out << "Network Stats" << endl; out << "Network Stats" << endl;
out << "-------------" << endl; out << "-------------" << endl;
out << endl; out << endl;
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]->printStats(out); m_switch_ptr_vector[i]->printStats(out);
} }
m_topology_ptr->printStats(out); m_topology_ptr->printStats(out);
} }
void SimpleNetwork::clearStats() void
SimpleNetwork::clearStats()
{ {
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]->clearStats(); m_switch_ptr_vector[i]->clearStats();
} }
m_topology_ptr->clearStats(); m_topology_ptr->clearStats();
} }
void SimpleNetwork::printConfig(ostream& out) const void
SimpleNetwork::printConfig(ostream& out) const
{ {
out << endl; out << endl;
out << "Network Configuration" << endl; out << "Network Configuration" << endl;
@ -259,14 +270,16 @@ void SimpleNetwork::printConfig(ostream& out) const
} }
} }
out << endl; out << endl;
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]->printConfig(out); m_switch_ptr_vector[i]->printConfig(out);
} }
m_topology_ptr->printConfig(out); m_topology_ptr->printConfig(out);
} }
void SimpleNetwork::print(ostream& out) const void
SimpleNetwork::print(ostream& out) const
{ {
out << "[SimpleNetwork]"; 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,18 +76,15 @@ 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);
// Destructor
~SimpleNetwork(); ~SimpleNetwork();
void init(); void init();
// Public Methods
void printStats(ostream& out) const; void printStats(ostream& out) const;
void clearStats(); void clearStats();
void printConfig(ostream& out) const; void printConfig(ostream& out) const;
@ -111,26 +102,31 @@ public:
int getNumNodes() {return m_nodes; } int getNumNodes() {return m_nodes; }
// Methods used by Topology to setup the network // 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 makeOutLink(SwitchID src, NodeID dest,
void makeInLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int bw_multiplier, bool isReconfiguration); const NetDest& routing_table_entry, int link_latency, int link_weight,
void makeInternalLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration); 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; 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, const NetDest& routing_table_entry, int link_latency); void makeLink(SwitchID src, SwitchID dest,
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 // Private copy constructor and assignment operator
SimpleNetwork(const SimpleNetwork& obj); SimpleNetwork(const SimpleNetwork& obj);
SimpleNetwork& operator=(const SimpleNetwork& obj); SimpleNetwork& operator=(const SimpleNetwork& obj);
// Data Members (m_ prefix)
// vector of queues from the components // vector of queues from the components
Vector<Vector<MessageBuffer*> > m_toNetQueues; Vector<Vector<MessageBuffer*> > m_toNetQueues;
Vector<Vector<MessageBuffer*> > m_fromNetQueues; Vector<Vector<MessageBuffer*> > m_fromNetQueues;
@ -142,18 +138,12 @@ private:
Vector<Switch*> m_endpoint_switches; 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,23 +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.
*/ */
/*
* 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)
{ {
@ -63,27 +52,31 @@ Switch::~Switch()
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,
bw_multiplier);
m_throttles.insertAtBottom(throttle_ptr); 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); intermediateBuffers.insertAtBottom(buffer_ptr);
@ -95,112 +88,130 @@ void Switch::addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routin
// Hook the queues to the Throttle // Hook the queues to the Throttle
throttle_ptr->addLinks(intermediateBuffers, out); throttle_ptr->addLinks(intermediateBuffers, out);
} }
void Switch::clearRoutingTables() void
Switch::clearRoutingTables()
{ {
m_perfect_switch_ptr->clearRoutingTables(); m_perfect_switch_ptr->clearRoutingTables();
} }
void Switch::clearBuffers() void
Switch::clearBuffers()
{ {
m_perfect_switch_ptr->clearBuffers(); m_perfect_switch_ptr->clearBuffers();
for (int i=0; i<m_throttles.size(); i++) { for (int i = 0; i < m_throttles.size(); i++) {
if (m_throttles[i] != NULL) { if (m_throttles[i] != NULL) {
m_throttles[i]->clear(); m_throttles[i]->clear();
} }
} }
} }
void Switch::reconfigureOutPort(const NetDest& routing_table_entry) void
Switch::reconfigureOutPort(const NetDest& routing_table_entry)
{ {
m_perfect_switch_ptr->reconfigureOutPort(routing_table_entry); m_perfect_switch_ptr->reconfigureOutPort(routing_table_entry);
} }
const Throttle* Switch::getThrottle(LinkID link_number) const const Throttle*
Switch::getThrottle(LinkID link_number) const
{ {
assert(m_throttles[link_number] != NULL); assert(m_throttles[link_number] != NULL);
return m_throttles[link_number]; return m_throttles[link_number];
} }
const Vector<Throttle*>* Switch::getThrottles() const const Vector<Throttle*>*
Switch::getThrottles() const
{ {
return &m_throttles; return &m_throttles;
} }
void Switch::printStats(std::ostream& out) const void
Switch::printStats(std::ostream& out) const
{ {
using namespace std; using namespace std;
out << "switch_" << m_switch_id << "_inlinks: " << m_perfect_switch_ptr->getInLinks() << endl; ccprintf(out, "switch_%d_inlinks: %d\n", m_switch_id,
out << "switch_" << m_switch_id << "_outlinks: " << m_perfect_switch_ptr->getOutLinks() << endl; m_perfect_switch_ptr->getInLinks());
ccprintf(out, "switch_%d_outlinks: %d\n", m_switch_id,
m_perfect_switch_ptr->getOutLinks());
// Average link utilizations // Average link utilizations
double average_utilization = 0.0; double average_utilization = 0.0;
int throttle_count = 0; int throttle_count = 0;
for (int i=0; i<m_throttles.size(); i++) { for (int i = 0; i < m_throttles.size(); i++) {
Throttle* throttle_ptr = m_throttles[i]; Throttle* throttle_ptr = m_throttles[i];
if (throttle_ptr != NULL) { if (throttle_ptr) {
average_utilization += throttle_ptr->getUtilization(); average_utilization += throttle_ptr->getUtilization();
throttle_count++; throttle_count++;
} }
} }
average_utilization = (throttle_count == 0) ? 0 : average_utilization / float(throttle_count); average_utilization =
throttle_count == 0 ? 0 : average_utilization / throttle_count;
// Individual link utilizations // Individual link utilizations
out << "links_utilized_percent_switch_" << m_switch_id << ": " << average_utilization << endl; out << "links_utilized_percent_switch_" << m_switch_id << ": "
for (int link=0; link<m_throttles.size(); link++) { << average_utilization << endl;
for (int link = 0; link < m_throttles.size(); link++) {
Throttle* throttle_ptr = m_throttles[link]; Throttle* throttle_ptr = m_throttles[link];
if (throttle_ptr != NULL) { if (throttle_ptr != NULL) {
out << " links_utilized_percent_switch_" << m_switch_id << "_link_" << link << ": " out << " links_utilized_percent_switch_" << m_switch_id
<< throttle_ptr->getUtilization() << " bw: " << throttle_ptr->getLinkBandwidth() << "_link_" << link << ": "
<< throttle_ptr->getUtilization() << " bw: "
<< throttle_ptr->getLinkBandwidth()
<< " base_latency: " << throttle_ptr->getLatency() << endl; << " base_latency: " << throttle_ptr->getLatency() << endl;
} }
} }
out << endl; out << endl;
// Traffic breakdown // Traffic breakdown
for (int link=0; link<m_throttles.size(); link++) { for (int link = 0; link < m_throttles.size(); link++) {
Throttle* throttle_ptr = m_throttles[link]; Throttle* throttle_ptr = m_throttles[link];
if (throttle_ptr != NULL) { if (!throttle_ptr)
const Vector<Vector<int> >& message_counts = throttle_ptr->getCounters(); continue;
for (int int_type=0; int_type<MessageSizeType_NUM; int_type++) {
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); MessageSizeType type = MessageSizeType(int_type);
int sum = message_counts[type].sum(); int sum = message_counts[type].sum();
if (sum != 0) { if (sum == 0)
out << " outgoing_messages_switch_" << m_switch_id << "_link_" << link << "_" << type continue;
<< ": " << sum << " " << sum * (RubySystem::getNetwork()->MessageSizeType_to_int(type))
<< " " << message_counts[type] << " base_latency: " << throttle_ptr->getLatency() << endl; 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; out << endl;
} }
void Switch::clearStats() void
Switch::clearStats()
{ {
m_perfect_switch_ptr->clearStats(); m_perfect_switch_ptr->clearStats();
for (int i=0; i<m_throttles.size(); i++) { for (int i = 0; i < m_throttles.size(); i++) {
if (m_throttles[i] != NULL) { if (m_throttles[i] != NULL)
m_throttles[i]->clearStats(); m_throttles[i]->clearStats();
} }
}
} }
void Switch::printConfig(std::ostream& out) const void
Switch::printConfig(std::ostream& out) const
{ {
m_perfect_switch_ptr->printConfig(out); m_perfect_switch_ptr->printConfig(out);
for (int i=0; i<m_throttles.size(); i++) { for (int i = 0; i < m_throttles.size(); i++) {
if (m_throttles[i] != NULL) { if (m_throttles[i] != NULL)
m_throttles[i]->printConfig(out); m_throttles[i]->printConfig(out);
} }
}
} }
void Switch::print(std::ostream& out) const void
Switch::print(std::ostream& out) const
{ {
// FIXME printing // FIXME printing
out << "[Switch]"; 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,14 +51,16 @@ class SimpleNetwork;
class Throttle; class Throttle;
class Network; class Network;
class Switch { class Switch
public: {
// Constructors public:
// constructor specifying the number of ports
Switch(SwitchID sid, SimpleNetwork* network_ptr); Switch(SwitchID sid, SimpleNetwork* network_ptr);
~Switch();
void addInPort(const Vector<MessageBuffer*>& in); void addInPort(const Vector<MessageBuffer*>& in);
void addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routing_table_entry, int link_latency, int bw_multiplier); void addOutPort(const Vector<MessageBuffer*>& out,
const NetDest& routing_table_entry, int link_latency,
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();
@ -74,17 +71,13 @@ public:
void clearStats(); void clearStats();
void printConfig(std::ostream& out) const; void printConfig(std::ostream& out) const;
// Destructor
~Switch();
void print(std::ostream& out) const; void print(std::ostream& out) const;
private:
private:
// Private copy constructor and assignment operator // Private copy constructor and assignment operator
Switch(const Switch& obj); Switch(const Switch& obj);
Switch& operator=(const Switch& obj); Switch& operator=(const Switch& obj);
// Data Members (m_ prefix)
PerfectSwitch* m_perfect_switch_ptr; PerfectSwitch* m_perfect_switch_ptr;
Network* m_network_ptr; Network* m_network_ptr;
Vector<Throttle*> m_throttles; Vector<Throttle*> m_throttles;
@ -92,18 +85,12 @@ private:
SwitchID m_switch_id; 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,21 +43,24 @@ 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;
@ -77,7 +73,8 @@ void Throttle::init(NodeID node, int link_latency, int link_bandwidth_multiplier
clearStats(); clearStats();
} }
void Throttle::clear() void
Throttle::clear()
{ {
for (int counter = 0; counter < m_vnets; counter++) { for (int counter = 0; counter < m_vnets; counter++) {
m_in[counter]->clear(); m_in[counter]->clear();
@ -85,7 +82,9 @@ void Throttle::clear()
} }
} }
void Throttle::addLinks(const Vector<MessageBuffer*>& in_vec, const Vector<MessageBuffer*>& out_vec) void
Throttle::addLinks(const Vector<MessageBuffer*>& in_vec,
const Vector<MessageBuffer*>& out_vec)
{ {
assert(in_vec.size() == out_vec.size()); assert(in_vec.size() == out_vec.size());
for (int i=0; i<in_vec.size(); i++) { for (int i=0; i<in_vec.size(); i++) {
@ -93,15 +92,16 @@ void Throttle::addLinks(const Vector<MessageBuffer*>& in_vec, const Vector<Messa
} }
m_message_counters.setSize(MessageSizeType_NUM); m_message_counters.setSize(MessageSizeType_NUM);
for (int i=0; i<MessageSizeType_NUM; i++) { for (int i = 0; i < MessageSizeType_NUM; i++) {
m_message_counters[i].setSize(in_vec.size()); m_message_counters[i].setSize(in_vec.size());
for (int j=0; j<m_message_counters[i].size(); j++) { for (int j = 0; j<m_message_counters[i].size(); j++) {
m_message_counters[i][j] = 0; m_message_counters[i][j] = 0;
} }
} }
} }
void Throttle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr) void
Throttle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr)
{ {
m_units_remaining.insertAtBottom(0); m_units_remaining.insertAtBottom(0);
m_in.insertAtBottom(in_ptr); m_in.insertAtBottom(in_ptr);
@ -109,12 +109,14 @@ void Throttle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr)
// Set consumer and description // Set consumer and description
m_in[m_vnets]->setConsumer(this); m_in[m_vnets]->setConsumer(this);
string desc = "[Queue to Throttle " + NodeIDToString(m_sID) + " " + NodeIDToString(m_node) + "]"; string desc = "[Queue to Throttle " + NodeIDToString(m_sID) + " " +
NodeIDToString(m_node) + "]";
m_in[m_vnets]->setDescription(desc); m_in[m_vnets]->setDescription(desc);
m_vnets++; m_vnets++;
} }
void Throttle::wakeup() void
Throttle::wakeup()
{ {
// Limits the number of message sent to a limited number of bytes/cycle. // Limits the number of message sent to a limited number of bytes/cycle.
assert(getLinkBandwidth() > 0); assert(getLinkBandwidth() > 0);
@ -135,27 +137,34 @@ void Throttle::wakeup()
counter = -1; counter = -1;
} }
for (int vnet = highest_prio_vnet; (vnet*counter) >= (counter*lowest_prio_vnet); vnet -= counter) { for (int vnet = highest_prio_vnet;
(vnet * counter) >= (counter * lowest_prio_vnet);
vnet -= counter) {
assert(m_out[vnet] != NULL); assert(m_out[vnet] != NULL);
assert(m_in[vnet] != NULL); assert(m_in[vnet] != NULL);
assert(m_units_remaining[vnet] >= 0); assert(m_units_remaining[vnet] >= 0);
while ((bw_remaining > 0) && ((m_in[vnet]->isReady()) || (m_units_remaining[vnet] > 0)) && m_out[vnet]->areNSlotsAvailable(1)) { while (bw_remaining > 0 &&
(m_in[vnet]->isReady() || m_units_remaining[vnet] > 0) &&
m_out[vnet]->areNSlotsAvailable(1)) {
// See if we are done transferring the previous message on this virtual network // See if we are done transferring the previous message on
// this virtual network
if (m_units_remaining[vnet] == 0 && m_in[vnet]->isReady()) { if (m_units_remaining[vnet] == 0 && m_in[vnet]->isReady()) {
// Find the size of the message we are moving // Find the size of the message we are moving
MsgPtr msg_ptr = m_in[vnet]->peekMsgPtr(); MsgPtr msg_ptr = m_in[vnet]->peekMsgPtr();
NetworkMessage* net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref()); NetworkMessage* net_msg_ptr =
m_units_remaining[vnet] += network_message_to_size(net_msg_ptr); safe_cast<NetworkMessage*>(msg_ptr.ref());
m_units_remaining[vnet] +=
network_message_to_size(net_msg_ptr);
DEBUG_NEWLINE(NETWORK_COMP,HighPrio); DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
DEBUG_MSG(NETWORK_COMP,HighPrio,"throttle: " + int_to_string(m_node) DEBUG_MSG(NETWORK_COMP, HighPrio,
+ " my bw " + int_to_string(getLinkBandwidth()) csprintf("throttle: %d my bw %d bw spent enqueueing "
+ " bw spent enqueueing net msg " + int_to_string(m_units_remaining[vnet]) "net msg %d time: %d.",
+ " time: " + int_to_string(g_eventQueue_ptr->getTime()) + "."); m_node, getLinkBandwidth(), m_units_remaining[vnet],
g_eventQueue_ptr->getTime()));
// Move the message // Move the message
m_out[vnet]->enqueue(m_in[vnet]->peekMsgPtr(), m_link_latency); m_out[vnet]->enqueue(m_in[vnet]->peekMsgPtr(), m_link_latency);
@ -174,76 +183,92 @@ void Throttle::wakeup()
bw_remaining = 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)) { if (bw_remaining > 0 &&
(m_in[vnet]->isReady() || m_units_remaining[vnet] > 0) &&
!m_out[vnet]->areNSlotsAvailable(1)) {
DEBUG_MSG(NETWORK_COMP,LowPrio,vnet); DEBUG_MSG(NETWORK_COMP,LowPrio,vnet);
schedule_wakeup = true; // schedule me to wakeup again because I'm waiting for my output queue to become available // 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 // We should only wake up when we use the bandwidth
// assert(bw_remaining != getLinkBandwidth()); // This is only mostly true // This is only mostly true
// assert(bw_remaining != getLinkBandwidth());
// Record that we used some or all of the link bandwidth this cycle // Record that we used some or all of the link bandwidth this cycle
double ratio = 1.0-(double(bw_remaining)/double(getLinkBandwidth())); double ratio = 1.0 - (double(bw_remaining) / double(getLinkBandwidth()));
// If ratio = 0, we used no bandwidth, if ratio = 1, we used all // If ratio = 0, we used no bandwidth, if ratio = 1, we used all
linkUtilized(ratio); linkUtilized(ratio);
if ((bw_remaining > 0) && !schedule_wakeup) { 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. // We have extra bandwidth and our output buffer was
DEBUG_MSG(NETWORK_COMP,LowPrio,*this); // available, so we must not have anything else to do until
DEBUG_MSG(NETWORK_COMP,LowPrio,"not scheduled again"); // another message arrives.
DEBUG_MSG(NETWORK_COMP, LowPrio, *this);
DEBUG_MSG(NETWORK_COMP, LowPrio, "not scheduled again");
} else { } else {
DEBUG_MSG(NETWORK_COMP,LowPrio,*this); DEBUG_MSG(NETWORK_COMP, LowPrio, *this);
DEBUG_MSG(NETWORK_COMP,LowPrio,"scheduled again"); DEBUG_MSG(NETWORK_COMP, LowPrio, "scheduled again");
// We are out of bandwidth for this cycle, so wakeup next cycle and continue
// We are out of bandwidth for this cycle, so wakeup next
// cycle and continue
g_eventQueue_ptr->scheduleEvent(this, 1); g_eventQueue_ptr->scheduleEvent(this, 1);
} }
} }
void Throttle::printStats(ostream& out) const void
Throttle::printStats(ostream& out) const
{ {
out << "utilized_percent: " << getUtilization() << endl; out << "utilized_percent: " << getUtilization() << endl;
} }
void Throttle::clearStats() void
Throttle::clearStats()
{ {
m_ruby_start = g_eventQueue_ptr->getTime(); m_ruby_start = g_eventQueue_ptr->getTime();
m_links_utilized = 0.0; m_links_utilized = 0.0;
for (int i=0; i<m_message_counters.size(); i++) { for (int i = 0; i < m_message_counters.size(); i++) {
for (int j=0; j<m_message_counters[i].size(); j++) { for (int j = 0; j < m_message_counters[i].size(); j++) {
m_message_counters[i][j] = 0; m_message_counters[i][j] = 0;
} }
} }
} }
void Throttle::printConfig(ostream& out) const void
Throttle::printConfig(ostream& out) const
{ {
} }
double Throttle::getUtilization() const double
Throttle::getUtilization() const
{ {
return (100.0 * double(m_links_utilized)) / (double(g_eventQueue_ptr->getTime()-m_ruby_start)); return 100.0 * double(m_links_utilized) /
double(g_eventQueue_ptr->getTime()-m_ruby_start);
} }
void Throttle::print(ostream& out) const void
Throttle::print(ostream& out) const
{ {
out << "[Throttle: " << m_sID << " " << m_node << " bw: " << getLinkBandwidth() << "]"; out << "[Throttle: " << m_sID << " " << m_node
<< " bw: " << getLinkBandwidth() << "]";
} }
// Helper function int
network_message_to_size(NetworkMessage* net_msg_ptr)
static
int network_message_to_size(NetworkMessage* net_msg_ptr)
{ {
assert(net_msg_ptr != NULL); 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 // Artificially increase the size of broadcast messages
if (BROADCAST_SCALING > 1) { if (BROADCAST_SCALING > 1 && net_msg_ptr->getDestination().isBroadcast())
if (net_msg_ptr->getDestination().isBroadcast()) { size *= BROADCAST_SCALING;
return (RubySystem::getNetwork()->MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER * BROADCAST_SCALING);
} return size;
}
return (RubySystem::getNetwork()->MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER);
} }

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,57 +27,62 @@
*/ */
/* /*
* $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,
int link_bandwidth_multiplier);
Throttle(NodeID node, int link_latency, int link_bandwidth_multiplier); Throttle(NodeID node, int link_latency, int link_bandwidth_multiplier);
// Destructor
~Throttle() {} ~Throttle() {}
// Public Methods void addLinks(const Vector<MessageBuffer*>& in_vec,
void addLinks(const Vector<MessageBuffer*>& in_vec, const Vector<MessageBuffer*>& out_vec); const Vector<MessageBuffer*>& out_vec);
void wakeup(); void wakeup();
void printStats(ostream& out) const; void printStats(ostream& out) const;
void clearStats(); void clearStats();
void printConfig(ostream& out) const; void printConfig(ostream& out) const;
double getUtilization() const; // The average utilization (a percent) since last clearStats() // The average utilization (a percent) since last clearStats()
int getLinkBandwidth() const { return RubySystem::getNetwork()->getEndpointBandwidth() * m_link_bandwidth_multiplier; } double getUtilization() const;
int
getLinkBandwidth() const
{
return RubySystem::getNetwork()->getEndpointBandwidth() *
m_link_bandwidth_multiplier;
}
int getLatency() const { return m_link_latency; } int getLatency() const { return m_link_latency; }
const Vector<Vector<int> >& getCounters() const { return m_message_counters; } 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: private:
// Private Methods
void init(NodeID node, int link_latency, int link_bandwidth_multiplier); void init(NodeID node, int link_latency, int link_bandwidth_multiplier);
void addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr); void addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr);
void linkUtilized(double ratio) { m_links_utilized += ratio; } void linkUtilized(double ratio) { m_links_utilized += ratio; }
@ -87,7 +91,6 @@ private:
Throttle(const Throttle& obj); Throttle(const Throttle& obj);
Throttle& operator=(const Throttle& obj); Throttle& operator=(const Throttle& obj);
// Data Members (m_ prefix)
Vector<MessageBuffer*> m_in; Vector<MessageBuffer*> m_in;
Vector<MessageBuffer*> m_out; Vector<MessageBuffer*> m_out;
Vector<Vector<int> > m_message_counters; Vector<Vector<int> > m_message_counters;
@ -104,18 +107,12 @@ private:
double m_links_utilized; 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,25 +65,21 @@ 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(); for (vector<ExtLink*>::const_iterator i = params()->ext_links.begin();
i != params()->ext_links.end(); ++i) i != params()->ext_links.end(); ++i) {
{
const ExtLinkParams *p = (*i)->params(); const ExtLinkParams *p = (*i)->params();
AbstractController *c = p->ext_node; AbstractController *c = p->ext_node;
@ -107,8 +97,7 @@ Topology::Topology(const Params *p)
} }
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;
@ -120,21 +109,20 @@ Topology::Topology(const Params *p)
} }
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]);
} }
@ -147,69 +135,93 @@ void Topology::createLinks(Network *net, bool isReconfiguration)
topology_weights.setSize(num_switches); topology_weights.setSize(num_switches);
topology_latency.setSize(num_switches); topology_latency.setSize(num_switches);
topology_bw_multis.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! // FIXME setting the size of a member variable here is a HACK!
for(int i=0; i<topology_weights.size(); i++) { 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);
for (int i = 0; i < topology_weights.size(); i++) {
topology_weights[i].setSize(num_switches); topology_weights[i].setSize(num_switches);
topology_latency[i].setSize(num_switches); topology_latency[i].setSize(num_switches);
topology_bw_multis[i].setSize(num_switches); topology_bw_multis[i].setSize(num_switches);
m_component_latencies[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++) { // FIXME setting the size of a member variable here is a HACK!
m_component_inter_switches[i].setSize(num_switches);
for (int j = 0; j < topology_weights[i].size(); j++) {
topology_weights[i][j] = INFINITE_LATENCY; 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 // initialize to invalid values
m_component_latencies[i][j] = -1; // initialize to an invalid value topology_latency[i][j] = -1;
m_component_inter_switches[i][j] = 0; // initially assume direct connections / no intermediate switches between components 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 // Set identity weights to zero
for(int i=0; i<topology_weights.size(); i++) { for (int i = 0; i < topology_weights.size(); i++) {
topology_weights[i][i] = 0; topology_weights[i][i] = 0;
} }
// Fill in the topology weights and bandwidth multipliers // Fill in the topology weights and bandwidth multipliers
for (int i=0; i<m_links_src_vector.size(); i++) { for (int i = 0; i < m_links_src_vector.size(); i++) {
topology_weights[m_links_src_vector[i]][m_links_dest_vector[i]] = m_links_weight_vector[i]; int src = m_links_src_vector[i];
topology_latency[m_links_src_vector[i]][m_links_dest_vector[i]] = m_links_latency_vector[i]; int dst = m_links_dest_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_weights[src][dst] = m_links_weight_vector[i];
topology_bw_multis[m_links_src_vector[i]][m_links_dest_vector[i]] = m_bw_multiplier_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 // Walk topology and hookup the links
Matrix dist = shortest_path(topology_weights, m_component_latencies, m_component_inter_switches); Matrix dist = shortest_path(topology_weights, m_component_latencies,
for(int i=0; i<topology_weights.size(); i++) { m_component_inter_switches);
for(int j=0; j<topology_weights[i].size(); j++) { 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 weight = topology_weights[i][j];
int bw_multiplier = topology_bw_multis[i][j]; int bw_multiplier = topology_bw_multis[i][j];
int latency = topology_latency[i][j]; int latency = topology_latency[i][j];
if (weight > 0 && weight != INFINITE_LATENCY) { if (weight > 0 && weight != INFINITE_LATENCY) {
NetDest destination_set = shortest_path_to_node(i, j, topology_weights, dist); NetDest destination_set = shortest_path_to_node(i, j,
topology_weights, dist);
assert(latency != -1); assert(latency != -1);
makeLink(net, i, j, destination_set, latency, weight, bw_multiplier, isReconfiguration); 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);
@ -220,63 +232,88 @@ void Topology::addLink(SwitchID src, SwitchID dest, int link_latency, int bw_mul
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,
link_latency, bw_multiplier, isReconfiguration);
} else if (dest < 2*m_nodes) { } else if (dest < 2*m_nodes) {
assert(dest >= m_nodes); assert(dest >= m_nodes);
NodeID node = dest-m_nodes; NodeID node = dest-m_nodes;
net->makeOutLink(src-(2*m_nodes), node, routing_table_entry, link_latency, link_weight, bw_multiplier, isReconfiguration); net->makeOutLink(src-(2*m_nodes), node, routing_table_entry,
link_latency, link_weight, bw_multiplier, isReconfiguration);
} else { } else {
assert((src >= 2*m_nodes) && (dest >= 2*m_nodes)); 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); 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++) {
for (int m = 0; m < MachineType_NUM; m++) {
int i_end = MachineType_base_count((MachineType)m);
for (int i = 0; i < i_end; i++) {
MachineID cur_mach = {(MachineType)m, i}; MachineID cur_mach = {(MachineType)m, i};
out << cur_mach << " Network Latencies" << endl; out << cur_mach << " Network Latencies" << endl;
for (int n=0; n<MachineType_NUM; n++) { for (int n = 0; n < MachineType_NUM; n++) {
for (int j=0; j<MachineType_base_count((MachineType)n); j++) { int j_end = MachineType_base_count((MachineType)n);
for (int j = 0; j < j_end; j++) {
MachineID dest_mach = {(MachineType)n, j}; MachineID dest_mach = {(MachineType)n, j};
if (cur_mach != dest_mach) { if (cur_mach == dest_mach)
int link_latency = m_component_latencies[MachineType_base_number((MachineType)m)+i][MachineType_base_number(MachineType_NUM)+MachineType_base_number((MachineType)n)+j]; continue;
int intermediate_switches = m_component_inter_switches[MachineType_base_number((MachineType)m)+i][MachineType_base_number(MachineType_NUM)+MachineType_base_number((MachineType)n)+j];
out << " " << cur_mach << " -> " << dest_mach << " net_lat: " int src = MachineType_base_number((MachineType)m) + i;
<< link_latency+intermediate_switches << endl; // NOTE switches are assumed to have single cycle latency 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;
@ -286,28 +323,30 @@ void Topology::printConfig(std::ostream& out) const
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,
current_dist[i][k] + current_dist[k][j]);
if (previous_minimum != minimum) { if (previous_minimum != minimum) {
intermediate_switch = k; intermediate_switch = k;
inter_switches[i][j] = inter_switches[i][k] + inter_switches[k][j] + 1; inter_switches[i][j] =
inter_switches[i][k] +
inter_switches[k][j] + 1;
} }
previous_minimum = minimum; previous_minimum = minimum;
} }
@ -316,28 +355,32 @@ static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix
current_dist[i][j] = minimum; current_dist[i][j] = minimum;
assert(intermediate_switch >= 0); assert(intermediate_switch >= 0);
assert(intermediate_switch < latencies[i].size()); assert(intermediate_switch < latencies[i].size());
latencies[i][j] = latencies[i][intermediate_switch] + latencies[intermediate_switch][j]; latencies[i][j] = latencies[i][intermediate_switch] +
latencies[intermediate_switch][j];
} }
} }
} }
} }
} }
static Matrix shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches) Matrix
shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches)
{ {
Matrix dist = weights; Matrix dist = weights;
extend_shortest_path(dist, latencies, inter_switches); extend_shortest_path(dist, latencies, inter_switches);
return dist; return dist;
} }
static bool link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final, bool
link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final,
const Matrix& weights, const Matrix& dist) const Matrix& weights, const Matrix& dist)
{ {
return (weights[src][next] + dist[next][final] == dist[src][final]); return weights[src][next] + dist[next][final] == dist[src][final];
} }
static NetDest shortest_path_to_node(SwitchID src, SwitchID next, NetDest
const Matrix& weights, const Matrix& dist) shortest_path_to_node(SwitchID src, SwitchID next, const Matrix& weights,
const Matrix& dist)
{ {
NetDest result; NetDest result;
int d = 0; int d = 0;
@ -347,13 +390,14 @@ static NetDest shortest_path_to_node(SwitchID src, SwitchID next,
machines = MachineType_NUM; machines = MachineType_NUM;
max_machines = MachineType_base_number(MachineType_NUM); max_machines = MachineType_base_number(MachineType_NUM);
for (int m=0; m<machines; m++) { for (int m = 0; m < machines; m++) {
for (int i=0; i<MachineType_base_count((MachineType)m); i++) { 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 // we use "d+max_machines" below since the "destination"
// [MachineType_base_number(MachineType_NUM)...2*MachineType_base_number(MachineType_NUM)-1] // switches for the machines are numbered
// for the component network // [MachineType_base_number(MachineType_NUM)...
if (link_is_shortest_path_to_node(src, next, // 2*MachineType_base_number(MachineType_NUM)-1] for the
d+max_machines, // component network
if (link_is_shortest_path_to_node(src, next, d + max_machines,
weights, dist)) { weights, dist)) {
MachineID mach = {(MachineType)m, i}; MachineID mach = {(MachineType)m, i};
result.add(mach); result.add(mach);

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,77 +27,68 @@
*/ */
/* /*
* 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
* bandwidth, since we don't control bandwidth on input ports.
* Basically, the class has a vector of nodes and edges. First
* 2*m_nodes elements in the node vector are input and output * 2*m_nodes elements in the node vector are input and output
* ports. Edges are represented in two vectors of src and dest * ports. Edges are represented in two vectors of src and dest
* nodes. All edges have latency. * 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
virtual ~Topology() {}
// Public Methods
int numSwitches() const { return m_number_of_switches; } int numSwitches() const { return m_number_of_switches; }
void createLinks(Network *net, bool isReconfiguration); void createLinks(Network *net, bool isReconfiguration);
@ -110,22 +100,25 @@ public:
void printConfig(std::ostream& out) const; void printConfig(std::ostream& out) const;
void print(std::ostream& out) const { out << "[Topology]"; } void print(std::ostream& out) const { out << "[Topology]"; }
protected: protected:
// Private Methods
SwitchID newSwitchID(); SwitchID newSwitchID();
void addLink(SwitchID src, SwitchID dest, int link_latency); 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,
void addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier, int link_weight); int bw_multiplier);
void makeLink(Network *net, SwitchID src, SwitchID dest, const NetDest& routing_table_entry, int link_latency, int weight, int bw_multiplier, bool isReconfiguration); 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); //void makeSwitchesPerChip(Vector<Vector< SwitchID> > &nodePairs,
// Vector<int> &latencies, Vector<int> &bw_multis, int numberOfChips);
std::string getDesignStr(); std::string getDesignStr();
// Private copy constructor and assignment operator // Private copy constructor and assignment operator
Topology(const Topology& obj); Topology(const Topology& obj);
Topology& operator=(const Topology& obj); Topology& operator=(const Topology& obj);
// Data Members (m_ prefix)
std::string m_name; std::string m_name;
bool m_print_config; bool m_print_config;
NodeID m_nodes; NodeID m_nodes;
@ -143,18 +136,12 @@ protected:
Matrix m_component_inter_switches; 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,16 +26,12 @@
* 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()
{ {
@ -48,16 +43,16 @@ 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()) {
@ -74,6 +69,7 @@ int CacheRecorder::dumpRecords(string filename)
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();
// Destructor
~CacheRecorder(); ~CacheRecorder();
// Public Methods void addRecord(Sequencer* sequencer, const Address& data_addr,
void addRecord(Sequencer* sequencer, const Address& pc_addr, RubyRequestType type, Time time);
const Address& data_addr,
const Address& pc_addr,
RubyRequestType type,
Time time);
int dumpRecords(std::string filename); int dumpRecords(std::string filename);
void print(std::ostream& out) const; void print(std::ostream& out) const;
private:
// Private Methods
private:
// Private copy constructor and assignment operator // Private copy constructor and assignment operator
CacheRecorder(const CacheRecorder& obj); CacheRecorder(const CacheRecorder& obj);
CacheRecorder& operator=(const CacheRecorder& obj); CacheRecorder& operator=(const CacheRecorder& obj);
// Data Members (m_ prefix)
PrioHeap<TraceRecord>* m_records_ptr; 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,22 +26,14 @@
* 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;
@ -54,19 +45,19 @@ TraceRecord::TraceRecord(Sequencer* _sequencer,
// 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;
@ -76,17 +67,14 @@ TraceRecord& TraceRecord::operator=(const TraceRecord& obj)
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()) {
@ -101,14 +89,16 @@ void TraceRecord::issueRequest() const
} }
} }
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);
@ -119,22 +109,23 @@ void TraceRecord::output(ostream& out) const
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 trace // simObjectList to find the sequencer pointer. Therefore, expect
// playback to be slow. // trace 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);
if (in.eof())
return false;
string type; string type;
if (!in.eof()) {
in >> type; in >> type;
m_type = string_to_RubyRequestType(type); m_type = string_to_RubyRequestType(type);
@ -145,7 +136,4 @@ bool TraceRecord::input(istream& in)
} }
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,57 +27,50 @@
*/ */
/* /*
* $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_sequencer_ptr = NULL;
m_time = 0; m_time = 0;
m_type = RubyRequestType_NULL; m_type = RubyRequestType_NULL;
} }
// Destructor
// ~TraceRecord();
// Public copy constructor and assignment operator
TraceRecord(const TraceRecord& obj); TraceRecord(const TraceRecord& obj);
TraceRecord& operator=(const TraceRecord& obj); TraceRecord& operator=(const TraceRecord& obj);
// Public Methods bool
bool node_less_then_eq(const TraceRecord& rec) const { return (this->m_time <= rec.m_time); } node_less_then_eq(const TraceRecord& rec) const
{
return this->m_time <= rec.m_time;
}
void issueRequest() const; 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;
@ -86,26 +78,18 @@ private:
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,18 +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/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)
{ {
@ -48,64 +42,49 @@ Tracer::Tracer(const Params *p)
RubySystem::m_tracer_ptr = this; RubySystem::m_tracer_ptr = this;
} }
//commented by SS void
//Tracer::Tracer() Tracer::startTrace(std::string filename)
//{
// m_enabled = false;
//}
Tracer::~Tracer()
{ {
} if (m_enabled)
void Tracer::init()
{
}
void Tracer::startTrace(std::string filename)
{
if (m_enabled) {
stopTrace(); stopTrace();
}
if (filename != "") { if (filename != "") {
m_trace_file.open(filename.c_str()); m_trace_file.open(filename.c_str());
if (m_trace_file.fail()) { if (m_trace_file.fail()) {
cout << "Error: error opening file '" << filename << "'" << endl; cprintf("Error: error opening file '%s'\n", filename);
cout << "Trace not enabled." << endl; cprintf("Trace not enabled.\n");
return; return;
} }
cout << "Request trace enabled to output file '" << filename << "'" << endl; cprintf("Request trace enabled to output file '%s'\n", filename);
m_enabled = true; m_enabled = true;
} }
} }
void Tracer::stopTrace() void
Tracer::stopTrace()
{ {
if (m_enabled == true) { if (m_enabled) {
m_trace_file.close(); m_trace_file.close();
cout << "Request trace file closed." << endl; cout << "Request trace file closed." << endl;
m_enabled = false; m_enabled = false;
} }
} }
void Tracer::traceRequest(Sequencer* sequencer, void
const Address& data_addr, Tracer::traceRequest(Sequencer* sequencer, const Address& data_addr,
const Address& pc_addr, const Address& pc_addr, RubyRequestType type, Time time)
RubyRequestType type,
Time time)
{ {
assert(m_enabled == true); assert(m_enabled);
TraceRecord tr(sequencer, data_addr, pc_addr, type, time); TraceRecord tr(sequencer, data_addr, pc_addr, type, time);
tr.output(m_trace_file); tr.output(m_trace_file);
} }
// Class method int
int Tracer::playbackTrace(std::string filename) Tracer::playbackTrace(std::string filename)
{ {
igzstream in(filename.c_str()); igzstream in(filename.c_str());
if (in.fail()) { if (in.fail()) {
cout << "Error: error opening file '" << filename << "'" << endl; cprintf("Error: error opening file '%s'\n", filename);
return 0; return 0;
} }
@ -124,20 +103,16 @@ int Tracer::playbackTrace(std::string filename)
ok = record.input(in); ok = record.input(in);
// Clear the statistics after warmup // Clear the statistics after warmup
/* if (counter == m_warmup_length) {
cout << "Clearing stats after warmup of length " << m_warmup_length << endl;
g_system_ptr->clearStats();
}
*/
if (counter == m_warmup_length) { if (counter == m_warmup_length) {
cout << "Clearing stats after warmup of length " << m_warmup_length << endl; cprintf("Clearing stats after warmup of length %s\n",
m_warmup_length);
g_system_ptr->clearStats(); g_system_ptr->clearStats();
} }
} }
// Flush the prefetches through the system // Flush the prefetches through the system
g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 1000); // FIXME - should be smarter // FIXME - should be smarter
g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 1000);
time_t stop_time = time(NULL); time_t stop_time = time(NULL);
double seconds = difftime(stop_time, start_time); double seconds = difftime(stop_time, start_time);
@ -147,11 +122,11 @@ int Tracer::playbackTrace(std::string filename)
return counter; 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,68 +27,51 @@
*/ */
/* /*
* $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
~Tracer();
// Public Methods
void startTrace(std::string filename); void startTrace(std::string filename);
void stopTrace(); void stopTrace();
bool traceEnabled() { return m_enabled; } bool traceEnabled() { return m_enabled; }
void traceRequest(Sequencer* sequencer, void traceRequest(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);
void print(std::ostream& out) const; void print(std::ostream& out) const;
// Public Class Methods
int playbackTrace(std::string filename); int playbackTrace(std::string filename);
void init();
private:
// Private Methods
private:
// Private copy constructor and assignment operator // Private copy constructor and assignment operator
Tracer(const Tracer& obj); Tracer(const Tracer& obj);
Tracer& operator=(const Tracer& obj); Tracer& operator=(const Tracer& obj);
// Data Members (m_ prefix)
ogzstream m_trace_file; ogzstream m_trace_file;
bool m_enabled; bool m_enabled;
@ -97,18 +79,12 @@ private:
int m_warmup_length; 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)
{
StoreBuffer *stb = new StoreBuffer(id, block_bits, storebuffer_size);
return stb; return stb;
} }
storebuffer_status_t handleStore (StoreBuffer * storebuffer, const RubyRequest & request) { storebuffer_status_t
handleStore(StoreBuffer *storebuffer, const RubyRequest &request)
{
assert(request.type == RubyRequestType_ST); assert(request.type == RubyRequestType_ST);
if (storebuffer->storeBufferFull()){ if (storebuffer->storeBufferFull()){
return WB_FULL; return WB_FULL;
} } else if (storebuffer->storeBufferFlushing()) {
else if (storebuffer->storeBufferFlushing()) {
return WB_FLUSHING; 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
handleLoad(StoreBuffer *storebuffer, const RubyRequest &request)
{
assert(request.type == RubyRequestType_LD); assert(request.type == RubyRequestType_LD);
return storebuffer->handleLoad(request); return storebuffer->handleLoad(request);
} }
#if 0 #if 0
uint64_t handleAtomic(StoreBuffer * storebuffer, const RubyRequest & request) { uint64_t
handleAtomic(StoreBuffer *storebuffer, const RubyRequest &request)
{
// flush the store buffer // flush the store buffer
storebuffer->flushStoreBuffer(); storebuffer->flushStoreBuffer();
// let storebuffer issue atomic // let storebuffer issue atomic
//return storebuffer->issueAtomic(request); // return storebuffer->issueAtomic(request);
} }
#endif #endif
void flushSTB(StoreBuffer * storebuffer) { void
flushSTB(StoreBuffer *storebuffer)
{
// in in-order can't get a request to flushSTB if already flushing // in in-order can't get a request to flushSTB if already flushing
// on out of order, have to check if already flushing // on out of order, have to check if already flushing
storebuffer->flushStoreBuffer(); storebuffer->flushStoreBuffer();
} }
void registerHitCallback(StoreBuffer * storebuffer, void (*hit_callback)(int64_t access_id)) { void
registerHitCallback(StoreBuffer *storebuffer,
void (*hit_callback)(int64_t access_id))
{
storebuffer->registerHitCallback(hit_callback); 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,51 +26,33 @@
* 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 {
void hit(int64_t id) {
if (request_map.find(id) == request_map.end()) { if (request_map.find(id) == request_map.end()) {
ERROR_OUT("Request ID not found in the map"); ERROR_OUT("Request ID not found in the map");
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id); DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id);
ASSERT(0); ASSERT(0);
} } else {
else {
request_map[id]->complete(id); request_map[id]->complete(id);
request_map.erase(id); request_map.erase(id);
} }
} }
StoreBuffer::StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size)
//***************************************************************************************** {
StoreBuffer::StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size) {
#if RUBY_TSO_CHECKER
if (id == 0) {
g_tsoChecker = new Tso::TsoChecker();
g_tsoChecker->init(64);
}
#endif
iseq = 0; iseq = 0;
tso_iseq = 0; tso_iseq = 0;
char name [] = "Sequencer_"; char name [] = "Sequencer_";
@ -88,43 +70,51 @@ StoreBuffer::StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size) {
m_storebuffer_full = false; m_storebuffer_full = false;
m_storebuffer_flushing = false; m_storebuffer_flushing = false;
m_stalled_issue = true; m_stalled_issue = true;
if(m_storebuffer_size > 0){ if (m_storebuffer_size > 0){
m_use_storebuffer = true; m_use_storebuffer = true;
} }
#ifdef DEBUG_WRITE_BUFFER #ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("*******storebuffer_t::Using Write Buffer? %d\n",m_use_storebuffer); DEBUG_OUT("*******storebuffer_t::Using Write Buffer? %d\n",
#endif m_use_storebuffer);
}
//******************************************************************************************
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)) { {
}
void
StoreBuffer::registerHitCallback(void (*hit_callback)(int64_t request_id))
{
assert(m_hit_callback == NULL); // can't assign hit_callback twice assert(m_hit_callback == NULL); // can't assign hit_callback twice
m_hit_callback = hit_callback; 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) {
// 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;
}
#ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("\n***StoreBuffer: addToStoreBuffer BEGIN, contents:\n"); DEBUG_OUT("\n***StoreBuffer: addToStoreBuffer BEGIN, contents:\n");
DEBUG_OUT("\n"); DEBUG_OUT("\n");
#endif
#ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("\t INSERTING new request\n"); DEBUG_OUT("\t INSERTING new request\n");
#endif #endif
buffer.push_front(SBEntry(request, NULL)); buffer.push_front(SBEntry(request, NULL));
@ -132,103 +122,94 @@ void StoreBuffer::addToStoreBuffer(struct RubyRequest request){
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) {
else if (match == NO_MATCH) {
// make request to libruby and return the id // make request to libruby and return the id
uint64_t id = libruby_issue_request(m_port, request); uint64_t id = libruby_issue_request(m_port, request);
if (request_map.find(id) != request_map.end()) { if (request_map.find(id) != request_map.end()) {
ERROR_OUT("Request ID is already in the map"); ERROR_OUT("Request ID is already in the map");
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id); DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id);
ASSERT(0); 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)); outstanding_requests.insert(make_pair(id, request));
} }
iseq++; iseq++;
return id; return id;
} } else { // partial match
else { // partial match
return -3; 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;
@ -238,28 +219,23 @@ load_match StoreBuffer::checkForLoadHit(struct RubyRequest request) {
if (unmatched_bytes == 0) { if (unmatched_bytes == 0) {
delete data; delete data;
return FULL_MATCH; return FULL_MATCH;
} } else {
else {
delete data; delete data;
return PARTIAL_MATCH; return PARTIAL_MATCH;
} }
} } else {
else {
delete data; delete data;
return NO_MATCH; 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,28 +248,12 @@ 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;
for (deque<struct SBEntry>::iterator it = buffer.begin(); it != buffer.end(); it++) {
if ((it->m_request.paddr & m_block_mask) == lineaddr) { if ((it->m_request.paddr & m_block_mask) == lineaddr) {
if (!found) { if (!found) {
found = true; found = true;
#if RUBY_TSO_CHECKER
satisfying_store = it;
cmd = new Tso::TsoCheckerCmd(m_id, // this thread id
iseq, // instruction sequence
ITYPE_LOAD, // is a store
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; uint8_t * dataPtr = it->m_request.data;
int offset = it->m_request.paddr%64; int offset = it->m_request.paddr%64;
@ -313,73 +273,50 @@ void StoreBuffer::returnMatchedData(struct RubyRequest request) {
} }
} }
#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()
void StoreBuffer::flushStoreBuffer(){ {
if (m_use_storebuffer) { if (!m_use_storebuffer) {
#ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("\n***StoreBuffer: flushStoreBuffer BEGIN, contents:\n");
DEBUG_OUT("\n");
#endif
if(m_buffer_size > 0) {
m_storebuffer_flushing = true; // indicate that we are flushing
}
else {
m_storebuffer_flushing = false;
return;
}
}
else {
// do nothing // do nothing
return; return;
} }
#ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("\n***StoreBuffer: flushStoreBuffer BEGIN, contents:\n");
DEBUG_OUT("\n");
#endif
m_storebuffer_flushing = (m_buffer_size > 0);
} }
//**************************************************************************************** void
void StoreBuffer::issueNextStore() { StoreBuffer::issueNextStore()
{
SBEntry request = buffer.back(); SBEntry request = buffer.back();
uint64_t id = libruby_issue_request(m_port, request.m_request); uint64_t id = libruby_issue_request(m_port, request.m_request);
if (request_map.find(id) != request_map.end()) { if (request_map.find(id) != request_map.end()) {
assert(0); 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");
@ -389,69 +326,33 @@ void StoreBuffer::complete(uint64_t id) {
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 &&
from_buffer.m_request.type == type) {
buffer.pop_back(); buffer.pop_back();
m_buffer_size--; m_buffer_size--;
ASSERT(m_buffer_size >= 0); ASSERT(m_buffer_size >= 0);
#if RUBY_TSO_CHECKER
int len = outstanding_requests.find(id)->second.len;
uint64_t data = 0;
memcpy(&data, from_buffer.m_request.data, 4);
cerr << m_id << " INSERTING STORE" << endl << flush;
// 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 // schedule the next request
if (m_buffer_size > 0) { if (m_buffer_size > 0) {
issueNextStore(); issueNextStore();
} } else if (m_buffer_size == 0) {
else if (m_buffer_size == 0) {
m_storebuffer_flushing = false; m_storebuffer_flushing = false;
m_stalled_issue = true; 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);
} }
@ -460,111 +361,22 @@ void StoreBuffer::complete(uint64_t id) {
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) {
#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); 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)
}
else{
DEBUG_OUT("\t WRITE BUFFER NOT USED\n"); 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,34 +46,30 @@ 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: public:
///Constructor /// Note that the size of the Write Buffer is determined by the
/// Note that the size of the Write Buffer is determined by the WRITE_BUFFER_SIZE config parameter /// WRITE_BUFFER_SIZE config parameter
StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size); StoreBuffer(uint32_t id, uint32_t block_bits, int storebuffer_size);
~StoreBuffer();
/// Register hitcallback back to CPU /// Register hitcallback back to CPU
void registerHitCallback(void (*hit_callback)(int64_t request_id)); void registerHitCallback(void (*hit_callback)(int64_t request_id));
/// Destructor
~StoreBuffer();
///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();
@ -87,13 +78,14 @@ class StoreBuffer {
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();
@ -101,11 +93,6 @@ class StoreBuffer {
/// prints out the contents of the Write Buffer /// prints out the contents of the Write Buffer
void print(); void print();
#if RUBY_TSO_CHECKER
/// if load completes before store, insert correctly to be issued to TSOChecker
void insertTsoLL(Tso::TsoCheckerCmd * cmd);
#endif
/// Returns flag indicating whether we are using the write buffer /// Returns flag indicating whether we are using the write buffer
bool useStoreBuffer() { return m_use_storebuffer; } bool useStoreBuffer() { return m_use_storebuffer; }
@ -115,22 +102,22 @@ class StoreBuffer {
private: private:
/// id of this write buffer (one per sequencer object) /// id of this write buffer (one per sequencer object)
uint32 m_id; uint32_t m_id;
/// number of bytes in cacheline /// number of bytes in cacheline
uint32 m_block_size; uint32_t m_block_size;
/// the size of the write buffer /// the size of the write buffer
uint32 m_storebuffer_size; uint32_t m_storebuffer_size;
/// mask to strip off non-cache line bits /// mask to strip off non-cache line bits
pa_t m_block_mask; pa_t m_block_mask;
/// list of store requests in the write buffer /// list of store requests in the write buffer
deque <struct SBEntry> buffer; std::deque<SBEntry> buffer;
/// the current length of the write buffer /// the current length of the write buffer
uint32 m_buffer_size; uint32_t m_buffer_size;
/// whether we want to simulate the write buffer or not: /// whether we want to simulate the write buffer or not:
bool m_use_storebuffer; bool m_use_storebuffer;
@ -141,7 +128,8 @@ class StoreBuffer {
/// indicates that we are currently flushing the write buffer /// indicates that we are currently flushing the write buffer
bool m_storebuffer_flushing; bool m_storebuffer_flushing;
/// indicates that automatic issue is stalled and the next store to be added should issue itself /// indicates that automatic issue is stalled and the next store
/// to be added should issue itself
bool m_stalled_issue; bool m_stalled_issue;
/// RubyPort to make requests to /// RubyPort to make requests to
@ -151,14 +139,13 @@ class StoreBuffer {
void (*m_hit_callback)(int64_t); void (*m_hit_callback)(int64_t);
/// Map the request id to rubyrequest /// Map the request id to rubyrequest
map<uint64_t, struct RubyRequest> outstanding_requests; std::map<uint64_t, RubyRequest> outstanding_requests;
/// current instruction counter /// current instruction counter
uint64_t iseq; uint64_t iseq;
/// input into tso counter /// input into tso counter
uint64_t tso_iseq; uint64_t tso_iseq;
}; };
#endif #endif // __MEM_RUBY_STOREBUFFER_STOREBUFFER_HH__