Daniel Carvalho has uploaded this change for review. (
https://gem5-review.googlesource.com/9741
Change subject: mem-cache: Create Sector Cache
......................................................................
mem-cache: Create Sector Cache
Implementation of Sector Caches, i.e., a cache with multiple data
entries per tag entry.
Change-Id: I8e1e9448fa44ba308ccb16cd5bcc5fd36c988feb
---
M src/mem/cache/Cache.py
M src/mem/cache/SConscript
M src/mem/cache/blk.hh
M src/mem/cache/cache.cc
A src/mem/cache/sector_blk.cc
A src/mem/cache/sector_blk.hh
M src/mem/cache/tags/SConscript
M src/mem/cache/tags/Tags.py
M src/mem/cache/tags/base.cc
M src/mem/cache/tags/base.hh
M src/mem/cache/tags/base_set_assoc.cc
M src/mem/cache/tags/base_set_assoc.hh
M src/mem/cache/tags/cacheset.hh
M src/mem/cache/tags/fa_lru.cc
M src/mem/cache/tags/fa_lru.hh
A src/mem/cache/tags/sector_tags.cc
A src/mem/cache/tags/sector_tags.hh
17 files changed, 870 insertions(+), 51 deletions(-)
diff --git a/src/mem/cache/Cache.py b/src/mem/cache/Cache.py
index faee092..657be53 100644
--- a/src/mem/cache/Cache.py
+++ b/src/mem/cache/Cache.py
@@ -75,7 +75,7 @@
prefetch_on_access = Param.Bool(False,
"Notify the hardware prefetcher on every access (not just
misses)")
- tags = Param.BaseTags(BaseSetAssoc(), "Tag store")
+ tags = Param.BaseTags(SectorTags(), "Tag store")
replacement_policy = Param.BaseReplacementPolicy(LRURP(),
"Replacement policy")
diff --git a/src/mem/cache/SConscript b/src/mem/cache/SConscript
index 1c9b002..5547024 100644
--- a/src/mem/cache/SConscript
+++ b/src/mem/cache/SConscript
@@ -37,6 +37,7 @@
Source('blk.cc')
Source('mshr.cc')
Source('mshr_queue.cc')
+Source('sector_blk.cc')
Source('write_queue.cc')
Source('write_queue_entry.cc')
diff --git a/src/mem/cache/blk.hh b/src/mem/cache/blk.hh
index 83807b7..dc3c523 100644
--- a/src/mem/cache/blk.hh
+++ b/src/mem/cache/blk.hh
@@ -73,9 +73,11 @@
BlkSecure = 0x40,
};
+class SectorBlk;
+
/**
* A Basic Cache block.
- * Contains the tag, status, and a pointer to data.
+ * Contains a pointer to its tag, its status, and a pointer to its data.
*/
class CacheBlk
{
@@ -83,8 +85,23 @@
/** Task Id associated with this block */
uint32_t task_id;
- /** Data block tag value. */
- Addr tag;
+ /**
+ * Data block tag pointer.
+ * A block may share its tag with many other blocks when used
compressed
+ * or sectored caches.
+ * @sa BaseSetAssoc
+ */
+ std::shared_ptr<Addr> tag;
+
+ /**
+ * Sector block associated to this block.
+ * @sa SectorTags
+ */
+ SectorBlk* secBlk;
+
+ /** Copy of the block's address, for debugging reasons. */
+ Addr addr;
+
/**
* Contains a copy of the data in this block for easy access. This is
used
* for efficient execution when the data could be actually stored in
@@ -104,10 +121,10 @@
Tick whenReady;
/**
- * The set and way this block belongs to.
+ * The set, way and sector offset this block belongs to.
* @todo Move this into subclasses when we fix CacheTags to use them.
*/
- int set, way;
+ int set, way, sectorOffset;
/** holds the source requestor ID for this block. */
int srcMasterId;
@@ -116,7 +133,7 @@
* Replacement data associated to this block.
* It is instantiated by the replacement policy.
*/
- std::unique_ptr<ReplacementData> replacementData;
+ std::shared_ptr<ReplacementData> replacementData;
protected:
/**
@@ -161,8 +178,7 @@
std::list<Lock> lockList;
public:
-
- CacheBlk()
+ CacheBlk() : tag(nullptr), secBlk(nullptr)
{
invalidate();
}
@@ -197,7 +213,7 @@
* Checks that a block is valid.
* @return True if the block is valid.
*/
- bool isValid() const
+ virtual bool isValid() const
{
return (status & BlkValid) != 0;
}
@@ -207,7 +223,11 @@
*/
virtual void invalidate()
{
- tag = MaxAddr;
+ // The first invalidate is called before a tag is instantiated by
tags
+ if (tag) {
+ *tag = MaxAddr;
+ }
+
task_id = ContextSwitchTaskId::Unknown;
status = 0;
whenReady = MaxTick;
@@ -251,6 +271,19 @@
}
/**
+ * Check if block corresponds to given tag. For a match to happen, the
+ * must be valid and belong to the same secure space.
+ *
+ * @param The tag to be matched.
+ * @param is_secure True if the target memory space is secure.
+ * @return True if block matches tag.
+ */
+ bool match(const Addr tag, const bool is_secure) const
+ {
+ return (*(this->tag) == tag) && isValid() && (isSecure() ==
is_secure);
+ }
+
+ /**
* Track the fact that a local locked was issued to the
* block. Invalidate any previous LL to the same address.
*/
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
index 28c4343..f1b4c42 100644
--- a/src/mem/cache/cache.cc
+++ b/src/mem/cache/cache.cc
@@ -80,6 +80,7 @@
{
tempBlock = new CacheBlk();
tempBlock->data = new uint8_t[blkSize];
+ tempBlock->tag = std::unique_ptr<Addr>(new Addr());
cpuSidePort = new CpuSidePort(p->name + ".cpu_side", this,
"CpuSidePort");
@@ -1815,26 +1816,36 @@
Cache::allocateBlock(Addr addr, bool is_secure, PacketList &writebacks)
{
// Find replacement victim
- CacheBlk *blk = tags->findVictim(addr);
+ std::vector<CacheBlk*> evictBlks;
+ CacheBlk *victim = tags->findVictim(addr, evictBlks);
// It is valid to return nullptr if there is no victim
- if (!blk)
+ if (!victim)
return nullptr;
- if (blk->isValid()) {
- Addr repl_addr = tags->regenerateBlkAddr(blk);
- MSHR *repl_mshr = mshrQueue.findMatch(repl_addr, blk->isSecure());
- if (repl_mshr) {
- // must be an outstanding upgrade or clean request
- // on a block we're about to replace...
- assert((!blk->isWritable() && repl_mshr->needsWritable()) ||
- repl_mshr->isCleaning());
- // too hard to replace block with transient state
- // allocation failed, block not inserted
- return nullptr;
- } else {
+ // Check for transient state allocations
+ for (const auto& blk : evictBlks){
+ if (blk->isValid()) {
+ Addr repl_addr = tags->regenerateBlkAddr(blk);
+ MSHR *repl_mshr = mshrQueue.findMatch(repl_addr,
blk->isSecure());
+ if (repl_mshr) {
+ // must be an outstanding upgrade or clean request
+ // on a block we're about to replace...
+ assert((!blk->isWritable() && repl_mshr->needsWritable()) |
|
+ repl_mshr->isCleaning());
+ // too hard to replace block with transient state
+ // allocation failed, block not inserted
+ return nullptr;
+ }
+ }
+ }
+
+ // Evict valid blocks associated to this victim block
+ for (const auto& blk : evictBlks){
+ if (blk->isValid()) {
DPRINTF(Cache, "replacement: replacing %#llx (%s) with %#llx "
- "(%s): %s\n", repl_addr, blk->isSecure() ? "s" : "ns",
+ "(%s): %s\n", tags->regenerateBlkAddr(blk),
+ blk->isSecure() ? "s" : "ns",
addr, is_secure ? "s" : "ns",
blk->isDirty() ? "writeback" : "clean");
@@ -1849,10 +1860,22 @@
} else {
writebacks.push_back(cleanEvictBlk(blk));
}
+
+ // A successful block allocation is followed by an insertion
to the
+ // victim block. If multiple blocks are evicted, that means
that
+ // we are evicting all blocks co-associated to this victim, and
+ // they should be invalidated after writeback/evict
+ if (blk != victim) {
+ tags->invalidate(blk);
+ blk->task_id = ContextSwitchTaskId::Unknown;
+ blk->status = 0;
+ blk->whenReady = MaxTick;
+ blk->srcMasterId = Request::invldMasterId;
+ }
}
}
- return blk;
+ return victim;
}
void
@@ -1902,8 +1925,9 @@
// current request and then get rid of it
assert(!tempBlock->isValid());
blk = tempBlock;
+ tempBlock->sectorOffset = tags->extractSectorOffset(addr);
tempBlock->set = tags->extractSet(addr);
- tempBlock->tag = tags->extractTag(addr);
+ *(tempBlock->tag) = tags->extractTag(addr);
if (is_secure) {
tempBlock->status |= BlkSecure;
}
@@ -1917,7 +1941,7 @@
assert(!blk->isValid());
} else {
// existing block... probably an upgrade
- assert(blk->tag == tags->extractTag(addr));
+ assert(*(blk->tag) == tags->extractTag(addr));
// either we're getting new data or the block should already be
valid
assert(pkt->hasData() || blk->isValid());
// don't clear block status... if block is already dirty we
diff --git a/src/mem/cache/sector_blk.cc b/src/mem/cache/sector_blk.cc
new file mode 100644
index 0000000..ddaaba2
--- /dev/null
+++ b/src/mem/cache/sector_blk.cc
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2018 Inria
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Daniel Carvalho
+ */
+
+#include "mem/cache/sector_blk.hh"
+
+SectorBlk::SectorBlk() : CacheBlk()
+{
+ // A sector does not contain data
+ data = nullptr;
+}
+
+bool
+SectorBlk::isValid() const
+{
+ // If any of the blocks in the sector is valid, so is the sector
+ for (const auto& blk : blks) {
+ if (blk->isValid()) {
+ return true;
+ }
+ }
+ return false;
+}
+
diff --git a/src/mem/cache/sector_blk.hh b/src/mem/cache/sector_blk.hh
new file mode 100644
index 0000000..f0aa85f
--- /dev/null
+++ b/src/mem/cache/sector_blk.hh
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2018 Inria
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Daniel Carvalho
+ */
+
+/** @file
+ * Definitions of a simple sector block class. Each sector consists of a
+ * sequence of cache blocks that may or may not be present in the cache.
+ */
+
+#ifndef __MEM_CACHE_SECTOR_BLK_HH__
+#define __MEM_CACHE_SECTOR_BLK_HH__
+
+#include <vector>
+
+#include "mem/cache/blk.hh"
+
+/**
+ * A Basic Sector block.
+ * Contains the tag and a list of blocks associated to this sector.
+ */
+class SectorBlk : public CacheBlk
+{
+ public:
+ /** List of blocks associated to this sector. */
+ std::vector<CacheBlk*> blks;
+
+ /** Default constructor. */
+ SectorBlk();
+ SectorBlk(const SectorBlk&) = delete;
+ SectorBlk& operator=(const SectorBlk&) = delete;
+ ~SectorBlk(){}
+
+ /**
+ * Checks that a sector block is valid.
+ * @return True if any of the blocks in the sector is valid.
+ */
+ bool isValid() const override;
+};
+
+#endif //__MEM_CACHE_SECTOR_BLK_HH__
diff --git a/src/mem/cache/tags/SConscript b/src/mem/cache/tags/SConscript
index 9758b56..136abac 100644
--- a/src/mem/cache/tags/SConscript
+++ b/src/mem/cache/tags/SConscript
@@ -35,3 +35,4 @@
Source('base.cc')
Source('base_set_assoc.cc')
Source('fa_lru.cc')
+Source('sector_tags.cc')
diff --git a/src/mem/cache/tags/Tags.py b/src/mem/cache/tags/Tags.py
index ff4eff4..7f06070 100644
--- a/src/mem/cache/tags/Tags.py
+++ b/src/mem/cache/tags/Tags.py
@@ -73,6 +73,18 @@
replacement_policy = Param.BaseReplacementPolicy(
Parent.replacement_policy, "Replacement policy")
+class SectorTags(BaseTags):
+ type = 'SectorTags'
+ cxx_header = "mem/cache/tags/sector_tags.hh"
+ assoc = Param.Int(Parent.assoc, "associativity")
+
+ # Get the size of a sector, in number of data blocks
+ sector_size = Param.Int(1, "Number of data blocks per sector");
+
+ # Get replacement policy from the parent (cache)
+ replacement_policy = Param.BaseReplacementPolicy(
+ Parent.replacement_policy, "Replacement policy")
+
class FALRU(BaseTags):
type = 'FALRU'
cxx_class = 'FALRU'
diff --git a/src/mem/cache/tags/base.cc b/src/mem/cache/tags/base.cc
index 91f922a..050bd03 100644
--- a/src/mem/cache/tags/base.cc
+++ b/src/mem/cache/tags/base.cc
@@ -50,6 +50,7 @@
#include "cpu/smt.hh" //maxThreadsPerCPU
#include "mem/cache/base.hh"
+#include "mem/cache/sector_blk.hh" // TODO remove
#include "sim/sim_exit.hh"
BaseTags::BaseTags(const Params *p)
@@ -79,6 +80,9 @@
// Get address
Addr addr = pkt->getAddr();
+ // Store address in block for debugging
+ blk->addr = addr;
+
// Update warmup data
if (!blk->replacementData->isTouched) {
if (!warmedUp && tagsInUse.value() >= warmupBound) {
@@ -104,8 +108,14 @@
// to insert the new one
tagsInUse++;
- // Set tag for new block. Caller is responsible for setting status.
- blk->tag = extractTag(addr);
+ // Check if it is overwriting a sector
+ if (blk->secBlk && blk->secBlk->isValid() &&
+ (*(blk->secBlk->tag) != extractTag(addr))){
+ panic("Overwriting valid sector!");
+ }
+
+ // Set tag for new block. Caller is responsible for setting status.
+ *(blk->tag) = extractTag(addr);
// Deal with what we are bringing in
MasterID master_id = pkt->req->masterId();
diff --git a/src/mem/cache/tags/base.hh b/src/mem/cache/tags/base.hh
index 4cf6774..6e4cd1f 100644
--- a/src/mem/cache/tags/base.hh
+++ b/src/mem/cache/tags/base.hh
@@ -257,9 +257,11 @@
* Find replacement victim based on address.
*
* @param addr Address to find a victim for.
+ * @param evictBlks Cache blocks to be evicted.
* @return Cache block to be replaced.
*/
- virtual CacheBlk* findVictim(Addr addr) = 0;
+ virtual CacheBlk* findVictim(Addr addr, std::vector<CacheBlk*>&
evictBlks)
+ const
= 0;
virtual CacheBlk* accessBlock(Addr addr, bool is_secure, Cycles &lat)
= 0;
@@ -283,6 +285,8 @@
virtual int extractSet(Addr addr) const = 0;
+ virtual int extractSectorOffset(Addr addr) const { return 0; };
+
virtual void forEachBlk(CacheBlkVisitor &visitor) = 0;
};
diff --git a/src/mem/cache/tags/base_set_assoc.cc
b/src/mem/cache/tags/base_set_assoc.cc
index 41ccbc6..ca4c1d8 100644
--- a/src/mem/cache/tags/base_set_assoc.cc
+++ b/src/mem/cache/tags/base_set_assoc.cc
@@ -96,7 +96,8 @@
// Setting the tag to j is just to prevent long chains in the
// hash table; won't matter because the block is invalid
- blk->tag = j;
+ blk->tag = std::unique_ptr<Addr>(new Addr());
+ *(blk->tag) = j;
// Set its set and way
blk->set = i;
@@ -111,10 +112,21 @@
CacheBlk*
BaseSetAssoc::findBlock(Addr addr, bool is_secure) const
{
+ // Extract block tag
Addr tag = extractTag(addr);
- unsigned set = extractSet(addr);
- BlkType *blk = sets[set].findBlk(tag, is_secure);
- return blk;
+
+ // Find possible locations for the given address
+ std::vector<CacheBlk*> locations = getPossibleLocations(addr);
+
+ // Search for block
+ for (const auto& blk : locations) {
+ if (blk->match(tag, is_secure)) {
+ return blk;
+ }
+ }
+
+ // Did not find block
+ return nullptr;
}
CacheBlk*
diff --git a/src/mem/cache/tags/base_set_assoc.hh
b/src/mem/cache/tags/base_set_assoc.hh
index 21613a4..6bb29dc 100644
--- a/src/mem/cache/tags/base_set_assoc.hh
+++ b/src/mem/cache/tags/base_set_assoc.hh
@@ -187,15 +187,18 @@
/**
* Find replacement victim based on address.
*
- * @param addr Address to find a victim for.
+ * @param evictBlks Cache blocks to be evicted.
* @return Cache block to be replaced.
*/
- CacheBlk* findVictim(Addr addr) override
+ CacheBlk* findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks)
const
+
override
{
// Choose replacement victim from replacement candidates
CacheBlk* victim = replacementPolicy->getVictim(
getPossibleLocations(addr));
+ evictBlks.push_back(victim);
+
DPRINTF(CacheRepl, "set %x, way %x: selecting blk for
replacement\n",
victim->set, victim->way);
@@ -211,7 +214,7 @@
* @param addr The addr to a find possible locations for.
* @return The possible locations.
*/
- const std::vector<CacheBlk*> getPossibleLocations(Addr addr)
+ const std::vector<CacheBlk*> getPossibleLocations(Addr addr) const
{
return sets[extractSet(addr)].blks;
}
@@ -278,7 +281,7 @@
*/
Addr regenerateBlkAddr(const CacheBlk* blk) const override
{
- return ((blk->tag << tagShift) | ((Addr)blk->set << setShift));
+ return ((*(blk->tag) << tagShift) | ((Addr)blk->set << setShift));
}
/**
diff --git a/src/mem/cache/tags/cacheset.hh b/src/mem/cache/tags/cacheset.hh
index 5a34456..0ace837 100644
--- a/src/mem/cache/tags/cacheset.hh
+++ b/src/mem/cache/tags/cacheset.hh
@@ -95,14 +95,13 @@
* Way_id returns the id of the way that matches the block
* If no block is found way_id is set to assoc.
*/
- way_id = assoc;
+ /*way_id = assoc;
for (int i = 0; i < assoc; ++i) {
- if (blks[i]->tag == tag && blks[i]->isValid() &&
- blks[i]->isSecure() == is_secure) {
+ if (blks[i]->match(tag, is_secure)) {
way_id = i;
return blks[i];
}
- }
+ }*/
return nullptr;
}
diff --git a/src/mem/cache/tags/fa_lru.cc b/src/mem/cache/tags/fa_lru.cc
index f02b55a..66a86f1 100644
--- a/src/mem/cache/tags/fa_lru.cc
+++ b/src/mem/cache/tags/fa_lru.cc
@@ -168,7 +168,7 @@
BaseTags::invalidate(blk);
// Erase block entry in the hash table
- tagHash.erase(blk->tag);
+ tagHash.erase(*(blk->tag));
}
CacheBlk*
@@ -196,7 +196,7 @@
lat = cache->ticksToCycles(blk->whenReady - curTick()) +
accessLatency;
}
- assert(blk->tag == blkAddr);
+ assert(*(blk->tag) == blkAddr);
tmp_in_cache = blk->inCache;
for (unsigned i = 0; i < numCaches; i++) {
if (1<<i & blk->inCache) {
@@ -233,7 +233,7 @@
FALRUBlk* blk = hashLookup(blkAddr);
if (blk && blk->isValid()) {
- assert(blk->tag == blkAddr);
+ assert(*(blk->tag) == blkAddr);
} else {
blk = nullptr;
}
@@ -248,8 +248,9 @@
}
CacheBlk*
-FALRU::findVictim(Addr addr)
+FALRU::findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks) const
{
+ evictBlks.push_back(tail);
return tail;
}
@@ -268,7 +269,7 @@
moveToHead(falruBlk);
// Insert new block in the hash table
- tagHash[falruBlk->tag] = falruBlk;
+ tagHash[*(falruBlk->tag)] = falruBlk;
//assert(check());
}
diff --git a/src/mem/cache/tags/fa_lru.hh b/src/mem/cache/tags/fa_lru.hh
index 129af9f..0cc67fa 100644
--- a/src/mem/cache/tags/fa_lru.hh
+++ b/src/mem/cache/tags/fa_lru.hh
@@ -204,9 +204,11 @@
* Find replacement victim based on address.
*
* @param addr Address to find a victim for.
+ * @param evictBlks Cache blocks to be evicted.
* @return Cache block to be replaced.
*/
- CacheBlk* findVictim(Addr addr) override;
+ CacheBlk* findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks)
const
+
override;
/**
* Insert the new block into the cache and update replacement data.
@@ -253,7 +255,7 @@
*/
Addr regenerateBlkAddr(const CacheBlk* blk) const override
{
- return blk->tag;
+ return *(blk->tag);
}
/**
diff --git a/src/mem/cache/tags/sector_tags.cc
b/src/mem/cache/tags/sector_tags.cc
new file mode 100644
index 0000000..ef11417
--- /dev/null
+++ b/src/mem/cache/tags/sector_tags.cc
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2018 Inria
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Daniel Carvalho
+ */
+
+/**
+ * @file
+ * Definitions of a base set associative sector tag store.
+ */
+
+#include "mem/cache/tags/sector_tags.hh"
+
+#include <cassert>
+#include <string>
+
+#include "base/intmath.hh"
+#include "debug/CacheRepl.hh"
+
+SectorTags::SectorTags(const Params *p)
+ :BaseTags(p), assoc(p->assoc), allocAssoc(p->assoc),
+ sectorSize(p->sector_size),
+ blks(p->size / p->block_size),
+ secBlks(p->size / (p->block_size * p->sector_size)),
+ numSets(p->size / (p->block_size * p->assoc * p->sector_size)),
+ numSectors(p->size / (p->block_size * p->sector_size)),
+ sequentialAccess(p->sequential_access),
+ sets(p->size / (p->block_size * p->assoc * p->sector_size)),
+ replacementPolicy(p->replacement_policy)
+{
+ // Check parameters
+ if (blkSize < 4 || !isPowerOf2(blkSize)) {
+ fatal("Block size must be at least 4 and a power of 2");
+ }
+ if (!isPowerOf2(numSets)) {
+ fatal("# of sets must be non-zero and a power of 2");
+ }
+ if (!isPowerOf2(sectorSize)) {
+ fatal("# of blocks per sector must be non-zero and a power of 2");
+ }
+ if (assoc <= 0) {
+ fatal("associativity must be greater than zero");
+ }
+
+ // Calculate masks
+ // Tag | Set # | Sector Offset # | Offset #
+ sectorShift = floorLog2(blkSize);
+ sectorMask = sectorSize - 1;
+ setShift = sectorShift + floorLog2(sectorSize);
+ setMask = numSets - 1;
+ tagShift = sectorShift + floorLog2(numSets);
+
+ // Initialize all sets
+ unsigned secBlkIndex = 0; // index into sector blks array
+ unsigned blkIndex = 0; // index into blks array
+ for (unsigned i = 0; i < numSets; ++i) {
+ sets[i].assoc = assoc;
+
+ sets[i].blks.resize(assoc);
+
+ // Initialize all sectors in this set
+ for (unsigned j = 0; j < assoc; ++j) {
+ // Select block within the set to be linked
+ SectorBlk*& secBlk = sets[i].blks[j];
+
+ // Locate next cache sector
+ secBlk = &secBlks[secBlkIndex];
+
+ // Associate a replacement data entry to the sector
+ secBlk->replacementData =
replacementPolicy->instantiateEntry();
+
+ // Setting the tag to j is just to prevent long chains in the
+ // hash table; won't matter because the block is invalid
+ secBlk->tag = std::shared_ptr<Addr>(new Addr());
+ *(secBlk->tag) = j;
+
+ // Initialize all blocks in this sector
+ secBlk->blks.resize(sectorSize);
+ for (unsigned k = 0; k < sectorSize; ++k){
+ // Select block within the set to be linked
+ CacheBlk*& blk = secBlk->blks[k];
+
+ // Locate next cache block
+ blk = &blks[blkIndex];
+
+ // Associate a data chunk to the block
+ blk->data = &dataBlks[blkSize*blkIndex];
+
+ // Associate sector block to this block
+ blk->secBlk = secBlk;
+
+ // Associate the sector replacement data to this block
+ blk->replacementData = secBlk->replacementData;
+
+ // Associate sector tag to this block
+ blk->tag = secBlk->tag;
+
+ // Set its set, way and sector offset
+ blk->set = i;
+ blk->way = j;
+ blk->sectorOffset = k;
+
+ // Update block index
+ ++blkIndex;
+ }
+
+ // Update sector block index
+ ++secBlkIndex;
+ }
+ }
+}
+
+CacheBlk*
+SectorTags::findBlock(Addr addr, bool is_secure) const
+{
+ // Extract sector tag
+ const Addr tag = extractTag(addr);
+ const Addr offset = extractSectorOffset(addr);
+
+ // Find possible locations for the given address
+ const std::vector<SectorBlk*> locations = getPossibleLocations(addr);
+
+ // Search for block
+ for (const auto& sector : locations) {
+ if (sector->blks[offset]->match(tag, is_secure)) {
+ return sector->blks[offset];
+ }
+ }
+
+ // Did not find block
+ return nullptr;
+}
+
+CacheBlk*
+SectorTags::findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks) const
+{
+ // Get all possible locations of this sector
+ const std::vector<SectorBlk*> sectorLocations =
getPossibleLocations(addr);
+
+ SectorBlk* victimSector = nullptr;
+
+ // Check if the sector this address belongs to has been allocated
+ Addr tag = extractTag(addr);
+ for (const auto& sector : sectorLocations){
+ if (tag == *(sector->tag)){
+ victimSector = sector;
+ break;
+ }
+ }
+
+ // If the sector is not present
+ if (victimSector == nullptr){
+ // Choose replacement victim from replacement candidates
+ victimSector =
static_cast<SectorBlk*>(replacementPolicy->getVictim(
+
std::vector<CacheBlk*>(sectorLocations.begin(),
+
sectorLocations.end())));
+ }
+
+ // Get the location of the victim block within the sector
+ CacheBlk* victim = victimSector->blks[extractSectorOffset(addr)];
+
+ // Get evicted blocks
+ if (tag == *(victimSector->tag)){
+ // If new block belongs to the same sector we just need to evict
the
+ // block at its final location. This block will be invalid, as only
+ // one block can map to a specific offset of a sector
+ assert(!victim->isValid());
+
+ evictBlks.push_back(victim);
+ } else {
+ // The whole sector must be evicted to make room for the new sector
+ evictBlks = victimSector->blks;
+ }
+
+ DPRINTF(CacheRepl, "set %x, way %x, sector offset %x: %s\n",
+ "selecting blk for replacement\n", victim->set, victim->way,
+ victim->sectorOffset);
+
+ return victim;
+}
+
+Addr
+SectorTags::extractTag(Addr addr) const
+{
+ return addr >> tagShift;
+}
+
+int
+SectorTags::extractSet(Addr addr) const
+{
+ return (addr >> setShift) & setMask;
+}
+
+int
+SectorTags::extractSectorOffset(Addr addr) const
+{
+ return (addr >> sectorShift) & sectorMask;
+}
+
+Addr
+SectorTags::regenerateBlkAddr(const CacheBlk* blk) const
+{
+ Addr addr = ((*(blk->tag) << tagShift) |
+ ((Addr)blk->set << setShift) |
+ ((Addr)blk->sectorOffset << sectorShift));
+ assert(blk->addr == addr);
+ return addr;
+}
+
+CacheBlk*
+SectorTags::findBlockBySetAndWay(int set, int way) const
+{
+ return sets[set].blks[way];
+}
+
+const std::vector<SectorBlk*>
+SectorTags::getPossibleLocations(Addr addr) const
+{
+ return sets[extractSet(addr)].blks;
+}
+
+CacheBlk*
+SectorTags::accessBlock(Addr addr, bool is_secure, Cycles &lat)
+{
+ CacheBlk *blk = findBlock(addr, is_secure);
+
+ // Access all tags in parallel, hence one in each way. The data side
+ // either accesses all blocks in parallel, or one block sequentially on
+ // a hit. Sequential access with a miss doesn't access data.
+ tagAccesses += allocAssoc;
+ if (sequentialAccess) {
+ if (blk != nullptr) {
+ dataAccesses += 1;
+ }
+ } else {
+ dataAccesses += allocAssoc;
+ }
+
+ if (blk != nullptr) {
+ // If a cache hit
+ lat = accessLatency;
+ // Check if the block to be accessed is available. If not,
+ // apply the accessLatency on top of block->whenReady.
+ if (blk->whenReady > curTick() &&
+ cache->ticksToCycles(blk->whenReady - curTick()) >
+ accessLatency) {
+ lat = cache->ticksToCycles(blk->whenReady - curTick()) +
+ accessLatency;
+ }
+
+ // Update replacement data of accessed block
+ replacementPolicy->touch(blk->replacementData.get());
+ } else {
+ // If a cache miss
+ lat = lookupLatency;
+ }
+
+ return blk;
+}
+
+void
+SectorTags::insertBlock(PacketPtr pkt, CacheBlk *blk)
+{
+ // Insert block
+ BaseTags::insertBlock(pkt, blk);
+
+ // Update replacement policy
+ replacementPolicy->reset(blk->replacementData.get());
+}
+
+void
+SectorTags::cleanupRefs()
+{
+ for (unsigned i = 0; i < numSets*assoc; ++i) {
+ if (blks[i].isValid()) {
+ totalRefs += blks[i].replacementData->refCount;
+ ++sampledRefs;
+ }
+ }
+}
+
+std::string
+SectorTags::print() const {
+ std::string cache_state;
+ for (unsigned i = 0; i < numSets; ++i) {
+ // link in the data blocks
+ for (unsigned j = 0; j < assoc; ++j) {
+ SectorBlk* sectorBlk = sets[i].blks[j];
+ // Print all blocks in the sector
+ for (const auto& blk : sectorBlk->blks){
+ if (blk->isValid())
+ cache_state += csprintf("\tset: %d block: %d %s\n", i,
j,
+ blk->print());
+ }
+ }
+ }
+ if (cache_state.empty())
+ cache_state = "no valid tags\n";
+ return cache_state;
+}
+
+void
+SectorTags::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]++;
+ assert(blks[i].replacementData->tickInserted <= curTick());
+ Tick age = curTick() - blks[i].replacementData->tickInserted;
+
+ 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]++;
+ }
+ }
+}
+
+SectorTags *
+SectorTagsParams::create()
+{
+ return new SectorTags(this);
+}
diff --git a/src/mem/cache/tags/sector_tags.hh
b/src/mem/cache/tags/sector_tags.hh
new file mode 100644
index 0000000..53fd75c
--- /dev/null
+++ b/src/mem/cache/tags/sector_tags.hh
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2018 Inria
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Daniel Carvalho
+ */
+
+/**
+ * @file
+ * Declaration of a sector set associative tag store.
+ */
+
+#ifndef __MEM_CACHE_TAGS_SECTOR_TAGS_HH__
+#define __MEM_CACHE_TAGS_SECTOR_TAGS_HH__
+
+#include <vector>
+
+#include "mem/cache/base.hh"
+#include "mem/cache/sector_blk.hh"
+#include "mem/cache/tags/base.hh"
+#include "mem/cache/tags/cacheset.hh"
+#include "mem/packet.hh"
+#include "params/SectorTags.hh"
+
+/**
+ * A SectorTags cache tag store.
+ * @sa \ref gem5MemorySystem "gem5 Memory System"
+ *
+ * The SectorTags placement policy divides the cache into s sectors of w
+ * consecutive cache lines (ways) that may or may not be present.
+ */
+class SectorTags : public BaseTags
+{
+ private:
+ /**
+ * Calculate a block's offset in a sector from the address.
+ * @param addr The address to get the offset from.
+ * @return Offset of the corresponding block within its sector.
+ */
+ int extractSectorOffset(Addr addr) const;
+
+ public:
+ /** Typedef the set type used in this tag store. */
+ typedef CacheSet<SectorBlk> SetType;
+
+ protected:
+ /** The associativity of the cache. */
+ const unsigned assoc;
+ /** The allocatable associativity of the cache (alloc mask). */
+ unsigned allocAssoc;
+
+ /** Number of cache lines per sector. */
+ const unsigned sectorSize;
+
+ /** The cache blocks. */
+ std::vector<CacheBlk> blks;
+ /** The cache sector blocks. */
+ std::vector<SectorBlk> secBlks;
+
+ /** The number of sets in the cache. */
+ const unsigned numSets;
+ /** The number of sectors in the cache. */
+ const unsigned numSectors;
+
+ /** Whether tags and data are accessed sequentially. */
+ const bool sequentialAccess;
+
+ /** The cache sets. */
+ std::vector<SetType> sets;
+
+ /** The amount to shift the address to get the set. */
+ int setShift;
+ /** The amount to shift the address to get the tag. */
+ int tagShift;
+ /** Mask out all bits that aren't part of the set index. */
+ unsigned setMask;
+ /** The amount to shift the address to get the sector tag. */
+ int sectorShift;
+ /** Mask out all bits that aren't part of the sector tag. */
+ unsigned sectorMask;
+
+ /** Replacement policy */
+ BaseReplacementPolicy *replacementPolicy;
+
+ public:
+ /** Convenience typedef. */
+ typedef SectorTagsParams Params;
+
+ /**
+ * Construct and initialize this tag store.
+ */
+ SectorTags(const Params *p);
+
+ /**
+ * Destructor.
+ */
+ ~SectorTags() {};
+
+ /**
+ * Find the cache sector block given set and way.
+ * @param set The set of the block.
+ * @param way The way of the block.
+ * @return The cache block.
+ */
+ CacheBlk *findBlockBySetAndWay(int set, int way) const override;
+
+ /**
+ * Access block and update replacement data. May not succeed, in which
case
+ * nullptr is returned. This has all the implications of a cache
+ * access and should only be used as such. Returns the access latency
as a
+ * side effect.
+ * @param addr The address to find.
+ * @param is_secure True if the target memory space is secure.
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ CacheBlk* accessBlock(Addr addr, bool is_secure, Cycles &lat) override;
+
+ /**
+ * Finds the given address in the cache, do not update replacement
data.
+ * i.e. This is a no-side-effect find of a block.
+ * @param addr The address to find.
+ * @param is_secure True if the target memory space is secure.
+ * @param asid The address space ID.
+ * @return Pointer to the cache block if found.
+ */
+ CacheBlk* findBlock(Addr addr, bool is_secure) const override;
+
+ /**
+ * Find replacement victim based on address.
+ *
+ * @param addr Address to find a victim for.
+ * @param evictBlks Cache blocks to be evicted.
+ * @return Cache block to be replaced.
+ */
+ CacheBlk* findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks)
const
+
override;
+
+ /**
+ * Find all possible block locations for insertion and replacement of
+ * an address. Should be called immediately before ReplacementPolicy's
+ * findVictim() not to break cache resizing.
+ * Returns blocks in all ways belonging to the set of the address.
+ *
+ * @param addr The addr to a find possible locations for.
+ * @return The possible locations.
+ */
+ const std::vector<SectorBlk*> getPossibleLocations(Addr addr) const;
+
+ /**
+ * Insert the new block into the cache.
+ * @param pkt Packet holding the address to update
+ * @param blk The block to update.
+ */
+ void insertBlock(PacketPtr pkt, CacheBlk *blk) override;
+
+ /**
+ * Generate the sector tag from the given address.
+ * @param addr The address to get the sector tag from.
+ * @return The sector tag of the address.
+ */
+ Addr extractTag(Addr addr) const override;
+
+ /**
+ * Calculate the set index from the address.
+ * @param addr The address to get the set from.
+ * @return The set index of the address.
+ */
+ int extractSet(Addr addr) const override;
+
+ /**
+ * Regenerate the block address from the tag and set.
+ *
+ * @param block The block.
+ * @return the block address.
+ */
+ Addr regenerateBlkAddr(const CacheBlk* blk) const override;
+
+ /**
+ * Called at end of simulation to complete average block reference
stats.
+ */
+ void cleanupRefs() override;
+
+ /**
+ * Print all tags used
+ */
+ std::string print() const override;
+
+ /**
+ * Called prior to dumping stats to compute task occupancy
+ */
+ void computeStats() override;
+
+ /**
+ * Visit each block in the tag store and apply a visitor to the
+ * block.
+ *
+ * The visitor should be a function (or object that behaves like a
+ * function) that takes a cache block reference as its parameter
+ * and returns a bool. A visitor can request the traversal to be
+ * stopped by returning false, returning true causes it to be
+ * called for the next block in the tag store.
+ *
+ * \param visitor Visitor to call on each block.
+ */
+ void forEachBlk(CacheBlkVisitor &visitor) override {
+ for (unsigned i = 0; i < numSets * assoc; ++i) {
+ if (!visitor(blks[i]))
+ return;
+ }
+ }
+};
+
+#endif //__MEM_CACHE_TAGS_SECTOR_TAGS_HH__
--
To view, visit https://gem5-review.googlesource.com/9741
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: I8e1e9448fa44ba308ccb16cd5bcc5fd36c988feb
Gerrit-Change-Number: 9741
Gerrit-PatchSet: 1
Gerrit-Owner: Daniel Carvalho <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev