blob: 5bed44bd34211b86fc28dca128566fe67ac206bf [file] [log] [blame]
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* 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: Lisa Hsu
*/
/**
* @file
* Definitions of split cache tag store.
*/
#include <string>
#include <iostream>
#include <fstream>
#include "base/cprintf.hh"
#include "base/intmath.hh"
#include "base/output.hh"
#include "base/trace.hh"
#include "mem/cache/base.hh"
#include "mem/cache/tags/split.hh"
#include "mem/cache/tags/split_lifo.hh"
#include "mem/cache/tags/split_lru.hh"
using namespace std;
using namespace TheISA;
// create and initialize a partitioned cache structure
Split::Split(int _numSets, int _blkSize, int total_ways, int LRU1_assoc,
bool _lifo, bool _two_queue, int _hit_latency) :
numSets(_numSets), blkSize(_blkSize), lifo(_lifo), hitLatency(_hit_latency)
{
DPRINTF(Split, "new split cache!!\n");
DPRINTF(Split, "lru has %d numSets, %d blkSize, %d assoc, and %d hit_latency\n",
numSets, blkSize, LRU1_assoc, hitLatency);
lru = new SplitLRU(_numSets, _blkSize, LRU1_assoc, _hit_latency, 1);
if (total_ways - LRU1_assoc == 0) {
lifo_net = NULL;
lru_net = NULL;
} else {
if (lifo) {
DPRINTF(Split, "Other partition is a LIFO with size %d in bytes. it gets %d ways\n",
(total_ways - LRU1_assoc)*_numSets*_blkSize, (total_ways - LRU1_assoc));
lifo_net = new SplitLIFO(_blkSize, (total_ways - LRU1_assoc)*_numSets*_blkSize,
(total_ways - LRU1_assoc), _hit_latency, _two_queue, 2);
lru_net = NULL;
}
else {
DPRINTF(Split, "other LRU gets %d ways\n", total_ways - LRU1_assoc);
lru_net = new SplitLRU(_numSets, _blkSize, total_ways - LRU1_assoc, _hit_latency, 2);
lifo_net = NULL;
}
}
blkMask = blkSize - 1;
if (!isPowerOf2(total_ways))
warn("total cache ways/columns %d should be power of 2",
total_ways);
warmedUp = false;
/** @todo Make warmup percentage a parameter. */
warmupBound = numSets * total_ways;
}
Split::~Split()
{
delete lru;
if (lifo)
delete lifo_net;
else
delete lru_net;
}
void
Split::regStats(const string &name)
{
using namespace Stats;
BaseTags::regStats(name);
usedEvictDist.init(0,3000,40);
unusedEvictDist.init(0,3000,40);
useByCPUCycleDist.init(0,35,1);
nic_repl
.name(name + ".nic_repl")
.desc("number of replacements in the nic partition")
.precision(0)
;
cpu_repl
.name(name + ".cpu_repl")
.desc("number of replacements in the cpu partition")
.precision(0)
;
lru->regStats(name + ".lru");
if (lifo && lifo_net) {
lifo_net->regStats(name + ".lifo_net");
} else if (lru_net) {
lru_net->regStats(name + ".lru_net");
}
nicUsedWhenEvicted
.name(name + ".nicUsedWhenEvicted")
.desc("number of NIC blks that were used before evicted")
;
nicUsedTotLatency
.name(name + ".nicUsedTotLatency")
.desc("total cycles before eviction of used NIC blks")
;
nicUsedTotEvicted
.name(name + ".nicUsedTotEvicted")
.desc("total number of used NIC blks evicted")
;
nicUsedAvgLatency
.name(name + ".nicUsedAvgLatency")
.desc("avg number of cycles a used NIC blk is in cache")
.precision(0)
;
nicUsedAvgLatency = nicUsedTotLatency / nicUsedTotEvicted;
usedEvictDist
.name(name + ".usedEvictDist")
.desc("distribution of used NIC blk eviction times")
.flags(pdf | cdf)
;
nicUnusedWhenEvicted
.name(name + ".nicUnusedWhenEvicted")
.desc("number of NIC blks that were unused when evicted")
;
nicUnusedTotLatency
.name(name + ".nicUnusedTotLatency")
.desc("total cycles before eviction of unused NIC blks")
;
nicUnusedTotEvicted
.name(name + ".nicUnusedTotEvicted")
.desc("total number of unused NIC blks evicted")
;
nicUnusedAvgLatency
.name(name + ".nicUnusedAvgLatency")
.desc("avg number of cycles an unused NIC blk is in cache")
.precision(0)
;
nicUnusedAvgLatency = nicUnusedTotLatency / nicUnusedTotEvicted;
unusedEvictDist
.name(name + ".unusedEvictDist")
.desc("distribution of unused NIC blk eviction times")
.flags(pdf | cdf)
;
nicUseByCPUCycleTotal
.name(name + ".nicUseByCPUCycleTotal")
.desc("total latency of NIC blks til usage time")
;
nicBlksUsedByCPU
.name(name + ".nicBlksUsedByCPU")
.desc("total number of NIC blks used")
;
nicAvgUsageByCPULatency
.name(name + ".nicAvgUsageByCPULatency")
.desc("average number of cycles before a NIC blk that is used gets used")
.precision(0)
;
nicAvgUsageByCPULatency = nicUseByCPUCycleTotal / nicBlksUsedByCPU;
useByCPUCycleDist
.name(name + ".useByCPUCycleDist")
.desc("the distribution of cycle time in cache before NIC blk is used")
.flags(pdf | cdf)
;
cpuUsedBlks
.name(name + ".cpuUsedBlks")
.desc("number of cpu blks that were used before evicted")
;
cpuUnusedBlks
.name(name + ".cpuUnusedBlks")
.desc("number of cpu blks that were unused before evicted")
;
nicAvgLatency
.name(name + ".nicAvgLatency")
.desc("avg number of cycles a NIC blk is in cache before evicted")
.precision(0)
;
nicAvgLatency = (nicUnusedTotLatency + nicUsedTotLatency) /
(nicUnusedTotEvicted + nicUsedTotEvicted);
NR_CP_hits
.name(name + ".NR_CP_hits")
.desc("NIC requests hitting in CPU Partition")
;
NR_NP_hits
.name(name + ".NR_NP_hits")
.desc("NIC requests hitting in NIC Partition")
;
CR_CP_hits
.name(name + ".CR_CP_hits")
.desc("CPU requests hitting in CPU partition")
;
CR_NP_hits
.name(name + ".CR_NP_hits")
.desc("CPU requests hitting in NIC partition")
;
}
// probe cache for presence of given block.
bool
Split::probe(Addr addr) const
{
bool success = lru->probe(addr);
if (!success) {
if (lifo && lifo_net)
success = lifo_net->probe(addr);
else if (lru_net)
success = lru_net->probe(addr);
}
return success;
}
SplitBlk*
Split::findBlock(Addr addr, int &lat)
{
SplitBlk *blk = lru->findBlock(addr, lat);
if (!blk) {
if (lifo && lifo_net) {
blk = lifo_net->findBlock(addr, lat);
} else if (lru_net) {
blk = lru_net->findBlock(addr, lat);
}
}
return blk;
}
SplitBlk*
Split::findBlock(Addr addr) const
{
SplitBlk *blk = lru->findBlock(addr);
if (!blk) {
if (lifo && lifo_net) {
blk = lifo_net->findBlock(addr);
} else if (lru_net) {
blk = lru_net->findBlock(addr);
}
}
return blk;
}
SplitBlk*
Split::findReplacement(Addr addr, PacketList &writebacks)
{
SplitBlk *blk = NULL;
assert(0);
#if 0
if (pkt->nic_pkt()) {
DPRINTF(Split, "finding a replacement for nic_req\n");
nic_repl++;
if (lifo && lifo_net)
blk = lifo_net->findReplacement(addr, writebacks);
else if (lru_net)
blk = lru_net->findReplacement(addr, writebacks);
// in this case, this is an LRU only cache, it's non partitioned
else
blk = lru->findReplacement(addr, writebacks);
} else {
DPRINTF(Split, "finding replacement for cpu_req\n");
blk = lru->findReplacement(addr, writebacks);
cpu_repl++;
}
Tick latency = curTick - blk->ts;
if (blk->isNIC) {
if (blk->isUsed) {
nicUsedWhenEvicted++;
usedEvictDist.sample(latency);
nicUsedTotLatency += latency;
nicUsedTotEvicted++;
} else {
nicUnusedWhenEvicted++;
unusedEvictDist.sample(latency);
nicUnusedTotLatency += latency;
nicUnusedTotEvicted++;
}
} else {
if (blk->isUsed) {
cpuUsedBlks++;
} else {
cpuUnusedBlks++;
}
}
// blk attributes for the new blk coming IN
blk->ts = curTick;
blk->isNIC = (pkt->nic_pkt()) ? true : false;
#endif
return blk;
}
void
Split::invalidateBlk(Split::BlkType *blk)
{
if (!blk) {
fatal("FIXME!\n");
#if 0
if (lifo && lifo_net)
blk = lifo_net->findBlock(addr);
else if (lru_net)
blk = lru_net->findBlock(addr);
#endif
if (!blk)
return;
}
blk->status = 0;
blk->isTouched = false;
tagsInUse--;
}
void
Split::cleanupRefs()
{
lru->cleanupRefs();
if (lifo && lifo_net)
lifo_net->cleanupRefs();
else if (lru_net)
lru_net->cleanupRefs();
ostream *memPrint = simout.create("memory_footprint.txt");
// this shouldn't be here but it happens at the end, which is what i want
memIter end = memHash.end();
for (memIter iter = memHash.begin(); iter != end; ++iter) {
ccprintf(*memPrint, "%8x\t%d\n", (*iter).first, (*iter).second);
}
}
Addr
Split::regenerateBlkAddr(Addr tag, int set) const
{
if (lifo_net)
return lifo_net->regenerateBlkAddr(tag, set);
else
return lru->regenerateBlkAddr(tag, set);
}
Addr
Split::extractTag(Addr addr) const
{
// need to fix this if we want to use it... old interface of
// passing in blk was too weird
assert(0);
return 0;
/*
if (blk->part == 2) {
if (lifo_net)
return lifo_net->extractTag(addr);
else if (lru_net)
return lru_net->extractTag(addr);
else
panic("this shouldn't happen");
} else
return lru->extractTag(addr);
*/
}