changeset 9feb100066e1 in /z/repo/gem5
details: http://repo.gem5.org/gem5?cmd=changeset;node=9feb100066e1
description:
        Ruby: Add infrastructure for recording cache contents
        This patch changes CacheRecorder, CacheMemory, CacheControllers
        so that the contents of a cache can be recorded for checkpointing
        purposes.

diffstat:

 src/mem/SConscript                                 |    3 +-
 src/mem/ruby/recorder/CacheRecorder.cc             |  166 +++++++++++++++++---
 src/mem/ruby/recorder/CacheRecorder.hh             |   80 ++++++++-
 src/mem/ruby/recorder/SConscript                   |    1 -
 src/mem/ruby/recorder/TraceRecord.cc               |  139 -----------------
 src/mem/ruby/recorder/TraceRecord.hh               |   91 -----------
 src/mem/ruby/slicc_interface/AbstractController.hh |    5 +-
 src/mem/ruby/system/CacheMemory.cc                 |   49 +++--
 src/mem/ruby/system/CacheMemory.hh                 |   16 +-
 src/mem/slicc/symbols/StateMachine.py              |   31 +++
 10 files changed, 275 insertions(+), 306 deletions(-)

diffs (truncated from 791 to 300 lines):

diff -r d70d2dfb1c20 -r 9feb100066e1 src/mem/SConscript
--- a/src/mem/SConscript        Wed Jan 11 11:46:23 2012 -0600
+++ b/src/mem/SConscript        Wed Jan 11 13:29:15 2012 -0600
@@ -62,6 +62,7 @@
 
 DebugFlag('ProtocolTrace')
 DebugFlag('RubyCache')
+DebugFlag('RubyCacheTrace')
 DebugFlag('RubyDma')
 DebugFlag('RubyGenerated')
 DebugFlag('RubyMemory')
@@ -75,4 +76,4 @@
 
 CompoundFlag('Ruby', [ 'RubyQueue', 'RubyNetwork', 'RubyTester',
     'RubyGenerated', 'RubySlicc', 'RubyStorebuffer', 'RubyCache',
-    'RubyMemory', 'RubyDma', 'RubyPort', 'RubySequencer'])
+    'RubyMemory', 'RubyDma', 'RubyPort', 'RubySequencer', 'RubyCacheTrace'])
diff -r d70d2dfb1c20 -r 9feb100066e1 src/mem/ruby/recorder/CacheRecorder.cc
--- a/src/mem/ruby/recorder/CacheRecorder.cc    Wed Jan 11 11:46:23 2012 -0600
+++ b/src/mem/ruby/recorder/CacheRecorder.cc    Wed Jan 11 13:29:15 2012 -0600
@@ -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
@@ -26,43 +27,154 @@
  * 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
 {
-    TraceRecord rec(sequencer, data_addr, pc_addr, type, time);
+    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)
+{
+}
+
+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)
+{
+}
+
+CacheRecorder::~CacheRecorder()
+{
+    if (m_uncompressed_trace != NULL) {
+        delete m_uncompressed_trace;
+        m_uncompressed_trace = NULL;
+    }
+    m_seq_map.clear();
+}
+
+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);
+
+        Sequencer* m_sequencer_ptr = m_seq_map[rec->m_cntrl_id];
+        assert(m_sequencer_ptr != NULL);
+        m_sequencer_ptr->makeRequest(pkt);
+
+        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);
+
+        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::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);
 }
 
-int
-CacheRecorder::dumpRecords(string filename)
+uint64
+CacheRecorder::aggregateRecords(uint8_t** buf, uint64 total_size)
 {
-    ogzstream out(filename.c_str());
-    if (out.fail()) {
-        cout << "Error: error opening file '" << filename << "'" << endl;
-        return 0;
+    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;
     }
 
-    std::sort(m_records.begin(), m_records.end(), greater<TraceRecord>());
-
-    int size = m_records.size();
-    for (int i = 0; i < size; ++i)
-        m_records[i].output(out);
-
     m_records.clear();
-
-    return size;
+    return current_size;
 }
-
-void
-CacheRecorder::print(ostream& out) const
-{
-}
diff -r d70d2dfb1c20 -r 9feb100066e1 src/mem/ruby/recorder/CacheRecorder.hh
--- a/src/mem/ruby/recorder/CacheRecorder.hh    Wed Jan 11 11:46:23 2012 -0600
+++ b/src/mem/ruby/recorder/CacheRecorder.hh    Wed Jan 11 13:29:15 2012 -0600
@@ -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
@@ -34,37 +35,90 @@
 #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);
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to