style: another ruby style pass
This commit is contained in:
parent
60ae1d2b10
commit
be10204729
46 changed files with 2244 additions and 3007 deletions
|
@ -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' ]
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
public:
|
||||
// Constructors
|
||||
class Network : public SimObject
|
||||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
|
@ -94,15 +93,12 @@ public:
|
|||
virtual void printConfig(ostream& out) const = 0;
|
||||
virtual void print(ostream& out) const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
// Private Methods
|
||||
protected:
|
||||
// Private copy constructor and assignment operator
|
||||
Network(const Network& obj);
|
||||
Network& operator=(const Network& obj);
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
protected:
|
||||
protected:
|
||||
const string m_name;
|
||||
int m_nodes;
|
||||
int m_virtual_networks;
|
||||
|
@ -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__
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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,30 +83,32 @@ 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++) {
|
||||
for (int i = 0; i < m_in.size(); i++){
|
||||
for(int vnet = 0; vnet < m_virtual_networks; vnet++) {
|
||||
m_in[i][vnet]->clear();
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<m_out.size(); i++){
|
||||
for(int vnet=0; vnet < m_virtual_networks; vnet++) {
|
||||
for (int i = 0; i < m_out.size(); i++){
|
||||
for(int vnet = 0; vnet < m_virtual_networks; vnet++) {
|
||||
m_out[i][vnet]->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PerfectSwitch::reconfigureOutPort(const NetDest& routing_table_entry)
|
||||
void
|
||||
PerfectSwitch::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,67 +187,74 @@ 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();
|
||||
for (int v = 0; v < m_virtual_networks; v++) {
|
||||
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++) {
|
||||
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++) {
|
||||
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);
|
||||
}
|
||||
|
||||
// There were not enough resources
|
||||
if(!enough) {
|
||||
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 << "]";
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
// constructor specifying the number of ports
|
||||
class PerfectSwitch : public Consumer
|
||||
{
|
||||
public:
|
||||
PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr);
|
||||
~PerfectSwitch();
|
||||
|
||||
void addInPort(const Vector<MessageBuffer*>& in);
|
||||
void addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routing_table_entry);
|
||||
void 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__
|
||||
|
|
|
@ -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
|
|
@ -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++) {
|
||||
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++) {
|
||||
|
@ -118,7 +108,7 @@ void SimpleNetwork::reset()
|
|||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<m_switch_ptr_vector.size(); i++){
|
||||
for(int i = 0; i < m_switch_ptr_vector.size(); i++){
|
||||
m_switch_ptr_vector[i]->clearBuffers();
|
||||
}
|
||||
}
|
||||
|
@ -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,27 +224,30 @@ 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;
|
||||
out << "-------------" << endl;
|
||||
out << endl;
|
||||
for(int i=0; i<m_switch_ptr_vector.size(); i++) {
|
||||
for (int i = 0; i < m_switch_ptr_vector.size(); i++) {
|
||||
m_switch_ptr_vector[i]->printStats(out);
|
||||
}
|
||||
m_topology_ptr->printStats(out);
|
||||
}
|
||||
|
||||
void SimpleNetwork::clearStats()
|
||||
void
|
||||
SimpleNetwork::clearStats()
|
||||
{
|
||||
for(int i=0; i<m_switch_ptr_vector.size(); i++) {
|
||||
for (int i = 0; i < m_switch_ptr_vector.size(); i++) {
|
||||
m_switch_ptr_vector[i]->clearStats();
|
||||
}
|
||||
m_topology_ptr->clearStats();
|
||||
}
|
||||
|
||||
void SimpleNetwork::printConfig(ostream& out) const
|
||||
void
|
||||
SimpleNetwork::printConfig(ostream& out) const
|
||||
{
|
||||
out << endl;
|
||||
out << "Network Configuration" << endl;
|
||||
|
@ -259,14 +270,16 @@ void SimpleNetwork::printConfig(ostream& out) const
|
|||
}
|
||||
}
|
||||
out << endl;
|
||||
for(int i=0; i<m_switch_ptr_vector.size(); i++) {
|
||||
|
||||
for(int i = 0; i < m_switch_ptr_vector.size(); i++) {
|
||||
m_switch_ptr_vector[i]->printConfig(out);
|
||||
}
|
||||
|
||||
m_topology_ptr->printConfig(out);
|
||||
}
|
||||
|
||||
void SimpleNetwork::print(ostream& out) const
|
||||
void
|
||||
SimpleNetwork::print(ostream& out) const
|
||||
{
|
||||
out << "[SimpleNetwork]";
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
public:
|
||||
// Constructors
|
||||
class SimpleNetwork : public Network
|
||||
{
|
||||
public:
|
||||
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:
|
||||
|
||||
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__
|
||||
|
|
|
@ -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,27 +52,31 @@ 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)
|
||||
Vector<MessageBuffer*> intermediateBuffers;
|
||||
for (int i=0; i<out.size(); i++) {
|
||||
for (int i = 0; i < out.size(); i++) {
|
||||
MessageBuffer* buffer_ptr = new MessageBuffer;
|
||||
// Make these queues ordered
|
||||
buffer_ptr->setOrdering(true);
|
||||
Network* net_ptr = RubySystem::getNetwork();
|
||||
if(net_ptr->getBufferSize() > 0) {
|
||||
if (net_ptr->getBufferSize() > 0) {
|
||||
buffer_ptr->setSize(net_ptr->getBufferSize());
|
||||
}
|
||||
intermediateBuffers.insertAtBottom(buffer_ptr);
|
||||
|
@ -95,112 +88,130 @@ 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++) {
|
||||
for (int i = 0; i < m_throttles.size(); i++) {
|
||||
if (m_throttles[i] != NULL) {
|
||||
m_throttles[i]->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Switch::reconfigureOutPort(const NetDest& routing_table_entry)
|
||||
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;
|
||||
int throttle_count = 0;
|
||||
|
||||
for (int i=0; i<m_throttles.size(); i++) {
|
||||
for (int i = 0; i < m_throttles.size(); i++) {
|
||||
Throttle* throttle_ptr = m_throttles[i];
|
||||
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;
|
||||
for (int link=0; link<m_throttles.size(); link++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
out << endl;
|
||||
|
||||
// Traffic breakdown
|
||||
for (int link=0; link<m_throttles.size(); link++) {
|
||||
for (int link = 0; link < m_throttles.size(); link++) {
|
||||
Throttle* throttle_ptr = m_throttles[link];
|
||||
if (throttle_ptr != NULL) {
|
||||
const Vector<Vector<int> >& message_counts = throttle_ptr->getCounters();
|
||||
for (int int_type=0; int_type<MessageSizeType_NUM; int_type++) {
|
||||
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) {
|
||||
for (int i = 0; i < m_throttles.size(); i++) {
|
||||
if (m_throttles[i] != NULL)
|
||||
m_throttles[i]->clearStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Switch::printConfig(std::ostream& out) const
|
||||
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) {
|
||||
for (int i = 0; i < m_throttles.size(); i++) {
|
||||
if (m_throttles[i] != NULL)
|
||||
m_throttles[i]->printConfig(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Switch::print(std::ostream& out) const
|
||||
void
|
||||
Switch::print(std::ostream& out) const
|
||||
{
|
||||
// FIXME printing
|
||||
out << "[Switch]";
|
||||
|
|
|
@ -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 {
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
// constructor specifying the number of ports
|
||||
class Switch
|
||||
{
|
||||
public:
|
||||
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__
|
||||
|
|
|
@ -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;
|
||||
|
@ -50,21 +43,24 @@ const int PRIORITY_SWITCH_LIMIT = 128;
|
|||
|
||||
static int network_message_to_size(NetworkMessage* net_msg_ptr);
|
||||
|
||||
extern std::ostream * debug_cout_ptr;
|
||||
extern std::ostream *debug_cout_ptr;
|
||||
|
||||
Throttle::Throttle(int sID, NodeID node, int link_latency, int link_bandwidth_multiplier)
|
||||
Throttle::Throttle(int sID, NodeID node, int link_latency,
|
||||
int link_bandwidth_multiplier)
|
||||
{
|
||||
init(node, link_latency, link_bandwidth_multiplier);
|
||||
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++) {
|
||||
|
@ -93,15 +92,16 @@ void Throttle::addLinks(const Vector<MessageBuffer*>& in_vec, const Vector<Messa
|
|||
}
|
||||
|
||||
m_message_counters.setSize(MessageSizeType_NUM);
|
||||
for (int i=0; i<MessageSizeType_NUM; i++) {
|
||||
for (int i = 0; i < MessageSizeType_NUM; i++) {
|
||||
m_message_counters[i].setSize(in_vec.size());
|
||||
for (int j=0; j<m_message_counters[i].size(); j++) {
|
||||
for (int j = 0; j<m_message_counters[i].size(); j++) {
|
||||
m_message_counters[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,76 +183,92 @@ 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()));
|
||||
double ratio = 1.0 - (double(bw_remaining) / double(getLinkBandwidth()));
|
||||
|
||||
// If ratio = 0, we used no bandwidth, if ratio = 1, we used all
|
||||
linkUtilized(ratio);
|
||||
|
||||
if ((bw_remaining > 0) && !schedule_wakeup) {
|
||||
// We have extra bandwidth and our output buffer was available, so we must not have anything else to do until another message arrives.
|
||||
DEBUG_MSG(NETWORK_COMP,LowPrio,*this);
|
||||
DEBUG_MSG(NETWORK_COMP,LowPrio,"not scheduled again");
|
||||
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
|
||||
DEBUG_MSG(NETWORK_COMP, LowPrio, *this);
|
||||
DEBUG_MSG(NETWORK_COMP, LowPrio, "scheduled again");
|
||||
|
||||
// We are out of bandwidth for this cycle, so wakeup next
|
||||
// cycle and continue
|
||||
g_eventQueue_ptr->scheduleEvent(this, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Throttle::printStats(ostream& out) const
|
||||
void
|
||||
Throttle::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;
|
||||
|
||||
for (int i=0; i<m_message_counters.size(); i++) {
|
||||
for (int j=0; j<m_message_counters[i].size(); j++) {
|
||||
for (int i = 0; i < m_message_counters.size(); i++) {
|
||||
for (int j = 0; j < m_message_counters[i].size(); j++) {
|
||||
m_message_counters[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Throttle::printConfig(ostream& out) const
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
public:
|
||||
// Constructors
|
||||
Throttle(int sID, NodeID node, int link_latency, int link_bandwidth_multiplier);
|
||||
class Throttle : public Consumer
|
||||
{
|
||||
public:
|
||||
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
|
||||
private:
|
||||
void init(NodeID node, int link_latency, int link_bandwidth_multiplier);
|
||||
void addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr);
|
||||
void linkUtilized(double ratio) { m_links_utilized += ratio; }
|
||||
|
@ -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__
|
||||
|
|
|
@ -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,21 +109,20 @@ Topology::Topology(const Params *p)
|
|||
}
|
||||
|
||||
|
||||
void Topology::initNetworkPtr(Network* net_ptr)
|
||||
void
|
||||
Topology::initNetworkPtr(Network* net_ptr)
|
||||
{
|
||||
for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++)
|
||||
{
|
||||
for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) {
|
||||
m_controller_vector[cntrl]->initNetworkPtr(net_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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++) {
|
||||
for (int i = 0; i < m_links_src_vector.size(); i++) {
|
||||
max_switch_id = max(max_switch_id, m_links_src_vector[i]);
|
||||
max_switch_id = max(max_switch_id, m_links_dest_vector[i]);
|
||||
}
|
||||
|
@ -147,69 +135,93 @@ 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!
|
||||
for(int i=0; i<topology_weights.size(); i++) {
|
||||
|
||||
// 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!
|
||||
for(int j=0; j<topology_weights[i].size(); j++) {
|
||||
|
||||
// FIXME setting the size of a member variable here is a HACK!
|
||||
m_component_inter_switches[i].setSize(num_switches);
|
||||
|
||||
for (int j = 0; j < topology_weights[i].size(); j++) {
|
||||
topology_weights[i][j] = INFINITE_LATENCY;
|
||||
topology_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;
|
||||
}
|
||||
}
|
||||
|
||||
// Set identity weights to zero
|
||||
for(int i=0; i<topology_weights.size(); i++) {
|
||||
for (int i = 0; i < topology_weights.size(); i++) {
|
||||
topology_weights[i][i] = 0;
|
||||
}
|
||||
|
||||
// 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];
|
||||
for (int i = 0; i < m_links_src_vector.size(); i++) {
|
||||
int src = m_links_src_vector[i];
|
||||
int dst = m_links_dest_vector[i];
|
||||
topology_weights[src][dst] = m_links_weight_vector[i];
|
||||
topology_latency[src][dst] = m_links_latency_vector[i];
|
||||
m_component_latencies[src][dst] = m_links_latency_vector[i];
|
||||
topology_bw_multis[src][dst] = m_bw_multiplier_vector[i];
|
||||
}
|
||||
|
||||
// Walk topology and hookup the links
|
||||
Matrix dist = shortest_path(topology_weights, m_component_latencies, m_component_inter_switches);
|
||||
for(int i=0; i<topology_weights.size(); i++) {
|
||||
for(int j=0; j<topology_weights[i].size(); j++) {
|
||||
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;
|
||||
for (int m=0; m<MachineType_NUM; m++) {
|
||||
for (int i=0; i<MachineType_base_count((MachineType)m); i++) {
|
||||
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++) {
|
||||
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++) {
|
||||
for (int n = 0; n < MachineType_NUM; n++) {
|
||||
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,28 +323,30 @@ 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();
|
||||
|
||||
while (change) {
|
||||
change = false;
|
||||
for (int i=0; i<nodes; i++) {
|
||||
for (int j=0; j<nodes; j++) {
|
||||
for (int i = 0; i < nodes; i++) {
|
||||
for (int j = 0; j < nodes; j++) {
|
||||
int minimum = current_dist[i][j];
|
||||
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]);
|
||||
for (int k = 0; k < nodes; k++) {
|
||||
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;
|
||||
|
@ -347,13 +390,14 @@ static NetDest shortest_path_to_node(SwitchID src, SwitchID next,
|
|||
machines = MachineType_NUM;
|
||||
max_machines = MachineType_base_number(MachineType_NUM);
|
||||
|
||||
for (int m=0; m<machines; m++) {
|
||||
for (int i=0; i<MachineType_base_count((MachineType)m); i++) {
|
||||
// we use "d+max_machines" below since the "destination" switches for the machines are numbered
|
||||
// [MachineType_base_number(MachineType_NUM)...2*MachineType_base_number(MachineType_NUM)-1]
|
||||
// for the component network
|
||||
if (link_is_shortest_path_to_node(src, next,
|
||||
d+max_machines,
|
||||
for (int m = 0; m < machines; m++) {
|
||||
for (int i = 0; i < MachineType_base_count((MachineType)m); i++) {
|
||||
// we use "d+max_machines" below since the "destination"
|
||||
// switches for the machines are numbered
|
||||
// [MachineType_base_number(MachineType_NUM)...
|
||||
// 2*MachineType_base_number(MachineType_NUM)-1] for the
|
||||
// component network
|
||||
if (link_is_shortest_path_to_node(src, next, d + max_machines,
|
||||
weights, dist)) {
|
||||
MachineID mach = {(MachineType)m, i};
|
||||
result.add(mach);
|
||||
|
|
|
@ -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;
|
||||
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 {
|
||||
public:
|
||||
// Constructors
|
||||
class Topology : public SimObject
|
||||
{
|
||||
public:
|
||||
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);
|
||||
|
||||
|
@ -110,22 +100,25 @@ public:
|
|||
void printConfig(std::ostream& out) const;
|
||||
void print(std::ostream& out) const { out << "[Topology]"; }
|
||||
|
||||
protected:
|
||||
// Private Methods
|
||||
protected:
|
||||
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__
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# -*- mode:python -*-
|
||||
|
||||
# Copyright (c) 2010 Advanced Micro Devices, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
|
|
|
@ -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
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
public:
|
||||
// Constructors
|
||||
class CacheRecorder
|
||||
{
|
||||
public:
|
||||
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__
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
public:
|
||||
// Constructors
|
||||
TraceRecord(Sequencer* _sequencer,
|
||||
const Address& data_addr,
|
||||
const Address& pc_addr,
|
||||
RubyRequestType type,
|
||||
Time time);
|
||||
class TraceRecord
|
||||
{
|
||||
public:
|
||||
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__
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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 {
|
||||
public:
|
||||
// Constructors
|
||||
// Tracer();
|
||||
class Tracer : public SimObject
|
||||
{
|
||||
public:
|
||||
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__
|
||||
|
|
|
@ -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_ */
|
||||
|
||||
|
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -27,49 +27,59 @@
|
|||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "mem/ruby/storebuffer/stb_interface.hh"
|
||||
|
||||
StoreBuffer * createNewSTB(uint32 id, uint32 block_bits, int storebuffer_size) {
|
||||
StoreBuffer * stb = new StoreBuffer(id, block_bits, 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
|
||||
//return storebuffer->issueAtomic(request);
|
||||
// return storebuffer->issueAtomic(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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
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));
|
||||
StoreBuffer *createNewSTB(uint32 id, uint32 block_bits, int storebuffer_size);
|
||||
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));
|
||||
|
|
|
@ -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;
|
||||
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_";
|
||||
|
@ -88,43 +70,51 @@ StoreBuffer::StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size) {
|
|||
m_storebuffer_full = false;
|
||||
m_storebuffer_flushing = false;
|
||||
m_stalled_issue = true;
|
||||
if(m_storebuffer_size > 0){
|
||||
if (m_storebuffer_size > 0){
|
||||
m_use_storebuffer = true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_WRITE_BUFFER
|
||||
DEBUG_OUT("*******storebuffer_t::Using Write Buffer? %d\n",m_use_storebuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
//******************************************************************************************
|
||||
StoreBuffer::~StoreBuffer(){
|
||||
#if RUBY_TSO_CHECKER
|
||||
if (m_id == 0) {
|
||||
delete g_tsoChecker;
|
||||
}
|
||||
#ifdef DEBUG_WRITE_BUFFER
|
||||
DEBUG_OUT("*******storebuffer_t::Using Write Buffer? %d\n",
|
||||
m_use_storebuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
//*****************************************************************************************************
|
||||
void StoreBuffer::registerHitCallback(void (*hit_callback)(int64_t request_id)) {
|
||||
StoreBuffer::~StoreBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
StoreBuffer::registerHitCallback(void (*hit_callback)(int64_t request_id))
|
||||
{
|
||||
assert(m_hit_callback == NULL); // can't assign hit_callback twice
|
||||
m_hit_callback = hit_callback;
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************************************
|
||||
void StoreBuffer::addToStoreBuffer(struct RubyRequest request){
|
||||
if(m_use_storebuffer){
|
||||
#ifdef DEBUG_WRITE_BUFFER
|
||||
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
|
||||
|
||||
#endif
|
||||
|
||||
buffer.push_front(SBEntry(request, NULL));
|
||||
|
||||
|
@ -132,103 +122,94 @@ void StoreBuffer::addToStoreBuffer(struct RubyRequest request){
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
iseq++;
|
||||
|
||||
#ifdef DEBUG_WRITE_BUFFER
|
||||
#ifdef DEBUG_WRITE_BUFFER
|
||||
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));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************************************
|
||||
// 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");
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//***************************************************************************************************
|
||||
void StoreBuffer::returnMatchedData(struct RubyRequest request) {
|
||||
if (m_use_storebuffer) {
|
||||
void
|
||||
StoreBuffer::returnMatchedData(RubyRequest request)
|
||||
{
|
||||
if (!m_use_storebuffer) {
|
||||
ERROR_OUT("returnMatchedData called while write buffer is not in use");
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
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) {
|
||||
#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 {
|
||||
void
|
||||
StoreBuffer::flushStoreBuffer()
|
||||
{
|
||||
if (!m_use_storebuffer) {
|
||||
// do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_WRITE_BUFFER
|
||||
DEBUG_OUT("\n***StoreBuffer: flushStoreBuffer BEGIN, contents:\n");
|
||||
DEBUG_OUT("\n");
|
||||
#endif
|
||||
|
||||
m_storebuffer_flushing = (m_buffer_size > 0);
|
||||
}
|
||||
|
||||
//****************************************************************************************
|
||||
void 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!
|
||||
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 );
|
||||
// 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);
|
||||
}
|
||||
|
||||
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,111 +361,22 @@ 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
Loading…
Reference in a new issue