Giacomo Travaglini has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/52124 )

Change subject: arch-arm: Allow TLB to be used as a WalkCache
......................................................................

arch-arm: Allow TLB to be used as a WalkCache

This patch allows partial translation entries (intermediate PAs obtained
from a table walk) to be stored in an ArmTLB. This effectively means
reserving a fraction of the TLB entries to cache table walks

JIRA: https://gem5.atlassian.net/browse/GEM5-1108

Change-Id: Id0efb7d75dd017366c4c3b74de7b57355a53a01a
Signed-off-by: Giacomo Travaglini <[email protected]>
---
M src/arch/arm/ArmTLB.py
M src/arch/arm/mmu.cc
M src/arch/arm/mmu.hh
M src/arch/arm/tlb.cc
M src/arch/arm/tlb.hh
5 files changed, 185 insertions(+), 37 deletions(-)



diff --git a/src/arch/arm/ArmTLB.py b/src/arch/arm/ArmTLB.py
index 4c86f72..10ed48b 100644
--- a/src/arch/arm/ArmTLB.py
+++ b/src/arch/arm/ArmTLB.py
@@ -51,6 +51,11 @@
     size = Param.Int(64, "TLB size")
     is_stage2 = Param.Bool(False, "Is this a stage 2 TLB?")

+    partial_levels = VectorParam.ArmLookupLevel([],
+ "List of intermediate lookup levels allowed to be cached in the TLB "
+        "(=holding intermediate PAs obtained during a table walk")
+
+
 class ArmStage2TLB(ArmTLB):
     size = 32
     is_stage2 = True
diff --git a/src/arch/arm/mmu.cc b/src/arch/arm/mmu.cc
index ce052f1..6b6d10c 100644
--- a/src/arch/arm/mmu.cc
+++ b/src/arch/arm/mmu.cc
@@ -65,7 +65,7 @@
     test(nullptr),
     miscRegContext(0),
     s1State(this, false), s2State(this, true),
-    _attr(0),
+    _attr(0), _hasWalkCache(false),
     stats(this)
 {
     // Cache system-level properties
@@ -101,6 +101,27 @@
     getDTBPtr()->setTableWalker(dtbWalker);

     BaseMMU::init();
+
+    _hasWalkCache = checkWalkCache();
+}
+
+bool
+MMU::checkWalkCache() const
+{
+    for (auto tlb : instruction) {
+        if (static_cast<TLB*>(tlb)->walkCache())
+            return true;
+    }
+    for (auto tlb : data) {
+        if (static_cast<TLB*>(tlb)->walkCache())
+            return true;
+    }
+    for (auto tlb : unified) {
+        if (static_cast<TLB*>(tlb)->walkCache())
+            return true;
+    }
+
+    return false;
 }

 void
diff --git a/src/arch/arm/mmu.hh b/src/arch/arm/mmu.hh
index 2d0ef7b..7fa8210 100644
--- a/src/arch/arm/mmu.hh
+++ b/src/arch/arm/mmu.hh
@@ -342,6 +342,8 @@
         _attr = attr;
     }

+    bool hasWalkCache() const { return _hasWalkCache; }
+
     /**
      * Determine the EL to use for the purpose of a translation given
      * a specific translation type. If the translation type doesn't
@@ -423,6 +425,13 @@
                    LookupLevel lookup_level, CachedState &state);

   protected:
+    bool checkWalkCache() const;
+
+    CachedState& updateMiscReg(
+        ThreadContext *tc, ArmTranslationType tran_type,
+        bool stage2);
+
+  protected:
     ContextID miscRegContext;

   public:
@@ -439,9 +448,7 @@

     AddrRange m5opRange;

-    CachedState& updateMiscReg(
-        ThreadContext *tc, ArmTranslationType tran_type,
-        bool stage2);
+    bool _hasWalkCache;

     struct Stats : public statistics::Group
     {
diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc
index e2897f8..a7c3f12 100644
--- a/src/arch/arm/tlb.cc
+++ b/src/arch/arm/tlb.cc
@@ -61,9 +61,33 @@
 TLB::TLB(const ArmTLBParams &p)
     : BaseTLB(p), table(new TlbEntry[p.size]), size(p.size),
       isStage2(p.is_stage2),
+      _walkCache(false),
       tableWalker(nullptr),
       stats(*this), rangeMRU(1), vmid(0)
 {
+    for (int lvl = LookupLevel::L0;
+         lvl < LookupLevel::Num_ArmLookupLevel; lvl++) {
+
+        auto it = std::find(
+            p.partial_levels.begin(),
+            p.partial_levels.end(),
+            lvl);
+
+        auto lookup_lvl = static_cast<LookupLevel>(lvl);
+
+        if (it != p.partial_levels.end()) {
+            // A partial entry from of the current LookupLevel can be
+            // cached within the TLB
+            partialLevels[lookup_lvl] = true;
+
+            // Make sure this is not the last level (complete translation)
+            if (lvl != LookupLevel::Num_ArmLookupLevel - 1) {
+                _walkCache = true;
+            }
+        } else {
+            partialLevels[lookup_lvl] = false;
+        }
+    }
 }

 TLB::~TLB()
@@ -79,32 +103,63 @@
 }

 TlbEntry*
-TLB::lookup(const Lookup &lookup_data)
+TLB::match(const Lookup &lookup_data)
 {
-    TlbEntry *retval = NULL;
-    const auto functional = lookup_data.functional;
-    const auto mode = lookup_data.mode;
+    // Vector of TLB entry candidates.
+    // Only one of them will be assigned to retval and will
+    // be returned to the MMU (in case of a hit)
+    // The vector has one entry per lookup level as it stores
+    // both complete and partial matches
+    std::vector<std::pair<int, const TlbEntry*>> hits{
+        LookupLevel::Num_ArmLookupLevel, {0, nullptr}};

-    // Maintaining LRU array
     int x = 0;
-    while (retval == NULL && x < size) {
+    while (x < size) {
         if (table[x].match(lookup_data)) {
-            // We only move the hit entry ahead when the position is higher
-            // than rangeMRU
-            if (x > rangeMRU && !functional) {
-                TlbEntry tmp_entry = table[x];
-                for (int i = x; i > 0; i--)
-                    table[i] = table[i - 1];
-                table[0] = tmp_entry;
-                retval = &table[0];
-            } else {
-                retval = &table[x];
-            }
-            break;
+            const TlbEntry &entry = table[x];
+            hits[entry.lookupLevel] = std::make_pair(x, &entry);
+
+            // This is a complete translation, no need to loop further
+            if (!entry.partial)
+                break;
         }
         ++x;
     }

+    // Loop over the list of TLB entries matching our translation
+    // request, starting from the highest lookup level (complete
+    // translation) and iterating backwards (using reverse iterators)
+    for (auto it = hits.rbegin(); it != hits.rend(); it++) {
+        const auto& [idx, entry] = *it;
+        if (!entry) {
+            // No match for the current LookupLevel
+            continue;
+        }
+
+        // Maintaining LRU array
+        // We only move the hit entry ahead when the position is higher
+        // than rangeMRU
+        if (idx > rangeMRU && !lookup_data.functional) {
+            TlbEntry tmp_entry = *entry;
+            for (int i = idx; i > 0; i--)
+                table[i] = table[i - 1];
+            table[0] = tmp_entry;
+            return &table[0];
+        } else {
+            return &table[idx];
+        }
+    }
+
+    return nullptr;
+}
+
+TlbEntry*
+TLB::lookup(const Lookup &lookup_data)
+{
+    const auto mode = lookup_data.mode;
+
+    TlbEntry *retval = match(lookup_data);
+
DPRINTF(TLBVerbose, "Lookup %#x, asn %#x -> %s vmn 0x%x hyp %d secure %d "
             "ppn %#x size: %#x pa: %#x ap:%d ns:%d nstid:%d g:%d asid: %d "
             "el: %d\n",
@@ -118,21 +173,27 @@
             retval ? retval->el        : 0);

     // Updating stats if this was not a functional lookup
-    if (!functional) {
+    if (!lookup_data.functional) {
         if (!retval) {
-            if (mode == BaseMMU::Execute)
+            if (mode == BaseMMU::Execute) {
                 stats.instMisses++;
-            else if (mode == BaseMMU::Write)
+            } else if (mode == BaseMMU::Write) {
                 stats.writeMisses++;
-            else
+            } else {
                 stats.readMisses++;
+            }
         } else {
-            if (mode == BaseMMU::Execute)
+            if (retval->partial) {
+                stats.partialHits++;
+            }
+
+            if (mode == BaseMMU::Execute) {
                 stats.instHits++;
-            else if (mode == BaseMMU::Write)
+            } else if (mode == BaseMMU::Write) {
                stats.writeHits++;
-            else
+            } else {
                 stats.readHits++;
+            }
         }
     }

@@ -149,8 +210,13 @@
     } else {
         if (auto tlb = static_cast<TLB*>(nextLevel())) {
             te = tlb->multiLookup(lookup_data);
-            if (te && !lookup_data.functional)
+            if (te && !lookup_data.functional &&
+                (!te->partial || partialLevels[te->lookupLevel])) {
+                // Insert entry only if this is not a functional
+                // lookup and if the translation is complete (unless this
+                // TLB caches partial translations)
                 insert(*te);
+            }
         }
     }

@@ -203,7 +269,11 @@
 void
 TLB::multiInsert(TlbEntry &entry)
 {
-    insert(entry);
+    // Insert a partial translation only if the TLB is configured
+    // as a walk cache
+    if (!entry.partial || partialLevels[entry.lookupLevel]) {
+        insert(entry);
+    }

     if (auto next_level = static_cast<TLB*>(nextLevel())) {
         next_level->multiInsert(entry);
@@ -233,9 +303,11 @@
     while (x < size) {
         te = &table[x];

-        DPRINTF(TLB, " -  %s\n", te->print());
-        te->valid = false;
-        stats.flushedEntries++;
+        if (te->valid) {
+            DPRINTF(TLB, " -  %s\n", te->print());
+            te->valid = false;
+            stats.flushedEntries++;
+        }
         ++x;
     }

@@ -559,6 +631,8 @@

 TLB::TlbStats::TlbStats(TLB &parent)
   : statistics::Group(&parent), tlb(parent),
+    ADD_STAT(partialHits, statistics::units::Count::get(),
+             "partial translation hits"),
     ADD_STAT(instHits, statistics::units::Count::get(), "Inst hits"),
     ADD_STAT(instMisses, statistics::units::Count::get(), "Inst misses"),
     ADD_STAT(readHits, statistics::units::Count::get(), "Read hits"),
@@ -615,6 +689,8 @@
         readAccesses.flags(statistics::nozero);
         writeAccesses.flags(statistics::nozero);
     }
+
+    partialHits.flags(statistics::nozero);
 }

 void
diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh
index 8eb7d01..40ad76c 100644
--- a/src/arch/arm/tlb.hh
+++ b/src/arch/arm/tlb.hh
@@ -115,9 +115,25 @@
 class TLB : public BaseTLB
 {
   protected:
-    TlbEntry* table;     // the Page Table
-    int size;            // TLB Size
- bool isStage2; // Indicates this TLB is part of the second stage MMU
+    TlbEntry* table;
+
+    /** TLB Size */
+    int size;
+
+    /** Indicates this TLB caches IPA->PA translations */
+    bool isStage2;
+
+    /**
+     * Hash map containing one entry per lookup level
+     * The TLB is caching partial translations from the key lookup level
+     * if the matching value is true.
+     */
+    std::unordered_map<enums::ArmLookupLevel, bool> partialLevels;
+
+    /**
+     * True if the TLB caches partial translations
+     */
+    bool _walkCache;

     TableWalker *tableWalker;

@@ -128,6 +144,7 @@
         const TLB &tlb;

         // Access Stats
+        mutable statistics::Scalar partialHits;
         mutable statistics::Scalar instHits;
         mutable statistics::Scalar instMisses;
         mutable statistics::Scalar readHits;
@@ -186,6 +203,8 @@

     int getsize() const { return size; }

+    bool walkCache() const { return _walkCache; }
+
     void setVMID(vmid_t _vmid) { vmid = _vmid; }

     /** Insert a PTE in the current TLB */
@@ -313,6 +332,10 @@
      * data access or a data TLB entry on an instruction access:
      */
     void checkPromotion(TlbEntry *entry, BaseMMU::Mode mode);
+
+    /** Helper function looking up for a matching TLB entry
+     * Does not update stats; see lookup method instead */
+    TlbEntry *match(const Lookup &lookup_data);
 };

 } // namespace ArmISA

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/52124
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: Id0efb7d75dd017366c4c3b74de7b57355a53a01a
Gerrit-Change-Number: 52124
Gerrit-PatchSet: 1
Gerrit-Owner: Giacomo Travaglini <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to