Daniel Carvalho has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/13835

Change subject: mem-cache: Fix and use blk->whenReady for latency calculation
......................................................................

mem-cache: Fix and use blk->whenReady for latency calculation

Add missing blk->whenReady sets by including them on the
access calculation function.

Use new block access latency calculation to determine
when the a block is ready to be accessed after a write
or read-modify-write. This includes the payload delay.

Change-Id: Idc2c9773d0b788c3b3190c6099694173d0be6f32
Signed-off-by: Daniel R. Carvalho <[email protected]>
---
M src/mem/cache/base.cc
M src/mem/cache/base.hh
M src/mem/cache/cache.cc
3 files changed, 99 insertions(+), 47 deletions(-)



diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc
index fdc6eb8..901ebea 100644
--- a/src/mem/cache/base.cc
+++ b/src/mem/cache/base.cc
@@ -360,13 +360,12 @@
         doWritebacks(writebacks, forward_time);
     }

-    // Here we charge the headerDelay that takes into account the latencies
+    // The latency charged is just the value calculated in access(), which
+ // includes the headerDelay. The latter takes into account the latencies
     // of the bus, if the packet comes from it.
- // The latency charged it is just lat that is the value of lookupLatency
-    // modified by access() function, or if not just lookupLatency.
     // In case of a hit we are neglecting response latency.
     // In case of a miss we are neglecting forward latency.
-    Tick request_time = clockEdge(lat) + pkt->headerDelay;
+    Tick request_time = clockEdge(lat);
     // Here we reset the timing of the packet.
     pkt->headerDelay = pkt->payloadDelay = 0;
     // track time of availability of next prefetch, if any
@@ -759,7 +758,8 @@
     }

     // Calculate read or read-modify-write latency
-    lat = calculateAccessLatency(blk, true, overwrite_mem);
+    lat = calculateAccessLatency(blk, true, overwrite_mem,
+        clockEdge() + pkt->headerDelay, pkt->payloadDelay);
 }

 QueueEntry*
@@ -878,7 +878,8 @@
             blk->status |= BlkDirty;

             // Calculate read-modify-write latency
-            lat = calculateAccessLatency(blk, true, true);
+            lat = calculateAccessLatency(blk, true, true,
+                clockEdge() + pkt->headerDelay, pkt->payloadDelay);
         } else {
             cmpAndSwap(blk, pkt, lat);
         }
@@ -893,7 +894,8 @@
             pkt->writeDataToBlock(blk->data, blkSize);

             // Calculate write latency
-            lat = calculateAccessLatency(blk, false, true);
+            lat = calculateAccessLatency(blk, false, true,
+                clockEdge() + pkt->headerDelay, pkt->payloadDelay);
         }
         // Always mark the line as dirty (and thus transition to the
         // Modified state) even if we are a failed StoreCond so we
@@ -911,7 +913,10 @@
         pkt->setDataFromBlock(blk->data, blkSize);

         // Calculate read latency
-        lat = calculateAccessLatency(blk, true, false);
+        lat = calculateAccessLatency(blk, true, false,
+            clockEdge() + pkt->headerDelay, pkt->payloadDelay);
+
+
     } else if (pkt->isUpgrade()) {
         // sanity check
         assert(!pkt->hasSharers());
@@ -939,41 +944,83 @@
 //
 /////////////////////////////////////////////////////
 Cycles
-BaseCache::calculateAccessLatency(const CacheBlk* blk, const bool is_read,
-                                  const bool is_write) const
+BaseCache::calculateAccessLatency(CacheBlk* blk, const bool is_read,
+                                  const bool is_write, const Tick tick,
+                                  const Tick payload_delay) const
 {
-    Cycles lat(lookupLatency);
+    Cycles lat(0);

     if (blk != nullptr) {
-        // Check if operation is a read
+        // Time to wait until block is available
+        Cycles ready_lat(0);
+
+        // Time to finish read access
+        Cycles read_lat(0);
+
+        // Time to finish write access
+        Cycles write_lat(0);
+
+ // Check if the block to be accessed is available on the access tick.
+        // If not, apply the access latency on top of block->whenReady.
+        if (blk->whenReady > tick) {
+            ready_lat = ticksToCycles(blk->whenReady - tick);
+        }
+
+        // Calculate read latency
         if (is_read) {
-            // First access tags, then data
+            // Check if it is a sequential or parallel access
             if (sequentialAccess) {
-                lat += dataLatency;
-            // Latency is dictated by the slowest of tag and data latencies
+ // In a sequential read, latency is the time to perform a tag
+                // lookup and then a data entry access
+                read_lat = lookupLatency + dataLatency;
             } else {
-                lat = std::max(lookupLatency, dataLatency);
+ // In a parallel read, latency is dictated by the slowest of
+                // tag and data latencies
+                read_lat = std::max(lookupLatency, dataLatency);
             }
         }

-        // Takes into account writes and read-modify-writes
+        // Calculate write latency
         if (is_write) {
-            // @todo Write latency is not added to the latency because this
-            // latency accounts just for the time to service a request. It
- // should, however, be used to update the block's whenReady tick.
-            // A write is always sequential
+            // A write is always sequential, and while the lookup is done
+            // in parallel with the payload arrival, the data can only be
+            // inserted after the payload is present
+ write_lat = std::max(lookupLatency, ticksToCycles(payload_delay)) +
+                                 fillLatency;
         }

- // Check if the block to be accessed is available. If not, apply the
-        // access latency on top of block->whenReady.
-        if (blk->whenReady > curTick()) {
-            lat += ticksToCycles(blk->whenReady - curTick());
+        // Calculate final latency, taking into account block availability
+        if (is_read) {
+            // Add the read latency to the final access latency. RMW is a
+            // special case that must wait until both read and write are
+            // done, so we include the write latency in the final latency
+            if (is_write) {
+                write_lat = std::max(read_lat, write_lat);
+                lat = ready_lat + write_lat;
+            } else {
+                lat = ready_lat + read_lat;
+            }
+        } else {
+ // For writes, the latency that delays the critical path is just
+            // the lookup latency
+            lat = ready_lat + lookupLatency;
+        }
+
+        // If dealing with a write, the off-critical path must be taken
+        // into account for subsequent accesses to the block. The block
+        // will be ready when the write has finished. The write latency,
+        // which includes the payload delay, is added on top of the time
+        // the block is requested to be accessed
+        if (is_write) {
+            blk->whenReady = tick + cyclesToTicks(ready_lat + write_lat);
         }
     } else {
// In case of a miss, latency is the tag lookup latency. For parallel
         // accesses, however, a read implies a data lookup
         if (!sequentialAccess && is_read) {
             lat = std::max(lookupLatency, dataLatency);
+        } else {
+            lat = lookupLatency;
         }
     }

@@ -997,9 +1044,11 @@

// Calculate access latency. This is a dummy value set for early exits, and // that will be overridden when appropriate (i.e., when the data is read or
-    // written).
+ // written). The is_write bit should not be set, otherwise whenReady would
+    // be updated twice.
     // @todo Is this safe to be substituted by a zero-value initialization?
-    lat = calculateAccessLatency(blk, pkt->isRead(), false);
+    lat = calculateAccessLatency(blk, pkt->isRead(), false,
+        clockEdge() + pkt->headerDelay, pkt->payloadDelay);

     DPRINTF(Cache, "%s for %s %s\n", __func__, pkt->print(),
             blk ? "hit " + blk->print() : "miss");
@@ -1096,13 +1145,11 @@
         pkt->writeDataToBlock(blk->data, blkSize);

         // Calculate write latency
-        lat = calculateAccessLatency(blk, false, true);
+        lat = calculateAccessLatency(blk, false, true,
+            clockEdge() + pkt->headerDelay, pkt->payloadDelay);

         DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print());
         incHitCount(pkt);
-        // populate the time when the block will be ready to access.
-        blk->whenReady = clockEdge(fillLatency) + pkt->headerDelay +
-            pkt->payloadDelay;
         return true;
     } else if (pkt->cmd == MemCmd::CleanEvict) {
         if (blk) {
@@ -1156,14 +1203,11 @@
         pkt->writeDataToBlock(blk->data, blkSize);

         // Calculate write latency
-        lat = calculateAccessLatency(blk, false, true);
+        lat = calculateAccessLatency(blk, false, true,
+            clockEdge() + pkt->headerDelay, pkt->payloadDelay);

         DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print());
-
         incHitCount(pkt);
-        // populate the time when the block will be ready to access.
-        blk->whenReady = clockEdge(fillLatency) + pkt->headerDelay +
-            pkt->payloadDelay;
         // if this a write-through packet it will be sent to cache
         // below
         return !pkt->writeThrough();
@@ -1183,7 +1227,8 @@
     incMissCount(pkt);

     // Get miss latency
-    lat = calculateAccessLatency(nullptr, pkt->isRead(), false);
+    lat = calculateAccessLatency(nullptr, pkt->isRead(), false,
+        clockEdge() + pkt->headerDelay, pkt->payloadDelay);

     if (!blk && pkt->isLLSC() && pkt->isWrite()) {
         // complete miss on store conditional... just give up now
@@ -1298,12 +1343,11 @@

         pkt->writeDataToBlock(blk->data, blkSize);

-        // @todo Use write latency.
-        Cycles M5_VAR_USED lat = calculateAccessLatency(blk, false, true);
+        // Calculate write latency and update ready time of block
+        // @todo Use write latency
+ const Cycles M5_VAR_USED lat = calculateAccessLatency(blk, false, true,
+            clockEdge() + pkt->headerDelay, pkt->payloadDelay);
     }
-    // We pay for fillLatency here.
-    blk->whenReady = clockEdge() + fillLatency * clockPeriod() +
-        pkt->payloadDelay;

     return blk;
 }
diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh
index be479a6..134612b 100644
--- a/src/mem/cache/base.hh
+++ b/src/mem/cache/base.hh
@@ -420,17 +420,24 @@
      * Calculate access latency in ticks based on the access type (read,
* write or read-modify-write), and whether using sequential or parallel * tag-data access. If both is_read and is_write are set, this is a RMW op. + * When dealing with writes, this functions updates the when ready time of
+     * the block according to the tick at which the write is finished.
+     * Read-Modify-Writes lock the block for the whole duration of the
+     * operation, therefore its latency includes writing to the block.
      * @todo Take into account the LSQ, which would be able to provide the
      *       desired data faster than having to access it in the tags
-     * @todo Take into account lock time for atomic operations
      *
      * @param blk The cache block that was accessed.
      * @param is_read Whether this access is a read.
      * @param is_write Whether this access is a write.
-     * @return The number of ticks that pass due to a block access.
+     * @param tick The Tick at which the packet arrived (without payload).
+     * @param payload_delay The extra ticks until the payload arrives
+     *                      (relevant for writes).
+     * @return The number of cycles needed to complete the block access.
      */
-    Cycles calculateAccessLatency(const CacheBlk* blk, const bool is_read,
-                                  const bool is_write) const;
+    Cycles calculateAccessLatency(CacheBlk* blk, const bool is_read,
+                                  const bool is_write, const Tick tick,
+                                  const Tick payload_delay) const;

     /**
      * Does all the processing necessary to perform the provided request.
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
index 323992f..1e13b10 100644
--- a/src/mem/cache/cache.cc
+++ b/src/mem/cache/cache.cc
@@ -183,7 +183,8 @@
         blk = nullptr;

// An uncacheable block's access latency is aliased as a miss latency
-        lat = calculateAccessLatency(blk, pkt->isRead(), false);
+        lat = calculateAccessLatency(blk, pkt->isRead(), false,
+            clockEdge() + pkt->headerDelay, pkt->payloadDelay);
         return false;
     }


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

Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: Idc2c9773d0b788c3b3190c6099694173d0be6f32
Gerrit-Change-Number: 13835
Gerrit-PatchSet: 1
Gerrit-Owner: Daniel Carvalho
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to