16145SN/A/*
28683SN/A * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood
38683SN/A * Copyright (c) 2010 Advanced Micro Devices, Inc.
46145SN/A * All rights reserved.
56145SN/A *
66145SN/A * Redistribution and use in source and binary forms, with or without
76145SN/A * modification, are permitted provided that the following conditions are
86145SN/A * met: redistributions of source code must retain the above copyright
96145SN/A * notice, this list of conditions and the following disclaimer;
106145SN/A * redistributions in binary form must reproduce the above copyright
116145SN/A * notice, this list of conditions and the following disclaimer in the
126145SN/A * documentation and/or other materials provided with the distribution;
136145SN/A * neither the name of the copyright holders nor the names of its
146145SN/A * contributors may be used to endorse or promote products derived from
156145SN/A * this software without specific prior written permission.
166145SN/A *
176145SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
186145SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
196145SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
206145SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
216145SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
226145SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
236145SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
246145SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
256145SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
266145SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
276145SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286145SN/A */
296145SN/A
3011793Sbrandon.potter@amd.com#include "mem/ruby/system/CacheRecorder.hh"
3111793Sbrandon.potter@amd.com
328683SN/A#include "debug/RubyCacheTrace.hh"
3311108Sdavid.hashe@amd.com#include "mem/ruby/system/RubySystem.hh"
348683SN/A#include "mem/ruby/system/Sequencer.hh"
356145SN/A
367055SN/Ausing namespace std;
377055SN/A
387054SN/Avoid
398683SN/ATraceRecord::print(ostream& out) const
406145SN/A{
418683SN/A    out << "[TraceRecord: Node, " << m_cntrl_id << ", "
428683SN/A        << m_data_address << ", " << m_pc_address << ", "
438683SN/A        << m_type << ", Time: " << m_time << "]";
448683SN/A}
458683SN/A
468683SN/ACacheRecorder::CacheRecorder()
478683SN/A    : m_uncompressed_trace(NULL),
4810163SN/A      m_uncompressed_trace_size(0),
4910163SN/A      m_block_size_bytes(RubySystem::getBlockSizeBytes())
508683SN/A{
518683SN/A}
528683SN/A
538683SN/ACacheRecorder::CacheRecorder(uint8_t* uncompressed_trace,
548683SN/A                             uint64_t uncompressed_trace_size,
5510163SN/A                             std::vector<Sequencer*>& seq_map,
5610163SN/A                             uint64_t block_size_bytes)
578683SN/A    : m_uncompressed_trace(uncompressed_trace),
588683SN/A      m_uncompressed_trace_size(uncompressed_trace_size),
598683SN/A      m_seq_map(seq_map),  m_bytes_read(0), m_records_read(0),
6010163SN/A      m_records_flushed(0), m_block_size_bytes(block_size_bytes)
618683SN/A{
6211049Snilay@cs.wisc.edu    if (m_uncompressed_trace != NULL) {
6311049Snilay@cs.wisc.edu        if (m_block_size_bytes < RubySystem::getBlockSizeBytes()) {
6411049Snilay@cs.wisc.edu            // Block sizes larger than when the trace was recorded are not
6511049Snilay@cs.wisc.edu            // supported, as we cannot reliably turn accesses to smaller blocks
6611049Snilay@cs.wisc.edu            // into larger ones.
6711049Snilay@cs.wisc.edu            panic("Recorded cache block size (%d) < current block size (%d) !!",
6811049Snilay@cs.wisc.edu                    m_block_size_bytes, RubySystem::getBlockSizeBytes());
6911049Snilay@cs.wisc.edu        }
7011049Snilay@cs.wisc.edu    }
718683SN/A}
728683SN/A
738683SN/ACacheRecorder::~CacheRecorder()
748683SN/A{
758683SN/A    if (m_uncompressed_trace != NULL) {
769627SN/A        delete [] m_uncompressed_trace;
778683SN/A        m_uncompressed_trace = NULL;
788683SN/A    }
798683SN/A    m_seq_map.clear();
808683SN/A}
818683SN/A
828683SN/Avoid
838683SN/ACacheRecorder::enqueueNextFlushRequest()
848683SN/A{
858683SN/A    if (m_records_flushed < m_records.size()) {
868683SN/A        TraceRecord* rec = m_records[m_records_flushed];
878683SN/A        m_records_flushed++;
8812749Sgiacomo.travaglini@arm.com        auto req = std::make_shared<Request>(rec->m_data_address,
8912749Sgiacomo.travaglini@arm.com                                             m_block_size_bytes, 0,
9012749Sgiacomo.travaglini@arm.com                                             Request::funcMasterId);
918683SN/A        MemCmd::Command requestType = MemCmd::FlushReq;
928949SN/A        Packet *pkt = new Packet(req, requestType);
938683SN/A
948683SN/A        Sequencer* m_sequencer_ptr = m_seq_map[rec->m_cntrl_id];
958683SN/A        assert(m_sequencer_ptr != NULL);
968683SN/A        m_sequencer_ptr->makeRequest(pkt);
978683SN/A
988683SN/A        DPRINTF(RubyCacheTrace, "Flushing %s\n", *rec);
9910991Stimothy.jones@cl.cam.ac.uk    } else {
10010991Stimothy.jones@cl.cam.ac.uk        DPRINTF(RubyCacheTrace, "Flushed all %d records\n", m_records_flushed);
1018683SN/A    }
1028683SN/A}
1038683SN/A
1048683SN/Avoid
1058683SN/ACacheRecorder::enqueueNextFetchRequest()
1068683SN/A{
1078683SN/A    if (m_bytes_read < m_uncompressed_trace_size) {
1088683SN/A        TraceRecord* traceRecord = (TraceRecord*) (m_uncompressed_trace +
1098683SN/A                                                                m_bytes_read);
1108683SN/A
1118683SN/A        DPRINTF(RubyCacheTrace, "Issuing %s\n", *traceRecord);
1128683SN/A
11310163SN/A        for (int rec_bytes_read = 0; rec_bytes_read < m_block_size_bytes;
11410163SN/A                rec_bytes_read += RubySystem::getBlockSizeBytes()) {
11512749Sgiacomo.travaglini@arm.com            RequestPtr req;
11610163SN/A            MemCmd::Command requestType;
11710163SN/A
11810163SN/A            if (traceRecord->m_type == RubyRequestType_LD) {
11910163SN/A                requestType = MemCmd::ReadReq;
12012749Sgiacomo.travaglini@arm.com                req = std::make_shared<Request>(
12112749Sgiacomo.travaglini@arm.com                    traceRecord->m_data_address + rec_bytes_read,
12210163SN/A                    RubySystem::getBlockSizeBytes(), 0, Request::funcMasterId);
12310163SN/A            }   else if (traceRecord->m_type == RubyRequestType_IFETCH) {
12410163SN/A                requestType = MemCmd::ReadReq;
12512749Sgiacomo.travaglini@arm.com                req = std::make_shared<Request>(
12612749Sgiacomo.travaglini@arm.com                        traceRecord->m_data_address + rec_bytes_read,
12710163SN/A                        RubySystem::getBlockSizeBytes(),
12810163SN/A                        Request::INST_FETCH, Request::funcMasterId);
12910163SN/A            }   else {
13010163SN/A                requestType = MemCmd::WriteReq;
13112749Sgiacomo.travaglini@arm.com                req = std::make_shared<Request>(
13212749Sgiacomo.travaglini@arm.com                    traceRecord->m_data_address + rec_bytes_read,
13310163SN/A                    RubySystem::getBlockSizeBytes(), 0, Request::funcMasterId);
13410163SN/A            }
13510163SN/A
13610163SN/A            Packet *pkt = new Packet(req, requestType);
13710163SN/A            pkt->dataStatic(traceRecord->m_data + rec_bytes_read);
13810163SN/A
13910163SN/A            Sequencer* m_sequencer_ptr = m_seq_map[traceRecord->m_cntrl_id];
14010163SN/A            assert(m_sequencer_ptr != NULL);
14110163SN/A            m_sequencer_ptr->makeRequest(pkt);
1428683SN/A        }
1438683SN/A
14410163SN/A        m_bytes_read += (sizeof(TraceRecord) + m_block_size_bytes);
1458683SN/A        m_records_read++;
14610991Stimothy.jones@cl.cam.ac.uk    } else {
14710991Stimothy.jones@cl.cam.ac.uk        DPRINTF(RubyCacheTrace, "Fetched all %d records\n", m_records_read);
1488683SN/A    }
1498683SN/A}
1508683SN/A
1518683SN/Avoid
15211025Snilay@cs.wisc.eduCacheRecorder::addRecord(int cntrl, Addr data_addr, Addr pc_addr,
15310302Snilay@cs.wisc.edu                         RubyRequestType type, Tick time, DataBlock& data)
1548683SN/A{
1558683SN/A    TraceRecord* rec = (TraceRecord*)malloc(sizeof(TraceRecord) +
15610163SN/A                                            m_block_size_bytes);
1578683SN/A    rec->m_cntrl_id     = cntrl;
1588683SN/A    rec->m_time         = time;
1598683SN/A    rec->m_data_address = data_addr;
1608683SN/A    rec->m_pc_address   = pc_addr;
1618683SN/A    rec->m_type         = type;
16210163SN/A    memcpy(rec->m_data, data.getData(0, m_block_size_bytes),
16310163SN/A           m_block_size_bytes);
1648683SN/A
1657456SN/A    m_records.push_back(rec);
1666145SN/A}
1676145SN/A
16811061Snilay@cs.wisc.eduuint64_t
16911061Snilay@cs.wisc.eduCacheRecorder::aggregateRecords(uint8_t **buf, uint64_t total_size)
1706145SN/A{
1718683SN/A    std::sort(m_records.begin(), m_records.end(), compareTraceRecords);
1728683SN/A
1738683SN/A    int size = m_records.size();
17411061Snilay@cs.wisc.edu    uint64_t current_size = 0;
17510163SN/A    int record_size = sizeof(TraceRecord) + m_block_size_bytes;
1768683SN/A
1778683SN/A    for (int i = 0; i < size; ++i) {
1788683SN/A        // Determine if we need to expand the buffer size
1798683SN/A        if (current_size + record_size > total_size) {
1808683SN/A            uint8_t* new_buf = new (nothrow) uint8_t[total_size * 2];
1818683SN/A            if (new_buf == NULL) {
1828683SN/A                fatal("Unable to allocate buffer of size %s\n",
1838683SN/A                      total_size * 2);
1848683SN/A            }
1858683SN/A            total_size = total_size * 2;
1868683SN/A            uint8_t* old_buf = *buf;
1878683SN/A            memcpy(new_buf, old_buf, current_size);
1888683SN/A            *buf = new_buf;
1898683SN/A            delete [] old_buf;
1908683SN/A        }
1918683SN/A
1928683SN/A        // Copy the current record into the buffer
1938683SN/A        memcpy(&((*buf)[current_size]), m_records[i], record_size);
1948683SN/A        current_size += record_size;
1958683SN/A
1968683SN/A        free(m_records[i]);
1978683SN/A        m_records[i] = NULL;
1987054SN/A    }
1996145SN/A
2007456SN/A    m_records.clear();
2018683SN/A    return current_size;
2026145SN/A}
203