cpu: Added new stats to TAGE and LTAGE branch predictors
authorPau Cabre <pau.cabre@metempsy.com>
Thu, 22 Nov 2018 13:48:30 +0000 (14:48 +0100)
committerPau Cabre <pau.cabre@metempsy.com>
Wed, 28 Nov 2018 17:25:50 +0000 (17:25 +0000)
They are basically used to tell wich component of the predictor is
providing the prediction and whether it is correct or wrong

Change-Id: I7b3db66535f159091f1b37d70c2d942d50b20fb2
Signed-off-by: Pau Cabre <pau.cabre@metempsy.com>
Reviewed-on: https://gem5-review.googlesource.com/c/14535
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Jason Lowe-Power <jason@lowepower.com>

src/cpu/pred/ltage.cc
src/cpu/pred/ltage.hh
src/cpu/pred/tage.cc
src/cpu/pred/tage.hh

index 3be01936e98b8a1b8af0b358897e4e165b211a6c..73f4777454f43ea63c0231c8c91683904ce1ac52 100644 (file)
@@ -228,6 +228,7 @@ LTAGE::predict(ThreadID tid, Addr branch_pc, bool cond_branch, void* &b)
 
         if ((loopUseCounter >= 0) && bi->loopPredValid) {
             pred_taken = bi->loopPred;
+            bi->provider = LOOP;
         }
         DPRINTF(LTage, "Predict for %lx: taken?:%d, loopTaken?:%d, "
                 "loopValid?:%d, loopUseCounter:%d, tagePred:%d, altPred:%d\n",
@@ -288,6 +289,43 @@ LTAGE::squash(ThreadID tid, void *bp_history)
     TAGE::squash(tid, bp_history);
 }
 
+
+void
+LTAGE::updateStats(bool taken, TageBranchInfo* bi)
+{
+    TAGE::updateStats(taken, bi);
+
+    LTageBranchInfo * ltage_bi = static_cast<LTageBranchInfo *>(bi);
+
+    if (ltage_bi->provider == LOOP) {
+        if (taken == ltage_bi->loopPred) {
+            loopPredictorCorrect++;
+        } else {
+            loopPredictorWrong++;
+        }
+    }
+}
+
+
+
+void
+LTAGE::regStats()
+{
+    TAGE::regStats();
+
+    loopPredictorCorrect
+        .name(name() + ".loopPredictorCorrect")
+        .desc("Number of times the loop predictor is the provider and "
+              "the prediction is correct");
+
+    loopPredictorWrong
+        .name(name() + ".loopPredictorWrong")
+        .desc("Number of times the loop predictor is the provier and "
+              "the prediction is wrong");
+}
+
+
+
 LTAGE*
 LTAGEParams::create()
 {
index d614026d218dd73352f726d6db4f7d3da99a436a..e9e34b75dd0ae6a4eb36a38bea61394f4c4f4d3e 100644 (file)
@@ -67,6 +67,8 @@ class LTAGE: public TAGE
     // Base class methods.
     void squash(ThreadID tid, void *bp_history) override;
 
+    void regStats() override;
+
   private:
     // Prediction Structures
     // Loop Predictor Entry
@@ -84,6 +86,11 @@ class LTAGE: public TAGE
                       confidence(0), tag(0), age(0), dir(0) { }
     };
 
+    // more provider types
+    enum {
+        LOOP = LAST_TAGE_PROVIDER_TYPE + 1
+    };
+
     // Primary branch history entry
     struct LTageBranchInfo : public TageBranchInfo
     {
@@ -177,6 +184,14 @@ class LTAGE: public TAGE
     void squash(
         ThreadID tid, bool taken, void *bp_history) override;
 
+    /**
+     * Update the stats
+     * @param taken Actual branch outcome
+     * @param bi Pointer to information on the prediction
+     * recorded at prediction time.
+     */
+    void updateStats(bool taken, TageBranchInfo* bi) override;
+
     const unsigned logSizeLoopPred;
     const unsigned loopTableAgeBits;
     const unsigned loopTableConfidenceBits;
@@ -191,6 +206,10 @@ class LTAGE: public TAGE
 
     int8_t loopUseCounter;
     unsigned withLoopBits;
+
+    // stats
+    Stats::Scalar loopPredictorCorrect;
+    Stats::Scalar loopPredictorWrong;
 };
 
 #endif // __CPU_PRED_LTAGE
index c22e6b7a55b3b0b457de6c6b054fcf0970023bc1..061f808e8fc78a5457d78be431990dd07fe08a04 100644 (file)
@@ -348,16 +348,19 @@ TAGE::tagePredict(ThreadID tid, Addr branch_pc,
             //if the entry is recognized as a newly allocated entry and
             //useAltPredForNewlyAllocated is positive use the alternate
             //prediction
-            if ((useAltPredForNewlyAllocated < 0)
-                   || abs(2 *
-                   gtable[bi->hitBank][tableIndices[bi->hitBank]].ctr + 1) > 1)
+            if ((useAltPredForNewlyAllocated < 0) || ! bi->pseudoNewAlloc) {
                 bi->tagePred = bi->longestMatchPred;
-            else
+                bi->provider = TAGE_LONGEST_MATCH;
+            } else {
                 bi->tagePred = bi->altTaken;
+                bi->provider = bi->altBank ? TAGE_ALT_MATCH
+                                           : BIMODAL_ALT_MATCH;
+            }
         } else {
             bi->altTaken = getBimodePred(pc, bi);
             bi->tagePred = bi->altTaken;
             bi->longestMatchPred = bi->altTaken;
+            bi->provider = BIMODAL_ONLY;
         }
         //end TAGE prediction
 
@@ -390,6 +393,7 @@ TAGE::update(ThreadID tid, Addr branch_pc, bool taken, void* bp_history,
     if (bi->condBranch) {
         DPRINTF(Tage, "Updating tables for branch:%lx; taken?:%d\n",
                 branch_pc, taken);
+        updateStats(taken, bi);
         condBranchUpdate(branch_pc, taken, bi, nrand);
     }
     if (!squashed) {
@@ -602,6 +606,119 @@ TAGE::uncondBranch(ThreadID tid, Addr br_pc, void* &bp_history)
            &threadHistory[tid].globalHistory[threadHistory[tid].ptGhist]);
 }
 
+void
+TAGE::updateStats(bool taken, TageBranchInfo* bi)
+{
+    if (taken == bi->tagePred) {
+        // correct prediction
+        switch (bi->provider) {
+          case BIMODAL_ONLY: tageBimodalProviderCorrect++; break;
+          case TAGE_LONGEST_MATCH: tageLongestMatchProviderCorrect++; break;
+          case BIMODAL_ALT_MATCH: bimodalAltMatchProviderCorrect++; break;
+          case TAGE_ALT_MATCH: tageAltMatchProviderCorrect++; break;
+        }
+    } else {
+        // wrong prediction
+        switch (bi->provider) {
+          case BIMODAL_ONLY: tageBimodalProviderWrong++; break;
+          case TAGE_LONGEST_MATCH:
+            tageLongestMatchProviderWrong++;
+            if (bi->altTaken == taken) {
+                tageAltMatchProviderWouldHaveHit++;
+            }
+            break;
+          case BIMODAL_ALT_MATCH:
+            bimodalAltMatchProviderWrong++;
+            break;
+          case TAGE_ALT_MATCH:
+            tageAltMatchProviderWrong++;
+            break;
+        }
+
+        switch (bi->provider) {
+          case BIMODAL_ALT_MATCH:
+          case TAGE_ALT_MATCH:
+            if (bi->longestMatchPred == taken) {
+                tageLongestMatchProviderWouldHaveHit++;
+            }
+        }
+    }
+
+    switch (bi->provider) {
+      case TAGE_LONGEST_MATCH:
+      case TAGE_ALT_MATCH:
+        tageLongestMatchProvider[bi->hitBank]++;
+        tageAltMatchProvider[bi->altBank]++;
+        break;
+    }
+}
+
+void
+TAGE::regStats()
+{
+    BPredUnit::regStats();
+
+    tageLongestMatchProviderCorrect
+        .name(name() + ".tageLongestMatchProviderCorrect")
+        .desc("Number of times TAGE Longest Match is the provider and "
+              "the prediction is correct");
+
+    tageAltMatchProviderCorrect
+        .name(name() + ".tageAltMatchProviderCorrect")
+        .desc("Number of times TAGE Alt Match is the provider and "
+              "the prediction is correct");
+
+    bimodalAltMatchProviderCorrect
+        .name(name() + ".bimodalAltMatchProviderCorrect")
+        .desc("Number of times TAGE Alt Match is the bimodal and it is the "
+              "provider and the prediction is correct");
+
+    tageBimodalProviderCorrect
+        .name(name() + ".tageBimodalProviderCorrect")
+        .desc("Number of times there are no hits on the TAGE tables "
+              "and the bimodal prediction is correct");
+
+    tageLongestMatchProviderWrong
+        .name(name() + ".tageLongestMatchProviderWrong")
+        .desc("Number of times TAGE Longest Match is the provider and "
+              "the prediction is wrong");
+
+    tageAltMatchProviderWrong
+        .name(name() + ".tageAltMatchProviderWrong")
+        .desc("Number of times TAGE Alt Match is the provider and "
+              "the prediction is wrong");
+
+    bimodalAltMatchProviderWrong
+        .name(name() + ".bimodalAltMatchProviderWrong")
+        .desc("Number of times TAGE Alt Match is the bimodal and it is the "
+              "provider and the prediction is wrong");
+
+    tageBimodalProviderWrong
+        .name(name() + ".tageBimodalProviderWrong")
+        .desc("Number of times there are no hits on the TAGE tables "
+              "and the bimodal prediction is wrong");
+
+    tageAltMatchProviderWouldHaveHit
+        .name(name() + ".tageAltMatchProviderWouldHaveHit")
+        .desc("Number of times TAGE Longest Match is the provider, "
+              "the prediction is wrong and Alt Match prediction was correct");
+
+    tageLongestMatchProviderWouldHaveHit
+        .name(name() + ".tageLongestMatchProviderWouldHaveHit")
+        .desc("Number of times TAGE Alt Match is the provider, the "
+              "prediction is wrong and Longest Match prediction was correct");
+
+    tageLongestMatchProvider
+        .init(nHistoryTables + 1)
+        .name(name() + ".tageLongestMatchProvider")
+        .desc("TAGE provider for longest match");
+
+    tageAltMatchProvider
+        .init(nHistoryTables + 1)
+        .name(name() + ".tageAltMatchProvider")
+        .desc("TAGE provider for alt match");
+}
+
 TAGE*
 TAGEParams::create()
 {
index 9ba02414cb02ad1cd3886249163f6211eabed33e..c66c28cb1bf4f51991a50257dbe34863f9572c1d 100644 (file)
@@ -71,6 +71,8 @@ class TAGE: public BPredUnit
     virtual void squash(ThreadID tid, void *bp_history) override;
     unsigned getGHR(ThreadID tid, void *bp_history) const override;
 
+    virtual void regStats() override;
+
   protected:
     // Prediction Structures
 
@@ -110,6 +112,15 @@ class TAGE: public BPredUnit
         }
     };
 
+    // provider type
+    enum {
+        BIMODAL_ONLY = 0,
+        TAGE_LONGEST_MATCH,
+        BIMODAL_ALT_MATCH,
+        TAGE_ALT_MATCH,
+        LAST_TAGE_PROVIDER_TYPE = TAGE_ALT_MATCH
+    };
+
     // Primary branch history entry
     struct TageBranchInfo
     {
@@ -141,6 +152,9 @@ class TAGE: public BPredUnit
         int *ct0;
         int *ct1;
 
+        // for stats purposes
+        unsigned provider;
+
         TageBranchInfo(int sz)
             : pathHist(0), ptGhist(0),
               hitBank(0), hitBankIndex(0),
@@ -148,7 +162,8 @@ class TAGE: public BPredUnit
               bimodalIndex(0),
               tagePred(false), altTaken(false),
               condBranch(false), longestMatchPred(false),
-              pseudoNewAlloc(false), branchPC(0)
+              pseudoNewAlloc(false), branchPC(0),
+              provider(-1)
         {
             storage = new int [sz * 5];
             tableIndices = storage;
@@ -320,6 +335,14 @@ class TAGE: public BPredUnit
     bool tagePredict(
         ThreadID tid, Addr branch_pc, bool cond_branch, TageBranchInfo* bi);
 
+    /**
+     * Update the stats
+     * @param taken Actual branch outcome
+     * @param bi Pointer to information on the prediction
+     * recorded at prediction time.
+     */
+    virtual void updateStats(bool taken, TageBranchInfo* bi);
+
     const unsigned logRatioBiModalHystEntries;
     const unsigned nHistoryTables;
     const unsigned tagTableCounterBits;
@@ -369,6 +392,21 @@ class TAGE: public BPredUnit
     uint64_t tCounter;
     uint64_t logUResetPeriod;
     unsigned useAltOnNaBits;
+
+    // stats
+    Stats::Scalar tageLongestMatchProviderCorrect;
+    Stats::Scalar tageAltMatchProviderCorrect;
+    Stats::Scalar bimodalAltMatchProviderCorrect;
+    Stats::Scalar tageBimodalProviderCorrect;
+    Stats::Scalar tageLongestMatchProviderWrong;
+    Stats::Scalar tageAltMatchProviderWrong;
+    Stats::Scalar bimodalAltMatchProviderWrong;
+    Stats::Scalar tageBimodalProviderWrong;
+    Stats::Scalar tageAltMatchProviderWouldHaveHit;
+    Stats::Scalar tageLongestMatchProviderWouldHaveHit;
+
+    Stats::Vector tageLongestMatchProvider;
+    Stats::Vector tageAltMatchProvider;
 };
 
 #endif // __CPU_PRED_TAGE