Ruby: Add infrastructure for recording cache contents
authorNilay Vaish <nilay@cs.wisc.edu>
Wed, 11 Jan 2012 19:29:15 +0000 (13:29 -0600)
committerNilay Vaish <nilay@cs.wisc.edu>
Wed, 11 Jan 2012 19:29:15 +0000 (13:29 -0600)
This patch changes CacheRecorder, CacheMemory, CacheControllers
so that the contents of a cache can be recorded for checkpointing
purposes.

src/mem/SConscript
src/mem/ruby/recorder/CacheRecorder.cc
src/mem/ruby/recorder/CacheRecorder.hh
src/mem/ruby/recorder/SConscript
src/mem/ruby/recorder/TraceRecord.cc [deleted file]
src/mem/ruby/recorder/TraceRecord.hh [deleted file]
src/mem/ruby/slicc_interface/AbstractController.hh
src/mem/ruby/system/CacheMemory.cc
src/mem/ruby/system/CacheMemory.hh
src/mem/slicc/symbols/StateMachine.py

index f4e4cc038b65861a446700e747b07b7584ce01b1..a0ba4d66ac6a2453e6d7b659fbdf49b7609136a6 100644 (file)
@@ -62,6 +62,7 @@ DebugFlag('MemoryAccess')
 
 DebugFlag('ProtocolTrace')
 DebugFlag('RubyCache')
+DebugFlag('RubyCacheTrace')
 DebugFlag('RubyDma')
 DebugFlag('RubyGenerated')
 DebugFlag('RubyMemory')
@@ -75,4 +76,4 @@ DebugFlag('RubyTester')
 
 CompoundFlag('Ruby', [ 'RubyQueue', 'RubyNetwork', 'RubyTester',
     'RubyGenerated', 'RubySlicc', 'RubyStorebuffer', 'RubyCache',
-    'RubyMemory', 'RubyDma', 'RubyPort', 'RubySequencer'])
+    'RubyMemory', 'RubyDma', 'RubyPort', 'RubySequencer', 'RubyCacheTrace'])
index fc6ad097528dbf0a524fc59436581cf55a7afc04..8b724859e3cbec5c2b0139ca2e718ef19d6f7f01 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood
+ * Copyright (c) 2010 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <algorithm>
-
-#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "debug/RubyCacheTrace.hh"
 #include "mem/ruby/recorder/CacheRecorder.hh"
-#include "gzstream.hh"
+#include "mem/ruby/system/Sequencer.hh"
+#include "mem/ruby/system/System.hh"
 
 using namespace std;
 
 void
-CacheRecorder::addRecord(Sequencer* sequencer, const Address& data_addr,
-    const Address& pc_addr, RubyRequestType type, Time time)
+TraceRecord::print(ostream& out) const
+{
+    out << "[TraceRecord: Node, " << m_cntrl_id << ", "
+        << m_data_address << ", " << m_pc_address << ", "
+        << m_type << ", Time: " << m_time << "]";
+}
+
+CacheRecorder::CacheRecorder()
+    : m_uncompressed_trace(NULL),
+      m_uncompressed_trace_size(0)
 {
-    TraceRecord rec(sequencer, data_addr, pc_addr, type, time);
-    m_records.push_back(rec);
 }
 
-int
-CacheRecorder::dumpRecords(string filename)
+CacheRecorder::CacheRecorder(uint8_t* uncompressed_trace,
+                             uint64_t uncompressed_trace_size,
+                             std::vector<Sequencer*>& seq_map)
+    : m_uncompressed_trace(uncompressed_trace),
+      m_uncompressed_trace_size(uncompressed_trace_size),
+      m_seq_map(seq_map),  m_bytes_read(0), m_records_read(0),
+      m_records_flushed(0)
 {
-    ogzstream out(filename.c_str());
-    if (out.fail()) {
-        cout << "Error: error opening file '" << filename << "'" << endl;
-        return 0;
+}
+
+CacheRecorder::~CacheRecorder()
+{
+    if (m_uncompressed_trace != NULL) {
+        delete m_uncompressed_trace;
+        m_uncompressed_trace = NULL;
     }
+    m_seq_map.clear();
+}
 
-    std::sort(m_records.begin(), m_records.end(), greater<TraceRecord>());
+void
+CacheRecorder::enqueueNextFlushRequest()
+{
+    if (m_records_flushed < m_records.size()) {
+        TraceRecord* rec = m_records[m_records_flushed];
+        m_records_flushed++;
+        Request* req = new Request(rec->m_data_address,
+                                   RubySystem::getBlockSizeBytes(),0);
+        MemCmd::Command requestType = MemCmd::FlushReq;
+        Packet *pkt = new Packet(req, requestType, -1);
 
-    int size = m_records.size();
-    for (int i = 0; i < size; ++i)
-        m_records[i].output(out);
+        Sequencer* m_sequencer_ptr = m_seq_map[rec->m_cntrl_id];
+        assert(m_sequencer_ptr != NULL);
+        m_sequencer_ptr->makeRequest(pkt);
 
-    m_records.clear();
+        DPRINTF(RubyCacheTrace, "Flushing %s\n", *rec);
+    }
+}
+
+void
+CacheRecorder::enqueueNextFetchRequest()
+{
+    if (m_bytes_read < m_uncompressed_trace_size) {
+        TraceRecord* traceRecord = (TraceRecord*) (m_uncompressed_trace +
+                                                                m_bytes_read);
 
-    return size;
+        DPRINTF(RubyCacheTrace, "Issuing %s\n", *traceRecord);
+        Request* req = new Request();
+        MemCmd::Command requestType;
+
+        if (traceRecord->m_type == RubyRequestType_LD) {
+            requestType = MemCmd::ReadReq;
+            req->setPhys(traceRecord->m_data_address,
+                    RubySystem::getBlockSizeBytes(),0);
+        }   else if (traceRecord->m_type == RubyRequestType_IFETCH) {
+            requestType = MemCmd::ReadReq;
+            req->setPhys(traceRecord->m_data_address,
+                    RubySystem::getBlockSizeBytes(),
+                    Request::INST_FETCH);
+        }   else {
+            requestType = MemCmd::WriteReq;
+            req->setPhys(traceRecord->m_data_address,
+                    RubySystem::getBlockSizeBytes(),0);
+        }
+
+        Packet *pkt = new Packet(req, requestType, -1);
+        pkt->dataStatic(traceRecord->m_data);
+
+        Sequencer* m_sequencer_ptr = m_seq_map[traceRecord->m_cntrl_id];
+        assert(m_sequencer_ptr != NULL);
+        m_sequencer_ptr->makeRequest(pkt);
+
+        m_bytes_read += (sizeof(TraceRecord) +
+                RubySystem::getBlockSizeBytes());
+        m_records_read++;
+    }
 }
 
 void
-CacheRecorder::print(ostream& out) const
+CacheRecorder::addRecord(int cntrl, const physical_address_t data_addr,
+                         const physical_address_t pc_addr,
+                         RubyRequestType type, Time time, DataBlock& data)
+{
+    TraceRecord* rec = (TraceRecord*)malloc(sizeof(TraceRecord) +
+                                            RubySystem::getBlockSizeBytes());
+    rec->m_cntrl_id     = cntrl;
+    rec->m_time         = time;
+    rec->m_data_address = data_addr;
+    rec->m_pc_address   = pc_addr;
+    rec->m_type         = type;
+    memcpy(rec->m_data, data.getData(0, RubySystem::getBlockSizeBytes()),
+           RubySystem::getBlockSizeBytes());
+
+    m_records.push_back(rec);
+}
+
+uint64
+CacheRecorder::aggregateRecords(uint8_t** buf, uint64 total_size)
 {
+    std::sort(m_records.begin(), m_records.end(), compareTraceRecords);
+
+    int size = m_records.size();
+    uint64 current_size = 0;
+    int record_size = sizeof(TraceRecord) + RubySystem::getBlockSizeBytes();
+
+    for (int i = 0; i < size; ++i) {
+        // Determine if we need to expand the buffer size
+        if (current_size + record_size > total_size) {
+            uint8_t* new_buf = new (nothrow) uint8_t[total_size * 2];
+            if (new_buf == NULL) {
+                fatal("Unable to allocate buffer of size %s\n",
+                      total_size * 2);
+            }
+            total_size = total_size * 2;
+            uint8_t* old_buf = *buf;
+            memcpy(new_buf, old_buf, current_size);
+            *buf = new_buf;
+            delete [] old_buf;
+        }
+
+        // Copy the current record into the buffer
+        memcpy(&((*buf)[current_size]), m_records[i], record_size);
+        current_size += record_size;
+
+        free(m_records[i]);
+        m_records[i] = NULL;
+    }
+
+    m_records.clear();
+    return current_size;
 }
index 9f96f4fa09411b0dd77a6b2a8f95933e6eb8fcc9..839c4f6b186a1b87d36d974c899e6f907a5e06bd 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood
+ * Copyright (c) 2010 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #ifndef __MEM_RUBY_RECORDER_CACHERECORDER_HH__
 #define __MEM_RUBY_RECORDER_CACHERECORDER_HH__
 
-#include <iostream>
-#include <string>
 #include <vector>
 
+#include "base/hashmap.hh"
 #include "mem/protocol/RubyRequestType.hh"
-#include "mem/ruby/common/Global.hh"
-#include "mem/ruby/recorder/TraceRecord.hh"
+#include "mem/ruby/common/Address.hh"
+#include "mem/ruby/common/DataBlock.hh"
+#include "mem/ruby/common/TypeDefines.hh"
 
-class Address;
-class TraceRecord;
 class Sequencer;
 
+/*!
+ * Class for recording cache contents. Note that the last element of the
+ * class is an array of length zero. It is used for creating variable
+ * length object, so that while writing the data to a file one does not
+ * need to copy the meta data and the actual data separately.
+ */
+class TraceRecord {
+  public:
+    int m_cntrl_id;
+    Time m_time;
+    physical_address_t m_data_address;
+    physical_address_t m_pc_address;
+    RubyRequestType m_type;
+    uint8_t m_data[0];
+
+    void print(std::ostream& out) const;
+};
+
 class CacheRecorder
 {
   public:
-    void addRecord(Sequencer* sequencer, const Address& data_addr,
-        const Address& pc_addr, RubyRequestType type, Time time);
-    int dumpRecords(std::string filename);
+    CacheRecorder();
+    ~CacheRecorder();
 
-    void print(std::ostream& out) const;
+    CacheRecorder(uint8_t* uncompressed_trace,
+                  uint64_t uncompressed_trace_size,
+                  std::vector<Sequencer*>& SequencerMap);
+    void addRecord(int cntrl, const physical_address_t data_addr,
+                   const physical_address_t pc_addr,  RubyRequestType type,
+                   Time time, DataBlock& data);
+
+    uint64 aggregateRecords(uint8_t** data, uint64 size);
+
+    /*!
+     * Function for flushing the memory contents of the caches to the
+     * main memory. It goes through the recorded contents of the caches,
+     * and issues flush requests. Except for the first one, a flush request
+     * is issued only after the previous one has completed. This currently
+     * requires use of MOESI Hammer protocol since only that protocol
+     * supports flush requests.
+     */
+    void enqueueNextFlushRequest();
+
+    /*!
+     * Function for fetching warming up the memory and the caches. It goes
+     * through the recorded contents of the caches, as available in the
+     * checkpoint and issues fetch requests. Except for the first one, a
+     * fetch request is issued only after the previous one has completed.
+     * It should be possible to use this with any protocol.
+     */
+    void enqueueNextFetchRequest();
 
   private:
     // Private copy constructor and assignment operator
     CacheRecorder(const CacheRecorder& obj);
     CacheRecorder& operator=(const CacheRecorder& obj);
 
-    std::vector<TraceRecord> m_records;
+    std::vector<TraceRecord*> m_records;
+    uint8_t* m_uncompressed_trace;
+    uint64_t m_uncompressed_trace_size;
+    std::vector<Sequencer*> m_seq_map;
+    uint64_t m_bytes_read;
+    uint64_t m_records_read;
+    uint64_t m_records_flushed;
 };
 
+inline bool
+compareTraceRecords(const TraceRecord* n1, const TraceRecord* n2)
+{
+    return n1->m_time > n2->m_time;
+}
+
 inline std::ostream&
-operator<<(std::ostream& out, const CacheRecorder& obj)
+operator<<(std::ostream& out, const TraceRecord& obj)
 {
     obj.print(out);
     out << std::flush;
index 4258d2c479e3829f54cbecf2f20aea66f4f80665..e1b3d78b78c62d5d1f6f7a01674f0f23a07f81d8 100644 (file)
@@ -34,4 +34,3 @@ if env['PROTOCOL'] == 'None':
     Return()
 
 Source('CacheRecorder.cc')
-Source('TraceRecord.cc', Werror=False)
diff --git a/src/mem/ruby/recorder/TraceRecord.cc b/src/mem/ruby/recorder/TraceRecord.cc
deleted file mode 100644 (file)
index 79186d3..0000000
+++ /dev/null
@@ -1,139 +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/protocol/RubyRequest.hh"
-#include "mem/ruby/recorder/TraceRecord.hh"
-#include "mem/ruby/system/Sequencer.hh"
-#include "mem/ruby/system/System.hh"
-#include "sim/sim_object.hh"
-
-using namespace std;
-
-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;
-    m_pc_address = pc_addr;
-    m_time = time;
-    m_type = type;
-
-    // Don't differentiate between store misses and atomic requests in
-    // the trace
-    if (m_type == RubyRequestType_Load_Linked) {
-        m_type = RubyRequestType_ST;
-    } else if (m_type == RubyRequestType_Store_Conditional) {
-        m_type = RubyRequestType_ST;
-    }
-}
-
-TraceRecord::TraceRecord(const TraceRecord& obj)
-{
-    // Call assignment operator
-    *this = obj;
-}
-
-TraceRecord&
-TraceRecord::operator=(const TraceRecord& obj)
-{
-    m_sequencer_ptr = obj.m_sequencer_ptr;
-    m_time = obj.m_time;
-    m_data_address = obj.m_data_address;
-    m_pc_address = obj.m_pc_address;
-    m_type = obj.m_type;
-    return *this;
-}
-
-void
-TraceRecord::issueRequest() const
-{
-    assert(m_sequencer_ptr != NULL);
-    Request req(m_data_address.getAddress(), 0, 0);
-    Packet *pkt = new Packet(&req, MemCmd(MemCmd::InvalidCmd), -1);
-
-    // Clear out the sequencer
-    while (!m_sequencer_ptr->empty()) {
-        g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 100);
-    }
-
-    m_sequencer_ptr->makeRequest(pkt);
-
-    // Clear out the sequencer
-    while (!m_sequencer_ptr->empty()) {
-        g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 100);
-    }
-}
-
-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
-{
-    out << m_sequencer_ptr->name() << " ";
-    m_data_address.output(out);
-    out << " ";
-    m_pc_address.output(out);
-    out << " ";
-    out << m_type;
-    out << endl;
-}
-
-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.
-    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;
-    in >> type;
-    m_type = string_to_RubyRequestType(type);
-
-    // Ignore the rest of the line
-    char c = '\0';
-    while ((!in.eof()) && (c != '\n')) {
-        in.get(c);
-    }
-
-    return true;
-}
diff --git a/src/mem/ruby/recorder/TraceRecord.hh b/src/mem/ruby/recorder/TraceRecord.hh
deleted file mode 100644 (file)
index 42f2135..0000000
+++ /dev/null
@@ -1,91 +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.
- */
-
-/*
- * A entry in the cache request record. It is aware of the ruby time
- * and can issue the request back to the cache.
- */
-
-#ifndef __MEM_RUBY_RECORDER_TRACERECORD_HH__
-#define __MEM_RUBY_RECORDER_TRACERECORD_HH__
-
-#include <iostream>
-
-#include "mem/ruby/common/Address.hh"
-#include "mem/ruby/common/Global.hh"
-#include "mem/ruby/system/Sequencer.hh"
-
-class CacheMsg;
-
-class TraceRecord
-{
-  public:
-    TraceRecord(Sequencer* _sequencer, const Address& data_addr,
-        const Address& pc_addr, RubyRequestType type, Time time);
-
-    TraceRecord()
-    {
-        m_sequencer_ptr = NULL;
-        m_time = 0;
-        m_type = RubyRequestType_NULL;
-    }
-
-    TraceRecord(const TraceRecord& obj);
-    TraceRecord& operator=(const TraceRecord& obj);
-
-    void issueRequest() const;
-
-    void print(std::ostream& out) const;
-    void output(std::ostream& out) const;
-    bool input(std::istream& in);
-
-  private:
-    friend bool operator>(const TraceRecord& n1, const TraceRecord& n2);
-
-    Sequencer* m_sequencer_ptr;
-    Time m_time;
-    Address m_data_address;
-    Address m_pc_address;
-    RubyRequestType m_type;
-};
-
-inline bool
-operator>(const TraceRecord& n1, const TraceRecord& n2)
-{
-    return n1.m_time > n2.m_time;
-}
-
-inline std::ostream&
-operator<<(std::ostream& out, const TraceRecord& obj)
-{
-    obj.print(out);
-    out << std::flush;
-    return out;
-}
-
-#endif // __MEM_RUBY_RECORDER_TRACERECORD_HH__
index ca37a90de68a64e608935f0cbb04ac6ed992c2de..a0e3b3fbbf105bbe2494e44266f4d5aece9b7bde 100644 (file)
 #include <string>
 
 #include "mem/protocol/AccessPermission.hh"
-#include "mem/protocol/MachineType.hh"
 #include "mem/ruby/common/Address.hh"
 #include "mem/ruby/common/Consumer.hh"
 #include "mem/ruby/common/DataBlock.hh"
 #include "mem/ruby/network/Network.hh"
-#include "mem/ruby/system/System.hh"
+#include "mem/ruby/recorder/CacheRecorder.hh"
 #include "params/RubyController.hh"
 #include "sim/sim_object.hh"
 
@@ -68,6 +67,8 @@ class AbstractController : public SimObject, public Consumer
     virtual void wakeup() = 0;
     //  virtual void dumpStats(std::ostream & out) = 0;
     virtual void clearStats() = 0;
+    virtual void recordCacheTrace(int cntrl, CacheRecorder* tr) = 0;
+    virtual Sequencer* getSequencer() const = 0;
 };
 
 #endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
index 1564128d3dff4b736b064529a0ac6f2d4c637394..9f1fe632087dcafc24c22668349732b61313ddad 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,9 @@
 
 #include "base/intmath.hh"
 #include "debug/RubyCache.hh"
+#include "mem/protocol/AccessPermission.hh"
 #include "mem/ruby/system/CacheMemory.hh"
+#include "mem/ruby/system/System.hh"
 
 using namespace std;
 
@@ -364,31 +366,42 @@ CacheMemory::profileGenericRequest(GenericRequestType requestType,
 }
 
 void
-CacheMemory::recordCacheContents(CacheRecorder& tr) const
+CacheMemory::recordCacheContents(int cntrl, CacheRecorder* tr) const
 {
+    uint64 warmedUpBlocks = 0;
+    uint64 totalBlocks M5_VAR_USED = (uint64)m_cache_num_sets
+                                                  * (uint64)m_cache_assoc;
+
     for (int i = 0; i < m_cache_num_sets; i++) {
         for (int j = 0; j < m_cache_assoc; j++) {
-            AccessPermission perm = m_cache[i][j]->m_Permission;
-            RubyRequestType request_type = RubyRequestType_NULL;
-            if (perm == AccessPermission_Read_Only) {
-                if (m_is_instruction_only_cache) {
-                    request_type = RubyRequestType_IFETCH;
-                } else {
-                    request_type = RubyRequestType_LD;
+            if (m_cache[i][j] != NULL) {
+                AccessPermission perm = m_cache[i][j]->m_Permission;
+                RubyRequestType request_type = RubyRequestType_NULL;
+                if (perm == AccessPermission_Read_Only) {
+                    if (m_is_instruction_only_cache) {
+                        request_type = RubyRequestType_IFETCH;
+                    } else {
+                        request_type = RubyRequestType_LD;
+                    }
+                } else if (perm == AccessPermission_Read_Write) {
+                    request_type = RubyRequestType_ST;
                 }
-            } else if (perm == AccessPermission_Read_Write) {
-                request_type = RubyRequestType_ST;
-            }
 
-            if (request_type != RubyRequestType_NULL) {
-#if 0
-                tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address,
-                             Address(0), request_type,
-                             m_replacementPolicy_ptr->getLastAccess(i, j));
-#endif
+                if (request_type != RubyRequestType_NULL) {
+                    tr->addRecord(cntrl, m_cache[i][j]->m_Address.getAddress(),
+                                  0, request_type,
+                                  m_replacementPolicy_ptr->getLastAccess(i, j),
+                                  m_cache[i][j]->getDataBlk());
+                    warmedUpBlocks++;
+                }
             }
         }
     }
+
+    DPRINTF(RubyCache, "%s: %lli blocks of %lli total blocks"
+            "recorded %.2f%% \n", name().c_str(), warmedUpBlocks,
+            (uint64)m_cache_num_sets * (uint64)m_cache_assoc,
+            (float(warmedUpBlocks)/float(totalBlocks))*100.0);
 }
 
 void
index f0acba9cb817be5570ffe3af36953f5e9ffe4e4e..f270e88cd8ac0a71405bb31a6f71693261742b59 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <vector>
 
 #include "base/hashmap.hh"
-#include "mem/protocol/AccessPermission.hh"
 #include "mem/protocol/GenericRequestType.hh"
 #include "mem/protocol/RubyRequest.hh"
-#include "mem/protocol/RubyRequestType.hh"
-#include "mem/ruby/common/Address.hh"
 #include "mem/ruby/common/DataBlock.hh"
-#include "mem/ruby/common/Global.hh"
 #include "mem/ruby/profiler/CacheProfiler.hh"
 #include "mem/ruby/recorder/CacheRecorder.hh"
 #include "mem/ruby/slicc_interface/AbstractCacheEntry.hh"
-#include "mem/ruby/slicc_interface/AbstractController.hh"
 #include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh"
 #include "mem/ruby/system/LRUPolicy.hh"
 #include "mem/ruby/system/PseudoLRUPolicy.hh"
-#include "mem/ruby/system/System.hh"
 #include "params/RubyCache.hh"
 #include "sim/sim_object.hh"
 
@@ -100,12 +94,7 @@ class CacheMemory : public SimObject
     int getLatency() const { return m_latency; }
 
     // Hook for checkpointing the contents of the cache
-    void recordCacheContents(CacheRecorder& tr) const;
-    void
-    setAsInstructionCache(bool is_icache)
-    {
-        m_is_instruction_only_cache = is_icache;
-    }
+    void recordCacheContents(int cntrl, CacheRecorder* tr) const;
 
     // Set this address to most recently used
     void setMRU(const Address& address);
@@ -146,7 +135,6 @@ class CacheMemory : public SimObject
 
     // Data Members (m_prefix)
     bool m_is_instruction_only_cache;
-    bool m_is_data_only_cache;
 
     // The first index is the # of cache lines.
     // The second index is the the amount associativity.
index a3ea1ca8adb7113aedafc36ddcbe757a7b27677a..85df3f9e883c01b9be251d207c6ef8b2e3f7df0f 100644 (file)
@@ -264,6 +264,8 @@ public:
     void clearStats();
     void blockOnQueue(Address addr, MessageBuffer* port);
     void unblock(Address addr);
+    void recordCacheTrace(int cntrl, CacheRecorder* tr);
+    Sequencer* getSequencer() const;
 
 private:
 ''')
@@ -674,6 +676,12 @@ $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{v
         else:
             mq_ident = "NULL"
 
+        seq_ident = "NULL"
+        for param in self.config_parameters:
+            if param.name == "sequencer":
+                assert(param.pointer)
+                seq_ident = "m_%s_ptr" % param.name
+
         code('''
 int
 $c_ident::getNumControllers()
@@ -687,6 +695,12 @@ $c_ident::getMandatoryQueue() const
     return $mq_ident;
 }
 
+Sequencer*
+$c_ident::getSequencer() const
+{
+    return $seq_ident;
+}
+
 const int &
 $c_ident::getVersion() const
 {
@@ -875,6 +889,23 @@ $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
 
         code('''
 
+void
+$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
+{
+''')
+        #
+        # Record cache contents for all associated caches.
+        #
+        code.indent()
+        for param in self.config_parameters:
+            if param.type_ast.type.ident == "CacheMemory":
+                assert(param.pointer)
+                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
+
+        code.dedent()
+        code('''
+}
+
 // Actions
 ''')
         if self.TBEType != None and self.EntryType != None: