More major reorg of cache. Seems to work for atomic mode now,
timing mode still broken.
configs/example/memtest.py:
Revamp options.
src/cpu/memtest/memtest.cc:
No need for memory initialization.
No need to make atomic response... memory system should do that now.
src/cpu/memtest/memtest.hh:
MemTest really doesn't want to snoop.
src/mem/bridge.cc:
checkFunctional() cleanup.
src/mem/bus.cc:
src/mem/bus.hh:
src/mem/cache/base_cache.cc:
src/mem/cache/base_cache.hh:
src/mem/cache/cache.cc:
src/mem/cache/cache.hh:
src/mem/cache/cache_blk.hh:
src/mem/cache/cache_builder.cc:
src/mem/cache/cache_impl.hh:
src/mem/cache/coherence/coherence_protocol.cc:
src/mem/cache/coherence/coherence_protocol.hh:
src/mem/cache/coherence/simple_coherence.hh:
src/mem/cache/miss/SConscript:
src/mem/cache/miss/mshr.cc:
src/mem/cache/miss/mshr.hh:
src/mem/cache/miss/mshr_queue.cc:
src/mem/cache/miss/mshr_queue.hh:
src/mem/cache/prefetch/base_prefetcher.cc:
src/mem/cache/tags/fa_lru.cc:
src/mem/cache/tags/fa_lru.hh:
src/mem/cache/tags/iic.cc:
src/mem/cache/tags/iic.hh:
src/mem/cache/tags/lru.cc:
src/mem/cache/tags/lru.hh:
src/mem/cache/tags/split.cc:
src/mem/cache/tags/split.hh:
src/mem/cache/tags/split_lifo.cc:
src/mem/cache/tags/split_lifo.hh:
src/mem/cache/tags/split_lru.cc:
src/mem/cache/tags/split_lru.hh:
src/mem/packet.cc:
src/mem/packet.hh:
src/mem/physical.cc:
src/mem/physical.hh:
src/mem/tport.cc:
More major reorg. Seems to work for atomic mode now,
timing mode still broken.
--HG--
extra : convert_revision : 7e70dfc4a752393b911880ff028271433855ae87
This commit is contained in:
413
src/mem/cache/base_cache.cc
vendored
413
src/mem/cache/base_cache.cc
vendored
@@ -41,18 +41,23 @@
|
||||
using namespace std;
|
||||
|
||||
BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache)
|
||||
: Port(_name, _cache), cache(_cache), otherPort(NULL)
|
||||
: SimpleTimingPort(_name, _cache), cache(_cache), otherPort(NULL),
|
||||
blocked(false), waitingOnRetry(false), mustSendRetry(false),
|
||||
requestCauses(0)
|
||||
{
|
||||
blocked = false;
|
||||
waitingOnRetry = false;
|
||||
}
|
||||
|
||||
|
||||
BaseCache::BaseCache(const std::string &name, Params ¶ms)
|
||||
: MemObject(name),
|
||||
blocked(0), blockedSnoop(0),
|
||||
mshrQueue(params.numMSHRs, 4),
|
||||
writeBuffer(params.numWriteBuffers, params.numMSHRs+1000),
|
||||
blkSize(params.blkSize),
|
||||
missCount(params.maxMisses), drainEvent(NULL)
|
||||
numTarget(params.numTargets),
|
||||
blocked(0),
|
||||
noTargetMSHR(NULL),
|
||||
missCount(params.maxMisses),
|
||||
drainEvent(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -71,139 +76,21 @@ BaseCache::CachePort::deviceBlockSize()
|
||||
return cache->getBlockSize();
|
||||
}
|
||||
|
||||
bool
|
||||
BaseCache::CachePort::checkFunctional(PacketPtr pkt)
|
||||
{
|
||||
//Check storage here first
|
||||
list<PacketPtr>::iterator i = drainList.begin();
|
||||
list<PacketPtr>::iterator iend = drainList.end();
|
||||
bool notDone = true;
|
||||
while (i != iend && notDone) {
|
||||
PacketPtr target = *i;
|
||||
// If the target contains data, and it overlaps the
|
||||
// probed request, need to update data
|
||||
if (target->intersect(pkt)) {
|
||||
DPRINTF(Cache, "Functional %s access to blk_addr %x intersects a drain\n",
|
||||
pkt->cmdString(), pkt->getAddr() & ~(cache->getBlockSize() - 1));
|
||||
notDone = fixPacket(pkt, target);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
//Also check the response not yet ready to be on the list
|
||||
std::list<std::pair<Tick,PacketPtr> >::iterator j = transmitList.begin();
|
||||
std::list<std::pair<Tick,PacketPtr> >::iterator jend = transmitList.end();
|
||||
|
||||
while (j != jend && notDone) {
|
||||
PacketPtr target = j->second;
|
||||
// If the target contains data, and it overlaps the
|
||||
// probed request, need to update data
|
||||
if (target->intersect(pkt)) {
|
||||
DPRINTF(Cache, "Functional %s access to blk_addr %x intersects a response\n",
|
||||
pkt->cmdString(), pkt->getAddr() & ~(cache->getBlockSize() - 1));
|
||||
notDone = fixDelayedResponsePacket(pkt, target);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
return notDone;
|
||||
}
|
||||
|
||||
void
|
||||
BaseCache::CachePort::checkAndSendFunctional(PacketPtr pkt)
|
||||
{
|
||||
bool notDone = checkFunctional(pkt);
|
||||
if (notDone)
|
||||
checkFunctional(pkt);
|
||||
if (pkt->result != Packet::Success)
|
||||
sendFunctional(pkt);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BaseCache::CachePort::respond(PacketPtr pkt, Tick time)
|
||||
{
|
||||
assert(time >= curTick);
|
||||
if (pkt->needsResponse()) {
|
||||
if (transmitList.empty()) {
|
||||
assert(!responseEvent->scheduled());
|
||||
responseEvent->schedule(time);
|
||||
transmitList.push_back(std::pair<Tick,PacketPtr>(time,pkt));
|
||||
return;
|
||||
}
|
||||
|
||||
// something is on the list and this belongs at the end
|
||||
if (time >= transmitList.back().first) {
|
||||
transmitList.push_back(std::pair<Tick,PacketPtr>(time,pkt));
|
||||
return;
|
||||
}
|
||||
// Something is on the list and this belongs somewhere else
|
||||
std::list<std::pair<Tick,PacketPtr> >::iterator i =
|
||||
transmitList.begin();
|
||||
std::list<std::pair<Tick,PacketPtr> >::iterator end =
|
||||
transmitList.end();
|
||||
bool done = false;
|
||||
|
||||
while (i != end && !done) {
|
||||
if (time < i->first) {
|
||||
if (i == transmitList.begin()) {
|
||||
//Inserting at begining, reschedule
|
||||
responseEvent->reschedule(time);
|
||||
}
|
||||
transmitList.insert(i,std::pair<Tick,PacketPtr>(time,pkt));
|
||||
done = true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
// this code was on the cpuSidePort only... do we still need it?
|
||||
if (pkt->cmd != MemCmd::UpgradeReq)
|
||||
{
|
||||
delete pkt->req;
|
||||
delete pkt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
BaseCache::CachePort::drainResponse()
|
||||
{
|
||||
DPRINTF(CachePort,
|
||||
"%s attempting to send a retry for response (%i waiting)\n",
|
||||
name(), drainList.size());
|
||||
//We have some responses to drain first
|
||||
PacketPtr pkt = drainList.front();
|
||||
if (sendTiming(pkt)) {
|
||||
drainList.pop_front();
|
||||
DPRINTF(CachePort, "%s sucessful in sending a retry for"
|
||||
"response (%i still waiting)\n", name(), drainList.size());
|
||||
if (!drainList.empty() || isBusRequested()) {
|
||||
|
||||
DPRINTF(CachePort, "%s has more responses/requests\n", name());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
waitingOnRetry = true;
|
||||
DPRINTF(CachePort, "%s now waiting on a retry\n", name());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BaseCache::CachePort::recvRetryCommon()
|
||||
{
|
||||
assert(waitingOnRetry);
|
||||
waitingOnRetry = false;
|
||||
if (!drainList.empty()) {
|
||||
if (!drainResponse()) {
|
||||
// more responses to drain... re-request bus
|
||||
scheduleRequestEvent(curTick + 1);
|
||||
}
|
||||
// Check if we're done draining once this list is empty
|
||||
if (drainList.empty()) {
|
||||
cache->checkDrain();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -451,17 +338,289 @@ BaseCache::regStats()
|
||||
.desc("number of cache copies performed")
|
||||
;
|
||||
|
||||
writebacks
|
||||
.init(maxThreadsPerCPU)
|
||||
.name(name() + ".writebacks")
|
||||
.desc("number of writebacks")
|
||||
.flags(total)
|
||||
;
|
||||
|
||||
// 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(maxThreadsPerCPU)
|
||||
.name(name() + "." + cstr + "_mshr_hits")
|
||||
.desc("number of " + cstr + " MSHR hits")
|
||||
.flags(total | nozero | nonan)
|
||||
;
|
||||
}
|
||||
|
||||
demandMshrHits
|
||||
.name(name() + ".demand_mshr_hits")
|
||||
.desc("number of demand (read+write) MSHR hits")
|
||||
.flags(total)
|
||||
;
|
||||
demandMshrHits = mshr_hits[MemCmd::ReadReq] + mshr_hits[MemCmd::WriteReq];
|
||||
|
||||
overallMshrHits
|
||||
.name(name() + ".overall_mshr_hits")
|
||||
.desc("number of overall MSHR hits")
|
||||
.flags(total)
|
||||
;
|
||||
overallMshrHits = demandMshrHits + mshr_hits[MemCmd::SoftPFReq] +
|
||||
mshr_hits[MemCmd::HardPFReq];
|
||||
|
||||
// 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(maxThreadsPerCPU)
|
||||
.name(name() + "." + cstr + "_mshr_misses")
|
||||
.desc("number of " + cstr + " MSHR misses")
|
||||
.flags(total | nozero | nonan)
|
||||
;
|
||||
}
|
||||
|
||||
demandMshrMisses
|
||||
.name(name() + ".demand_mshr_misses")
|
||||
.desc("number of demand (read+write) MSHR misses")
|
||||
.flags(total)
|
||||
;
|
||||
demandMshrMisses = mshr_misses[MemCmd::ReadReq] + mshr_misses[MemCmd::WriteReq];
|
||||
|
||||
overallMshrMisses
|
||||
.name(name() + ".overall_mshr_misses")
|
||||
.desc("number of overall MSHR misses")
|
||||
.flags(total)
|
||||
;
|
||||
overallMshrMisses = demandMshrMisses + mshr_misses[MemCmd::SoftPFReq] +
|
||||
mshr_misses[MemCmd::HardPFReq];
|
||||
|
||||
// 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(maxThreadsPerCPU)
|
||||
.name(name() + "." + cstr + "_mshr_miss_latency")
|
||||
.desc("number of " + cstr + " MSHR miss cycles")
|
||||
.flags(total | nozero | nonan)
|
||||
;
|
||||
}
|
||||
|
||||
demandMshrMissLatency
|
||||
.name(name() + ".demand_mshr_miss_latency")
|
||||
.desc("number of demand (read+write) MSHR miss cycles")
|
||||
.flags(total)
|
||||
;
|
||||
demandMshrMissLatency = mshr_miss_latency[MemCmd::ReadReq]
|
||||
+ mshr_miss_latency[MemCmd::WriteReq];
|
||||
|
||||
overallMshrMissLatency
|
||||
.name(name() + ".overall_mshr_miss_latency")
|
||||
.desc("number of overall MSHR miss cycles")
|
||||
.flags(total)
|
||||
;
|
||||
overallMshrMissLatency = demandMshrMissLatency +
|
||||
mshr_miss_latency[MemCmd::SoftPFReq] + mshr_miss_latency[MemCmd::HardPFReq];
|
||||
|
||||
// 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(maxThreadsPerCPU)
|
||||
.name(name() + "." + cstr + "_mshr_uncacheable")
|
||||
.desc("number of " + cstr + " MSHR uncacheable")
|
||||
.flags(total | nozero | nonan)
|
||||
;
|
||||
}
|
||||
|
||||
overallMshrUncacheable
|
||||
.name(name() + ".overall_mshr_uncacheable_misses")
|
||||
.desc("number of overall MSHR uncacheable misses")
|
||||
.flags(total)
|
||||
;
|
||||
overallMshrUncacheable = mshr_uncacheable[MemCmd::ReadReq]
|
||||
+ mshr_uncacheable[MemCmd::WriteReq] + mshr_uncacheable[MemCmd::SoftPFReq]
|
||||
+ mshr_uncacheable[MemCmd::HardPFReq];
|
||||
|
||||
// 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(maxThreadsPerCPU)
|
||||
.name(name() + "." + cstr + "_mshr_uncacheable_latency")
|
||||
.desc("number of " + cstr + " MSHR uncacheable cycles")
|
||||
.flags(total | nozero | nonan)
|
||||
;
|
||||
}
|
||||
|
||||
overallMshrUncacheableLatency
|
||||
.name(name() + ".overall_mshr_uncacheable_latency")
|
||||
.desc("number of overall MSHR uncacheable cycles")
|
||||
.flags(total)
|
||||
;
|
||||
overallMshrUncacheableLatency = mshr_uncacheable_lat[MemCmd::ReadReq]
|
||||
+ mshr_uncacheable_lat[MemCmd::WriteReq]
|
||||
+ mshr_uncacheable_lat[MemCmd::SoftPFReq]
|
||||
+ mshr_uncacheable_lat[MemCmd::HardPFReq];
|
||||
|
||||
#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];
|
||||
}
|
||||
|
||||
demandMshrMissRate
|
||||
.name(name() + ".demand_mshr_miss_rate")
|
||||
.desc("mshr miss rate for demand accesses")
|
||||
.flags(total)
|
||||
;
|
||||
demandMshrMissRate = demandMshrMisses / demandAccesses;
|
||||
|
||||
overallMshrMissRate
|
||||
.name(name() + ".overall_mshr_miss_rate")
|
||||
.desc("mshr miss rate for overall accesses")
|
||||
.flags(total)
|
||||
;
|
||||
overallMshrMissRate = overallMshrMisses / overallAccesses;
|
||||
|
||||
// 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];
|
||||
}
|
||||
|
||||
demandAvgMshrMissLatency
|
||||
.name(name() + ".demand_avg_mshr_miss_latency")
|
||||
.desc("average overall mshr miss latency")
|
||||
.flags(total)
|
||||
;
|
||||
demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses;
|
||||
|
||||
overallAvgMshrMissLatency
|
||||
.name(name() + ".overall_avg_mshr_miss_latency")
|
||||
.desc("average overall mshr miss latency")
|
||||
.flags(total)
|
||||
;
|
||||
overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses;
|
||||
|
||||
// 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];
|
||||
}
|
||||
|
||||
overallAvgMshrUncacheableLatency
|
||||
.name(name() + ".overall_avg_mshr_uncacheable_latency")
|
||||
.desc("average overall mshr uncacheable latency")
|
||||
.flags(total)
|
||||
;
|
||||
overallAvgMshrUncacheableLatency = overallMshrUncacheableLatency / overallMshrUncacheable;
|
||||
|
||||
mshr_cap_events
|
||||
.init(maxThreadsPerCPU)
|
||||
.name(name() + ".mshr_cap_events")
|
||||
.desc("number of times MSHR cap was activated")
|
||||
.flags(total)
|
||||
;
|
||||
|
||||
//software prefetching stats
|
||||
soft_prefetch_mshr_full
|
||||
.init(maxThreadsPerCPU)
|
||||
.name(name() + ".soft_prefetch_mshr_full")
|
||||
.desc("number of mshr full events for SW prefetching instrutions")
|
||||
.flags(total)
|
||||
;
|
||||
|
||||
mshr_no_allocate_misses
|
||||
.name(name() +".no_allocate_misses")
|
||||
.desc("Number of misses that were no-allocate")
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
unsigned int
|
||||
BaseCache::drain(Event *de)
|
||||
{
|
||||
int count = memSidePort->drain(de) + cpuSidePort->drain(de);
|
||||
|
||||
// Set status
|
||||
if (!canDrain()) {
|
||||
if (count != 0) {
|
||||
drainEvent = de;
|
||||
|
||||
changeState(SimObject::Draining);
|
||||
return 1;
|
||||
return count;
|
||||
}
|
||||
|
||||
changeState(SimObject::Drained);
|
||||
|
||||
Reference in New Issue
Block a user