mem: per-thread cache occupancy and per-block ages
authorDam Sunwoo <dam.sunwoo@arm.com>
Fri, 24 Jan 2014 21:29:30 +0000 (15:29 -0600)
committerDam Sunwoo <dam.sunwoo@arm.com>
Fri, 24 Jan 2014 21:29:30 +0000 (15:29 -0600)
This patch enables tracking of cache occupancy per thread along with
ages (in buckets) per cache blocks.  Cache occupancy stats are
recalculated on each stat dump.

15 files changed:
src/arch/arm/table_walker.cc
src/arch/arm/tlb.cc
src/cpu/base_dyn_inst.hh
src/cpu/o3/fetch_impl.hh
src/cpu/simple/atomic.cc
src/cpu/simple/timing.cc
src/dev/dma_device.cc
src/mem/cache/blk.hh
src/mem/cache/cache_impl.hh
src/mem/cache/prefetch/base.cc
src/mem/cache/tags/base.cc
src/mem/cache/tags/base.hh
src/mem/cache/tags/lru.cc
src/mem/cache/tags/lru.hh
src/mem/request.hh

index 9755299ffa0ba7c8a856453a740c37f1292acf9f..d419fdec5b80e110b56315a989f4cc8f4b78cbeb 100644 (file)
@@ -308,6 +308,7 @@ TableWalker::processWalk()
         f = currState->fault;
     } else {
         RequestPtr req = new Request(l1desc_addr, sizeof(uint32_t), flag, masterId);
+        req->taskId(ContextSwitchTaskId::DMA);
         PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
         pkt->dataStatic((uint8_t*)&currState->l1Desc.data);
         port.sendFunctional(pkt);
@@ -653,6 +654,7 @@ TableWalker::doL1Descriptor()
         } else {
             RequestPtr req = new Request(l2desc_addr, sizeof(uint32_t), 0,
                                          masterId);
+            req->taskId(ContextSwitchTaskId::DMA);
             PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
             pkt->dataStatic((uint8_t*)&currState->l2Desc.data);
             port.sendFunctional(pkt);
index 107901f99801050a58540f94771f6119682b1482..8058985766d58e4f277cbd63348aa40e6fa641e4 100644 (file)
@@ -54,6 +54,7 @@
 #include "base/inifile.hh"
 #include "base/str.hh"
 #include "base/trace.hh"
+#include "cpu/base.hh"
 #include "cpu/thread_context.hh"
 #include "debug/Checkpoint.hh"
 #include "debug/TLB.hh"
@@ -477,6 +478,8 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
     if (is_priv)
         req->setFlags(Request::PRIVILEGED);
 
+    req->taskId(tc->getCpuPtr()->taskId());
+
     DPRINTF(TLBVerbose, "CPSR is priv:%d UserMode:%d\n",
             isPriv, flags & UserMode);
     // If this is a clrex instruction, provide a PA of 0 with no fault
index b7b0768203d585fb98fedb02a1a102c0215626c3..f12a89bbd614eba600e722f2c2509b9c15436398 100644 (file)
@@ -890,6 +890,8 @@ BaseDynInst<Impl>::readMem(Addr addr, uint8_t *data,
         req = new Request(asid, addr, size, flags, masterId(), this->pc.instAddr(),
                           thread->contextId(), threadNumber);
 
+        req->taskId(cpu->taskId());
+
         // Only split the request if the ISA supports unaligned accesses.
         if (TheISA::HasUnalignedMemAcc) {
             splitRequest(req, sreqLow, sreqHigh);
@@ -953,6 +955,8 @@ BaseDynInst<Impl>::writeMem(uint8_t *data, unsigned size,
         req = new Request(asid, addr, size, flags, masterId(), this->pc.instAddr(),
                           thread->contextId(), threadNumber);
 
+        req->taskId(cpu->taskId());
+
         // Only split the request if the ISA supports unaligned accesses.
         if (TheISA::HasUnalignedMemAcc) {
             splitRequest(req, sreqLow, sreqHigh);
index 5b04c2a253b49d549226a030a001b8041f0b719a..a81125da6c580f7ed96bb70ec0db208dd34925da 100644 (file)
@@ -604,6 +604,8 @@ DefaultFetch<Impl>::fetchCacheLine(Addr vaddr, ThreadID tid, Addr pc)
                     Request::INST_FETCH, cpu->instMasterId(), pc,
                     cpu->thread[tid]->contextId(), tid);
 
+    mem_req->taskId(cpu->taskId());
+
     memReq[tid] = mem_req;
 
     // Initiate translation of the icache block
index 13c4b9bd3c77c78e905f2c68ffa3e3e0cfb69fcf..617e845a550b2c417ad602419bcd2a9c3305897c 100644 (file)
@@ -301,6 +301,7 @@ AtomicSimpleCPU::readMem(Addr addr, uint8_t * data,
 
     dcache_latency = 0;
 
+    req->taskId(taskId());
     while (1) {
         req->setVirt(0, addr, size, flags, dataMasterId(), thread->pcState().instAddr());
 
@@ -387,6 +388,7 @@ AtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
 
     dcache_latency = 0;
 
+    req->taskId(taskId());
     while(1) {
         req->setVirt(0, addr, size, flags, dataMasterId(), thread->pcState().instAddr());
 
@@ -492,6 +494,7 @@ AtomicSimpleCPU::tick()
         bool needToFetch = !isRomMicroPC(pcState.microPC()) &&
                            !curMacroStaticInst;
         if (needToFetch) {
+            ifetch_req.taskId(taskId());
             setupFetchRequest(&ifetch_req);
             fault = thread->itb->translateAtomic(&ifetch_req, tc,
                                                  BaseTLB::Execute);
index 9253d8005fe5f3613ff356affa050da1ac54e632..7996a6ddd96a6131213bddf60ab85e3ac4c8eb65 100644 (file)
@@ -415,6 +415,8 @@ TimingSimpleCPU::readMem(Addr addr, uint8_t *data,
     RequestPtr req  = new Request(asid, addr, size,
                                   flags, dataMasterId(), pc, _cpuId, tid);
 
+    req->taskId(taskId());
+
     Addr split_addr = roundDown(addr + size - 1, block_size);
     assert(split_addr <= addr || split_addr - addr < block_size);
 
@@ -484,6 +486,8 @@ TimingSimpleCPU::writeMem(uint8_t *data, unsigned size,
     RequestPtr req = new Request(asid, addr, size,
                                  flags, dataMasterId(), pc, _cpuId, tid);
 
+    req->taskId(taskId());
+
     Addr split_addr = roundDown(addr + size - 1, block_size);
     assert(split_addr <= addr || split_addr - addr < block_size);
 
@@ -561,6 +565,7 @@ TimingSimpleCPU::fetch()
     if (needToFetch) {
         _status = BaseSimpleCPU::Running;
         Request *ifetch_req = new Request();
+        ifetch_req->taskId(taskId());
         ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
         setupFetchRequest(ifetch_req);
         DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr());
index 5eb5e1f9d2ef36255de9470e06537bbd71d8c322..5033c36175dad401dd8f5640b0e98083ceb91842 100644 (file)
@@ -166,6 +166,7 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
     for (ChunkGenerator gen(addr, size, sys->cacheLineSize());
          !gen.done(); gen.next()) {
         Request *req = new Request(gen.addr(), gen.size(), flag, masterId);
+        req->taskId(ContextSwitchTaskId::DMA);
         PacketPtr pkt = new Packet(req, cmd);
 
         // Increment the data pointer on a write
index 4a89f3892ffd87849470eaf86a68ea35f9172b3d..47cd305c068a9a254638f2f0988aca86546131c5 100644 (file)
@@ -80,6 +80,9 @@ enum CacheBlkStatusBits {
 class CacheBlk
 {
   public:
+    /** Task Id associated with this block */
+    uint32_t task_id;
+
     /** The address space ID of this block. */
     int asid;
     /** Data block tag value. */
@@ -119,6 +122,8 @@ class CacheBlk
     /** holds the source requestor ID for this block. */
     int srcMasterId;
 
+    Tick tickInserted;
+
   protected:
     /**
      * Represents that the indicated thread context has a "lock" on
@@ -162,9 +167,11 @@ class CacheBlk
   public:
 
     CacheBlk()
-        : asid(-1), tag(0), data(0) ,size(0), status(0), whenReady(0),
+        : task_id(ContextSwitchTaskId::Unknown),
+          asid(-1), tag(0), data(0) ,size(0), status(0), whenReady(0),
           set(-1), isTouched(false), refCount(0),
-          srcMasterId(Request::invldMasterId)
+          srcMasterId(Request::invldMasterId),
+          tickInserted(0)
     {}
 
     /**
@@ -182,6 +189,7 @@ class CacheBlk
         whenReady = rhs.whenReady;
         set = rhs.set;
         refCount = rhs.refCount;
+        task_id = rhs.task_id;
         return *this;
     }
 
index 6d70118199a94c0b79e68285cc274eb6f035ce8d..e86b3d704951adb0515dc40032e581ac196f39df 100644 (file)
@@ -1074,6 +1074,11 @@ Cache<TagStore>::writebackBlk(BlkType *blk)
     Request *writebackReq =
         new Request(tags->regenerateBlkAddr(blk->tag, blk->set), blkSize, 0,
                 Request::wbMasterId);
+
+    writebackReq->taskId(blk->task_id);
+    blk->task_id= ContextSwitchTaskId::Unknown;
+    blk->tickInserted = curTick();
+
     PacketPtr writeback = new Packet(writebackReq, MemCmd::Writeback);
     if (blk->isWritable()) {
         writeback->setSupplyExclusive();
@@ -1120,6 +1125,7 @@ Cache<TagStore>::writebackVisitor(BlkType &blk)
 
         Request request(tags->regenerateBlkAddr(blk.tag, blk.set),
                         blkSize, 0, Request::funcMasterId);
+        request.taskId(blk.task_id);
 
         Packet packet(&request, MemCmd::WriteReq);
         packet.dataStatic(blk.data);
index 6463f78f84e60bc90956f2e4ccd99eed373ccb1c..ed7b63f82589a5f5fcb1a1881bc481a63c85fe0a 100644 (file)
@@ -247,6 +247,7 @@ BasePrefetcher::notify(PacketPtr &pkt, Tick tick)
 
             // create a prefetch memreq
             Request *prefetchReq = new Request(*addrIter, blkSize, 0, masterId);
+            prefetchReq->taskId(ContextSwitchTaskId::Prefetcher);
             PacketPtr prefetch =
                 new Packet(prefetchReq, MemCmd::HardPFReq);
             prefetch->allocate();
index 947bd05dedeb74340237f16b14a71759696bf21d..b669a5b06491dd5b1771ca3a63532eca4f51a53b 100644 (file)
@@ -125,5 +125,28 @@ BaseTags::regStats()
 
     avgOccs = occupancies / Stats::constant(numBlocks);
 
+    occupanciesTaskId
+        .init(ContextSwitchTaskId::NumTaskId)
+        .name(name() + ".occ_task_id_blocks")
+        .desc("Occupied blocks per task id")
+        .flags(nozero | nonan)
+        ;
+
+    ageTaskId
+        .init(ContextSwitchTaskId::NumTaskId, 5)
+        .name(name() + ".age_task_id_blocks")
+        .desc("Occupied blocks per task id")
+        .flags(nozero | nonan)
+        ;
+
+    percentOccsTaskId
+        .name(name() + ".occ_task_id_percent")
+        .desc("Percentage of cache occupancy per task id")
+        .flags(nozero)
+        ;
+
+    percentOccsTaskId = occupanciesTaskId / Stats::constant(numBlocks);
+
+    registerDumpCallback(new BaseTagsDumpCallback(this));
     registerExitCallback(new BaseTagsCallback(this));
 }
index 8ce7d972ab80ac358558c6072b3668331f545564..e8c71f01f858cdffe1a96e85834ed947c0f9df17 100644 (file)
@@ -121,6 +121,15 @@ class BaseTags : public ClockedObject
     /** Average occ % of each requestor using the cache */
     Stats::Formula avgOccs;
 
+    /** Occupancy of each context/cpu using the cache */
+    Stats::Vector occupanciesTaskId;
+
+    /** Occupancy of each context/cpu using the cache */
+    Stats::Vector2d ageTaskId;
+
+    /** Occ % of each context/cpu using the cache */
+    Stats::Formula percentOccsTaskId;
+
     /**
      * @}
      */
@@ -151,6 +160,11 @@ class BaseTags : public ClockedObject
      */
     virtual void cleanupRefs() {}
 
+    /**
+     * Computes stats just prior to dump event
+     */
+    virtual void computeStats() {}
+
     /**
      *iterated through all blocks and clear all locks
      *Needed to clear all lock tracking at once
@@ -171,4 +185,12 @@ class BaseTagsCallback : public Callback
     virtual void process() { tags->cleanupRefs(); };
 };
 
+class BaseTagsDumpCallback : public Callback
+{
+    BaseTags *tags;
+  public:
+    BaseTagsDumpCallback(BaseTags *t) : tags(t) {}
+    virtual void process() { tags->computeStats(); };
+};
+
 #endif //__BASE_TAGS_HH__
index db0cc083995d18eb857bdfff26bb01eb05b36dfd..6b05744af08aa0b00efa1007be0edf0de7c3e2ff 100644 (file)
@@ -176,6 +176,7 @@ LRU::insertBlock(PacketPtr pkt, BlkType *blk)
 {
     Addr addr = pkt->getAddr();
     MasterID master_id = pkt->req->masterId();
+    uint32_t task_id = pkt->req->taskId();
     if (!blk->isTouched) {
         tagsInUse++;
         blk->isTouched = true;
@@ -210,6 +211,8 @@ LRU::insertBlock(PacketPtr pkt, BlkType *blk)
     assert(master_id < cache->system->maxMasters());
     occupancies[master_id]++;
     blk->srcMasterId = master_id;
+    blk->task_id = task_id;
+    blk->tickInserted = curTick();
 
     unsigned set = extractSet(addr);
     sets[set].moveToHead(blk);
@@ -224,6 +227,8 @@ LRU::invalidate(BlkType *blk)
     assert(blk->srcMasterId < cache->system->maxMasters());
     occupancies[blk->srcMasterId]--;
     blk->srcMasterId = Request::invldMasterId;
+    blk->task_id = ContextSwitchTaskId::Unknown;
+    blk->tickInserted = curTick();
 
     // should be evicted before valid blocks
     unsigned set = blk->set;
@@ -270,3 +275,38 @@ LRU::cleanupRefs()
         }
     }
 }
+
+void
+LRU::computeStats()
+{
+    for (unsigned i = 0; i < ContextSwitchTaskId::NumTaskId; ++i) {
+        occupanciesTaskId[i] = 0;
+        for (unsigned j = 0; j < 5; ++j) {
+            ageTaskId[i][j] = 0;
+        }
+    }
+
+    for (unsigned i = 0; i < numSets * assoc; ++i) {
+        if (blks[i].isValid()) {
+            assert(blks[i].task_id < ContextSwitchTaskId::NumTaskId);
+            occupanciesTaskId[blks[i].task_id]++;
+            Tick age = curTick() - blks[i].tickInserted;
+            assert(age >= 0);
+
+            int age_index;
+            if (age / SimClock::Int::us < 10) { // <10us
+                age_index = 0;
+            } else if (age / SimClock::Int::us < 100) { // <100us
+                age_index = 1;
+            } else if (age / SimClock::Int::ms < 1) { // <1ms
+                age_index = 2;
+            } else if (age / SimClock::Int::ms < 10) { // <10ms
+                age_index = 3;
+            } else
+                age_index = 4; // >10ms
+
+            ageTaskId[blks[i].task_id][age_index]++;
+        }
+    }
+}
+
index af7f8665d227b03d31f8f8c89f661f3782f79659..68c29b754f7548cba2371bd10fedeb28bcae6333 100644 (file)
@@ -252,6 +252,11 @@ public:
      */
     virtual std::string print() const;
 
+    /**
+     * Called prior to dumping stats to compute task occupancy
+     */
+    virtual void computeStats();
+
     /**
      * Visit each block in the tag store and apply a visitor to the
      * block.
index 54b671645cccffb1fba835490f807bd9be235988..fb21e3ff3886ca7bf47a615bed37196b6717034d 100644 (file)
@@ -219,6 +219,11 @@ class Request
      */
     Tick _time;
 
+    /**
+     * The task id associated with this request
+     */
+    uint32_t _taskId;
+
     /** The address space ID. */
     int _asid;
 
@@ -244,7 +249,8 @@ class Request
      *  default constructor.)
      */
     Request()
-        : translateDelta(0), accessDelta(0), depth(0)
+        : _taskId(ContextSwitchTaskId::Unknown),
+        translateDelta(0), accessDelta(0), depth(0)
     {}
 
     /**
@@ -253,16 +259,19 @@ class Request
      * These fields are adequate to perform a request. 
      */
     Request(Addr paddr, int size, Flags flags, MasterID mid)
+        : _taskId(ContextSwitchTaskId::Unknown)
     {
         setPhys(paddr, size, flags, mid);
     }
 
     Request(Addr paddr, int size, Flags flags, MasterID mid, Tick time)
+        : _taskId(ContextSwitchTaskId::Unknown)
     {
         setPhys(paddr, size, flags, mid, time);
     }
 
     Request(Addr paddr, int size, Flags flags, MasterID mid, Tick time, Addr pc)
+        : _taskId(ContextSwitchTaskId::Unknown)
     {
         setPhys(paddr, size, flags, mid, time);
         privateFlags.set(VALID_PC);
@@ -271,6 +280,7 @@ class Request
 
     Request(int asid, Addr vaddr, int size, Flags flags, MasterID mid, Addr pc,
             int cid, ThreadID tid)
+        : _taskId(ContextSwitchTaskId::Unknown)
     {
         setVirt(asid, vaddr, size, flags, mid, pc);
         setThreadContext(cid, tid);
@@ -477,6 +487,17 @@ class Request
         return _masterId;
     }
 
+    uint32_t
+    taskId() const
+    {
+        return _taskId;
+    }
+
+    void
+    taskId(uint32_t id) {
+        _taskId = id;
+    }
+
     /** Accessor function for asid.*/
     int
     getAsid()