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.
This commit is contained in:
parent
ab0347a1c6
commit
c3109f7775
10 changed files with 274 additions and 305 deletions
|
@ -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'])
|
||||
|
|
|
@ -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);
|
||||
m_records.push_back(rec);
|
||||
out << "[TraceRecord: Node, " << m_cntrl_id << ", "
|
||||
<< m_data_address << ", " << m_pc_address << ", "
|
||||
<< m_type << ", Time: " << m_time << "]";
|
||||
}
|
||||
|
||||
int
|
||||
CacheRecorder::dumpRecords(string filename)
|
||||
CacheRecorder::CacheRecorder()
|
||||
: m_uncompressed_trace(NULL),
|
||||
m_uncompressed_trace_size(0)
|
||||
{
|
||||
ogzstream out(filename.c_str());
|
||||
if (out.fail()) {
|
||||
cout << "Error: error opening file '" << filename << "'" << endl;
|
||||
return 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;
|
||||
}
|
||||
|
||||
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;
|
||||
m_seq_map.clear();
|
||||
}
|
||||
|
||||
void
|
||||
CacheRecorder::print(ostream& out) const
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
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;
|
||||
|
|
|
@ -34,4 +34,3 @@ if env['PROTOCOL'] == 'None':
|
|||
Return()
|
||||
|
||||
Source('CacheRecorder.cc')
|
||||
Source('TraceRecord.cc', Werror=False)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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__
|
|
@ -33,12 +33,11 @@
|
|||
#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__
|
||||
|
|
|
@ -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,10 +366,15 @@ 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++) {
|
||||
if (m_cache[i][j] != NULL) {
|
||||
AccessPermission perm = m_cache[i][j]->m_Permission;
|
||||
RubyRequestType request_type = RubyRequestType_NULL;
|
||||
if (perm == AccessPermission_Read_Only) {
|
||||
|
@ -381,14 +388,20 @@ CacheMemory::recordCacheContents(CacheRecorder& tr) const
|
|||
}
|
||||
|
||||
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
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
@ -34,21 +34,15 @@
|
|||
#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.
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue