mem-cache: Replace block visitor with std::function

This change modifies forEachBlk tags function to accept std::function
as parameter. It also adds an anyBlk tags function that given a
condition, it iterates through the blocks and returns whether the
condition is met.

Finally, it uses forEachBlk to implement the print, computeStats and
cleanupRefs functions that also work for the FALRU class.

Change-Id: I2f75f4baa1fdd5a1d343a63ecace3eb9458fbf03
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/10621
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
This commit is contained in:
Nikos Nikoleris
2018-05-30 11:54:57 +01:00
parent 56865ad115
commit 51f83a3cff
8 changed files with 145 additions and 211 deletions

19
src/mem/cache/base.cc vendored
View File

@@ -1326,27 +1326,22 @@ BaseCache::writecleanBlk(CacheBlk *blk, Request::Flags dest, PacketId id)
void
BaseCache::memWriteback()
{
CacheBlkVisitorWrapper visitor(*this, &BaseCache::writebackVisitor);
tags->forEachBlk(visitor);
tags->forEachBlk([this](CacheBlk &blk) { writebackVisitor(blk); });
}
void
BaseCache::memInvalidate()
{
CacheBlkVisitorWrapper visitor(*this, &BaseCache::invalidateVisitor);
tags->forEachBlk(visitor);
tags->forEachBlk([this](CacheBlk &blk) { invalidateVisitor(blk); });
}
bool
BaseCache::isDirty() const
{
CacheBlkIsDirtyVisitor visitor;
tags->forEachBlk(visitor);
return visitor.isDirty();
return tags->anyBlk([](CacheBlk &blk) { return blk.isDirty(); });
}
bool
void
BaseCache::writebackVisitor(CacheBlk &blk)
{
if (blk.isDirty()) {
@@ -1366,11 +1361,9 @@ BaseCache::writebackVisitor(CacheBlk &blk)
blk.status &= ~BlkDirty;
}
return true;
}
bool
void
BaseCache::invalidateVisitor(CacheBlk &blk)
{
if (blk.isDirty())
@@ -1381,8 +1374,6 @@ BaseCache::invalidateVisitor(CacheBlk &blk)
assert(!blk.isDirty());
invalidateBlock(&blk);
}
return true;
}
Tick

66
src/mem/cache/base.hh vendored
View File

@@ -1108,19 +1108,15 @@ class BaseCache : public MemObject
/**
* Cache block visitor that writes back dirty cache blocks using
* functional writes.
*
* @return Always returns true.
*/
bool writebackVisitor(CacheBlk &blk);
void writebackVisitor(CacheBlk &blk);
/**
* Cache block visitor that invalidates all blocks in the cache.
*
* @warn Dirty cache lines will not be written back to memory.
*
* @return Always returns true.
*/
bool invalidateVisitor(CacheBlk &blk);
void invalidateVisitor(CacheBlk &blk);
/**
* Take an MSHR, turn it into a suitable downstream packet, and
@@ -1152,62 +1148,4 @@ class BaseCache : public MemObject
};
/**
* Wrap a method and present it as a cache block visitor.
*
* For example the forEachBlk method in the tag arrays expects a
* callable object/function as their parameter. This class wraps a
* method in an object and presents callable object that adheres to
* the cache block visitor protocol.
*/
class CacheBlkVisitorWrapper : public CacheBlkVisitor
{
public:
typedef bool (BaseCache::*VisitorPtr)(CacheBlk &blk);
CacheBlkVisitorWrapper(BaseCache &_cache, VisitorPtr _visitor)
: cache(_cache), visitor(_visitor) {}
bool operator()(CacheBlk &blk) override {
return (cache.*visitor)(blk);
}
private:
BaseCache &cache;
VisitorPtr visitor;
};
/**
* Cache block visitor that determines if there are dirty blocks in a
* cache.
*
* Use with the forEachBlk method in the tag array to determine if the
* array contains dirty blocks.
*/
class CacheBlkIsDirtyVisitor : public CacheBlkVisitor
{
public:
CacheBlkIsDirtyVisitor()
: _isDirty(false) {}
bool operator()(CacheBlk &blk) override {
if (blk.isDirty()) {
_isDirty = true;
return false;
} else {
return true;
}
}
/**
* Does the array contain a dirty line?
*
* @return true if yes, false otherwise.
*/
bool isDirty() const { return _isDirty; };
private:
bool _isDirty;
};
#endif //__MEM_CACHE_BASE_HH__

18
src/mem/cache/blk.hh vendored
View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2017 ARM Limited
* Copyright (c) 2012-2018 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -409,20 +409,4 @@ class CacheBlkPrintWrapper : public Printable
const std::string &prefix = "") const;
};
/**
* Base class for cache block visitor, operating on the cache block
* base class (later subclassed for the various tag classes). This
* visitor class is used as part of the forEachBlk interface in the
* tag classes.
*/
class CacheBlkVisitor
{
public:
CacheBlkVisitor() {}
virtual ~CacheBlkVisitor() {}
virtual bool operator()(CacheBlk &blk) = 0;
};
#endif //__MEM_CACHE_BLK_HH__

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013,2016 ARM Limited
* Copyright (c) 2013,2016,2018 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -110,6 +110,77 @@ BaseTags::insertBlock(PacketPtr pkt, CacheBlk *blk)
dataAccesses += 1;
}
void
BaseTags::cleanupRefsVisitor(CacheBlk &blk)
{
if (blk.isValid()) {
totalRefs += blk.refCount;
++sampledRefs;
}
}
void
BaseTags::cleanupRefs()
{
forEachBlk([this](CacheBlk &blk) { cleanupRefsVisitor(blk); });
}
void
BaseTags::computeStatsVisitor(CacheBlk &blk)
{
if (blk.isValid()) {
assert(blk.task_id < ContextSwitchTaskId::NumTaskId);
occupanciesTaskId[blk.task_id]++;
assert(blk.tickInserted <= curTick());
Tick age = curTick() - blk.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[blk.task_id][age_index]++;
}
}
void
BaseTags::computeStats()
{
for (unsigned i = 0; i < ContextSwitchTaskId::NumTaskId; ++i) {
occupanciesTaskId[i] = 0;
for (unsigned j = 0; j < 5; ++j) {
ageTaskId[i][j] = 0;
}
}
forEachBlk([this](CacheBlk &blk) { computeStatsVisitor(blk); });
}
std::string
BaseTags::print()
{
std::string str;
auto print_blk = [&str](CacheBlk &blk) {
if (blk.isValid())
str += csprintf("\tset: %d way: %d %s\n", blk.set, blk.way,
blk.print());
};
forEachBlk(print_blk);
if (str.empty())
str = "no valid tags\n";
return str;
}
void
BaseTags::regStats()
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2014,2016-2017 ARM Limited
* Copyright (c) 2012-2014,2016-2018 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -50,6 +50,7 @@
#define __MEM_CACHE_TAGS_BASE_HH__
#include <cassert>
#include <functional>
#include <string>
#include "base/callback.hh"
@@ -177,17 +178,17 @@ class BaseTags : public ClockedObject
* Average in the reference count for valid blocks when the simulation
* exits.
*/
virtual void cleanupRefs() {}
void cleanupRefs();
/**
* Computes stats just prior to dump event
*/
virtual void computeStats() {}
void computeStats();
/**
* Print all tags used
*/
virtual std::string print() const = 0;
std::string print();
/**
* Find a block using the memory address
@@ -289,7 +290,42 @@ class BaseTags : public ClockedObject
virtual int extractSet(Addr addr) const = 0;
virtual void forEachBlk(CacheBlkVisitor &visitor) = 0;
/**
* Visit each block in the tags and apply a visitor
*
* The visitor should be a std::function that takes a cache block
* reference as its parameter.
*
* @param visitor Visitor to call on each block.
*/
virtual void forEachBlk(std::function<void(CacheBlk &)> visitor) = 0;
/**
* Find if any of the blocks satisfies a condition
*
* The visitor should be a std::function that takes a cache block
* reference as its parameter. The visitor will terminate the
* traversal early if the condition is satisfied.
*
* @param visitor Visitor to call on each block.
*/
virtual bool anyBlk(std::function<bool(CacheBlk &)> visitor) = 0;
private:
/**
* Update the reference stats using data from the input block
*
* @param blk The input block
*/
void cleanupRefsVisitor(CacheBlk &blk);
/**
* Update the occupancy and age stats using data from the input block
*
* @param blk The input block
*/
void computeStatsVisitor(CacheBlk &blk);
};
class BaseTagsCallback : public Callback

View File

@@ -47,11 +47,9 @@
#include "mem/cache/tags/base_set_assoc.hh"
#include <cassert>
#include <string>
#include "base/intmath.hh"
#include "mem/request.hh"
BaseSetAssoc::BaseSetAssoc(const Params *p)
:BaseTags(p), assoc(p->assoc), allocAssoc(p->assoc),
@@ -134,64 +132,6 @@ BaseSetAssoc::findBlockBySetAndWay(int set, int way) const
return sets[set].blks[way];
}
std::string
BaseSetAssoc::print() const {
std::string cache_state;
for (const CacheBlk& blk : blks) {
if (blk.isValid())
cache_state += csprintf("\tset: %d way: %d %s\n", blk.set,
blk.way, blk.print());
}
if (cache_state.empty())
cache_state = "no valid tags\n";
return cache_state;
}
void
BaseSetAssoc::cleanupRefs()
{
for (const CacheBlk& blk : blks) {
if (blk.isValid()) {
totalRefs += blk.refCount;
++sampledRefs;
}
}
}
void
BaseSetAssoc::computeStats()
{
for (unsigned i = 0; i < ContextSwitchTaskId::NumTaskId; ++i) {
occupanciesTaskId[i] = 0;
for (unsigned j = 0; j < 5; ++j) {
ageTaskId[i][j] = 0;
}
}
for (const CacheBlk& blk : blks) {
if (blk.isValid()) {
assert(blk.task_id < ContextSwitchTaskId::NumTaskId);
occupanciesTaskId[blk.task_id]++;
assert(blk.tickInserted <= curTick());
Tick age = curTick() - blk.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[blk.task_id][age_index]++;
}
}
}
BaseSetAssoc *
BaseSetAssocParams::create()
{

View File

@@ -48,6 +48,7 @@
#ifndef __MEM_CACHE_TAGS_BASE_SET_ASSOC_HH__
#define __MEM_CACHE_TAGS_BASE_SET_ASSOC_HH__
#include <functional>
#include <string>
#include <vector>
@@ -298,39 +299,20 @@ class BaseSetAssoc : public BaseTags
return ((blk->tag << tagShift) | ((Addr)blk->set << setShift));
}
/**
* 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 {
void forEachBlk(std::function<void(CacheBlk &)> visitor) override {
for (CacheBlk& blk : blks) {
if (!visitor(blk))
return;
visitor(blk);
}
}
bool anyBlk(std::function<bool(CacheBlk &)> visitor) override {
for (CacheBlk& blk : blks) {
if (visitor(blk)) {
return true;
}
}
return false;
}
};
#endif //__MEM_CACHE_TAGS_BASE_SET_ASSOC_HH__

View File

@@ -50,6 +50,7 @@
#define __MEM_CACHE_TAGS_FA_LRU_HH__
#include <cstdint>
#include <functional>
#include <string>
#include <unordered_map>
@@ -240,30 +241,21 @@ class FALRU : public BaseTags
return blk->tag;
}
/**
* @todo Implement as in lru. Currently not used
*/
virtual std::string print() const override { return ""; }
/**
* 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 {
void forEachBlk(std::function<void(CacheBlk &)> visitor) override {
for (int i = 0; i < numBlocks; i++) {
if (!visitor(blks[i]))
return;
visitor(blks[i]);
}
}
bool anyBlk(std::function<bool(CacheBlk &)> visitor) override {
for (int i = 0; i < numBlocks; i++) {
if (visitor(blks[i])) {
return true;
}
}
return false;
}
private:
/**
* Mechanism that allows us to simultaneously collect miss