ruby: provide a backing store
authorNilay Vaish <nilay@cs.wisc.edu>
Thu, 6 Nov 2014 11:42:21 +0000 (05:42 -0600)
committerNilay Vaish <nilay@cs.wisc.edu>
Thu, 6 Nov 2014 11:42:21 +0000 (05:42 -0600)
Ruby's functional accesses are not guaranteed to succeed as of now.  While
this is not a problem for the protocols that are currently in the mainline
repo, it seems that coherence protocols for gpus rely on a backing store to
supply the correct data.  The aim of this patch is to make this backing store
configurable i.e. it comes into play only when a particular option:
--access-backing-store is invoked.

The backing store has been there since M5 and GEMS were integrated.  The only
difference is that earlier the system used to maintain the backing store and
ruby's copy was write-only.  Sometime last year, we moved to data being
supplied supplied by ruby in SE mode simulations.  And now we have patches on
the reviewboard, which remove ruby's copy of memory altogether and rely
completely on the system's memory to supply data.  This patch adds back a
SimpleMemory member to RubySystem.  This member is used only if the option:
access-backing-store is set to true.  By default, the memory would not be
accessed.

configs/ruby/Ruby.py
src/mem/ruby/system/RubyPort.cc
src/mem/ruby/system/RubyPort.hh
src/mem/ruby/system/RubySystem.py
src/mem/ruby/system/Sequencer.py
src/mem/ruby/system/System.cc
src/mem/ruby/system/System.hh

index 35ff66a0c5b4d3f7c09f0410d54d303f0065a2c4..b99e251d37916a6ce9a72e08065830a8f2c84a78 100644 (file)
@@ -56,6 +56,9 @@ def define_options(parser):
                       default='2GHz',
                       help="Clock for blocks running at Ruby system's speed")
 
+    parser.add_option("--access-backing-store", action="store_true", default=False,
+                      help="Should ruby maintain a second copy of memory")
+
     # Options related to cache structure
     parser.add_option("--ports", action="store", type="int", default=4,
                       help="used of transitions per cycle which is a proxy \
@@ -229,3 +232,8 @@ def create_system(options, full_system, system, piobus = None, dma_ports = []):
     ruby._cpu_ports = cpu_sequencers
     ruby.num_of_sequencers = len(cpu_sequencers)
     ruby.random_seed    = options.random_seed
+
+    # Create a backing copy of physical memory in case required
+    if options.access_backing_store:
+        ruby.phys_mem = SimpleMemory(range=AddrRange(options.mem_size),
+                                     in_addr_map=False)
index 1374c356638a083fe707923b503aa95100c9129f..3abdecf3da8af3b33d6bd3cb06b2fa332d174515 100644 (file)
@@ -46,6 +46,7 @@
 #include "mem/protocol/AccessPermission.hh"
 #include "mem/ruby/slicc_interface/AbstractController.hh"
 #include "mem/ruby/system/RubyPort.hh"
+#include "mem/simple_mem.hh"
 #include "sim/full_system.hh"
 #include "sim/system.hh"
 
@@ -57,16 +58,15 @@ RubyPort::RubyPort(const Params *p)
       pioSlavePort(csprintf("%s.pio-slave-port", name()), this),
       memMasterPort(csprintf("%s.mem-master-port", name()), this),
       memSlavePort(csprintf("%s-mem-slave-port", name()), this,
-          p->ruby_system, p->access_phys_mem, -1),
-      gotAddrRanges(p->port_master_connection_count), drainManager(NULL),
-      access_phys_mem(p->access_phys_mem)
+          p->ruby_system, p->access_backing_store, -1),
+      gotAddrRanges(p->port_master_connection_count), drainManager(NULL)
 {
     assert(m_version != -1);
 
     // create the slave ports based on the number of connected ports
     for (size_t i = 0; i < p->port_slave_connection_count; ++i) {
         slave_ports.push_back(new MemSlavePort(csprintf("%s.slave%d", name(),
-            i), this, p->ruby_system, access_phys_mem, i));
+            i), this, p->ruby_system, p->access_backing_store, i));
     }
 
     // create the master ports based on the number of connected ports
@@ -155,9 +155,10 @@ RubyPort::MemMasterPort::MemMasterPort(const std::string &_name,
 }
 
 RubyPort::MemSlavePort::MemSlavePort(const std::string &_name, RubyPort *_port,
-                         RubySystem *_system, bool _access_phys_mem, PortID id)
+                                     RubySystem *_system,
+                                     bool _access_backing_store, PortID id)
     : QueuedSlavePort(_name, _port, queue, id), queue(*_port, *this),
-      ruby_system(_system), access_phys_mem(_access_phys_mem)
+      ruby_system(_system), access_backing_store(_access_backing_store)
 {
     DPRINTF(RubyPort, "Created slave memport on ruby sequencer %s\n", _name);
 }
@@ -281,11 +282,11 @@ void
 RubyPort::MemSlavePort::recvFunctional(PacketPtr pkt)
 {
     DPRINTF(RubyPort, "Functional access for address: %#x\n", pkt->getAddr());
-    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
 
     // Check for pio requests and directly send them to the dedicated
     // pio port.
     if (!isPhysMemAddress(pkt->getAddr())) {
+        RubyPort *ruby_port M5_VAR_USED = static_cast<RubyPort *>(&owner);
         assert(ruby_port->memMasterPort.isConnected());
         DPRINTF(RubyPort, "Pio Request for address: 0x%#x\n", pkt->getAddr());
         panic("RubyPort::PioMasterPort::recvFunctional() not implemented!\n");
@@ -314,23 +315,19 @@ RubyPort::MemSlavePort::recvFunctional(PacketPtr pkt)
               pkt->isWrite() ? "write" : "read", pkt->getAddr());
     }
 
-    if (access_phys_mem) {
+    if (access_backing_store) {
         // The attached physmem contains the official version of data.
         // The following command performs the real functional access.
         // This line should be removed once Ruby supplies the official version
         // of data.
-        ruby_port->system->getPhysMem().functionalAccess(pkt);
+        ruby_system->getPhysMem()->functionalAccess(pkt);
     }
 
     // turn packet around to go back to requester if response expected
     if (needsResponse) {
         pkt->setFunctionalResponseStatus(accessSucceeded);
-
-        // @todo There should not be a reverse call since the response is
-        // communicated through the packet pointer
-        // DPRINTF(RubyPort, "Sending packet back over port\n");
-        // sendFunctional(pkt);
     }
+
     DPRINTF(RubyPort, "Functional access %s!\n",
             accessSucceeded ? "successful":"failed");
 }
@@ -459,11 +456,9 @@ RubyPort::MemSlavePort::hitCallback(PacketPtr pkt)
 {
     bool needsResponse = pkt->needsResponse();
 
-    //
     // Unless specified at configuraiton, all responses except failed SC 
     // and Flush operations access M5 physical memory.
-    //
-    bool accessPhysMem = access_phys_mem;
+    bool accessPhysMem = access_backing_store;
 
     if (pkt->isLLSC()) {
         if (pkt->isWrite()) {
@@ -488,9 +483,7 @@ RubyPort::MemSlavePort::hitCallback(PacketPtr pkt)
         }
     }
 
-    //
     // Flush requests don't access physical memory
-    //
     if (pkt->isFlush()) {
         accessPhysMem = false;
     }
@@ -498,8 +491,7 @@ RubyPort::MemSlavePort::hitCallback(PacketPtr pkt)
     DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse);
 
     if (accessPhysMem) {
-        RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
-        ruby_port->system->getPhysMem().access(pkt);
+        ruby_system->getPhysMem()->functionalAccess(pkt);
     } else if (needsResponse) {
         pkt->makeResponse();
     }
@@ -512,6 +504,7 @@ RubyPort::MemSlavePort::hitCallback(PacketPtr pkt)
     } else {
         delete pkt;
     }
+
     DPRINTF(RubyPort, "Hit callback done!\n");
 }
 
index 64858024606f60e1614347e8dadf303cd09dffe3..28a416663e0d4b15178f109a4969a2ecb9c062f9 100644 (file)
@@ -73,14 +73,13 @@ class RubyPort : public MemObject
     class MemSlavePort : public QueuedSlavePort
     {
       private:
-
         SlavePacketQueue queue;
         RubySystem* ruby_system;
-        bool access_phys_mem;
+        bool access_backing_store;
 
       public:
         MemSlavePort(const std::string &_name, RubyPort *_port,
-               RubySystem*_system, bool _access_phys_mem, PortID id);
+               RubySystem*_system, bool _access_backing_store, PortID id);
         void hitCallback(PacketPtr pkt);
         void evictionCallback(const Address& address);
 
@@ -212,8 +211,6 @@ class RubyPort : public MemObject
     // that should be called when the Sequencer becomes available after a stall.
     //
     std::vector<MemSlavePort *> retryList;
-
-    bool access_phys_mem;
 };
 
 #endif // __MEM_RUBY_SYSTEM_RUBYPORT_HH__
index 77bd9448d0182affd52177aad4aa5b64d981454a..0deb794055584216b301aa6487a56e9cb46268a3 100644 (file)
@@ -29,6 +29,7 @@
 
 from m5.params import *
 from ClockedObject import ClockedObject
+from SimpleMemory import *
 
 class RubySystem(ClockedObject):
     type = 'RubySystem'
@@ -45,3 +46,4 @@ class RubySystem(ClockedObject):
     hot_lines = Param.Bool(False, "")
     all_instructions = Param.Bool(False, "")
     num_of_sequencers = Param.Int("")
+    phys_mem = Param.SimpleMemory(NULL, "")
index b54924ba7c11bd5b55ccff6608826d9710130d53..d91c2200ff16dc7e97fb63978eea18e730d32abe 100644 (file)
@@ -45,7 +45,7 @@ class RubyPort(MemObject):
     mem_slave_port = SlavePort("Ruby memory port")
 
     using_ruby_tester = Param.Bool(False, "")
-    access_phys_mem = Param.Bool(False,
+    access_backing_store = Param.Bool(False,
         "should the rubyport atomically update phys_mem")
     ruby_system = Param.RubySystem("")
     system = Param.System(Parent.any, "system object")
@@ -55,7 +55,6 @@ class RubyPort(MemObject):
 class RubyPortProxy(RubyPort):
     type = 'RubyPortProxy'
     cxx_header = "mem/ruby/system/RubyPortProxy.hh"
-    access_phys_mem = False
     
 class RubySequencer(RubyPort):
     type = 'RubySequencer'
index 066cfae8710c9ddfa51b04fa02711732ca98fcb0..6aad5bd0546ad8466021a917736c399eb6a0085b 100644 (file)
@@ -77,6 +77,7 @@ RubySystem::RubySystem(const Params *p)
     Stats::registerDumpCallback(new RubyStatsCallback(this));
     // Create the profiler
     m_profiler = new Profiler(p);
+    m_phys_mem = p->phys_mem;
 }
 
 void
index 81c6029c6242146a5ab9a2a8d9b0456b7df7c3d5..06f1c514f035fcfaf6660c0cfd2ae4bc1b8e9897 100644 (file)
@@ -75,6 +75,8 @@ class RubySystem : public ClockedObject
     static uint32_t getBlockSizeBits() { return m_block_size_bits; }
     static uint32_t getMemorySizeBits() { return m_memory_size_bits; }
 
+    SimpleMemory *getPhysMem() { return m_phys_mem; }
+
     // Public Methods
     Profiler*
     getProfiler()
@@ -122,6 +124,7 @@ class RubySystem : public ClockedObject
     static uint32_t m_block_size_bytes;
     static uint32_t m_block_size_bits;
     static uint32_t m_memory_size_bits;
+    SimpleMemory *m_phys_mem;
 
     Network* m_network;
     std::vector<AbstractController *> m_abs_cntrl_vec;