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('RUBY_DEBUG', "Add debugging stuff to Ruby", False),
('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',
'RUBY_TSO_CHECKER' ]
export_vars += [ 'NO_VECTOR_BOUNDS_CHECKS', 'RUBY_DEBUG', 'GEMS_ROOT' ]

View file

@ -41,28 +41,26 @@ Network::Network(const Params *p)
m_link_latency = p->link_latency;
m_control_msg_size = p->control_msg_size;
//
// Total nodes/controllers in network
// Must make sure this is called after the State Machine constructors
//
m_nodes = MachineType_base_number(MachineType_NUM);
assert(m_nodes != 0);
assert(m_virtual_networks != 0);
assert(m_topology_ptr != NULL);
//
// Initialize the controller's network pointers
//
m_topology_ptr->initNetworkPtr(this);
}
void Network::init()
void
Network::init()
{
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) {
case MessageSizeType_Undefined:
@ -79,17 +77,21 @@ int Network::MessageSizeType_to_int(MessageSizeType size_type)
case MessageSizeType_Persistent_Control:
case MessageSizeType_Completion_Control:
return m_control_msg_size;
break;
case MessageSizeType_Data:
case MessageSizeType_Response_Data:
case MessageSizeType_ResponseLocal_Data:
case MessageSizeType_ResponseL2hit_Data:
case MessageSizeType_Writeback_Data:
return m_data_msg_size;
break;
default:
ERROR_MSG("Invalid range for type MessageSizeType");
break;
}
return 0;
}
const Vector<Throttle*>*
Network::getThrottles(NodeID id) const
{
return NULL;
}

View file

@ -27,47 +27,40 @@
*/
/*
* Network.hh
*
* Description: The Network class is the base class for classes that
* implement the interconnection network between components
* (processor/cache components and memory/directory components). The
* interconnection network as described here is not a physical
* network, but a programming concept used to implement all
* communication between components. Thus parts of this 'network'
* will model the on-chip connections between cache controllers and
* directory controllers as well as the links between chip and network
* switches.
*
* $Id$
* */
* The Network class is the base class for classes that implement the
* interconnection network between components (processor/cache
* components and memory/directory components). The interconnection
* network as described here is not a physical network, but a
* programming concept used to implement all communication between
* components. Thus parts of this 'network' will model the on-chip
* connections between cache controllers and directory controllers as
* well as the links between chip and network switches.
*/
#ifndef NETWORK_H
#define NETWORK_H
#ifndef __MEM_RUBY_NETWORK_NETWORK_HH__
#define __MEM_RUBY_NETWORK_NETWORK_HH__
#include "mem/protocol/MessageSizeType.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/system/NodeID.hh"
#include "mem/protocol/MessageSizeType.hh"
#include "mem/ruby/system/System.hh"
#include "sim/sim_object.hh"
#include "params/RubyNetwork.hh"
#include "sim/sim_object.hh"
class NetDest;
class MessageBuffer;
class Throttle;
class Topology;
class Network : public SimObject {
class Network : public SimObject
{
public:
// Constructors
typedef RubyNetworkParams Params;
Network(const Params *p);
virtual void init();
// Destructor
virtual ~Network() {}
// Public Methods
virtual void init();
int getBufferSize() { return m_buffer_size; }
int getNumberOfVirtualNetworks() { return m_virtual_networks; }
int getEndpointBandwidth() { return m_endpoint_bandwidth; }
@ -75,17 +68,23 @@ public:
int getLinkLatency() { return m_link_latency; }
int MessageSizeType_to_int(MessageSizeType size_type);
// returns the queue requested for the given component
virtual MessageBuffer* getToNetQueue(NodeID id, bool ordered, int netNumber) = 0;
virtual MessageBuffer* getFromNetQueue(NodeID id, bool ordered, int netNumber) = 0;
virtual const Vector<Throttle*>* getThrottles(NodeID id) const { return NULL; }
virtual MessageBuffer* getToNetQueue(NodeID id, bool ordered,
int netNumber) = 0;
virtual MessageBuffer* getFromNetQueue(NodeID id, bool ordered,
int netNumber) = 0;
virtual const Vector<Throttle*>* getThrottles(NodeID id) const;
virtual int getNumNodes() {return 1;}
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 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 makeOutLink(SwitchID src, NodeID dest,
const NetDest& routing_table_entry, int link_latency, int link_weight,
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;
@ -95,13 +94,10 @@ public:
virtual void print(ostream& out) const = 0;
protected:
// Private Methods
// Private copy constructor and assignment operator
Network(const Network& obj);
Network& operator=(const Network& obj);
// Data Members (m_ prefix)
protected:
const string m_name;
int m_nodes;
@ -115,18 +111,12 @@ protected:
int m_data_msg_size;
};
// Output operator declaration
ostream& operator<<(ostream& out, const Network& obj);
// ******************* Definitions *******************
// Output operator definition
extern inline
ostream& operator<<(ostream& out, const Network& obj)
inline ostream&
operator<<(ostream& out, const Network& obj)
{
obj.print(out);
out << flush;
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
* All rights reserved.
@ -27,29 +26,21 @@
* 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/ruby/buffers/MessageBuffer.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;
// 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);
}
@ -62,19 +53,24 @@ PerfectSwitch::PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr)
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);
NodeID port = m_in.size();
m_in.insertAtBottom(in);
for (int j = 0; j < m_virtual_networks; j++) {
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);
}
}
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);
@ -87,15 +83,16 @@ void PerfectSwitch::addOutPort(const Vector<MessageBuffer*>& out, const NetDest&
// Add to routing table
m_out.insertAtBottom(out);
m_routing_table.insertAtBottom(routing_table_entry);
}
void PerfectSwitch::clearRoutingTables()
void
PerfectSwitch::clearRoutingTables()
{
m_routing_table.clear();
}
void PerfectSwitch::clearBuffers()
void
PerfectSwitch::clearBuffers()
{
for (int i = 0; i < m_in.size(); i++){
for(int vnet = 0; vnet < m_virtual_networks; vnet++) {
@ -110,7 +107,8 @@ void PerfectSwitch::clearBuffers()
}
}
void PerfectSwitch::reconfigureOutPort(const NetDest& routing_table_entry)
void
PerfectSwitch::reconfigureOutPort(const NetDest& 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);
MsgPtr msg_ptr;
@ -141,10 +139,13 @@ void PerfectSwitch::wakeup()
decrementer = -1;
}
for (int vnet = highest_prio_vnet; (vnet*decrementer) >= (decrementer*lowest_prio_vnet); vnet -= decrementer) {
// 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++;
if (m_round_robin_start >= m_in.size()) {
m_round_robin_start = 0;
@ -152,7 +153,6 @@ void PerfectSwitch::wakeup()
// for all input ports, use round robin scheduling
for (int counter = 0; counter < m_in.size(); counter++) {
// Round robin scheduling
incoming++;
if (incoming >= m_in.size()) {
@ -165,7 +165,6 @@ void PerfectSwitch::wakeup()
// Is there a message waiting?
while (m_in[incoming][vnet]->isReady()) {
DEBUG_EXPR(NETWORK_COMP, MedPrio, incoming);
// Peek at message
@ -175,11 +174,12 @@ void PerfectSwitch::wakeup()
output_links.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
// 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_out.size());
@ -187,58 +187,64 @@ void PerfectSwitch::wakeup()
if (m_network_ptr->getAdaptiveRouting()) {
if (m_network_ptr->isVNetOrdered(vnet)) {
// Don't adaptively route
for (int outlink=0; outlink<m_out.size(); outlink++) {
m_link_order[outlink].m_link = outlink;
m_link_order[outlink].m_value = 0;
for (int out = 0; out < m_out.size(); out++) {
m_link_order[out].m_link = out;
m_link_order[out].m_value = 0;
}
} else {
// Find how clogged each link is
for (int outlink=0; outlink<m_out.size(); outlink++) {
for (int out = 0; out < m_out.size(); out++) {
int out_queue_length = 0;
for (int v = 0; v < m_virtual_networks; v++) {
out_queue_length += m_out[outlink][v]->getSize();
out_queue_length += m_out[out][v]->getSize();
}
m_link_order[outlink].m_link = outlink;
m_link_order[outlink].m_value = 0;
m_link_order[outlink].m_value |= (out_queue_length << 8);
m_link_order[outlink].m_value |= (random() & 0xff);
int value =
(out_queue_length << 8) | (random() & 0xff);
m_link_order[out].m_link = out;
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++) {
// pick the next link to look at
int link = m_link_order[i].m_link;
NetDest dst = m_routing_table[link];
DEBUG_EXPR(NETWORK_COMP, MedPrio, dst);
DEBUG_EXPR(NETWORK_COMP, MedPrio, m_routing_table[link]);
if (msg_destinations.intersectionIsNotEmpty(m_routing_table[link])) {
if (!msg_dsts.intersectionIsNotEmpty(dst))
continue;
// Remember what link we're using
output_links.insertAtBottom(link);
// Need to remember which destinations need this message
// in another vector. This Set is the intersection of the
// routing_table entry and the current destination set.
// The intersection must not be empty, since we are inside "if"
output_link_destinations.insertAtBottom(msg_destinations.AND(m_routing_table[link]));
// Need to remember which destinations need this
// message in another vector. This Set is the
// intersection of the routing_table entry and the
// current destination set. The intersection must
// not be empty, since we are inside "if"
output_link_destinations.insertAtBottom(msg_dsts.AND(dst));
// Next, we update the msg_destination not to include
// those nodes that were already handled by this link
msg_destinations.removeNetDest(m_routing_table[link]);
}
// Next, we update the msg_destination not to
// include those nodes that were already handled
// by this link
msg_dsts.removeNetDest(dst);
}
assert(msg_destinations.count() == 0);
assert(msg_dsts.count() == 0);
//assert(output_links.size() > 0);
// Check for resources - for all outgoing queues
bool enough = true;
for (int i = 0; i < output_links.size(); i++) {
int outgoing = output_links[i];
enough = enough && m_out[outgoing][vnet]->areNSlotsAvailable(1);
DEBUG_MSG(NETWORK_COMP, HighPrio, "checking if node is blocked");
if (!m_out[outgoing][vnet]->areNSlotsAvailable(1))
enough = false;
DEBUG_MSG(NETWORK_COMP, HighPrio,
"checking if node is blocked");
DEBUG_EXPR(NETWORK_COMP, HighPrio, outgoing);
DEBUG_EXPR(NETWORK_COMP, HighPrio, vnet);
DEBUG_EXPR(NETWORK_COMP, HighPrio, enough);
@ -247,7 +253,8 @@ void PerfectSwitch::wakeup()
// There were not enough resources
if (!enough) {
g_eventQueue_ptr->scheduleEvent(this, 1);
DEBUG_MSG(NETWORK_COMP, HighPrio, "Can't deliver message to anyone since a node is blocked");
DEBUG_MSG(NETWORK_COMP, HighPrio,
"Can't deliver message since a node is blocked");
DEBUG_EXPR(NETWORK_COMP, HighPrio, *net_msg_ptr);
break; // go to next incoming port
}
@ -255,12 +262,16 @@ void PerfectSwitch::wakeup()
MsgPtr unmodified_msg_ptr;
if (output_links.size() > 1) {
// If we are sending this message down more than one link
// (size>1), we need to make a copy of the message so each
// branch can have a different internal destination
// we need to create an unmodified MsgPtr because the MessageBuffer enqueue func
// will modify the message
unmodified_msg_ptr = *(msg_ptr.ref()); // This magic line creates a private copy of the message
// If we are sending this message down more than
// one link (size>1), we need to make a copy of
// the message so each branch can have a different
// internal destination we need to create an
// unmodified MsgPtr because the MessageBuffer
// enqueue func will modify the message
// This magic line creates a private copy of the
// message
unmodified_msg_ptr = *(msg_ptr.ref());
}
// Enqueue it - for all outgoing queues
@ -268,21 +279,25 @@ void PerfectSwitch::wakeup()
int outgoing = output_links[i];
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
// knows which destinations this link is responsible for.
net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref());
net_msg_ptr->getInternalDestination() = output_link_destinations[i];
// Change the internal destination set of the
// message so it knows which destinations this
// link is responsible for.
net_msg_ptr = safe_cast<NetworkMessage*>(msg_ptr.ref());
net_msg_ptr->getInternalDestination() =
output_link_destinations[i];
// Enqeue msg
DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
DEBUG_MSG(NETWORK_COMP,HighPrio,"switch: " + int_to_string(m_switch_id)
+ " enqueuing net msg from inport[" + int_to_string(incoming) + "]["
+ int_to_string(vnet) +"] to outport [" + int_to_string(outgoing)
+ "][" + int_to_string(vnet) +"]"
+ " time: " + int_to_string(g_eventQueue_ptr->getTime()) + ".");
DEBUG_MSG(NETWORK_COMP, HighPrio,
csprintf("switch: %d enqueuing net msg from "
"inport[%d][%d] to outport [%d][%d] time: %d.",
m_switch_id, incoming, vnet, outgoing, vnet,
g_eventQueue_ptr->getTime()));
DEBUG_NEWLINE(NETWORK_COMP,HighPrio);
m_out[outgoing][vnet]->enqueue(msg_ptr);
@ -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;
}
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 << "]";
}

View file

@ -1,4 +1,3 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
@ -28,54 +27,47 @@
*/
/*
* $Id$
*
* Description: 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 routings that must be done. Note, this switch also
* has number of input ports/output ports and has a routing table
* as well.
*
* 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
* 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
#define PerfectSwitch_H
#ifndef __MEM_RUBY_NETWORK_SIMPLE_PERFECTSWITCH_HH__
#define __MEM_RUBY_NETWORK_SIMPLE_PERFECTSWITCH_HH__
#include <iostream>
#include "mem/ruby/common/Global.hh"
#include "mem/gems_common/Vector.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/system/NodeID.hh"
class MessageBuffer;
class NetDest;
class SimpleNetwork;
class LinkOrder {
public:
struct LinkOrder
{
int m_link;
int m_value;
};
class PerfectSwitch : public Consumer {
class PerfectSwitch : public Consumer
{
public:
// Constructors
// constructor specifying the number of ports
PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr);
~PerfectSwitch();
void addInPort(const Vector<MessageBuffer*>& in);
void addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routing_table_entry);
void addOutPort(const Vector<MessageBuffer*>& out,
const NetDest& routing_table_entry);
void clearRoutingTables();
void clearBuffers();
void reconfigureOutPort(const NetDest& routing_table_entry);
int getInLinks() const { return m_in.size(); }
int getOutLinks() const { return m_out.size(); }
// Destructor
~PerfectSwitch();
// Public Methods
void wakeup();
void printStats(std::ostream& out) const;
@ -83,13 +75,12 @@ public:
void printConfig(std::ostream& out) const;
void print(std::ostream& out) const;
private:
private:
// Private copy constructor and assignment operator
PerfectSwitch(const PerfectSwitch& obj);
PerfectSwitch& operator=(const PerfectSwitch& obj);
// Data Members (m_ prefix)
SwitchID m_switch_id;
// vector of queues from the components
@ -103,18 +94,12 @@ private:
SimpleNetwork* m_network_ptr;
};
// Output operator declaration
std::ostream& operator<<(std::ostream& out, const PerfectSwitch& obj);
// ******************* Definitions *******************
// Output operator definition
extern inline
std::ostream& operator<<(std::ostream& out, const PerfectSwitch& obj)
inline std::ostream&
operator<<(std::ostream& out, const PerfectSwitch& obj)
{
obj.print(out);
out << std::flush;
return out;
}
#endif //PerfectSwitch_H
#endif // __MEM_RUBY_NETWORK_SIMPLE_PERFECTSWITCH_HH__

View file

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

View file

@ -1,4 +1,3 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
@ -27,46 +26,36 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* SimpleNetwork.cc
*
* Description: See SimpleNetwork.hh
*
* $Id$
*
*/
#include "mem/gems_common/Map.hh"
#include "mem/protocol/MachineType.hh"
#include "mem/protocol/Protocol.hh"
#include "mem/protocol/TopologyType.hh"
#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/common/NetDest.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/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
// Note: Moved to Princeton Network
// calls new to abstract away from the network
/*
Network* Network::createNetwork(int nodes)
Network*
Network::createNetwork(int nodes)
{
return new SimpleNetwork(nodes);
}
*/
#endif
SimpleNetwork::SimpleNetwork(const Params *p)
: Network(p)
{
//
// Note: the parent Network Object constructor is called before the
// SimpleNetwork child constructor. Therefore, the member variables
// used below should already be initialized.
//
m_endpoint_switches.setSize(m_nodes);
@ -92,24 +81,25 @@ SimpleNetwork::SimpleNetwork(const Params *p)
}
}
void SimpleNetwork::init()
void
SimpleNetwork::init()
{
Network::init();
//
// The topology pointer should have already been initialized in the parent
// class network constructor.
//
// The topology pointer should have already been initialized in
// the parent class network constructor.
assert(m_topology_ptr != NULL);
int number_of_switches = m_topology_ptr->numSwitches();
for (int i = 0; i < number_of_switches; i++) {
m_switch_ptr_vector.insertAtBottom(new Switch(i, this));
}
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 j = 0; j < m_virtual_networks; j++) {
@ -135,34 +125,51 @@ SimpleNetwork::~SimpleNetwork()
}
// 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(src < m_switch_ptr_vector.size());
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);
m_endpoint_switches[dest] = m_switch_ptr_vector[src];
} else {
if (isReconfiguration) {
m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry);
return;
}
m_switch_ptr_vector[src]->addOutPort(m_fromNetQueues[dest],
routing_table_entry, link_latency, bw_multiplier);
m_endpoint_switches[dest] = m_switch_ptr_vector[src];
}
// 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);
if(!isReconfiguration){
m_switch_ptr_vector[dest]->addInPort(m_toNetQueues[src]);
} else {
if (isReconfiguration) {
// do nothing
return;
}
m_switch_ptr_vector[dest]->addInPort(m_toNetQueues[src]);
}
// 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
Vector<MessageBuffer*> queues;
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
m_buffers_to_free.insertAtBottom(buffer_ptr);
}
// Connect it to the two switches
m_switch_ptr_vector[dest]->addInPort(queues);
m_switch_ptr_vector[src]->addOutPort(queues, routing_table_entry, link_latency, bw_multiplier);
} else {
m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry);
}
m_switch_ptr_vector[src]->addOutPort(queues, routing_table_entry,
link_latency, bw_multiplier);
}
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(network_num < m_virtual_networks);
@ -196,19 +201,22 @@ void SimpleNetwork::checkNetworkAllocation(NodeID id, bool ordered, int network_
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);
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);
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 < m_nodes);
@ -216,7 +224,8 @@ const Vector<Throttle*>* SimpleNetwork::getThrottles(NodeID id) const
return m_endpoint_switches[id]->getThrottles();
}
void SimpleNetwork::printStats(ostream& out) const
void
SimpleNetwork::printStats(ostream& out) const
{
out << endl;
out << "Network Stats" << endl;
@ -228,7 +237,8 @@ void SimpleNetwork::printStats(ostream& out) const
m_topology_ptr->printStats(out);
}
void SimpleNetwork::clearStats()
void
SimpleNetwork::clearStats()
{
for (int i = 0; i < m_switch_ptr_vector.size(); i++) {
m_switch_ptr_vector[i]->clearStats();
@ -236,7 +246,8 @@ void SimpleNetwork::clearStats()
m_topology_ptr->clearStats();
}
void SimpleNetwork::printConfig(ostream& out) const
void
SimpleNetwork::printConfig(ostream& out) const
{
out << endl;
out << "Network Configuration" << endl;
@ -259,6 +270,7 @@ void SimpleNetwork::printConfig(ostream& out) const
}
}
out << endl;
for(int i = 0; i < m_switch_ptr_vector.size(); i++) {
m_switch_ptr_vector[i]->printConfig(out);
}
@ -266,7 +278,8 @@ void SimpleNetwork::printConfig(ostream& out) const
m_topology_ptr->printConfig(out);
}
void SimpleNetwork::print(ostream& out) const
void
SimpleNetwork::print(ostream& out) const
{
out << "[SimpleNetwork]";
}

View file

@ -1,4 +1,3 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
@ -28,9 +27,7 @@
*/
/*
* SimpleNetwork.hh
*
* Description: The SimpleNetwork class implements the interconnection
* The SimpleNetwork class implements the interconnection
* SimpleNetwork between components (processor/cache components and
* memory/directory components). The interconnection network as
* 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
* that to initial proper network. Or even better, just make the ruby
* system initializer choose the proper network to initiate.
*
* $Id$
*
*/
#ifndef SIMPLENETWORK_H
#define SIMPLENETWORK_H
#ifndef __MEM_RUBY_NETWORK_SIMPLE_SIMPLENETWORK_HH__
#define __MEM_RUBY_NETWORK_SIMPLE_SIMPLENETWORK_HH__
#include "mem/ruby/common/Global.hh"
#include "mem/gems_common/Vector.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/system/NodeID.hh"
#include "sim/sim_object.hh"
#include "params/SimpleNetwork.hh"
#include "sim/sim_object.hh"
class NetDest;
class MessageBuffer;
@ -82,18 +76,15 @@ class Throttle;
class Switch;
class Topology;
class SimpleNetwork : public Network {
class SimpleNetwork : public Network
{
public:
// Constructors
typedef SimpleNetworkParams Params;
SimpleNetwork(const Params *p);
// Destructor
~SimpleNetwork();
void init();
// Public Methods
void printStats(ostream& out) const;
void clearStats();
void printConfig(ostream& out) const;
@ -111,26 +102,31 @@ public:
int getNumNodes() {return m_nodes; }
// Methods used by Topology to setup the network
void makeOutLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration);
void makeInLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int bw_multiplier, bool isReconfiguration);
void makeInternalLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration);
void makeOutLink(SwitchID src, NodeID dest,
const NetDest& routing_table_entry, int link_latency, int link_weight,
int bw_multiplier, bool isReconfiguration);
void makeInLink(SwitchID src, NodeID dest,
const NetDest& routing_table_entry, int link_latency,
int bw_multiplier, bool isReconfiguration);
void makeInternalLink(SwitchID src, NodeID dest,
const NetDest& routing_table_entry, int link_latency, int link_weight,
int bw_multiplier, bool isReconfiguration);
void print(ostream& out) const;
private:
void checkNetworkAllocation(NodeID id, bool ordered, int network_num);
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();
void makeTopology();
void linkTopology();
// Private copy constructor and assignment operator
SimpleNetwork(const SimpleNetwork& obj);
SimpleNetwork& operator=(const SimpleNetwork& obj);
// Data Members (m_ prefix)
// vector of queues from the components
Vector<Vector<MessageBuffer*> > m_toNetQueues;
Vector<Vector<MessageBuffer*> > m_fromNetQueues;
@ -142,18 +138,12 @@ private:
Vector<Switch*> m_endpoint_switches;
};
// Output operator declaration
ostream& operator<<(ostream& out, const SimpleNetwork& obj);
// ******************* Definitions *******************
// Output operator definition
extern inline
ostream& operator<<(ostream& out, const SimpleNetwork& obj)
inline ostream&
operator<<(ostream& out, const SimpleNetwork& obj)
{
obj.print(out);
out << flush;
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
* All rights reserved.
@ -27,23 +26,13 @@
* 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/ruby/network/Network.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)
{
@ -63,17 +52,21 @@ Switch::~Switch()
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);
}
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;
// 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);
// Create one buffer per vnet (these are intermediaryQueues)
@ -95,15 +88,16 @@ void Switch::addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routin
// Hook the queues to the Throttle
throttle_ptr->addLinks(intermediateBuffers, out);
}
void Switch::clearRoutingTables()
void
Switch::clearRoutingTables()
{
m_perfect_switch_ptr->clearRoutingTables();
}
void Switch::clearBuffers()
void
Switch::clearBuffers()
{
m_perfect_switch_ptr->clearBuffers();
for (int i = 0; i < m_throttles.size(); i++) {
@ -113,28 +107,34 @@ void Switch::clearBuffers()
}
}
void Switch::reconfigureOutPort(const NetDest& routing_table_entry)
void
Switch::reconfigureOutPort(const NetDest& 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);
return m_throttles[link_number];
}
const Vector<Throttle*>* Switch::getThrottles() const
const Vector<Throttle*>*
Switch::getThrottles() const
{
return &m_throttles;
}
void Switch::printStats(std::ostream& out) const
void
Switch::printStats(std::ostream& out) const
{
using namespace std;
out << "switch_" << m_switch_id << "_inlinks: " << m_perfect_switch_ptr->getInLinks() << endl;
out << "switch_" << m_switch_id << "_outlinks: " << m_perfect_switch_ptr->getOutLinks() << endl;
ccprintf(out, "switch_%d_inlinks: %d\n", m_switch_id,
m_perfect_switch_ptr->getInLinks());
ccprintf(out, "switch_%d_outlinks: %d\n", m_switch_id,
m_perfect_switch_ptr->getOutLinks());
// Average link utilizations
double average_utilization = 0.0;
@ -142,20 +142,25 @@ void Switch::printStats(std::ostream& out) const
for (int i = 0; i < m_throttles.size(); i++) {
Throttle* throttle_ptr = m_throttles[i];
if (throttle_ptr != NULL) {
if (throttle_ptr) {
average_utilization += throttle_ptr->getUtilization();
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
out << "links_utilized_percent_switch_" << m_switch_id << ": " << average_utilization << endl;
out << "links_utilized_percent_switch_" << m_switch_id << ": "
<< average_utilization << endl;
for (int link = 0; link < m_throttles.size(); link++) {
Throttle* throttle_ptr = m_throttles[link];
if (throttle_ptr != NULL) {
out << " links_utilized_percent_switch_" << m_switch_id << "_link_" << link << ": "
<< throttle_ptr->getUtilization() << " bw: " << throttle_ptr->getLinkBandwidth()
out << " links_utilized_percent_switch_" << m_switch_id
<< "_link_" << link << ": "
<< throttle_ptr->getUtilization() << " bw: "
<< throttle_ptr->getLinkBandwidth()
<< " base_latency: " << throttle_ptr->getLatency() << endl;
}
}
@ -164,43 +169,49 @@ void Switch::printStats(std::ostream& out) const
// Traffic breakdown
for (int link = 0; link < m_throttles.size(); link++) {
Throttle* throttle_ptr = m_throttles[link];
if (throttle_ptr != NULL) {
const Vector<Vector<int> >& message_counts = throttle_ptr->getCounters();
if (!throttle_ptr)
continue;
const Vector<Vector<int> >& message_counts =
throttle_ptr->getCounters();
for (int int_type = 0; int_type < MessageSizeType_NUM; int_type++) {
MessageSizeType type = MessageSizeType(int_type);
int sum = message_counts[type].sum();
if (sum != 0) {
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;
}
}
if (sum == 0)
continue;
out << " outgoing_messages_switch_" << m_switch_id
<< "_link_" << link << "_" << type << ": " << sum << " "
<< sum * RubySystem::getNetwork()->MessageSizeType_to_int(type)
<< " " << message_counts[type] << " base_latency: "
<< throttle_ptr->getLatency() << endl;
}
}
out << endl;
}
void Switch::clearStats()
void
Switch::clearStats()
{
m_perfect_switch_ptr->clearStats();
for (int i = 0; i < m_throttles.size(); i++) {
if (m_throttles[i] != NULL) {
if (m_throttles[i] != NULL)
m_throttles[i]->clearStats();
}
}
}
void Switch::printConfig(std::ostream& out) const
void
Switch::printConfig(std::ostream& out) const
{
m_perfect_switch_ptr->printConfig(out);
for (int i = 0; i < m_throttles.size(); i++) {
if (m_throttles[i] != NULL) {
if (m_throttles[i] != NULL)
m_throttles[i]->printConfig(out);
}
}
}
void Switch::print(std::ostream& out) const
void
Switch::print(std::ostream& out) const
{
// FIXME printing
out << "[Switch]";

View file

@ -1,4 +1,3 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
@ -28,26 +27,22 @@
*/
/*
* $Id$
*
* Description: The actual modelled switch. It use the perfect switch and a
* Throttle object to control and bandwidth and timing *only for
* the output port*. So here we have un-realistic modelling,
* since the order of PerfectSwitch and Throttle objects get
* woke up affect the message timing. A more accurate model would
* 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.
*
* The actual modelled switch. It use the perfect switch and a
* Throttle object to control and bandwidth and timing *only for the
* output port*. So here we have un-realistic modelling, since the
* order of PerfectSwitch and Throttle objects get woke up affect the
* message timing. A more accurate model would 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
#define Switch_H
#ifndef __MEM_RUBY_NETWORK_SIMPLE_SWITCH_HH__
#define __MEM_RUBY_NETWORK_SIMPLE_SWITCH_HH__
#include <iostream>
#include "mem/ruby/common/Global.hh"
#include "mem/gems_common/Vector.hh"
#include "mem/ruby/common/Global.hh"
class MessageBuffer;
class PerfectSwitch;
@ -56,14 +51,16 @@ class SimpleNetwork;
class Throttle;
class Network;
class Switch {
class Switch
{
public:
// Constructors
// constructor specifying the number of ports
Switch(SwitchID sid, SimpleNetwork* network_ptr);
~Switch();
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 Vector<Throttle*>* getThrottles() const;
void clearRoutingTables();
@ -74,17 +71,13 @@ public:
void clearStats();
void printConfig(std::ostream& out) const;
// Destructor
~Switch();
void print(std::ostream& out) const;
private:
private:
// Private copy constructor and assignment operator
Switch(const Switch& obj);
Switch& operator=(const Switch& obj);
// Data Members (m_ prefix)
PerfectSwitch* m_perfect_switch_ptr;
Network* m_network_ptr;
Vector<Throttle*> m_throttles;
@ -92,18 +85,12 @@ private:
SwitchID m_switch_id;
};
// Output operator declaration
std::ostream& operator<<(std::ostream& out, const Switch& obj);
// ******************* Definitions *******************
// Output operator definition
extern inline
std::ostream& operator<<(std::ostream& out, const Switch& obj)
inline std::ostream&
operator<<(std::ostream& out, const Switch& obj)
{
obj.print(out);
out << std::flush;
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
* All rights reserved.
@ -27,19 +26,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* $Id$
*
* Description: see Throttle.hh
*
*/
#include "mem/ruby/network/simple/Throttle.hh"
#include "base/cprintf.hh"
#include "mem/protocol/Protocol.hh"
#include "mem/ruby/buffers/MessageBuffer.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/protocol/Protocol.hh"
#include "mem/ruby/system/System.hh"
const int HIGH_RANGE = 256;
const int ADJUST_INTERVAL = 50000;
@ -52,19 +45,22 @@ static int network_message_to_size(NetworkMessage* net_msg_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);
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);
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_vnets = 0;
@ -77,7 +73,8 @@ void Throttle::init(NodeID node, int link_latency, int link_bandwidth_multiplier
clearStats();
}
void Throttle::clear()
void
Throttle::clear()
{
for (int counter = 0; counter < m_vnets; counter++) {
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());
for (int i=0; i<in_vec.size(); i++) {
@ -101,7 +100,8 @@ void Throttle::addLinks(const Vector<MessageBuffer*>& in_vec, const Vector<Messa
}
}
void Throttle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr)
void
Throttle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr)
{
m_units_remaining.insertAtBottom(0);
m_in.insertAtBottom(in_ptr);
@ -109,12 +109,14 @@ void Throttle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr)
// Set consumer and description
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_vnets++;
}
void Throttle::wakeup()
void
Throttle::wakeup()
{
// Limits the number of message sent to a limited number of bytes/cycle.
assert(getLinkBandwidth() > 0);
@ -135,27 +137,34 @@ void Throttle::wakeup()
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_in[vnet] != NULL);
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()) {
// Find the size of the message we are moving
MsgPtr msg_ptr = m_in[vnet]->peekMsgPtr();
NetworkMessage* net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref());
m_units_remaining[vnet] += network_message_to_size(net_msg_ptr);
NetworkMessage* 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_MSG(NETWORK_COMP,HighPrio,"throttle: " + int_to_string(m_node)
+ " my bw " + int_to_string(getLinkBandwidth())
+ " bw spent enqueueing net msg " + int_to_string(m_units_remaining[vnet])
+ " time: " + int_to_string(g_eventQueue_ptr->getTime()) + ".");
DEBUG_MSG(NETWORK_COMP, HighPrio,
csprintf("throttle: %d my bw %d bw spent enqueueing "
"net msg %d time: %d.",
m_node, getLinkBandwidth(), m_units_remaining[vnet],
g_eventQueue_ptr->getTime()));
// Move the message
m_out[vnet]->enqueue(m_in[vnet]->peekMsgPtr(), m_link_latency);
@ -174,38 +183,50 @@ void Throttle::wakeup()
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);
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
// 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
double ratio = 1.0 - (double(bw_remaining) / double(getLinkBandwidth()));
// If ratio = 0, we used no bandwidth, if ratio = 1, we used all
linkUtilized(ratio);
if ((bw_remaining > 0) && !schedule_wakeup) {
// We have extra bandwidth and our output buffer was available, so we must not have anything else to do until another message arrives.
if (bw_remaining > 0 && !schedule_wakeup) {
// We have extra bandwidth and our output buffer was
// available, so we must not have anything else to do until
// another message arrives.
DEBUG_MSG(NETWORK_COMP, LowPrio, *this);
DEBUG_MSG(NETWORK_COMP, LowPrio, "not scheduled again");
} else {
DEBUG_MSG(NETWORK_COMP, LowPrio, *this);
DEBUG_MSG(NETWORK_COMP, LowPrio, "scheduled again");
// We are out of bandwidth for this cycle, so wakeup next cycle and continue
// We are out of bandwidth for this cycle, so wakeup next
// cycle and continue
g_eventQueue_ptr->scheduleEvent(this, 1);
}
}
void Throttle::printStats(ostream& out) const
void
Throttle::printStats(ostream& out) const
{
out << "utilized_percent: " << getUtilization() << endl;
}
void Throttle::clearStats()
void
Throttle::clearStats()
{
m_ruby_start = g_eventQueue_ptr->getTime();
m_links_utilized = 0.0;
@ -217,33 +238,37 @@ void Throttle::clearStats()
}
}
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
static
int network_message_to_size(NetworkMessage* net_msg_ptr)
int
network_message_to_size(NetworkMessage* net_msg_ptr)
{
assert(net_msg_ptr != NULL);
int size = RubySystem::getNetwork()->
MessageSizeType_to_int(net_msg_ptr->getMessageSize());
size *= MESSAGE_SIZE_MULTIPLIER;
// Artificially increase the size of broadcast messages
if (BROADCAST_SCALING > 1) {
if (net_msg_ptr->getDestination().isBroadcast()) {
return (RubySystem::getNetwork()->MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER * BROADCAST_SCALING);
}
}
return (RubySystem::getNetwork()->MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER);
if (BROADCAST_SCALING > 1 && net_msg_ptr->getDestination().isBroadcast())
size *= BROADCAST_SCALING;
return size;
}

View file

@ -1,4 +1,3 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
@ -28,57 +27,62 @@
*/
/*
* $Id$
*
* Description: The class to implement bandwidth and latency throttle. An
* instance of consumer class that can be woke up. It is only used
* to control bandwidth at output port of a switch. And the
* throttle is added *after* the output port, means the message is
* put in the output port of the PerfectSwitch (a
* intermediateBuffers) first, then go through the Throttle.
*
* The class to implement bandwidth and latency throttle. An instance
* of consumer class that can be woke up. It is only used to control
* bandwidth at output port of a switch. And the throttle is added
* *after* the output port, means the message is put in the output
* port of the PerfectSwitch (a intermediateBuffers) first, then go
* through the Throttle.
*/
#ifndef THROTTLE_H
#define THROTTLE_H
#ifndef __MEM_RUBY_NETWORK_SIMPLE_THROTTLE_HH__
#define __MEM_RUBY_NETWORK_SIMPLE_THROTTLE_HH__
#include "mem/ruby/common/Global.hh"
#include "mem/gems_common/Vector.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/System.hh"
#include "mem/ruby/network/Network.hh"
class MessageBuffer;
class Throttle : public Consumer {
class Throttle : public Consumer
{
public:
// Constructors
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);
// Destructor
~Throttle() {}
// Public Methods
void addLinks(const Vector<MessageBuffer*>& in_vec, const Vector<MessageBuffer*>& out_vec);
void addLinks(const Vector<MessageBuffer*>& in_vec,
const Vector<MessageBuffer*>& out_vec);
void wakeup();
void printStats(ostream& out) const;
void clearStats();
void printConfig(ostream& out) const;
double getUtilization() const; // The average utilization (a percent) since last clearStats()
int getLinkBandwidth() const { return RubySystem::getNetwork()->getEndpointBandwidth() * m_link_bandwidth_multiplier; }
// The average utilization (a percent) since last clearStats()
double getUtilization() const;
int
getLinkBandwidth() const
{
return RubySystem::getNetwork()->getEndpointBandwidth() *
m_link_bandwidth_multiplier;
}
int getLatency() const { return m_link_latency; }
const Vector<Vector<int> >& getCounters() const { return m_message_counters; }
const Vector<Vector<int> >&
getCounters() const
{
return m_message_counters;
}
void clear();
void print(ostream& out) const;
private:
// Private Methods
void init(NodeID node, int link_latency, int link_bandwidth_multiplier);
void addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr);
void linkUtilized(double ratio) { m_links_utilized += ratio; }
@ -87,7 +91,6 @@ private:
Throttle(const Throttle& obj);
Throttle& operator=(const Throttle& obj);
// Data Members (m_ prefix)
Vector<MessageBuffer*> m_in;
Vector<MessageBuffer*> m_out;
Vector<Vector<int> > m_message_counters;
@ -104,18 +107,12 @@ private:
double m_links_utilized;
};
// Output operator declaration
ostream& operator<<(ostream& out, const Throttle& obj);
// ******************* Definitions *******************
// Output operator definition
extern inline
ostream& operator<<(ostream& out, const Throttle& obj)
inline ostream&
operator<<(ostream& out, const Throttle& obj)
{
obj.print(out);
out << flush;
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
* All rights reserved.
@ -27,27 +26,18 @@
* 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/protocol/MachineType.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"
static 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 INFINITE_LATENCY = 10000; // Yes, this is a big hack
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
// 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.
// Helper functions based on chapter 29 of Cormen et al.
static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix& inter_switches);
static Matrix shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches);
static bool link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final, const Matrix& weights, const Matrix& dist);
static NetDest shortest_path_to_node(SwitchID src, SwitchID next, const Matrix& weights, const Matrix& dist);
void extend_shortest_path(Matrix& current_dist, Matrix& latencies,
Matrix& inter_switches);
Matrix shortest_path(const Matrix& weights, Matrix& latencies,
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)
: SimObject(p)
@ -71,25 +65,21 @@ Topology::Topology(const Params *p)
m_component_latencies.setSize(0);
m_component_inter_switches.setSize(0);
//
// Total nodes/controllers in network
// Must make sure this is called after the State Machine constructors
//
m_nodes = MachineType_base_number(MachineType_NUM);
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",
m_nodes != params()->ext_links.size());
}
//
// First create the links between the endpoints (i.e. controllers) and the
// network.
//
// First create the links between the endpoints (i.e. controllers)
// and the network.
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();
AbstractController *c = p->ext_node;
@ -107,8 +97,7 @@ Topology::Topology(const Params *p)
}
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();
int a = p->node_a + 2*m_nodes;
int b = p->node_b + 2*m_nodes;
@ -120,19 +109,18 @@ Topology::Topology(const Params *p)
}
void Topology::initNetworkPtr(Network* net_ptr)
{
for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++)
void
Topology::initNetworkPtr(Network* net_ptr)
{
for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) {
m_controller_vector[cntrl]->initNetworkPtr(net_ptr);
}
}
void Topology::createLinks(Network *net, bool isReconfiguration)
void
Topology::createLinks(Network *net, bool isReconfiguration)
{
// Find maximum switchID
SwitchID max_switch_id = 0;
for (int i = 0; i < m_links_src_vector.size(); i++) {
max_switch_id = max(max_switch_id, m_links_src_vector[i]);
@ -147,20 +135,33 @@ void Topology::createLinks(Network *net, bool isReconfiguration)
topology_weights.setSize(num_switches);
topology_latency.setSize(num_switches);
topology_bw_multis.setSize(num_switches);
m_component_latencies.setSize(num_switches); // FIXME setting the size of a member variable here is a HACK!
m_component_inter_switches.setSize(num_switches); // FIXME setting the size of a member variable here is a HACK!
// FIXME setting the size of a member variable here is a HACK!
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_latency[i].setSize(num_switches);
topology_bw_multis[i].setSize(num_switches);
m_component_latencies[i].setSize(num_switches);
m_component_inter_switches[i].setSize(num_switches); // FIXME setting the size of a member variable here is a HACK!
// 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_latency[i][j] = -1; // initialize to an invalid value
topology_bw_multis[i][j] = -1; // initialize to an invalid value
m_component_latencies[i][j] = -1; // initialize to an invalid value
m_component_inter_switches[i][j] = 0; // initially assume direct connections / no intermediate switches between components
// initialize to invalid values
topology_latency[i][j] = -1;
topology_bw_multis[i][j] = -1;
m_component_latencies[i][j] = -1;
// initially assume direct connections / no intermediate
// switches between components
m_component_inter_switches[i][j] = 0;
}
}
@ -171,45 +172,56 @@ void Topology::createLinks(Network *net, bool isReconfiguration)
// Fill in the topology weights and bandwidth multipliers
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];
topology_latency[m_links_src_vector[i]][m_links_dest_vector[i]] = m_links_latency_vector[i];
m_component_latencies[m_links_src_vector[i]][m_links_dest_vector[i]] = m_links_latency_vector[i]; // initialize to latency vector
topology_bw_multis[m_links_src_vector[i]][m_links_dest_vector[i]] = m_bw_multiplier_vector[i];
int src = m_links_src_vector[i];
int dst = m_links_dest_vector[i];
topology_weights[src][dst] = m_links_weight_vector[i];
topology_latency[src][dst] = m_links_latency_vector[i];
m_component_latencies[src][dst] = m_links_latency_vector[i];
topology_bw_multis[src][dst] = m_bw_multiplier_vector[i];
}
// Walk topology and hookup the links
Matrix dist = shortest_path(topology_weights, m_component_latencies, m_component_inter_switches);
Matrix dist = shortest_path(topology_weights, m_component_latencies,
m_component_inter_switches);
for (int i = 0; i < topology_weights.size(); i++) {
for (int j = 0; j < topology_weights[i].size(); j++) {
int weight = topology_weights[i][j];
int bw_multiplier = topology_bw_multis[i][j];
int latency = topology_latency[i][j];
if (weight > 0 && weight != INFINITE_LATENCY) {
NetDest destination_set = shortest_path_to_node(i, j, topology_weights, dist);
NetDest destination_set = shortest_path_to_node(i, j,
topology_weights, dist);
assert(latency != -1);
makeLink(net, i, j, destination_set, latency, weight, bw_multiplier, isReconfiguration);
makeLink(net, i, j, destination_set, latency, weight,
bw_multiplier, isReconfiguration);
}
}
}
}
SwitchID Topology::newSwitchID()
SwitchID
Topology::newSwitchID()
{
m_number_of_switches++;
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);
}
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);
}
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(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);
}
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
assert((src >= 2*m_nodes) || (dest >= 2*m_nodes));
// Make sure we're not trying to connect two end-point nodes
// directly together
assert(src >= 2 * m_nodes || dest >= 2 * 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) {
assert(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 {
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++) {
m_controller_vector[cntrl]->printStats(out);
}
}
void Topology::clearStats()
void
Topology::clearStats()
{
for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) {
m_controller_vector[cntrl]->clearStats();
}
}
void Topology::printConfig(std::ostream& out) const
void
Topology::printConfig(std::ostream& out) const
{
using namespace std;
if (m_print_config == false) return;
if (m_print_config == false)
return;
assert(m_component_latencies.size() > 0);
out << "--- Begin Topology Print ---" << endl;
out << endl;
out << "Topology print ONLY indicates the _NETWORK_ latency between two machines" << endl;
out << "It does NOT include the latency within the machines" << endl;
out << endl;
out << "--- Begin Topology Print ---" << endl
<< endl
<< "Topology print ONLY indicates the _NETWORK_ latency between two "
<< "machines" << endl
<< "It does NOT include the latency within the machines" << endl
<< endl;
for (int m = 0; m < MachineType_NUM; m++) {
for (int i=0; i<MachineType_base_count((MachineType)m); i++) {
int i_end = MachineType_base_count((MachineType)m);
for (int i = 0; i < i_end; i++) {
MachineID cur_mach = {(MachineType)m, i};
out << cur_mach << " Network Latencies" << endl;
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};
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];
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: "
<< link_latency+intermediate_switches << endl; // NOTE switches are assumed to have single cycle latency
}
if (cur_mach == dest_mach)
continue;
int src = MachineType_base_number((MachineType)m) + i;
int dst = MachineType_base_number(MachineType_NUM) +
MachineType_base_number((MachineType)n) + j;
int link_latency = m_component_latencies[src][dst];
int intermediate_switches =
m_component_inter_switches[src][dst];
// NOTE switches are assumed to have single
// cycle latency
out << " " << cur_mach << " -> " << dest_mach
<< " net_lat: "
<< link_latency + intermediate_switches << endl;
}
}
out << endl;
@ -286,12 +323,11 @@ void Topology::printConfig(std::ostream& out) const
out << "--- End Topology Print ---" << endl;
}
/**************************************************************************/
// The following all-pairs shortest path algorithm is based on the
// discussion from Cormen et al., Chapter 26.1.
static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix& inter_switches)
void
extend_shortest_path(Matrix& current_dist, Matrix& latencies,
Matrix& inter_switches)
{
bool change = true;
int nodes = current_dist.size();
@ -304,10 +340,13 @@ static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix
int previous_minimum = minimum;
int intermediate_switch = -1;
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) {
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;
}
@ -316,28 +355,32 @@ static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix
current_dist[i][j] = minimum;
assert(intermediate_switch >= 0);
assert(intermediate_switch < latencies[i].size());
latencies[i][j] = latencies[i][intermediate_switch] + latencies[intermediate_switch][j];
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;
extend_shortest_path(dist, latencies, inter_switches);
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)
{
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,
const Matrix& weights, const Matrix& dist)
NetDest
shortest_path_to_node(SwitchID src, SwitchID next, const Matrix& weights,
const Matrix& dist)
{
NetDest result;
int d = 0;
@ -349,11 +392,12 @@ static NetDest shortest_path_to_node(SwitchID src, SwitchID next,
for (int m = 0; m < machines; m++) {
for (int i = 0; i < MachineType_base_count((MachineType)m); i++) {
// we use "d+max_machines" below since the "destination" switches for the machines are numbered
// [MachineType_base_number(MachineType_NUM)...2*MachineType_base_number(MachineType_NUM)-1]
// for the component network
if (link_is_shortest_path_to_node(src, next,
d+max_machines,
// we use "d+max_machines" below since the "destination"
// switches for the machines are numbered
// [MachineType_base_number(MachineType_NUM)...
// 2*MachineType_base_number(MachineType_NUM)-1] for the
// component network
if (link_is_shortest_path_to_node(src, next, d + max_machines,
weights, dist)) {
MachineID mach = {(MachineType)m, i};
result.add(mach);

View file

@ -1,4 +1,3 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
@ -28,77 +27,68 @@
*/
/*
* Topology.hh
*
* Description: 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 all input port has a
* 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
* 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
* all input port has a 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
* ports. Edges are represented in two vectors of src and dest
* nodes. All edges have latency.
*
* $Id$
*
* */
*/
#ifndef TOPOLOGY_H
#define TOPOLOGY_H
#ifndef __MEM_RUBY_NETWORK_SIMPLE_TOPOLOGY_HH__
#define __MEM_RUBY_NETWORK_SIMPLE_TOPOLOGY_HH__
#include <iostream>
#include <string>
#include "mem/ruby/common/Global.hh"
#include "mem/gems_common/Vector.hh"
#include "mem/ruby/common/Global.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/IntLink.hh"
#include "params/Link.hh"
#include "params/Topology.hh"
#include "sim/sim_object.hh"
class Network;
class NetDest;
typedef Vector<Vector<int> > Matrix;
class Link : public SimObject {
class Link : public SimObject
{
public:
typedef LinkParams Params;
Link(const Params *p) : SimObject(p) {}
const Params *params() const { return (const Params *)_params; }
};
class ExtLink : public Link {
class ExtLink : public Link
{
public:
typedef ExtLinkParams Params;
ExtLink(const Params *p) : Link(p) {}
const Params *params() const { return (const Params *)_params; }
};
class IntLink : public Link {
class IntLink : public Link
{
public:
typedef IntLinkParams Params;
IntLink(const Params *p) : Link(p) {}
const Params *params() const { return (const Params *)_params; }
};
class Topology : public SimObject {
class Topology : public SimObject
{
public:
// Constructors
typedef TopologyParams Params;
Topology(const Params *p);
virtual ~Topology() {}
const Params *params() const { return (const Params *)_params; }
// Destructor
virtual ~Topology() {}
// Public Methods
int numSwitches() const { return m_number_of_switches; }
void createLinks(Network *net, bool isReconfiguration);
@ -111,21 +101,24 @@ public:
void print(std::ostream& out) const { out << "[Topology]"; }
protected:
// Private Methods
SwitchID newSwitchID();
void addLink(SwitchID src, SwitchID dest, int link_latency);
void addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier);
void addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier, int link_weight);
void makeLink(Network *net, SwitchID src, SwitchID dest, const NetDest& routing_table_entry, int link_latency, int weight, int bw_multiplier, bool isReconfiguration);
void addLink(SwitchID src, SwitchID dest, int link_latency,
int bw_multiplier);
void addLink(SwitchID src, SwitchID dest, int link_latency,
int bw_multiplier, int link_weight);
void makeLink(Network *net, SwitchID src, SwitchID dest,
const NetDest& routing_table_entry, int link_latency, int weight,
int bw_multiplier, bool isReconfiguration);
// void makeSwitchesPerChip(Vector< Vector < SwitchID > > &nodePairs, Vector<int> &latencies, Vector<int> &bw_multis, int numberOfChips);
//void makeSwitchesPerChip(Vector<Vector< SwitchID> > &nodePairs,
// Vector<int> &latencies, Vector<int> &bw_multis, int numberOfChips);
std::string getDesignStr();
// Private copy constructor and assignment operator
Topology(const Topology& obj);
Topology& operator=(const Topology& obj);
// Data Members (m_ prefix)
std::string m_name;
bool m_print_config;
NodeID m_nodes;
@ -143,18 +136,12 @@ protected:
Matrix m_component_inter_switches;
};
// Output operator declaration
std::ostream& operator<<(std::ostream& out, const Topology& obj);
// ******************* Definitions *******************
// Output operator definition
extern inline
std::ostream& operator<<(std::ostream& out, const Topology& obj)
inline std::ostream&
operator<<(std::ostream& out, const Topology& obj)
{
obj.print(out);
out << std::flush;
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.objects import *
#
# Makes a generic mesh assuming an equal number of cache and directory cntrls
#
def makeTopology(nodes, options):
num_routers = options.num_cpus
num_rows = options.mesh_rows
#
# There must be an evenly divisible number of cntrls to routers
# Also, obviously the number or rows must be <= the number of routers
#
cntrls_per_router, remainder = divmod(len(nodes), num_routers)
assert(num_rows <= num_routers)
num_columns = int(num_routers / num_rows)
assert(num_columns * num_rows == num_routers)
#
# Add all but the remainder nodes to the list of nodes to be uniformly
# distributed across the network.
#
network_nodes = []
remainder_nodes = []
for node_index in xrange(len(nodes)):
@ -59,27 +53,22 @@ def makeTopology(nodes, options):
else:
remainder_nodes.append(nodes[node_index])
#
# Connect each node to the appropriate router
#
ext_links = []
for (i, n) in enumerate(network_nodes):
cntrl_level, router_id = divmod(i, num_routers)
assert(cntrl_level < cntrls_per_router)
ext_links.append(ExtLink(ext_node=n, int_node=router_id))
#
# Connect the remainding nodes to router 0. These should only be DMA nodes.
#
# Connect the remainding nodes to router 0. These should only be
# DMA nodes.
for (i, node) in enumerate(remainder_nodes):
assert(node.type == 'DMA_Controller')
assert(i < remainder)
ext_links.append(ExtLink(ext_node=node, int_node=0))
#
# Create the mesh links. First row (east-west) links then column
# (north-south) links
#
int_links = []
for row in xrange(num_rows):
for col in xrange(num_columns):

View file

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

View file

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

View file

@ -1,4 +1,3 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
@ -27,16 +26,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* $Id$
*
*/
#include "gzstream.hh"
#include "mem/gems_common/PrioHeap.hh"
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
#include "mem/ruby/recorder/CacheRecorder.hh"
#include "mem/ruby/recorder/TraceRecord.hh"
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
#include "mem/gems_common/PrioHeap.hh"
#include "gzstream.hh"
CacheRecorder::CacheRecorder()
{
@ -48,16 +43,16 @@ CacheRecorder::~CacheRecorder()
delete m_records_ptr;
}
void CacheRecorder::addRecord(Sequencer* sequencer,
const Address& data_addr,
const Address& pc_addr,
RubyRequestType type,
Time time)
void
CacheRecorder::addRecord(Sequencer* sequencer, const Address& data_addr,
const Address& pc_addr, 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());
if (out.fail()) {
@ -74,6 +69,7 @@ int CacheRecorder::dumpRecords(string filename)
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
* All rights reserved.
@ -28,15 +27,12 @@
*/
/*
* $Id$
*
* Description: Recording cache requests made to a ruby cache at certain
* ruby time. Also dump the requests to a gziped file.
*
* Recording cache requests made to a ruby cache at certain ruby
* time. Also dump the requests to a gziped file.
*/
#ifndef CACHERECORDER_H
#define CACHERECORDER_H
#ifndef __MEM_RUBY_RECORDER_CACHERECORDER_HH__
#define __MEM_RUBY_RECORDER_CACHERECORDER_HH__
#include <iostream>
#include <string>
@ -51,46 +47,32 @@ class Address;
class TraceRecord;
class Sequencer;
class CacheRecorder {
class CacheRecorder
{
public:
// Constructors
CacheRecorder();
// Destructor
~CacheRecorder();
// Public Methods
void addRecord(Sequencer* sequencer,
const Address& data_addr,
const Address& pc_addr,
RubyRequestType type,
Time time);
void addRecord(Sequencer* sequencer, const Address& data_addr,
const Address& pc_addr, RubyRequestType type, Time time);
int dumpRecords(std::string filename);
void print(std::ostream& out) const;
private:
// Private Methods
private:
// Private copy constructor and assignment operator
CacheRecorder(const CacheRecorder& obj);
CacheRecorder& operator=(const CacheRecorder& obj);
// Data Members (m_ prefix)
PrioHeap<TraceRecord>* m_records_ptr;
};
// Output operator declaration
std::ostream& operator<<(std::ostream& out, const CacheRecorder& obj);
// ******************* Definitions *******************
// Output operator definition
extern inline
std::ostream& operator<<(std::ostream& out, const CacheRecorder& obj)
inline std::ostream&
operator<<(std::ostream& out, const CacheRecorder& obj)
{
obj.print(out);
out << std::flush;
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
* All rights reserved.
@ -27,22 +26,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* $Id$
*
*/
#include "mem/protocol/CacheMsg.hh"
#include "mem/ruby/recorder/TraceRecord.hh"
#include "mem/ruby/system/Sequencer.hh"
#include "mem/ruby/system/System.hh"
#include "mem/protocol/CacheMsg.hh"
#include "sim/sim_object.hh"
TraceRecord::TraceRecord(Sequencer* _sequencer,
const Address& data_addr,
const Address& pc_addr,
RubyRequestType type,
Time time)
TraceRecord::TraceRecord(Sequencer* _sequencer, const Address& data_addr,
const Address& pc_addr, RubyRequestType type, Time time)
{
m_sequencer_ptr = _sequencer;
m_data_address = data_addr;
@ -54,19 +45,19 @@ TraceRecord::TraceRecord(Sequencer* _sequencer,
// the trace
if (m_type == RubyRequestType_Locked_Read) {
m_type = RubyRequestType_ST;
}
else if (m_type == RubyRequestType_Locked_Write) {
} else if (m_type == RubyRequestType_Locked_Write) {
m_type = RubyRequestType_ST;
}
}
// Public copy constructor and assignment operator
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_time = obj.m_time;
@ -76,17 +67,14 @@ TraceRecord& TraceRecord::operator=(const TraceRecord& obj)
return *this;
}
void TraceRecord::issueRequest() const
void
TraceRecord::issueRequest() const
{
assert(m_sequencer_ptr != NULL);
RubyRequest request(m_data_address.getAddress(),
NULL,
RubySystem::getBlockSizeBytes(),
m_pc_address.getAddress(),
m_type,
RubyAccessMode_User,
NULL);
RubyRequest request(m_data_address.getAddress(), NULL,
RubySystem::getBlockSizeBytes(), m_pc_address.getAddress(),
m_type, RubyAccessMode_User, NULL);
// Clear out the sequencer
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() << ", "
<< m_data_address << ", " << m_pc_address << ", "
<< m_type << ", Time: " << m_time << "]";
}
void TraceRecord::output(ostream& out) const
void
TraceRecord::output(ostream& out) const
{
out << m_sequencer_ptr->name() << " ";
m_data_address.output(out);
@ -119,22 +109,23 @@ void TraceRecord::output(ostream& out) const
out << endl;
}
bool TraceRecord::input(istream& in)
bool
TraceRecord::input(istream& in)
{
string sequencer_name;
in >> sequencer_name;
//
// The SimObject find function is slow and iterates through the
// simObjectList to find the sequencer pointer. Therefore, expect trace
// playback to be slow.
//
// simObjectList to find the sequencer pointer. Therefore, expect
// trace playback to be slow.
m_sequencer_ptr = (Sequencer*)SimObject::find(sequencer_name.c_str());
m_data_address.input(in);
m_pc_address.input(in);
if (in.eof())
return false;
string type;
if (!in.eof()) {
in >> type;
m_type = string_to_RubyRequestType(type);
@ -145,7 +136,4 @@ bool TraceRecord::input(istream& in)
}
return true;
} else {
return false;
}
}

View file

@ -1,4 +1,3 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
@ -28,57 +27,50 @@
*/
/*
* $Id$
*
* Description: A entry in the cache request record. It is aware of
* the ruby time and can issue the request back to the
* cache.
*
* 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
#define TRACERECORD_H
#ifndef __MEM_RUBY_RECORDER_TRACERECORD_HH__
#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/Global.hh"
#include "mem/ruby/libruby_internal.hh"
#include "mem/ruby/system/NodeID.hh"
#include "mem/ruby/system/Sequencer.hh"
class CacheMsg;
class TraceRecord {
class TraceRecord
{
public:
// Constructors
TraceRecord(Sequencer* _sequencer,
const Address& data_addr,
const Address& pc_addr,
RubyRequestType type,
Time time);
TraceRecord(Sequencer* _sequencer, const Address& data_addr,
const Address& pc_addr, RubyRequestType type, Time time);
TraceRecord() {
TraceRecord()
{
m_sequencer_ptr = NULL;
m_time = 0;
m_type = RubyRequestType_NULL;
}
// Destructor
// ~TraceRecord();
// Public copy constructor and assignment operator
TraceRecord(const TraceRecord& obj);
TraceRecord& operator=(const TraceRecord& obj);
// Public Methods
bool node_less_then_eq(const TraceRecord& rec) const { return (this->m_time <= rec.m_time); }
bool
node_less_then_eq(const TraceRecord& rec) const
{
return this->m_time <= rec.m_time;
}
void issueRequest() const;
void print(ostream& out) const;
void output(ostream& out) const;
bool input(istream& in);
private:
// Private Methods
// Data Members (m_ prefix)
private:
Sequencer* m_sequencer_ptr;
Time m_time;
Address m_data_address;
@ -86,26 +78,18 @@ private:
RubyRequestType m_type;
};
inline extern 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)
inline bool
node_less_then_eq(const TraceRecord& n1, const TraceRecord& n2)
{
return n1.node_less_then_eq(n2);
}
// Output operator definition
extern inline
ostream& operator<<(ostream& out, const TraceRecord& obj)
inline std::ostream&
operator<<(ostream& out, const TraceRecord& obj)
{
obj.print(out);
out << flush;
out << std::flush;
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
* All rights reserved.
@ -27,18 +26,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* $Id$
*
*/
#include "mem/ruby/recorder/Tracer.hh"
#include "mem/ruby/recorder/TraceRecord.hh"
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
#include "base/cprintf.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"
//added by SS
Tracer::Tracer(const Params *p)
: SimObject(p)
{
@ -48,64 +42,49 @@ Tracer::Tracer(const Params *p)
RubySystem::m_tracer_ptr = this;
}
//commented by SS
//Tracer::Tracer()
//{
// m_enabled = false;
//}
Tracer::~Tracer()
void
Tracer::startTrace(std::string filename)
{
}
void Tracer::init()
{
}
void Tracer::startTrace(std::string filename)
{
if (m_enabled) {
if (m_enabled)
stopTrace();
}
if (filename != "") {
m_trace_file.open(filename.c_str());
if (m_trace_file.fail()) {
cout << "Error: error opening file '" << filename << "'" << endl;
cout << "Trace not enabled." << endl;
cprintf("Error: error opening file '%s'\n", filename);
cprintf("Trace not enabled.\n");
return;
}
cout << "Request trace enabled to output file '" << filename << "'" << endl;
cprintf("Request trace enabled to output file '%s'\n", filename);
m_enabled = true;
}
}
void Tracer::stopTrace()
void
Tracer::stopTrace()
{
if (m_enabled == true) {
if (m_enabled) {
m_trace_file.close();
cout << "Request trace file closed." << endl;
m_enabled = false;
}
}
void Tracer::traceRequest(Sequencer* sequencer,
const Address& data_addr,
const Address& pc_addr,
RubyRequestType type,
Time time)
void
Tracer::traceRequest(Sequencer* sequencer, const Address& data_addr,
const Address& pc_addr, RubyRequestType type, Time time)
{
assert(m_enabled == true);
assert(m_enabled);
TraceRecord tr(sequencer, data_addr, pc_addr, type, time);
tr.output(m_trace_file);
}
// Class method
int Tracer::playbackTrace(std::string filename)
int
Tracer::playbackTrace(std::string filename)
{
igzstream in(filename.c_str());
if (in.fail()) {
cout << "Error: error opening file '" << filename << "'" << endl;
cprintf("Error: error opening file '%s'\n", filename);
return 0;
}
@ -124,20 +103,16 @@ int Tracer::playbackTrace(std::string filename)
ok = record.input(in);
// 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) {
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();
}
}
// 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);
double seconds = difftime(stop_time, start_time);
@ -147,11 +122,11 @@ int Tracer::playbackTrace(std::string filename)
return counter;
}
void Tracer::print(std::ostream& out) const
void
Tracer::print(std::ostream& out) const
{
}
Tracer *
RubyTracerParams::create()
{

View file

@ -1,4 +1,3 @@
/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
@ -28,68 +27,51 @@
*/
/*
* $Id$
*
* Description: Controller class of the tracer. Can stop/start/playback
* the ruby cache requests trace.
*
* Controller class of the tracer. Can stop/start/playback the ruby
* cache requests trace.
*/
#ifndef TRACER_H
#define TRACER_H
#ifndef __MEM_RUBY_RECORDER_TRACER_HH__
#define __MEM_RUBY_RECORDER_TRACER_HH__
#include <iostream>
#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 "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;
class Address;
class TraceRecord;
class Sequencer;
class Tracer : public SimObject {
class Tracer : public SimObject
{
public:
// Constructors
// Tracer();
typedef RubyTracerParams Params;
Tracer(const Params *p);
// Destructor
~Tracer();
// Public Methods
void startTrace(std::string filename);
void stopTrace();
bool traceEnabled() { return m_enabled; }
void traceRequest(Sequencer* sequencer,
const Address& data_addr,
const Address& pc_addr,
RubyRequestType type,
Time time);
void traceRequest(Sequencer* sequencer, const Address& data_addr,
const Address& pc_addr, RubyRequestType type, Time time);
void print(std::ostream& out) const;
// Public Class Methods
int playbackTrace(std::string filename);
void init();
private:
// Private Methods
private:
// Private copy constructor and assignment operator
Tracer(const Tracer& obj);
Tracer& operator=(const Tracer& obj);
// Data Members (m_ prefix)
ogzstream m_trace_file;
bool m_enabled;
@ -97,18 +79,12 @@ private:
int m_warmup_length;
};
// Output operator declaration
std::ostream& operator<<(std::ostream& out, const Tracer& obj);
// ******************* Definitions *******************
// Output operator definition
extern inline
std::ostream& operator<<(std::ostream& out, const Tracer& obj)
inline std::ostream&
operator<<(std::ostream& out, const Tracer& obj)
{
obj.print(out);
out << std::flush;
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,34 +27,41 @@
*/
#include <iostream>
#include "mem/ruby/storebuffer/stb_interface.hh"
StoreBuffer * createNewSTB(uint32 id, uint32 block_bits, int storebuffer_size) {
StoreBuffer *
createNewSTB(uint32 id, uint32 block_bits, int storebuffer_size)
{
StoreBuffer *stb = new StoreBuffer(id, block_bits, storebuffer_size);
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);
if (storebuffer->storeBufferFull()){
return WB_FULL;
}
else if (storebuffer->storeBufferFlushing()) {
} else if (storebuffer->storeBufferFlushing()) {
return WB_FLUSHING;
}
else {
} else {
storebuffer->addToStoreBuffer(request);
return WB_OK;
}
}
uint64_t handleLoad(StoreBuffer * storebuffer, const RubyRequest & request) {
uint64_t
handleLoad(StoreBuffer *storebuffer, const RubyRequest &request)
{
assert(request.type == RubyRequestType_LD);
return storebuffer->handleLoad(request);
}
#if 0
uint64_t handleAtomic(StoreBuffer * storebuffer, const RubyRequest & request) {
uint64_t
handleAtomic(StoreBuffer *storebuffer, const RubyRequest &request)
{
// flush the store buffer
storebuffer->flushStoreBuffer();
// let storebuffer issue atomic
@ -62,14 +69,17 @@ uint64_t handleAtomic(StoreBuffer * storebuffer, const RubyRequest & request) {
}
#endif
void flushSTB(StoreBuffer * storebuffer) {
void
flushSTB(StoreBuffer *storebuffer)
{
// in in-order can't get a request to flushSTB if already flushing
// on out of order, have to check if already flushing
storebuffer->flushStoreBuffer();
}
void registerHitCallback(StoreBuffer * storebuffer, void (*hit_callback)(int64_t access_id)) {
void
registerHitCallback(StoreBuffer *storebuffer,
void (*hit_callback)(int64_t access_id))
{
storebuffer->registerHitCallback(hit_callback);
}

View file

@ -27,16 +27,12 @@
*/
#include "mem/ruby/storebuffer/storebuffer.hh"
#include <iostream>
StoreBuffer *createNewSTB(uint32 id, uint32 block_bits, int storebuffer_size);
storebuffer_status_t handleStore (StoreBuffer * storebuffer, const RubyRequest & request);
storebuffer_status_t handleStore(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);
void registerHitCallback(StoreBuffer * storebuffer, void (*hit_callback)(int64_t access_id));
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.
*/
/*------------------------------------------------------------------------*/
/* Includes */
/*------------------------------------------------------------------------*/
#include <map>
#include "mem/ruby/storebuffer/hfa.hh"
#include "mem/ruby/storebuffer/storebuffer.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/storebuffer/storebuffer.hh"
#if RUBY_TSO_CHECKER
#include "TsoChecker.hh"
#endif
using namespace std;
#define SYSTEM_EXIT ASSERT(0)
// global map of request id_s to map them back to storebuffer pointers
map<uint64_t, StoreBuffer *> request_map;
#if RUBY_TSO_CHECKER
Tso::TsoChecker * g_tsoChecker;
#endif
void hit(int64_t id) {
void
hit(int64_t id)
{
if (request_map.find(id) == request_map.end()) {
ERROR_OUT("Request ID not found in the map");
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id);
ASSERT(0);
}
else {
} else {
request_map[id]->complete(id);
request_map.erase(id);
}
}
//*****************************************************************************************
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
StoreBuffer::StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size)
{
iseq = 0;
tso_iseq = 0;
char name [] = "Sequencer_";
@ -93,47 +75,54 @@ StoreBuffer::StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size) {
}
#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",
m_use_storebuffer);
#endif
}
//******************************************************************************************
StoreBuffer::~StoreBuffer(){
#if RUBY_TSO_CHECKER
if (m_id == 0) {
delete g_tsoChecker;
}
#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
m_hit_callback = hit_callback;
}
//*****************************************************************************************************
void StoreBuffer::addToStoreBuffer(struct RubyRequest request){
if(m_use_storebuffer){
void
StoreBuffer::addToStoreBuffer(RubyRequest request)
{
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");
#endif
#ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("\t INSERTING new request\n");
#endif
buffer.push_front(SBEntry(request, NULL));
m_buffer_size++;
if (m_buffer_size >= m_storebuffer_size) {
m_storebuffer_full = true;
}
else if (m_stalled_issue) {
} else if (m_stalled_issue) {
m_stalled_issue = false;
issueNextStore();
}
@ -144,91 +133,83 @@ void StoreBuffer::addToStoreBuffer(struct RubyRequest request){
DEBUG_OUT("***StoreBuffer: addToStoreBuffer END, contents:\n");
DEBUG_OUT("\n");
#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 the store buffer
// Return value of -3 indicates a partial match, so the load has to retry until NO_MATCH
// Alternatively we could satisfy the partial match, but tso gets complicated and more races
//*****************************************************************************************************
int64_t StoreBuffer::handleLoad(struct RubyRequest request) {
if (m_use_storebuffer) {
// Return value of -2 indicates that the load request was satisfied by
// the store buffer
// Return value of -3 indicates a partial match, so the load has to
// retry until NO_MATCH
// Alternatively we could satisfy the partial match, but tso gets
// complicated and more races
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);
if (match == FULL_MATCH) {
// fill data
returnMatchedData(request);
iseq++;
return -2;
}
else if (match == NO_MATCH) {
} else if (match == NO_MATCH) {
// make request to libruby and return the id
uint64_t id = libruby_issue_request(m_port, request);
if (request_map.find(id) != request_map.end()) {
ERROR_OUT("Request ID is already in the map");
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id);
ASSERT(0);
}
else {
} else {
request_map.insert(make_pair(id, this));
outstanding_requests.insert(make_pair(id, request));
}
iseq++;
return id;
}
else { // partial match
} else { // partial match
return -3;
}
}
else {
// make a request to ruby
return libruby_issue_request(m_port, request);
}
}
//*****************************************************************************************************
// This function will fill the data array if any match is found
//*****************************************************************************************************
load_match StoreBuffer::checkForLoadHit(struct RubyRequest request) {
if (m_use_storebuffer) {
load_match
StoreBuffer::checkForLoadHit(RubyRequest request)
{
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;
int len = request.len;
uint8_t * data = new uint8_t[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;
}
bool found = false;
physical_address_t lineaddr = physical_address & m_block_mask;
// iterate over the buffer looking for hits
for (deque<struct SBEntry>::iterator it = buffer.begin(); it != buffer.end(); it++) {
if ((it->m_request.paddr & m_block_mask) == lineaddr) {
deque<SBEntry>::iterator it = buffer.begin();
for (; it != buffer.end(); it++) {
RubyRequest &req = it->m_request;
if ((req.paddr & m_block_mask) != lineaddr)
continue;
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;
}
}
}
// 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) {
ASSERT(m_buffer_size > 0);
int unmatched_bytes = 0;
@ -238,28 +219,23 @@ load_match StoreBuffer::checkForLoadHit(struct RubyRequest request) {
if (unmatched_bytes == 0) {
delete data;
return FULL_MATCH;
}
else {
} else {
delete data;
return PARTIAL_MATCH;
}
}
else {
} else {
delete data;
return NO_MATCH;
}
} // end of if (m_use_storebuffer)
else {
// this function should never be called if we are not using a store buffer
ERROR_OUT("checkForLoadHit called while write buffer is not in use");
}
void
StoreBuffer::returnMatchedData(RubyRequest request)
{
if (!m_use_storebuffer) {
ERROR_OUT("returnMatchedData called while write buffer is not in use");
ASSERT(0);
}
}
//***************************************************************************************************
void StoreBuffer::returnMatchedData(struct RubyRequest request) {
if (m_use_storebuffer) {
uint8_t * data = new uint8_t[64];
memset(data, 0, 64);
@ -272,28 +248,12 @@ void StoreBuffer::returnMatchedData(struct RubyRequest request) {
ASSERT(checkForLoadHit(request) != NO_MATCH);
physical_address_t lineaddr = physical_address & m_block_mask;
bool found = false;
#if RUBY_TSO_CHECKER
Tso::TsoCheckerCmd * cmd;
#endif
deque<struct SBEntry>::iterator satisfying_store;
for (deque<struct SBEntry>::iterator it = buffer.begin(); it != buffer.end(); it++) {
deque<SBEntry>::iterator satisfying_store;
deque<SBEntry>::iterator it = buffer.begin();
for (; it != buffer.end(); it++) {
if ((it->m_request.paddr & m_block_mask) == lineaddr) {
if (!found) {
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;
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 written;
}
else {
ERROR_OUT("returnMatchedData called while write buffer is not in use");
ASSERT(0);
}
void
StoreBuffer::flushStoreBuffer()
{
if (!m_use_storebuffer) {
// do nothing
return;
}
//******************************************************************************************
void StoreBuffer::flushStoreBuffer(){
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
return;
}
m_storebuffer_flushing = (m_buffer_size > 0);
}
//****************************************************************************************
void StoreBuffer::issueNextStore() {
void
StoreBuffer::issueNextStore()
{
SBEntry request = buffer.back();
uint64_t id = libruby_issue_request(m_port, request.m_request);
if (request_map.find(id) != request_map.end()) {
assert(0);
}
else {
} else {
request_map.insert(make_pair(id, this));
outstanding_requests.insert(make_pair(id, request.m_request));
}
}
//****************************************************************************************
void StoreBuffer::complete(uint64_t id) {
if (m_use_storebuffer) {
void
StoreBuffer::complete(uint64_t id)
{
if (!m_use_storebuffer) {
m_hit_callback(id);
return;
}
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;
#ifdef DEBUG_WRITE_BUFFER
DEBUG_OUT("\n***StoreBuffer: complete BEGIN, contents:\n");
@ -389,69 +326,33 @@ void StoreBuffer::complete(uint64_t id) {
if (type == RubyRequestType_ST) {
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
// must remove the WB entry!
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 );
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();
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();
m_buffer_size--;
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
if (m_buffer_size > 0) {
issueNextStore();
}
else if (m_buffer_size == 0) {
} else if (m_buffer_size == 0) {
m_storebuffer_flushing = false;
m_stalled_issue = true;
}
m_storebuffer_full = false;
}
else {
ERROR_OUT("[%d] error: StoreBuffer: at complete, address 0x%0llx not found.\n", m_id, lineaddr);
} else {
ERROR_OUT("[%d] error: StoreBuffer: at complete, address 0x%0llx "
"not found.\n", m_id, lineaddr);
ERROR_OUT("StoreBuffer:: complete FAILS\n");
ASSERT(0);
}
@ -460,112 +361,23 @@ void StoreBuffer::complete(uint64_t id) {
DEBUG_OUT("***StoreBuffer: complete END, contents:\n");
DEBUG_OUT("\n");
#endif
} // end if (type == ST)
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
} else if (type == RubyRequestType_LD) {
m_hit_callback(id);
}
// LD, ST or FETCH hit callback
outstanding_requests.erase(id);
} // end if(m_use_storebuffer)
else {
m_hit_callback(id);
}
}
#if RUBY_TSO_CHECKER
void StoreBuffer::insertTsoLL(Tso::TsoCheckerCmd * cmd) {
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 )
void
StoreBuffer::print()
{
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){
}
else{
if (!m_use_storebuffer)
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.
*/
#ifndef _STOREBUFFER_H_
#define _STOREBUFFER_H_
#ifndef __MEM_RUBY_STOREBUFFER_STOREBUFFER_HH__
#define __MEM_RUBY_STOREBUFFER_STOREBUFFER_HH__
#include <map>
#include <deque>
#include <map>
#include "config/ruby_tso_checker.hh"
#include "mem/ruby/storebuffer/hfa.hh"
#include "mem/ruby/common/TypeDefines.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
* successfully enqueue the store request
* Status for write buffer accesses. The Write buffer can hit in
* fastpath, be full, or successfully enqueue the store request
*/
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 };
struct SBEntry {
struct RubyRequest m_request;
#if RUBY_TSO_CHECKER
Tso::TsoCheckerCmd * m_next_ptr;
#endif
SBEntry(struct RubyRequest request, void * ptr)
struct SBEntry
{
RubyRequest m_request;
SBEntry(RubyRequest request, void * ptr)
: m_request(request)
{
#if RUBY_TSO_CHECKER
m_next_ptr = (Tso::TsoCheckerCmd*) ptr;
#endif
}
};
class StoreBuffer {
class StoreBuffer
{
public:
///Constructor
/// Note that the size of the Write Buffer is determined by the WRITE_BUFFER_SIZE config parameter
StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size);
/// Note that the size of the Write Buffer is determined by the
/// WRITE_BUFFER_SIZE config parameter
StoreBuffer(uint32_t id, uint32_t block_bits, int storebuffer_size);
~StoreBuffer();
/// Register hitcallback back to CPU
void registerHitCallback(void (*hit_callback)(int64_t request_id));
/// Destructor
~StoreBuffer();
///Adds a store entry to the write buffer
void addToStoreBuffer(struct RubyRequest request);
void addToStoreBuffer(RubyRequest request);
///Flushes the entire write buffer
void flushStoreBuffer();
@ -87,13 +78,14 @@ class StoreBuffer {
void complete(uint64_t);
/// 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
load_match checkForLoadHit(struct RubyRequest request);
/// Used by all load insts to check whether it hits to any entry
/// in the WB. If so, the WB is flushed
load_match checkForLoadHit(RubyRequest request);
/// Used to fill the load in case of FULL_MATCH
void returnMatchedData(struct RubyRequest request);
void returnMatchedData(RubyRequest request);
/// Issue next store in line
void issueNextStore();
@ -101,11 +93,6 @@ class StoreBuffer {
/// prints out the contents of the Write Buffer
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
bool useStoreBuffer() { return m_use_storebuffer; }
@ -115,22 +102,22 @@ class StoreBuffer {
private:
/// id of this write buffer (one per sequencer object)
uint32 m_id;
uint32_t m_id;
/// number of bytes in cacheline
uint32 m_block_size;
uint32_t m_block_size;
/// the size of the write buffer
uint32 m_storebuffer_size;
uint32_t m_storebuffer_size;
/// mask to strip off non-cache line bits
pa_t m_block_mask;
/// list of store requests in the write buffer
deque <struct SBEntry> buffer;
std::deque<SBEntry> 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:
bool m_use_storebuffer;
@ -141,7 +128,8 @@ class StoreBuffer {
/// indicates that we are currently flushing the write buffer
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;
/// RubyPort to make requests to
@ -151,14 +139,13 @@ class StoreBuffer {
void (*m_hit_callback)(int64_t);
/// Map the request id to rubyrequest
map<uint64_t, struct RubyRequest> outstanding_requests;
std::map<uint64_t, RubyRequest> outstanding_requests;
/// current instruction counter
uint64_t iseq;
/// input into tso counter
uint64_t tso_iseq;
};
#endif
#endif // __MEM_RUBY_STOREBUFFER_STOREBUFFER_HH__