Tiago Mück has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/31416 )
Change subject: mem-ruby: alternative interface for func. reads
......................................................................
mem-ruby: alternative interface for func. reads
A single functionalRead may not be able to get the whole latest
copy of the block in protocols that have features such as:
- a cache line can be partially present and dirty in a controller
- a cache line can be transferred over the network using multiple
protocol-level messages
To support these cases, this patch adds an alternative function:
bool functionalRead(PacketPtr, WriteMask&)
Protocols that implement this function can partially update
the packet and use the WriteMask to mark updated bytes.
The top-level RubySystem:functionalRead then issues functionalRead
to controllers until the whole block is read.
This patch implements functionalRead(PacketPtr, WriteMask&) for all the
common messages and SimpleNetwork. A protocol-specific implementation
will be provided in a future patch.
The new interface is compiled only if required by the protocol (see
src/mem/ruby/system/SConscript). Otherwise the original interface is
used thus maintaining compatibility with previous protocols.
Change-Id: I4600d5f1d7cc170bd7b09ccd09bfd3bb6605f86b
Signed-off-by: Tiago Mück <[email protected]>
---
M src/mem/ruby/network/MessageBuffer.cc
M src/mem/ruby/network/MessageBuffer.hh
M src/mem/ruby/network/Network.hh
M src/mem/ruby/network/simple/SimpleNetwork.cc
M src/mem/ruby/network/simple/SimpleNetwork.hh
M src/mem/ruby/network/simple/Switch.cc
M src/mem/ruby/network/simple/Switch.hh
M src/mem/ruby/protocol/RubySlicc_Exports.sm
M src/mem/ruby/protocol/RubySlicc_MemControl.sm
M src/mem/ruby/slicc_interface/AbstractController.hh
M src/mem/ruby/slicc_interface/Message.hh
M src/mem/ruby/slicc_interface/RubyRequest.cc
M src/mem/ruby/slicc_interface/RubyRequest.hh
M src/mem/ruby/system/RubySystem.cc
M src/mem/ruby/system/SConscript
M src/mem/slicc/symbols/StateMachine.py
16 files changed, 230 insertions(+), 16 deletions(-)
diff --git a/src/mem/ruby/network/MessageBuffer.cc
b/src/mem/ruby/network/MessageBuffer.cc
index f2c952e..8fe59ea 100644
--- a/src/mem/ruby/network/MessageBuffer.cc
+++ b/src/mem/ruby/network/MessageBuffer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 ARM Limited
+ * Copyright (c) 2019,2020 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -488,7 +488,7 @@
}
uint32_t
-MessageBuffer::functionalAccess(Packet *pkt, bool is_read)
+MessageBuffer::functionalAccess(Packet *pkt, bool is_read, WriteMask *mask)
{
DPRINTF(RubyQueue, "functional %s for %#x\n",
is_read ? "read" : "write", pkt->getAddr());
@@ -499,8 +499,10 @@
// correspond to the address in the packet.
for (unsigned int i = 0; i < m_prio_heap.size(); ++i) {
Message *msg = m_prio_heap[i].get();
- if (is_read && msg->functionalRead(pkt))
+ if (is_read && !mask && msg->functionalRead(pkt))
return 1;
+ else if (is_read && mask && msg->functionalRead(pkt, *mask))
+ num_functional_accesses++;
else if (!is_read && msg->functionalWrite(pkt))
num_functional_accesses++;
}
@@ -515,8 +517,10 @@
it != (map_iter->second).end(); ++it) {
Message *msg = (*it).get();
- if (is_read && msg->functionalRead(pkt))
+ if (is_read && !mask && msg->functionalRead(pkt))
return 1;
+ else if (is_read && mask && msg->functionalRead(pkt, *mask))
+ num_functional_accesses++;
else if (!is_read && msg->functionalWrite(pkt))
num_functional_accesses++;
}
diff --git a/src/mem/ruby/network/MessageBuffer.hh
b/src/mem/ruby/network/MessageBuffer.hh
index 8abf3bd..f10c834 100644
--- a/src/mem/ruby/network/MessageBuffer.hh
+++ b/src/mem/ruby/network/MessageBuffer.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 ARM Limited
+ * Copyright (c) 2019,2020 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -162,7 +162,7 @@
// Return value indicates the number of messages that were updated.
uint32_t functionalWrite(Packet *pkt)
{
- return functionalAccess(pkt, false);
+ return functionalAccess(pkt, false, nullptr);
}
// Function for figuring if message in the buffer has valid data for
@@ -171,13 +171,19 @@
// read was performed.
bool functionalRead(Packet *pkt)
{
- return functionalAccess(pkt, true) == 1;
+ return functionalAccess(pkt, true, nullptr) == 1;
+ }
+
+ // Functional read with mask
+ bool functionalRead(Packet *pkt, WriteMask &mask)
+ {
+ return functionalAccess(pkt, true, &mask) == 1;
}
private:
void reanalyzeList(std::list<MsgPtr> &, Tick);
- uint32_t functionalAccess(Packet *pkt, bool is_read);
+ uint32_t functionalAccess(Packet *pkt, bool is_read, WriteMask *mask);
private:
// Data Members (m_ prefix)
diff --git a/src/mem/ruby/network/Network.hh
b/src/mem/ruby/network/Network.hh
index bba0c5e..6efa298 100644
--- a/src/mem/ruby/network/Network.hh
+++ b/src/mem/ruby/network/Network.hh
@@ -117,6 +117,8 @@
*/
virtual bool functionalRead(Packet *pkt)
{ fatal("Functional read not implemented.\n"); }
+ virtual bool functionalRead(Packet *pkt, WriteMask& mask)
+ { fatal("Masked functional read not implemented.\n"); }
virtual uint32_t functionalWrite(Packet *pkt)
{ fatal("Functional write not implemented.\n"); }
diff --git a/src/mem/ruby/network/simple/SimpleNetwork.cc
b/src/mem/ruby/network/simple/SimpleNetwork.cc
index d3b5515..8d39418 100644
--- a/src/mem/ruby/network/simple/SimpleNetwork.cc
+++ b/src/mem/ruby/network/simple/SimpleNetwork.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 ARM Limited
+ * Copyright (c) 2019,2020 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -204,6 +204,21 @@
return false;
}
+bool
+SimpleNetwork::functionalRead(Packet *pkt, WriteMask &mask)
+{
+ bool read = false;
+ for (unsigned int i = 0; i < m_switches.size(); i++) {
+ if (m_switches[i]->functionalRead(pkt, mask))
+ read = true;
+ }
+ for (unsigned int i = 0; i < m_int_link_buffers.size(); ++i) {
+ if (m_int_link_buffers[i]->functionalRead(pkt, mask))
+ read = true;
+ }
+ return read;
+}
+
uint32_t
SimpleNetwork::functionalWrite(Packet *pkt)
{
diff --git a/src/mem/ruby/network/simple/SimpleNetwork.hh
b/src/mem/ruby/network/simple/SimpleNetwork.hh
index b2e5080..17e1f7a 100644
--- a/src/mem/ruby/network/simple/SimpleNetwork.hh
+++ b/src/mem/ruby/network/simple/SimpleNetwork.hh
@@ -71,6 +71,7 @@
void print(std::ostream& out) const;
bool functionalRead(Packet *pkt);
+ bool functionalRead(Packet *pkt, WriteMask &mask);
uint32_t functionalWrite(Packet *pkt);
private:
diff --git a/src/mem/ruby/network/simple/Switch.cc
b/src/mem/ruby/network/simple/Switch.cc
index d1e5026..462a0ab 100644
--- a/src/mem/ruby/network/simple/Switch.cc
+++ b/src/mem/ruby/network/simple/Switch.cc
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2020 Inria
- * Copyright (c) 2019 ARM Limited
+ * Copyright (c) 2019,2020 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -173,6 +173,17 @@
return false;
}
+bool
+Switch::functionalRead(Packet *pkt, WriteMask &mask)
+{
+ bool read = false;
+ for (unsigned int i = 0; i < m_port_buffers.size(); ++i) {
+ if (m_port_buffers[i]->functionalRead(pkt, mask))
+ read = true;
+ }
+ return read;
+}
+
uint32_t
Switch::functionalWrite(Packet *pkt)
{
diff --git a/src/mem/ruby/network/simple/Switch.hh
b/src/mem/ruby/network/simple/Switch.hh
index 5d26906..fdcb15c 100644
--- a/src/mem/ruby/network/simple/Switch.hh
+++ b/src/mem/ruby/network/simple/Switch.hh
@@ -79,6 +79,7 @@
void init_net_ptr(SimpleNetwork* net_ptr) { m_network_ptr = net_ptr; }
bool functionalRead(Packet *);
+ bool functionalRead(Packet *, WriteMask&);
uint32_t functionalWrite(Packet *);
private:
diff --git a/src/mem/ruby/protocol/RubySlicc_Exports.sm
b/src/mem/ruby/protocol/RubySlicc_Exports.sm
index 077e76d..d94fce8 100644
--- a/src/mem/ruby/protocol/RubySlicc_Exports.sm
+++ b/src/mem/ruby/protocol/RubySlicc_Exports.sm
@@ -106,6 +106,7 @@
// This is not supposed to be used in directory or token protocols where
// memory/NB has an idea of what is going on in the whole system.
Backing_Store, desc="for memory in Broadcast/Snoop protocols";
+ Backing_Store_Busy, desc="Backing_Store + cntrl is busy waiting for
data";
// Invalid data
Invalid, desc="block is in an Invalid base state";
diff --git a/src/mem/ruby/protocol/RubySlicc_MemControl.sm
b/src/mem/ruby/protocol/RubySlicc_MemControl.sm
index 801a7bb..3156e1d 100644
--- a/src/mem/ruby/protocol/RubySlicc_MemControl.sm
+++ b/src/mem/ruby/protocol/RubySlicc_MemControl.sm
@@ -1,5 +1,17 @@
/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
* All rights reserved.
*
@@ -64,7 +76,29 @@
int Acks, desc="How many acks to expect";
bool functionalRead(Packet *pkt) {
- return testAndRead(addr, DataBlk, pkt);
+ if ((MessageSize == MessageSizeType:Response_Data) ||
+ (MessageSize == MessageSizeType:Writeback_Data)) {
+ return testAndRead(addr, DataBlk, pkt);
+ }
+ return false;
+ }
+
+ bool functionalRead(Packet *pkt, WriteMask &mask) {
+ if ((MessageSize == MessageSizeType:Response_Data) ||
+ (MessageSize == MessageSizeType:Writeback_Data)) {
+ WriteMask read_mask;
+ read_mask.setMask(addressOffset(addr, makeLineAddress(addr)), Len,
true);
+ if (MessageSize != MessageSizeType:Writeback_Data) {
+ read_mask.invMask(mask);
+ }
+ if (read_mask.isEmpty()) {
+ return false;
+ } else if (testAndReadMask(addr, DataBlk, read_mask, pkt)) {
+ mask.orMask(read_mask);
+ return true;
+ }
+ }
+ return false;
}
bool functionalWrite(Packet *pkt) {
diff --git a/src/mem/ruby/slicc_interface/AbstractController.hh
b/src/mem/ruby/slicc_interface/AbstractController.hh
index 81c17d1..1dffba1 100644
--- a/src/mem/ruby/slicc_interface/AbstractController.hh
+++ b/src/mem/ruby/slicc_interface/AbstractController.hh
@@ -116,7 +116,16 @@
//! These functions are used by ruby system to read/write the data
blocks
//! that exist with in the controller.
virtual bool functionalReadBuffers(PacketPtr&) = 0;
- virtual void functionalRead(const Addr &addr, PacketPtr) = 0;
+ virtual void functionalRead(const Addr &addr, PacketPtr)
+ { panic("functionalRead(Addr,PacketPtr) not implemented"); }
+
+ //! Functional read that reads only blocks not present in the mask.
+ //! Return number of bytes read.
+ virtual bool functionalReadBuffers(PacketPtr&, WriteMask &mask) = 0;
+ virtual void functionalRead(const Addr &addr, PacketPtr pkt,
+ WriteMask &mask)
+ { panic("functionalRead(Addr,PacketPtr,WriteMask) not implemented"); }
+
void functionalMemoryRead(PacketPtr);
//! The return value indicates the number of messages written with the
//! data from the packet.
diff --git a/src/mem/ruby/slicc_interface/Message.hh
b/src/mem/ruby/slicc_interface/Message.hh
index 1044fe0..9011dee 100644
--- a/src/mem/ruby/slicc_interface/Message.hh
+++ b/src/mem/ruby/slicc_interface/Message.hh
@@ -35,6 +35,7 @@
#include "mem/packet.hh"
#include "mem/ruby/common/NetDest.hh"
+#include "mem/ruby/common/WriteMask.hh"
#include "mem/ruby/protocol/MessageSizeType.hh"
class Message;
@@ -73,8 +74,12 @@
* class that can be potentially searched for the address needs to
* implement these methods.
*/
- virtual bool functionalRead(Packet *pkt) = 0;
- virtual bool functionalWrite(Packet *pkt) = 0;
+ virtual bool functionalRead(Packet *pkt)
+ { panic("functionalRead(Packet) not implemented"); }
+ virtual bool functionalRead(Packet *pkt, WriteMask &mask)
+ { panic("functionalRead(Packet,WriteMask) not implemented"); }
+ virtual bool functionalWrite(Packet *pkt)
+ { panic("functionalWrite(Packet) not implemented"); }
//! Update the delay this message has experienced so far.
void updateDelayedTicks(Tick curTime)
diff --git a/src/mem/ruby/slicc_interface/RubyRequest.cc
b/src/mem/ruby/slicc_interface/RubyRequest.cc
index f30bde5..c1e8d37 100644
--- a/src/mem/ruby/slicc_interface/RubyRequest.cc
+++ b/src/mem/ruby/slicc_interface/RubyRequest.cc
@@ -72,6 +72,12 @@
}
bool
+RubyRequest::functionalRead(Packet *pkt, WriteMask &mask)
+{
+ return false;
+}
+
+bool
RubyRequest::functionalWrite(Packet *pkt)
{
// This needs a little explanation. I am not sure if this message
diff --git a/src/mem/ruby/slicc_interface/RubyRequest.hh
b/src/mem/ruby/slicc_interface/RubyRequest.hh
index b3e2396..8c086d9 100644
--- a/src/mem/ruby/slicc_interface/RubyRequest.hh
+++ b/src/mem/ruby/slicc_interface/RubyRequest.hh
@@ -141,6 +141,7 @@
void print(std::ostream& out) const;
bool functionalRead(Packet *pkt);
+ bool functionalRead(Packet *pkt, WriteMask &mask);
bool functionalWrite(Packet *pkt);
};
diff --git a/src/mem/ruby/system/RubySystem.cc
b/src/mem/ruby/system/RubySystem.cc
index 5babf2d..866b7d1 100644
--- a/src/mem/ruby/system/RubySystem.cc
+++ b/src/mem/ruby/system/RubySystem.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 ARM Limited
+ * Copyright (c) 2019,2020 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -473,6 +473,7 @@
}
}
+#ifndef PARTIAL_FUNC_READS
bool
RubySystem::functionalRead(PacketPtr pkt)
{
@@ -588,6 +589,95 @@
return false;
}
+#else
+bool
+RubySystem::functionalRead(PacketPtr pkt)
+{
+ Addr address(pkt->getAddr());
+ Addr line_address = makeLineAddress(address);
+
+ DPRINTF(RubySystem, "Functional Read request for %#x\n", address);
+
+ std::vector<AbstractController*> ctrl_ro;
+ std::vector<AbstractController*> ctrl_busy;
+ std::vector<AbstractController*> ctrl_others;
+ AbstractController *ctrl_rw = nullptr;
+ AbstractController *ctrl_bs = nullptr;
+
+ // Build lists of controllers that have line
+ for (auto ctrl : m_abs_cntrl_vec) {
+ switch(ctrl->getAccessPermission(line_address)) {
+ case AccessPermission_Read_Only:
+ ctrl_ro.push_back(ctrl);
+ break;
+ case AccessPermission_Busy:
+ ctrl_busy.push_back(ctrl);
+ break;
+ case AccessPermission_Read_Write:
+ assert(ctrl_rw == nullptr);
+ ctrl_rw = ctrl;
+ break;
+ case AccessPermission_Backing_Store:
+ assert(ctrl_bs == nullptr);
+ ctrl_bs = ctrl;
+ break;
+ case AccessPermission_Backing_Store_Busy:
+ assert(ctrl_bs == nullptr);
+ ctrl_bs = ctrl;
+ ctrl_busy.push_back(ctrl);
+ break;
+ default:
+ ctrl_others.push_back(ctrl);
+ break;
+ }
+ }
+
+ DPRINTF(RubySystem, "num_ro=%d, num_busy=%d , has_rw=%d, "
+ "backing_store=%d\n",
+ ctrl_ro.size(), ctrl_busy.size(),
+ ctrl_rw != nullptr, ctrl_bs != nullptr);
+
+ // Issue functional reads to all controllers found in a stable state
+ // until we get a full copy of the line
+ WriteMask bytes;
+ if (ctrl_rw != nullptr) {
+ ctrl_rw->functionalRead(line_address, pkt, bytes);
+ // if a RW controllter has the full line that's all uptodate
+ if (bytes.isFull())
+ return true;
+ }
+
+ // Get data from RO and BS
+ for (auto ctrl : ctrl_ro)
+ ctrl->functionalRead(line_address, pkt, bytes);
+
+ ctrl_bs->functionalRead(line_address, pkt, bytes);
+
+ // if there is any busy controller or bytes still not set, then a
partial
+ // and/or dirty copy of the line might be in a message buffer or the
+ // network
+ if (!ctrl_busy.empty() || !bytes.isFull()) {
+ DPRINTF(RubySystem, "Reading from busy controllers and network\n");
+ for (auto ctrl : ctrl_busy) {
+ ctrl->functionalRead(line_address, pkt, bytes);
+ ctrl->functionalReadBuffers(pkt, bytes);
+ }
+ for (auto& network : m_networks) {
+ network->functionalRead(pkt, bytes);
+ }
+ for (auto ctrl : ctrl_others) {
+ ctrl->functionalRead(line_address, pkt, bytes);
+ ctrl->functionalReadBuffers(pkt, bytes);
+ }
+ }
+ // we either got the full line or couldn't find anything at this point
+ panic_if(!(bytes.isFull() || bytes.isEmpty()),
+ "Inconsistent state on functional read for %#x %s\n",
+ address, bytes);
+
+ return bytes.isFull();
+}
+#endif
// The function searches through all the buffers that exist in different
// cache, directory and memory controllers, and in the network components
diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript
index 7496971..6f3854a 100644
--- a/src/mem/ruby/system/SConscript
+++ b/src/mem/ruby/system/SConscript
@@ -45,6 +45,12 @@
env.Append(CPPDEFINES=['PROTOCOL_' + env['PROTOCOL']])
+# list of protocols that require the partial functional read interface
+need_partial_func_reads = []
+
+if env['PROTOCOL'] in need_partial_func_reads:
+ env.Append(CPPDEFINES=['PARTIAL_FUNC_READS'])
+
if env['BUILD_GPU']:
SimObject('GPUCoalescer.py')
SimObject('RubySystem.py')
diff --git a/src/mem/slicc/symbols/StateMachine.py
b/src/mem/slicc/symbols/StateMachine.py
index 987f3b5..1f28069 100644
--- a/src/mem/slicc/symbols/StateMachine.py
+++ b/src/mem/slicc/symbols/StateMachine.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2019 ARM Limited
+# Copyright (c) 2019,2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
@@ -327,6 +327,7 @@
GPUCoalescer* getGPUCoalescer() const;
bool functionalReadBuffers(PacketPtr&);
+ bool functionalReadBuffers(PacketPtr&, WriteMask&);
int functionalWriteBuffers(PacketPtr&);
void countTransition(${ident}_State state, ${ident}_Event event);
@@ -1130,6 +1131,27 @@
code('''
return false;
}
+
+bool
+$c_ident::functionalReadBuffers(PacketPtr& pkt, WriteMask &mask)
+{
+ bool read = false;
+''')
+ for var in self.objects:
+ vtype = var.type
+ if vtype.isBuffer:
+ vid = "m_%s_ptr" % var.ident
+ code('if ($vid->functionalRead(pkt, mask)) read = true;')
+
+ for var in self.config_parameters:
+ vtype = var.type_ast.type
+ if vtype.isBuffer:
+ vid = "m_%s_ptr" % var.ident
+ code('if ($vid->functionalRead(pkt, mask)) read = true;')
+
+ code('''
+ return read;
+}
''')
code.write(path, "%s.cc" % c_ident)
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/31416
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I4600d5f1d7cc170bd7b09ccd09bfd3bb6605f86b
Gerrit-Change-Number: 31416
Gerrit-PatchSet: 1
Gerrit-Owner: Tiago Mück <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s