ce2722cdd9
If the cache access mode is parallel, i.e. "sequential_access" parameter is set to "False", tags and data are accessed in parallel. Therefore, the hit_latency is the maximum latency between tag_latency and data_latency. On the other hand, if the cache access mode is sequential, i.e. "sequential_access" parameter is set to "True", tags and data are accessed sequentially. Therefore, the hit_latency is the sum of tag_latency plus data_latency. Signed-off-by: Jason Lowe-Power <jason@lowepower.com>
763 lines
26 KiB
C++
763 lines
26 KiB
C++
/*
|
|
* Copyright (c) 2012-2013 ARM Limited
|
|
* All rights reserved.
|
|
*
|
|
* The license below extends only to copyright in the software and shall
|
|
* not be construed as granting a license to any other intellectual
|
|
* property including but not limited to intellectual property relating
|
|
* to a hardware implementation of the functionality of the software
|
|
* licensed hereunder. You may use the software subject to the license
|
|
* terms below provided that you ensure that this notice is replicated
|
|
* unmodified and in its entirety in all distributions of the software,
|
|
* modified or unmodified, in source code or in binary form.
|
|
*
|
|
* Copyright (c) 2003-2005 The Regents of The University of Michigan
|
|
* 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.
|
|
*
|
|
* Authors: Erik Hallnor
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* Definition of BaseCache functions.
|
|
*/
|
|
|
|
#include "mem/cache/base.hh"
|
|
|
|
#include "debug/Cache.hh"
|
|
#include "debug/Drain.hh"
|
|
#include "mem/cache/cache.hh"
|
|
#include "mem/cache/mshr.hh"
|
|
#include "mem/cache/tags/fa_lru.hh"
|
|
#include "mem/cache/tags/lru.hh"
|
|
#include "mem/cache/tags/random_repl.hh"
|
|
#include "sim/full_system.hh"
|
|
|
|
using namespace std;
|
|
|
|
BaseCache::CacheSlavePort::CacheSlavePort(const std::string &_name,
|
|
BaseCache *_cache,
|
|
const std::string &_label)
|
|
: QueuedSlavePort(_name, _cache, queue), queue(*_cache, *this, _label),
|
|
blocked(false), mustSendRetry(false), sendRetryEvent(this)
|
|
{
|
|
}
|
|
|
|
BaseCache::BaseCache(const BaseCacheParams *p, unsigned blk_size)
|
|
: MemObject(p),
|
|
cpuSidePort(nullptr), memSidePort(nullptr),
|
|
mshrQueue("MSHRs", p->mshrs, 0, p->demand_mshr_reserve), // see below
|
|
writeBuffer("write buffer", p->write_buffers, p->mshrs), // see below
|
|
blkSize(blk_size),
|
|
lookupLatency(p->tag_latency),
|
|
dataLatency(p->data_latency),
|
|
forwardLatency(p->tag_latency),
|
|
fillLatency(p->data_latency),
|
|
responseLatency(p->response_latency),
|
|
numTarget(p->tgts_per_mshr),
|
|
forwardSnoops(true),
|
|
isReadOnly(p->is_read_only),
|
|
blocked(0),
|
|
order(0),
|
|
noTargetMSHR(nullptr),
|
|
missCount(p->max_miss_count),
|
|
addrRanges(p->addr_ranges.begin(), p->addr_ranges.end()),
|
|
system(p->system)
|
|
{
|
|
// the MSHR queue has no reserve entries as we check the MSHR
|
|
// queue on every single allocation, whereas the write queue has
|
|
// as many reserve entries as we have MSHRs, since every MSHR may
|
|
// eventually require a writeback, and we do not check the write
|
|
// buffer before committing to an MSHR
|
|
|
|
// forward snoops is overridden in init() once we can query
|
|
// whether the connected master is actually snooping or not
|
|
}
|
|
|
|
void
|
|
BaseCache::CacheSlavePort::setBlocked()
|
|
{
|
|
assert(!blocked);
|
|
DPRINTF(CachePort, "Port is blocking new requests\n");
|
|
blocked = true;
|
|
// if we already scheduled a retry in this cycle, but it has not yet
|
|
// happened, cancel it
|
|
if (sendRetryEvent.scheduled()) {
|
|
owner.deschedule(sendRetryEvent);
|
|
DPRINTF(CachePort, "Port descheduled retry\n");
|
|
mustSendRetry = true;
|
|
}
|
|
}
|
|
|
|
void
|
|
BaseCache::CacheSlavePort::clearBlocked()
|
|
{
|
|
assert(blocked);
|
|
DPRINTF(CachePort, "Port is accepting new requests\n");
|
|
blocked = false;
|
|
if (mustSendRetry) {
|
|
// @TODO: need to find a better time (next cycle?)
|
|
owner.schedule(sendRetryEvent, curTick() + 1);
|
|
}
|
|
}
|
|
|
|
void
|
|
BaseCache::CacheSlavePort::processSendRetry()
|
|
{
|
|
DPRINTF(CachePort, "Port is sending retry\n");
|
|
|
|
// reset the flag and call retry
|
|
mustSendRetry = false;
|
|
sendRetryReq();
|
|
}
|
|
|
|
void
|
|
BaseCache::init()
|
|
{
|
|
if (!cpuSidePort->isConnected() || !memSidePort->isConnected())
|
|
fatal("Cache ports on %s are not connected\n", name());
|
|
cpuSidePort->sendRangeChange();
|
|
forwardSnoops = cpuSidePort->isSnooping();
|
|
}
|
|
|
|
BaseMasterPort &
|
|
BaseCache::getMasterPort(const std::string &if_name, PortID idx)
|
|
{
|
|
if (if_name == "mem_side") {
|
|
return *memSidePort;
|
|
} else {
|
|
return MemObject::getMasterPort(if_name, idx);
|
|
}
|
|
}
|
|
|
|
BaseSlavePort &
|
|
BaseCache::getSlavePort(const std::string &if_name, PortID idx)
|
|
{
|
|
if (if_name == "cpu_side") {
|
|
return *cpuSidePort;
|
|
} else {
|
|
return MemObject::getSlavePort(if_name, idx);
|
|
}
|
|
}
|
|
|
|
bool
|
|
BaseCache::inRange(Addr addr) const
|
|
{
|
|
for (const auto& r : addrRanges) {
|
|
if (r.contains(addr)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void
|
|
BaseCache::regStats()
|
|
{
|
|
MemObject::regStats();
|
|
|
|
using namespace Stats;
|
|
|
|
// Hit statistics
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
hits[access_idx]
|
|
.init(system->maxMasters())
|
|
.name(name() + "." + cstr + "_hits")
|
|
.desc("number of " + cstr + " hits")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
hits[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
// These macros make it easier to sum the right subset of commands and
|
|
// to change the subset of commands that are considered "demand" vs
|
|
// "non-demand"
|
|
#define SUM_DEMAND(s) \
|
|
(s[MemCmd::ReadReq] + s[MemCmd::WriteReq] + s[MemCmd::WriteLineReq] + \
|
|
s[MemCmd::ReadExReq] + s[MemCmd::ReadCleanReq] + s[MemCmd::ReadSharedReq])
|
|
|
|
// should writebacks be included here? prior code was inconsistent...
|
|
#define SUM_NON_DEMAND(s) \
|
|
(s[MemCmd::SoftPFReq] + s[MemCmd::HardPFReq])
|
|
|
|
demandHits
|
|
.name(name() + ".demand_hits")
|
|
.desc("number of demand (read+write) hits")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandHits = SUM_DEMAND(hits);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandHits.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallHits
|
|
.name(name() + ".overall_hits")
|
|
.desc("number of overall hits")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallHits = demandHits + SUM_NON_DEMAND(hits);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallHits.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// Miss statistics
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
misses[access_idx]
|
|
.init(system->maxMasters())
|
|
.name(name() + "." + cstr + "_misses")
|
|
.desc("number of " + cstr + " misses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
misses[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
demandMisses
|
|
.name(name() + ".demand_misses")
|
|
.desc("number of demand (read+write) misses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandMisses = SUM_DEMAND(misses);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandMisses.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallMisses
|
|
.name(name() + ".overall_misses")
|
|
.desc("number of overall misses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallMisses = demandMisses + SUM_NON_DEMAND(misses);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallMisses.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// Miss latency statistics
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
missLatency[access_idx]
|
|
.init(system->maxMasters())
|
|
.name(name() + "." + cstr + "_miss_latency")
|
|
.desc("number of " + cstr + " miss cycles")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
missLatency[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
demandMissLatency
|
|
.name(name() + ".demand_miss_latency")
|
|
.desc("number of demand (read+write) miss cycles")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandMissLatency = SUM_DEMAND(missLatency);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandMissLatency.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallMissLatency
|
|
.name(name() + ".overall_miss_latency")
|
|
.desc("number of overall miss cycles")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallMissLatency = demandMissLatency + SUM_NON_DEMAND(missLatency);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallMissLatency.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// access formulas
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
accesses[access_idx]
|
|
.name(name() + "." + cstr + "_accesses")
|
|
.desc("number of " + cstr + " accesses(hits+misses)")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
accesses[access_idx] = hits[access_idx] + misses[access_idx];
|
|
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
accesses[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
demandAccesses
|
|
.name(name() + ".demand_accesses")
|
|
.desc("number of demand (read+write) accesses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandAccesses = demandHits + demandMisses;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandAccesses.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallAccesses
|
|
.name(name() + ".overall_accesses")
|
|
.desc("number of overall (read+write) accesses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallAccesses = overallHits + overallMisses;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallAccesses.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// miss rate formulas
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
missRate[access_idx]
|
|
.name(name() + "." + cstr + "_miss_rate")
|
|
.desc("miss rate for " + cstr + " accesses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
missRate[access_idx] = misses[access_idx] / accesses[access_idx];
|
|
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
missRate[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
demandMissRate
|
|
.name(name() + ".demand_miss_rate")
|
|
.desc("miss rate for demand accesses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandMissRate = demandMisses / demandAccesses;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandMissRate.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallMissRate
|
|
.name(name() + ".overall_miss_rate")
|
|
.desc("miss rate for overall accesses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallMissRate = overallMisses / overallAccesses;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallMissRate.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// miss latency formulas
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
avgMissLatency[access_idx]
|
|
.name(name() + "." + cstr + "_avg_miss_latency")
|
|
.desc("average " + cstr + " miss latency")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
avgMissLatency[access_idx] =
|
|
missLatency[access_idx] / misses[access_idx];
|
|
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
avgMissLatency[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
demandAvgMissLatency
|
|
.name(name() + ".demand_avg_miss_latency")
|
|
.desc("average overall miss latency")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandAvgMissLatency = demandMissLatency / demandMisses;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandAvgMissLatency.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallAvgMissLatency
|
|
.name(name() + ".overall_avg_miss_latency")
|
|
.desc("average overall miss latency")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallAvgMissLatency = overallMissLatency / overallMisses;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallAvgMissLatency.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
blocked_cycles.init(NUM_BLOCKED_CAUSES);
|
|
blocked_cycles
|
|
.name(name() + ".blocked_cycles")
|
|
.desc("number of cycles access was blocked")
|
|
.subname(Blocked_NoMSHRs, "no_mshrs")
|
|
.subname(Blocked_NoTargets, "no_targets")
|
|
;
|
|
|
|
|
|
blocked_causes.init(NUM_BLOCKED_CAUSES);
|
|
blocked_causes
|
|
.name(name() + ".blocked")
|
|
.desc("number of cycles access was blocked")
|
|
.subname(Blocked_NoMSHRs, "no_mshrs")
|
|
.subname(Blocked_NoTargets, "no_targets")
|
|
;
|
|
|
|
avg_blocked
|
|
.name(name() + ".avg_blocked_cycles")
|
|
.desc("average number of cycles each access was blocked")
|
|
.subname(Blocked_NoMSHRs, "no_mshrs")
|
|
.subname(Blocked_NoTargets, "no_targets")
|
|
;
|
|
|
|
avg_blocked = blocked_cycles / blocked_causes;
|
|
|
|
unusedPrefetches
|
|
.name(name() + ".unused_prefetches")
|
|
.desc("number of HardPF blocks evicted w/o reference")
|
|
.flags(nozero)
|
|
;
|
|
|
|
writebacks
|
|
.init(system->maxMasters())
|
|
.name(name() + ".writebacks")
|
|
.desc("number of writebacks")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
writebacks.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// MSHR statistics
|
|
// MSHR hit statistics
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
mshr_hits[access_idx]
|
|
.init(system->maxMasters())
|
|
.name(name() + "." + cstr + "_mshr_hits")
|
|
.desc("number of " + cstr + " MSHR hits")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
mshr_hits[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
demandMshrHits
|
|
.name(name() + ".demand_mshr_hits")
|
|
.desc("number of demand (read+write) MSHR hits")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandMshrHits = SUM_DEMAND(mshr_hits);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandMshrHits.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallMshrHits
|
|
.name(name() + ".overall_mshr_hits")
|
|
.desc("number of overall MSHR hits")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallMshrHits = demandMshrHits + SUM_NON_DEMAND(mshr_hits);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallMshrHits.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// MSHR miss statistics
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
mshr_misses[access_idx]
|
|
.init(system->maxMasters())
|
|
.name(name() + "." + cstr + "_mshr_misses")
|
|
.desc("number of " + cstr + " MSHR misses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
mshr_misses[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
demandMshrMisses
|
|
.name(name() + ".demand_mshr_misses")
|
|
.desc("number of demand (read+write) MSHR misses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandMshrMisses = SUM_DEMAND(mshr_misses);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandMshrMisses.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallMshrMisses
|
|
.name(name() + ".overall_mshr_misses")
|
|
.desc("number of overall MSHR misses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallMshrMisses = demandMshrMisses + SUM_NON_DEMAND(mshr_misses);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallMshrMisses.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// MSHR miss latency statistics
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
mshr_miss_latency[access_idx]
|
|
.init(system->maxMasters())
|
|
.name(name() + "." + cstr + "_mshr_miss_latency")
|
|
.desc("number of " + cstr + " MSHR miss cycles")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
mshr_miss_latency[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
demandMshrMissLatency
|
|
.name(name() + ".demand_mshr_miss_latency")
|
|
.desc("number of demand (read+write) MSHR miss cycles")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandMshrMissLatency = SUM_DEMAND(mshr_miss_latency);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandMshrMissLatency.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallMshrMissLatency
|
|
.name(name() + ".overall_mshr_miss_latency")
|
|
.desc("number of overall MSHR miss cycles")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallMshrMissLatency =
|
|
demandMshrMissLatency + SUM_NON_DEMAND(mshr_miss_latency);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallMshrMissLatency.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// MSHR uncacheable statistics
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
mshr_uncacheable[access_idx]
|
|
.init(system->maxMasters())
|
|
.name(name() + "." + cstr + "_mshr_uncacheable")
|
|
.desc("number of " + cstr + " MSHR uncacheable")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
mshr_uncacheable[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
overallMshrUncacheable
|
|
.name(name() + ".overall_mshr_uncacheable_misses")
|
|
.desc("number of overall MSHR uncacheable misses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallMshrUncacheable =
|
|
SUM_DEMAND(mshr_uncacheable) + SUM_NON_DEMAND(mshr_uncacheable);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallMshrUncacheable.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// MSHR miss latency statistics
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
mshr_uncacheable_lat[access_idx]
|
|
.init(system->maxMasters())
|
|
.name(name() + "." + cstr + "_mshr_uncacheable_latency")
|
|
.desc("number of " + cstr + " MSHR uncacheable cycles")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
mshr_uncacheable_lat[access_idx].subname(
|
|
i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
overallMshrUncacheableLatency
|
|
.name(name() + ".overall_mshr_uncacheable_latency")
|
|
.desc("number of overall MSHR uncacheable cycles")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallMshrUncacheableLatency =
|
|
SUM_DEMAND(mshr_uncacheable_lat) +
|
|
SUM_NON_DEMAND(mshr_uncacheable_lat);
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallMshrUncacheableLatency.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
#if 0
|
|
// MSHR access formulas
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
mshrAccesses[access_idx]
|
|
.name(name() + "." + cstr + "_mshr_accesses")
|
|
.desc("number of " + cstr + " mshr accesses(hits+misses)")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
mshrAccesses[access_idx] =
|
|
mshr_hits[access_idx] + mshr_misses[access_idx]
|
|
+ mshr_uncacheable[access_idx];
|
|
}
|
|
|
|
demandMshrAccesses
|
|
.name(name() + ".demand_mshr_accesses")
|
|
.desc("number of demand (read+write) mshr accesses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandMshrAccesses = demandMshrHits + demandMshrMisses;
|
|
|
|
overallMshrAccesses
|
|
.name(name() + ".overall_mshr_accesses")
|
|
.desc("number of overall (read+write) mshr accesses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallMshrAccesses = overallMshrHits + overallMshrMisses
|
|
+ overallMshrUncacheable;
|
|
#endif
|
|
|
|
// MSHR miss rate formulas
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
mshrMissRate[access_idx]
|
|
.name(name() + "." + cstr + "_mshr_miss_rate")
|
|
.desc("mshr miss rate for " + cstr + " accesses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
mshrMissRate[access_idx] =
|
|
mshr_misses[access_idx] / accesses[access_idx];
|
|
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
mshrMissRate[access_idx].subname(i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
demandMshrMissRate
|
|
.name(name() + ".demand_mshr_miss_rate")
|
|
.desc("mshr miss rate for demand accesses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandMshrMissRate = demandMshrMisses / demandAccesses;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandMshrMissRate.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallMshrMissRate
|
|
.name(name() + ".overall_mshr_miss_rate")
|
|
.desc("mshr miss rate for overall accesses")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallMshrMissRate = overallMshrMisses / overallAccesses;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallMshrMissRate.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// mshrMiss latency formulas
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
avgMshrMissLatency[access_idx]
|
|
.name(name() + "." + cstr + "_avg_mshr_miss_latency")
|
|
.desc("average " + cstr + " mshr miss latency")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
avgMshrMissLatency[access_idx] =
|
|
mshr_miss_latency[access_idx] / mshr_misses[access_idx];
|
|
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
avgMshrMissLatency[access_idx].subname(
|
|
i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
demandAvgMshrMissLatency
|
|
.name(name() + ".demand_avg_mshr_miss_latency")
|
|
.desc("average overall mshr miss latency")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
demandAvgMshrMissLatency.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
overallAvgMshrMissLatency
|
|
.name(name() + ".overall_avg_mshr_miss_latency")
|
|
.desc("average overall mshr miss latency")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallAvgMshrMissLatency.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
// mshrUncacheable latency formulas
|
|
for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
|
|
MemCmd cmd(access_idx);
|
|
const string &cstr = cmd.toString();
|
|
|
|
avgMshrUncacheableLatency[access_idx]
|
|
.name(name() + "." + cstr + "_avg_mshr_uncacheable_latency")
|
|
.desc("average " + cstr + " mshr uncacheable latency")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
avgMshrUncacheableLatency[access_idx] =
|
|
mshr_uncacheable_lat[access_idx] / mshr_uncacheable[access_idx];
|
|
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
avgMshrUncacheableLatency[access_idx].subname(
|
|
i, system->getMasterName(i));
|
|
}
|
|
}
|
|
|
|
overallAvgMshrUncacheableLatency
|
|
.name(name() + ".overall_avg_mshr_uncacheable_latency")
|
|
.desc("average overall mshr uncacheable latency")
|
|
.flags(total | nozero | nonan)
|
|
;
|
|
overallAvgMshrUncacheableLatency =
|
|
overallMshrUncacheableLatency / overallMshrUncacheable;
|
|
for (int i = 0; i < system->maxMasters(); i++) {
|
|
overallAvgMshrUncacheableLatency.subname(i, system->getMasterName(i));
|
|
}
|
|
|
|
}
|