mem-cache: Allow moving data contractions
authorDaniel R. Carvalho <odanrc@yahoo.com.br>
Mon, 17 Jun 2019 15:41:09 +0000 (17:41 +0200)
committerDaniel Carvalho <odanrc@yahoo.com.br>
Thu, 12 Nov 2020 21:46:43 +0000 (21:46 +0000)
Data contractions happen when a block passes from a less compressed
(e.g., uncompressed) to a more compressed (e.g., compressed) state.

Some compaction methods enforce that a block can only be allocated
in a location matches an exact compression factor, thus on data
contractions such blocks must be moved to another location, or
they must be padded to fake a bigger size.

For compaction methods that do not have that limitation, performance
can be improved if the contracted block is moved to co-allocate with
another existing entry, since it frees up an entry.

Change-Id: I302bc561b897f9d3ce1426331fe4b5c2df76f4b5
Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/36578
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/mem/cache/Cache.py
src/mem/cache/base.cc
src/mem/cache/base.hh

index 149f48542f62d867e8f19510409f535706ef153a..a99d549c05b4517c608d9759de0304b6a73ef36c 100644 (file)
@@ -105,6 +105,11 @@ class BaseCache(ClockedObject):
     compressor = Param.BaseCacheCompressor(NULL, "Cache compressor.")
     replace_expansions = Param.Bool(True, "Apply replacement policy to " \
         "decide which blocks should be evicted on a data expansion")
+    # When a block passes from uncompressed to compressed, it may become
+    # co-allocatable with another existing entry of the same superblock,
+    # so try move the block to co-allocate it
+    move_contractions = Param.Bool(True, "Try to co-allocate blocks that "
+        "contract")
 
     sequential_access = Param.Bool(False,
         "Whether to access tags and data sequentially")
index b128b5c334734556e1d850cd337d15db202bffef..78e3f3e360ff35c72ef24c2fbce7f14835d1555e 100644 (file)
@@ -100,6 +100,7 @@ BaseCache::BaseCache(const BaseCacheParams &p, unsigned blk_size)
       clusivity(p.clusivity),
       isReadOnly(p.is_read_only),
       replaceExpansions(p.replace_expansions),
+      moveContractions(p.move_contractions),
       blocked(0),
       order(0),
       noTargetMSHR(nullptr),
@@ -862,15 +863,31 @@ BaseCache::updateCompressionData(CacheBlk *&blk, const uint64_t* data,
     const bool is_co_allocatable = superblock->isCompressed(compression_blk) &&
         superblock->canCoAllocate(compression_size);
 
-    // If block was compressed, possibly co-allocated with other blocks, and
-    // cannot be co-allocated anymore, one or more blocks must be evicted to
-    // make room for the expanded block
+    // If compressed size didn't change enough to modify its co-allocatability
+    // there is nothing to do. Otherwise we may be facing a data expansion
+    // (block passing from more compressed to less compressed state), or a
+    // data contraction (less to more).
     const bool was_compressed = compression_blk->isCompressed();
+    bool is_data_expansion = false;
+    bool is_data_contraction = false;
+    string op_name = "";
     if (was_compressed && !is_co_allocatable) {
+        is_data_expansion = true;
+        op_name = "expansion";
+    } else if (moveContractions && !was_compressed && is_co_allocatable) {
+        is_data_contraction = true;
+        op_name = "contraction";
+    }
+
+    // If block changed compression state, it was possibly co-allocated with
+    // other blocks and cannot be co-allocated anymore, so one or more blocks
+    // must be evicted to make room for the expanded/contracted block
+    std::vector<CacheBlk*> evict_blks;
+    if (is_data_expansion || is_data_contraction) {
         std::vector<CacheBlk*> evict_blks;
         bool victim_itself = false;
         CacheBlk *victim = nullptr;
-        if (replaceExpansions) {
+        if (replaceExpansions || is_data_contraction) {
             victim = tags->findVictim(regenerateBlkAddr(blk),
                 blk->isSecure(), compression_size, evict_blks);
 
@@ -889,8 +906,8 @@ BaseCache::updateCompressionData(CacheBlk *&blk, const uint64_t* data,
             }
 
             // Print victim block's information
-            DPRINTF(CacheRepl, "Data expansion replacement victim: %s\n",
-                victim->print());
+            DPRINTF(CacheRepl, "Data %s replacement victim: %s\n",
+                op_name, victim->print());
         } else {
             // If we do not move the expanded block, we must make room for
             // the expansion to happen, so evict every co-allocated block
@@ -908,12 +925,10 @@ BaseCache::updateCompressionData(CacheBlk *&blk, const uint64_t* data,
             return false;
         }
 
-        // Update the number of data expansions
-        stats.dataExpansions++;
-        DPRINTF(CacheComp, "Data expansion: expanding [%s] from %d to %d bits"
-                "\n", blk->print(), prev_size, compression_size);
+        DPRINTF(CacheComp, "Data %s: [%s] from %d to %d bits\n",
+                op_name, blk->print(), prev_size, compression_size);
 
-        if (!victim_itself && replaceExpansions) {
+        if (!victim_itself && (replaceExpansions || is_data_contraction)) {
             // Move the block's contents to the invalid block so that it now
             // co-allocates with the other existing superblock entry
             tags->moveBlock(blk, victim);
@@ -922,15 +937,27 @@ BaseCache::updateCompressionData(CacheBlk *&blk, const uint64_t* data,
         }
     }
 
-    // We always store compressed blocks when possible
-    if (is_co_allocatable) {
-        compression_blk->setCompressed();
-    } else {
-        compression_blk->setUncompressed();
+    // Update the number of data expansions/contractions
+    if (is_data_expansion) {
+        stats.dataExpansions++;
+    } else if (is_data_contraction) {
+        stats.dataContractions++;
     }
+
     compression_blk->setSizeBits(compression_size);
     compression_blk->setDecompressionLatency(decompression_lat);
 
+    if (is_data_expansion || is_data_contraction) {
+        // If contracting data, for sure data is compressed. If expanding,
+        // both situations can arise. When no contraction or expansion happens
+        // block keeps its old state
+        if (is_co_allocatable) {
+            compression_blk->setCompressed();
+        } else {
+            compression_blk->setUncompressed();
+        }
+    }
+
     return true;
 }
 
@@ -2088,6 +2115,7 @@ BaseCache::CacheStats::CacheStats(BaseCache &c)
     replacements(this, "replacements", "number of replacements"),
 
     dataExpansions(this, "data_expansions", "number of data expansions"),
+    dataContractions(this, "data_contractions", "number of data contractions"),
     cmd(MemCmd::NUM_MEM_CMDS)
 {
     for (int idx = 0; idx < MemCmd::NUM_MEM_CMDS; ++idx)
@@ -2307,6 +2335,7 @@ BaseCache::CacheStats::regStats()
     }
 
     dataExpansions.flags(nozero | nonan);
+    dataContractions.flags(nozero | nonan);
 }
 
 void
index 62c2953f2adc975a42d632e2c25c00d931be09da..8dad1b7f74903f9442c794942092d58bf86805ad 100644 (file)
@@ -901,6 +901,14 @@ class BaseCache : public ClockedObject
      */
     const bool replaceExpansions;
 
+    /**
+     * Similar to data expansions, after a block improves its compression,
+     * it may need to be moved elsewhere compatible with the new compression
+     * factor, or, if not required by the compaction method, it may be moved
+     * to co-allocate with an existing block and thus free an entry.
+     */
+    const bool moveContractions;
+
     /**
      * Bit vector of the blocking reasons for the access path.
      * @sa #BlockedCause
@@ -1074,6 +1082,12 @@ class BaseCache : public ClockedObject
         /** Number of data expansions. */
         Stats::Scalar dataExpansions;
 
+        /**
+         * Number of data contractions (blocks that had their compression
+         * factor improved).
+         */
+        Stats::Scalar dataContractions;
+
         /** Per-command statistics */
         std::vector<std::unique_ptr<CacheCmdStats>> cmd;
     } stats;