ruby: connect two controllers using only message buffers
This patch modifies ruby so that two controllers can be connected to each other with only message buffers in between. Before this patch, all the controllers had to be connected to the network for them to communicate with each other. With this patch, one can have protocols where a controller is not connected to the network, but communicates with another controller through a message buffer.
This commit is contained in:
parent
5aa43e130a
commit
eccc86e809
5 changed files with 80 additions and 17 deletions
|
@ -79,3 +79,10 @@ AbstractController::profileMsgDelay(uint32_t virtualNetwork, Cycles delay)
|
||||||
m_delayHistogram.add(delay);
|
m_delayHistogram.add(delay);
|
||||||
m_delayVCHistogram[virtualNetwork].add(delay);
|
m_delayVCHistogram[virtualNetwork].add(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AbstractController::connectWithPeer(AbstractController *c)
|
||||||
|
{
|
||||||
|
getQueuesFromPeer(c);
|
||||||
|
c->getQueuesFromPeer(this);
|
||||||
|
}
|
||||||
|
|
|
@ -97,12 +97,25 @@ class AbstractController : public ClockedObject, public Consumer
|
||||||
Histogram& getDelayVCHist(uint32_t index)
|
Histogram& getDelayVCHist(uint32_t index)
|
||||||
{ return m_delayVCHistogram[index]; }
|
{ return m_delayVCHistogram[index]; }
|
||||||
|
|
||||||
|
MessageBuffer *getPeerQueue(uint32_t pid)
|
||||||
|
{
|
||||||
|
std::map<uint32_t, MessageBuffer *>::iterator it =
|
||||||
|
peerQueueMap.find(pid);
|
||||||
|
assert(it != peerQueueMap.end());
|
||||||
|
return (*it).second;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Profiles original cache requests including PUTs
|
//! Profiles original cache requests including PUTs
|
||||||
void profileRequest(const std::string &request);
|
void profileRequest(const std::string &request);
|
||||||
//! Profiles the delay associated with messages.
|
//! Profiles the delay associated with messages.
|
||||||
void profileMsgDelay(uint32_t virtualNetwork, Cycles delay);
|
void profileMsgDelay(uint32_t virtualNetwork, Cycles delay);
|
||||||
|
|
||||||
|
//! Function for connecting peer controllers
|
||||||
|
void connectWithPeer(AbstractController *);
|
||||||
|
virtual void getQueuesFromPeer(AbstractController *)
|
||||||
|
{ fatal("getQueuesFromPeer() should be called only if implemented!"); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int m_transitions_per_cycle;
|
int m_transitions_per_cycle;
|
||||||
int m_buffer_size;
|
int m_buffer_size;
|
||||||
|
@ -120,6 +133,9 @@ class AbstractController : public ClockedObject, public Consumer
|
||||||
int m_cur_in_port_rank;
|
int m_cur_in_port_rank;
|
||||||
int m_number_of_TBEs;
|
int m_number_of_TBEs;
|
||||||
|
|
||||||
|
//! Map from physical network number to the Message Buffer.
|
||||||
|
std::map<uint32_t, MessageBuffer*> peerQueueMap;
|
||||||
|
|
||||||
//! Counter for the number of cycles when the transitions carried out
|
//! Counter for the number of cycles when the transitions carried out
|
||||||
//! were equal to the maximum allowed
|
//! were equal to the maximum allowed
|
||||||
uint64_t m_fully_busy_cycles;
|
uint64_t m_fully_busy_cycles;
|
||||||
|
|
|
@ -42,4 +42,6 @@ class RubyController(ClockedObject):
|
||||||
buffer_size = Param.Int(0, "max buffer size 0 means infinite")
|
buffer_size = Param.Int(0, "max buffer size 0 means infinite")
|
||||||
recycle_latency = Param.Cycles(10, "")
|
recycle_latency = Param.Cycles(10, "")
|
||||||
number_of_TBEs = Param.Int(256, "")
|
number_of_TBEs = Param.Int(256, "")
|
||||||
ruby_system = Param.RubySystem("");
|
ruby_system = Param.RubySystem("")
|
||||||
|
|
||||||
|
peer = Param.RubyController(NULL, "")
|
||||||
|
|
|
@ -41,7 +41,8 @@ class ObjDeclAST(DeclAST):
|
||||||
def generate(self):
|
def generate(self):
|
||||||
machineComponentSym = False
|
machineComponentSym = False
|
||||||
|
|
||||||
if "network" in self and "virtual_network" not in self:
|
if "network" in self and not ("virtual_network" in self or
|
||||||
|
"physical_network" in self) :
|
||||||
self.error("Network queues require a 'virtual_network' attribute")
|
self.error("Network queues require a 'virtual_network' attribute")
|
||||||
|
|
||||||
type = self.type_ast.type
|
type = self.type_ast.type
|
||||||
|
|
|
@ -239,9 +239,12 @@ class $py_ident(RubyController):
|
||||||
''')
|
''')
|
||||||
|
|
||||||
seen_types = set()
|
seen_types = set()
|
||||||
|
has_peer = False
|
||||||
for var in self.objects:
|
for var in self.objects:
|
||||||
if var.type.ident not in seen_types and not var.type.isPrimitive:
|
if var.type.ident not in seen_types and not var.type.isPrimitive:
|
||||||
code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
|
code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
|
||||||
|
if "network" in var and "physical_network" in var:
|
||||||
|
has_peer = True
|
||||||
seen_types.add(var.type.ident)
|
seen_types.add(var.type.ident)
|
||||||
|
|
||||||
# for adding information to the protocol debug trace
|
# for adding information to the protocol debug trace
|
||||||
|
@ -331,6 +334,8 @@ static int m_num_controllers;
|
||||||
if proto:
|
if proto:
|
||||||
code('$proto')
|
code('$proto')
|
||||||
|
|
||||||
|
if has_peer:
|
||||||
|
code('void getQueuesFromPeer(AbstractController *);')
|
||||||
if self.EntryType != None:
|
if self.EntryType != None:
|
||||||
code('''
|
code('''
|
||||||
|
|
||||||
|
@ -388,6 +393,7 @@ void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
|
||||||
code = self.symtab.codeFormatter()
|
code = self.symtab.codeFormatter()
|
||||||
ident = self.ident
|
ident = self.ident
|
||||||
c_ident = "%s_Controller" % self.ident
|
c_ident = "%s_Controller" % self.ident
|
||||||
|
has_peer = False
|
||||||
|
|
||||||
code('''
|
code('''
|
||||||
/** \\file $c_ident.cc
|
/** \\file $c_ident.cc
|
||||||
|
@ -514,8 +520,21 @@ m_dma_sequencer_ptr->setController(this);
|
||||||
code('''
|
code('''
|
||||||
m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
|
m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
|
||||||
m_${{var.c_ident}}_ptr->setReceiver(this);
|
m_${{var.c_ident}}_ptr->setReceiver(this);
|
||||||
|
''')
|
||||||
|
else:
|
||||||
|
if "network" in var and "physical_network" in var and \
|
||||||
|
var["network"] == "To":
|
||||||
|
has_peer = True
|
||||||
|
code('''
|
||||||
|
m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
|
||||||
|
peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
|
||||||
|
m_${{var.c_ident}}_ptr->setSender(this);
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
code('''
|
||||||
|
if (p->peer != NULL)
|
||||||
|
connectWithPeer(p->peer);
|
||||||
|
''')
|
||||||
code.dedent()
|
code.dedent()
|
||||||
code('''
|
code('''
|
||||||
}
|
}
|
||||||
|
@ -549,10 +568,7 @@ $c_ident::init()
|
||||||
code('(*$vid) = ${{var["default"]}};')
|
code('(*$vid) = ${{var["default"]}};')
|
||||||
else:
|
else:
|
||||||
# Normal Object
|
# Normal Object
|
||||||
# added by SS
|
if var.ident.find("mandatoryQueue") < 0:
|
||||||
if "factory" in var:
|
|
||||||
code('$vid = ${{var["factory"]}};')
|
|
||||||
elif var.ident.find("mandatoryQueue") < 0:
|
|
||||||
th = var.get("template", "")
|
th = var.get("template", "")
|
||||||
expr = "%s = new %s%s" % (vid, vtype.c_ident, th)
|
expr = "%s = new %s%s" % (vid, vtype.c_ident, th)
|
||||||
args = ""
|
args = ""
|
||||||
|
@ -593,16 +609,17 @@ $c_ident::init()
|
||||||
# Network port object
|
# Network port object
|
||||||
network = var["network"]
|
network = var["network"]
|
||||||
ordered = var["ordered"]
|
ordered = var["ordered"]
|
||||||
|
|
||||||
|
if "virtual_network" in var:
|
||||||
vnet = var["virtual_network"]
|
vnet = var["virtual_network"]
|
||||||
vnet_type = var["vnet_type"]
|
vnet_type = var["vnet_type"]
|
||||||
|
|
||||||
assert var.machine is not None
|
assert var.machine is not None
|
||||||
code('''
|
code('''
|
||||||
$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
|
$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
|
||||||
|
assert($vid != NULL);
|
||||||
''')
|
''')
|
||||||
|
|
||||||
code('assert($vid != NULL);')
|
|
||||||
|
|
||||||
# Set the end
|
# Set the end
|
||||||
if network == "To":
|
if network == "To":
|
||||||
code('$vid->setSender(this);')
|
code('$vid->setSender(this);')
|
||||||
|
@ -1007,6 +1024,26 @@ $c_ident::functionalWriteBuffers(PacketPtr& pkt)
|
||||||
}
|
}
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
# Check if this controller has a peer, if yes then write the
|
||||||
|
# function for connecting to the peer.
|
||||||
|
if has_peer:
|
||||||
|
code('''
|
||||||
|
|
||||||
|
void
|
||||||
|
$c_ident::getQueuesFromPeer(AbstractController *peer)
|
||||||
|
{
|
||||||
|
''')
|
||||||
|
for var in self.objects:
|
||||||
|
if "network" in var and "physical_network" in var and \
|
||||||
|
var["network"] == "From":
|
||||||
|
code('''
|
||||||
|
m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
|
||||||
|
assert(m_${{var.c_ident}}_ptr != NULL);
|
||||||
|
m_${{var.c_ident}}_ptr->setReceiver(this);
|
||||||
|
|
||||||
|
''')
|
||||||
|
code('}')
|
||||||
|
|
||||||
code.write(path, "%s.cc" % c_ident)
|
code.write(path, "%s.cc" % c_ident)
|
||||||
|
|
||||||
def printCWakeup(self, path, includes):
|
def printCWakeup(self, path, includes):
|
||||||
|
|
Loading…
Reference in a new issue