More cache fixes. Atomic coherence now works as well.

src/cpu/memtest/memtest.cc:
src/cpu/memtest/memtest.hh:
    Make Memtester able to test atomic as well
src/mem/bus.cc:
src/mem/bus.hh:
    Handle atomic snoops properly for cache->cache transfers
src/mem/cache/cache_impl.hh:
    Debug output.
    Clean up memleak in atomic mode.
    Set hitLatency.
    Still need to send back reasonable number for atomic return value.
src/mem/packet.cc:
    Add command strings for new commands
src/python/m5/objects/MemTest.py:
    Add param to test atomic memory.

--HG--
extra : convert_revision : 43f880e29215776167c16ea90793ebf8122c785b
This commit is contained in:
Ron Dreslinski 2006-10-11 18:28:33 -04:00
parent 03c42ea590
commit 567afbf6ce
7 changed files with 112 additions and 29 deletions

View file

@ -72,6 +72,9 @@ void
MemTest::CpuPort::recvFunctional(Packet *pkt) MemTest::CpuPort::recvFunctional(Packet *pkt)
{ {
//Do nothing if we see one come through //Do nothing if we see one come through
if (curTick != 0)//Supress warning durring initialization
warn("Functional Writes not implemented in MemTester\n");
//Need to find any response values that intersect and update
return; return;
} }
@ -90,6 +93,20 @@ MemTest::CpuPort::recvRetry()
memtest->doRetry(); memtest->doRetry();
} }
void
MemTest::sendPkt(Packet *pkt) {
if (atomic) {
cachePort.sendAtomic(pkt);
pkt->makeAtomicResponse();
completeRequest(pkt);
}
else if (!cachePort.sendTiming(pkt)) {
accessRetry = true;
retryPkt = pkt;
}
}
MemTest::MemTest(const string &name, MemTest::MemTest(const string &name,
// MemInterface *_cache_interface, // MemInterface *_cache_interface,
// PhysicalMemory *main_mem, // PhysicalMemory *main_mem,
@ -102,7 +119,8 @@ MemTest::MemTest(const string &name,
unsigned _percentSourceUnaligned, unsigned _percentSourceUnaligned,
unsigned _percentDestUnaligned, unsigned _percentDestUnaligned,
Addr _traceAddr, Addr _traceAddr,
Counter _max_loads) Counter _max_loads,
bool _atomic)
: MemObject(name), : MemObject(name),
tickEvent(this), tickEvent(this),
cachePort("test", this), cachePort("test", this),
@ -118,7 +136,8 @@ MemTest::MemTest(const string &name,
nextProgressMessage(_progressInterval), nextProgressMessage(_progressInterval),
percentSourceUnaligned(_percentSourceUnaligned), percentSourceUnaligned(_percentSourceUnaligned),
percentDestUnaligned(percentDestUnaligned), percentDestUnaligned(percentDestUnaligned),
maxLoads(_max_loads) maxLoads(_max_loads),
atomic(_atomic)
{ {
vector<string> cmd; vector<string> cmd;
cmd.push_back("/bin/ls"); cmd.push_back("/bin/ls");
@ -368,10 +387,7 @@ MemTest::tick()
completeRequest(pkt); completeRequest(pkt);
} else { } else {
// req->completionEvent = new MemCompleteEvent(req, result, this); // req->completionEvent = new MemCompleteEvent(req, result, this);
if (!cachePort.sendTiming(pkt)) { sendPkt(pkt);
accessRetry = true;
retryPkt = pkt;
}
} }
} else { } else {
// write // write
@ -406,13 +422,10 @@ MemTest::tick()
if (probe) { if (probe) {
cachePort.sendFunctional(pkt); cachePort.sendFunctional(pkt);
// completeRequest(req, NULL); completeRequest(pkt);
} else { } else {
// req->completionEvent = new MemCompleteEvent(req, NULL, this); // req->completionEvent = new MemCompleteEvent(req, NULL, this);
if (!cachePort.sendTiming(pkt)) { sendPkt(pkt);
accessRetry = true;
retryPkt = pkt;
}
} }
} }
/* else { /* else {
@ -484,6 +497,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest)
Param<unsigned> percent_dest_unaligned; Param<unsigned> percent_dest_unaligned;
Param<Addr> trace_addr; Param<Addr> trace_addr;
Param<Counter> max_loads; Param<Counter> max_loads;
Param<bool> atomic;
END_DECLARE_SIM_OBJECT_PARAMS(MemTest) END_DECLARE_SIM_OBJECT_PARAMS(MemTest)
@ -503,7 +517,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest)
INIT_PARAM(percent_dest_unaligned, INIT_PARAM(percent_dest_unaligned,
"percent of copy dest address that are unaligned"), "percent of copy dest address that are unaligned"),
INIT_PARAM(trace_addr, "address to trace"), INIT_PARAM(trace_addr, "address to trace"),
INIT_PARAM(max_loads, "terminate when we have reached this load count") INIT_PARAM(max_loads, "terminate when we have reached this load count"),
INIT_PARAM(atomic, "Is the tester testing atomic mode (or timing)")
END_INIT_SIM_OBJECT_PARAMS(MemTest) END_INIT_SIM_OBJECT_PARAMS(MemTest)
@ -514,7 +529,7 @@ CREATE_SIM_OBJECT(MemTest)
/*check_mem,*/ memory_size, percent_reads, /*percent_copies,*/ /*check_mem,*/ memory_size, percent_reads, /*percent_copies,*/
percent_uncacheable, progress_interval, percent_uncacheable, progress_interval,
percent_source_unaligned, percent_dest_unaligned, percent_source_unaligned, percent_dest_unaligned,
trace_addr, max_loads); trace_addr, max_loads, atomic);
} }
REGISTER_SIM_OBJECT("MemTest", MemTest) REGISTER_SIM_OBJECT("MemTest", MemTest)

View file

@ -61,7 +61,8 @@ class MemTest : public MemObject
unsigned _percentSourceUnaligned, unsigned _percentSourceUnaligned,
unsigned _percentDestUnaligned, unsigned _percentDestUnaligned,
Addr _traceAddr, Addr _traceAddr,
Counter _max_loads); Counter _max_loads,
bool _atomic);
virtual void init(); virtual void init();
@ -175,6 +176,9 @@ class MemTest : public MemObject
uint64_t numReads; uint64_t numReads;
uint64_t maxLoads; uint64_t maxLoads;
bool atomic;
Stats::Scalar<> numReadsStat; Stats::Scalar<> numReadsStat;
Stats::Scalar<> numWritesStat; Stats::Scalar<> numWritesStat;
Stats::Scalar<> numCopiesStat; Stats::Scalar<> numCopiesStat;
@ -182,6 +186,8 @@ class MemTest : public MemObject
// called by MemCompleteEvent::process() // called by MemCompleteEvent::process()
void completeRequest(Packet *pkt); void completeRequest(Packet *pkt);
void sendPkt(Packet *pkt);
void doRetry(); void doRetry();
friend class MemCompleteEvent; friend class MemCompleteEvent;

View file

@ -293,16 +293,22 @@ Bus::findSnoopPorts(Addr addr, int id)
return ports; return ports;
} }
void Tick
Bus::atomicSnoop(Packet *pkt) Bus::atomicSnoop(Packet *pkt)
{ {
std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc()); std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
Tick response_time = 0;
while (!ports.empty()) while (!ports.empty())
{ {
interfaces[ports.back()]->sendAtomic(pkt); Tick response = interfaces[ports.back()]->sendAtomic(pkt);
if (response) {
assert(!response_time); //Multiple responders
response_time = response;
}
ports.pop_back(); ports.pop_back();
} }
return response_time;
} }
void void
@ -341,8 +347,11 @@ Bus::recvAtomic(Packet *pkt)
DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
assert(pkt->getDest() == Packet::Broadcast); assert(pkt->getDest() == Packet::Broadcast);
atomicSnoop(pkt); Tick snoopTime = atomicSnoop(pkt);
return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt); if (snoopTime)
return snoopTime; //Snoop satisfies it
else
return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt);
} }
/** Function called by the port when the bus is receiving a Functional /** Function called by the port when the bus is receiving a Functional

View file

@ -107,7 +107,7 @@ class Bus : public MemObject
std::vector<int> findSnoopPorts(Addr addr, int id); std::vector<int> findSnoopPorts(Addr addr, int id);
/** Snoop all relevant ports atomicly. */ /** Snoop all relevant ports atomicly. */
void atomicSnoop(Packet *pkt); Tick atomicSnoop(Packet *pkt);
/** Snoop all relevant ports functionally. */ /** Snoop all relevant ports functionally. */
void functionalSnoop(Packet *pkt); void functionalSnoop(Packet *pkt);

View file

@ -100,7 +100,7 @@ doAtomicAccess(Packet *pkt, bool isCpuSide)
if (pkt->isResponse()) if (pkt->isResponse())
handleResponse(pkt); handleResponse(pkt);
else else
snoopProbe(pkt); return snoopProbe(pkt);
} }
//Fix this timing info //Fix this timing info
return hitLatency; return hitLatency;
@ -148,7 +148,8 @@ Cache(const std::string &_name,
prefetchAccess(params.prefetchAccess), prefetchAccess(params.prefetchAccess),
tags(params.tags), missQueue(params.missQueue), tags(params.tags), missQueue(params.missQueue),
coherence(params.coherence), prefetcher(params.prefetcher), coherence(params.coherence), prefetcher(params.prefetcher),
doCopy(params.doCopy), blockOnCopy(params.blockOnCopy) doCopy(params.doCopy), blockOnCopy(params.blockOnCopy),
hitLatency(params.hitLatency)
{ {
//FIX BUS POINTERS //FIX BUS POINTERS
// if (params.in == NULL) { // if (params.in == NULL) {
@ -284,8 +285,9 @@ Cache<TagStore,Buffering,Coherence>::sendResult(PacketPtr &pkt, MSHR* mshr, bool
BlkType *blk = tags->findBlock(pkt); BlkType *blk = tags->findBlock(pkt);
CacheBlk::State old_state = (blk) ? blk->status : 0; CacheBlk::State old_state = (blk) ? blk->status : 0;
CacheBlk::State new_state = coherence->getNewState(pkt,old_state); CacheBlk::State new_state = coherence->getNewState(pkt,old_state);
DPRINTF(Cache, "Block for blk addr %x moving from state %i to %i\n", if (old_state != new_state)
pkt->getAddr() & (((ULL(1))<<48)-1), old_state, new_state); DPRINTF(Cache, "Block for blk addr %x moving from state %i to %i\n",
pkt->getAddr() & (((ULL(1))<<48)-1), old_state, new_state);
//Set the state on the upgrade //Set the state on the upgrade
memcpy(pkt->getPtr<uint8_t>(), blk->data, blkSize); memcpy(pkt->getPtr<uint8_t>(), blk->data, blkSize);
PacketList writebacks; PacketList writebacks;
@ -324,8 +326,9 @@ Cache<TagStore,Buffering,Coherence>::handleResponse(Packet * &pkt)
CacheBlk::State old_state = (blk) ? blk->status : 0; CacheBlk::State old_state = (blk) ? blk->status : 0;
PacketList writebacks; PacketList writebacks;
CacheBlk::State new_state = coherence->getNewState(pkt,old_state); CacheBlk::State new_state = coherence->getNewState(pkt,old_state);
DPRINTF(Cache, "Block for blk addr %x moving from state %i to %i\n", if (old_state != new_state)
pkt->getAddr() & (((ULL(1))<<48)-1), old_state, new_state); DPRINTF(Cache, "Block for blk addr %x moving from state %i to %i\n",
pkt->getAddr() & (((ULL(1))<<48)-1), old_state, new_state);
blk = tags->handleFill(blk, (MSHR*)pkt->senderState, blk = tags->handleFill(blk, (MSHR*)pkt->senderState,
new_state, writebacks, pkt); new_state, writebacks, pkt);
while (!writebacks.empty()) { while (!writebacks.empty()) {
@ -531,6 +534,10 @@ Cache<TagStore,Buffering,Coherence>::probe(Packet * &pkt, bool update, CachePort
int lat; int lat;
BlkType *blk = tags->handleAccess(pkt, lat, writebacks, update); BlkType *blk = tags->handleAccess(pkt, lat, writebacks, update);
DPRINTF(Cache, "%s %x %s blk_addr: %x\n", pkt->cmdString(),
pkt->getAddr() & (((ULL(1))<<48)-1), (blk) ? "hit" : "miss",
pkt->getAddr() & ~((Addr)blkSize - 1));
if (!blk) { if (!blk) {
// Need to check for outstanding misses and writes // Need to check for outstanding misses and writes
Addr blk_addr = pkt->getAddr() & ~(blkSize - 1); Addr blk_addr = pkt->getAddr() & ~(blkSize - 1);
@ -637,6 +644,11 @@ Cache<TagStore,Buffering,Coherence>::probe(Packet * &pkt, bool update, CachePort
busPkt->time = curTick; busPkt->time = curTick;
DPRINTF(Cache, "Sending a atomic %s for %x blk_addr: %x\n",
busPkt->cmdString(),
busPkt->getAddr() & (((ULL(1))<<48)-1),
busPkt->getAddr() & ~((Addr)blkSize - 1));
lat = memSidePort->sendAtomic(busPkt); lat = memSidePort->sendAtomic(busPkt);
//Be sure to flip the response to a request for coherence //Be sure to flip the response to a request for coherence
@ -652,13 +664,26 @@ Cache<TagStore,Buffering,Coherence>::probe(Packet * &pkt, bool update, CachePort
*/ misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; */ misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
CacheBlk::State old_state = (blk) ? blk->status : 0; CacheBlk::State old_state = (blk) ? blk->status : 0;
CacheBlk::State new_state = coherence->getNewState(busPkt, old_state);
DPRINTF(Cache, "Receive response:%s for blk addr %x in state %i\n",
busPkt->cmdString(),
busPkt->getAddr() & (((ULL(1))<<48)-1), old_state);
if (old_state != new_state)
DPRINTF(Cache, "Block for blk addr %x moving from state %i to %i\n",
busPkt->getAddr() & (((ULL(1))<<48)-1), old_state, new_state);
tags->handleFill(blk, busPkt, tags->handleFill(blk, busPkt,
coherence->getNewState(busPkt, old_state), new_state,
writebacks, pkt); writebacks, pkt);
//Free the packet
delete busPkt;
// Handle writebacks if needed // Handle writebacks if needed
while (!writebacks.empty()){ while (!writebacks.empty()){
memSidePort->sendAtomic(writebacks.front()); Packet *wbPkt = writebacks.front();
memSidePort->sendAtomic(wbPkt);
writebacks.pop_front(); writebacks.pop_front();
delete wbPkt;
} }
return lat + hitLatency; return lat + hitLatency;
} else { } else {
@ -679,7 +704,7 @@ Cache<TagStore,Buffering,Coherence>::probe(Packet * &pkt, bool update, CachePort
// Still need to change data in all locations. // Still need to change data in all locations.
otherSidePort->sendFunctional(pkt); otherSidePort->sendFunctional(pkt);
} }
return curTick + lat; return hitLatency;
} }
fatal("Probe not handled.\n"); fatal("Probe not handled.\n");
return 0; return 0;

View file

@ -39,9 +39,18 @@
static const std::string ReadReqString("ReadReq"); static const std::string ReadReqString("ReadReq");
static const std::string WriteReqString("WriteReq"); static const std::string WriteReqString("WriteReq");
static const std::string WriteReqNoAckString("WriteReqNoAck"); static const std::string WriteReqNoAckString("WriteReqNoAck|Writeback");
static const std::string ReadRespString("ReadResp"); static const std::string ReadRespString("ReadResp");
static const std::string WriteRespString("WriteResp"); static const std::string WriteRespString("WriteResp");
static const std::string SoftPFReqString("SoftPFReq");
static const std::string SoftPFRespString("SoftPFResp");
static const std::string HardPFReqString("HardPFReq");
static const std::string HardPFRespString("HardPFResp");
static const std::string InvalidateReqString("InvalidateReq");
static const std::string WriteInvalidateReqString("WriteInvalidateReq");
static const std::string UpgradeReqString("UpgradeReq");
static const std::string ReadExReqString("ReadExReq");
static const std::string ReadExRespString("ReadExResp");
static const std::string OtherCmdString("<other>"); static const std::string OtherCmdString("<other>");
const std::string & const std::string &
@ -53,6 +62,15 @@ Packet::cmdString() const
case WriteReqNoAck: return WriteReqNoAckString; case WriteReqNoAck: return WriteReqNoAckString;
case ReadResp: return ReadRespString; case ReadResp: return ReadRespString;
case WriteResp: return WriteRespString; case WriteResp: return WriteRespString;
case SoftPFReq: return SoftPFReqString;
case SoftPFResp: return SoftPFRespString;
case HardPFReq: return HardPFReqString;
case HardPFResp: return HardPFRespString;
case InvalidateReq: return InvalidateReqString;
case WriteInvalidateReq:return WriteInvalidateReqString;
case UpgradeReq: return UpgradeReqString;
case ReadExReq: return ReadExReqString;
case ReadExResp: return ReadExRespString;
default: return OtherCmdString; default: return OtherCmdString;
} }
} }
@ -66,6 +84,15 @@ Packet::cmdIdxToString(Packet::Command idx)
case WriteReqNoAck: return WriteReqNoAckString; case WriteReqNoAck: return WriteReqNoAckString;
case ReadResp: return ReadRespString; case ReadResp: return ReadRespString;
case WriteResp: return WriteRespString; case WriteResp: return WriteRespString;
case SoftPFReq: return SoftPFReqString;
case SoftPFResp: return SoftPFRespString;
case HardPFReq: return HardPFReqString;
case HardPFResp: return HardPFRespString;
case InvalidateReq: return InvalidateReqString;
case WriteInvalidateReq:return WriteInvalidateReqString;
case UpgradeReq: return UpgradeReqString;
case ReadExReq: return ReadExReqString;
case ReadExResp: return ReadExRespString;
default: return OtherCmdString; default: return OtherCmdString;
} }
} }

View file

@ -6,6 +6,7 @@ from m5 import build_env
class MemTest(SimObject): class MemTest(SimObject):
type = 'MemTest' type = 'MemTest'
max_loads = Param.Counter("number of loads to execute") max_loads = Param.Counter("number of loads to execute")
atomic = Param.Bool(False, "Execute tester in atomic mode? (or timing)\n")
memory_size = Param.Int(65536, "memory size") memory_size = Param.Int(65536, "memory size")
percent_dest_unaligned = Param.Percent(50, percent_dest_unaligned = Param.Percent(50,
"percent of copy dest address that are unaligned") "percent of copy dest address that are unaligned")