Tejas/src/simulator/memorysystem/Cache.java

1147 lines
32 KiB
Java
Executable File

/*****************************************************************************
Tejas Simulator
------------------------------------------------------------------------------------------------------------
Copyright 2010 Indian Institute of Technology, Delhi
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
------------------------------------------------------------------------------------------------------------
Contributors: Moksh Upadhyay
*****************************************************************************/
package memorysystem;
import generic.Core;
import generic.Event;
import generic.EventQueue;
import generic.GlobalClock;
import generic.RequestType;
import generic.SimulationElement;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.TreeSet;
import main.ArchitecturalComponent;
import memorysystem.coherence.Coherence;
import memorysystem.nuca.NucaCache;
import memorysystem.nuca.NucaCache.NucaType;
import memorysystem.prefetcher.Power4Prefetcher;
import memorysystem.prefetcher.Prefetcher;
import misc.Util;
import net.NocInterface;
import config.CacheConfig;
import config.CacheConfig.PrefetcherType;
import config.CacheConfig.WritePolicy;
import config.CacheDataType;
import config.CacheEnergyConfig;
import config.EnergyConfig;
import config.SystemConfig;
import dram.MainMemoryDRAMController;
public class Cache extends SimulationElement {
/* cache parameters */
public CoreMemorySystem containingMemSys;
protected int blockSize; // in bytes
public int blockSizeBits; // in bits
public int assoc;
protected int assocBits; // in bits
protected int size; // MegaBytes
protected int numLines;
protected int numLinesBits;
public int numSetsBits;
protected long timestamp;
protected int numLinesMask;
public Coherence mycoherence;
public Prefetcher myprefetcher;
public int AMAT;
// public CacheType levelFromTop;
public boolean isLastLevel; // Tells whether there are any more levels of
// cache
public CacheConfig.WritePolicy writePolicy; // WRITE_BACK or WRITE_THROUGH
public String nextLevelName; // Name of the next level cache according to
// the configuration file
public ArrayList<Cache> prevLevel = new ArrayList<Cache>(); // Points
// towards the
// previous
// level in the
// cache
// hierarchy
public Cache nextLevel; // Points towards the next level in the cache
// hierarchy
protected CacheLine lines[];
public static boolean toCountCompulsoryMisses = false;
public TreeSet<Long> addressesAccessedSoFar;
public long numberOfCompulsoryMisses;
public long noOfRequests;
public long noOfAccesses;
public long noOfResponsesReceived;
public long noOfResponsesSent;
public long noOfWritesForwarded;
public long noOfWritesReceived;
public long hits;
public long misses;
public long halfmisses;
public long combinedWrites;
public long evictions;
public boolean debug = false;
public NucaType nucaType;
public long invalidAccesses = 0;
CacheEnergyConfig energy;
public String cacheName;
public void createLinkToNextLevelCache(Cache nextLevelCache) {
this.nextLevel = nextLevelCache;
this.nextLevel.prevLevel.add(this);
}
public CacheConfig cacheConfig;
public int id;
protected MSHR mshr;
public boolean isBusy(long addr) {
return mshr.isMSHRFull(addr);
}
public Cache(String cacheName, int id, CacheConfig cacheParameters,
CoreMemorySystem containingMemSys) {
super(cacheParameters.portType,
cacheParameters.getReadPorts(),
cacheParameters.getWritePorts(),
cacheParameters.getReadWritePorts(),
cacheParameters.getPortReadOccupancy() * cacheParameters.stepSize,
cacheParameters.getPortWriteOccupancy() * cacheParameters.stepSize,
cacheParameters.getReadLatency() * cacheParameters.stepSize,
cacheParameters.getWriteLatency() * cacheParameters.stepSize,
cacheParameters.operatingFreq);
// add myself to the global cache list
if(cacheParameters.isDirectory==true) {
ArchitecturalComponent.coherences.add((Coherence) this);
} else {
MemorySystem.addToCacheList(cacheName, this);
if(containingMemSys==null) {
ArchitecturalComponent.sharedCaches.add(this);
}
ArchitecturalComponent.caches.add(this);
}
if(cacheParameters.prefetcherType == PrefetcherType.Power4)
{
this.myprefetcher = new Power4Prefetcher(this);
}
this.AMAT = cacheParameters.AMAT;
if (cacheParameters.collectWorkingSetData == true) {
workingSet = new TreeSet<Long>();
workingSetChunkSize = cacheParameters.workingSetChunkSize;
}
this.containingMemSys = containingMemSys;
// set the parameters
this.blockSize = cacheParameters.getBlockSize();
this.assoc = cacheParameters.getAssoc();
this.size = cacheParameters.getSize();
this.blockSizeBits = Util.logbase2(blockSize);
this.assocBits = Util.logbase2(assoc);
this.numLines = getNumLines();
this.numLinesBits = Util.logbase2(numLines);
this.numSetsBits = numLinesBits - assocBits;
this.writePolicy = cacheParameters.getWritePolicy();
this.cacheConfig = cacheParameters;
if (this.containingMemSys == null) {
// Use the core memory system of core 0 for all the shared caches.
this.isSharedCache = true;
// this.containingMemSys =
// ArchitecturalComponent.getCore(0).getExecEngine().getCoreMemorySystem();
}
if (cacheParameters.nextLevel == "") {
this.isLastLevel = true;
} else {
this.isLastLevel = false;
}
this.cacheName = cacheName;
this.id = id;
this.nextLevelName = cacheParameters.getNextLevel();
// this.enforcesCoherence = cacheParameters.isEnforcesCoherence();
this.timestamp = 0;
this.numLinesMask = numLines - 1;
this.noOfRequests = 0;
noOfAccesses = 0;
noOfResponsesReceived = 0;
noOfResponsesSent = 0;
noOfWritesForwarded = 0;
noOfWritesReceived = 0;
this.hits = 0;
this.misses = 0;
this.halfmisses = 0;
this.combinedWrites = 0;
this.evictions = 0;
// make the cache
makeCache(cacheParameters.isDirectory);
this.mshr = new MSHR(cacheConfig.mshrSize, blockSizeBits, this);
this.nucaType = cacheParameters.nucaType;
energy = cacheParameters.power;
eventsWaitingOnMSHR = new LinkedList<AddressCarryingEvent>();
if(toCountCompulsoryMisses)
{
addressesAccessedSoFar = new TreeSet<Long>();
numberOfCompulsoryMisses = 0;
}
halfmissList = new ArrayList<Event>();
}
public void setCoherence(Coherence c) {
this.mycoherence = c;
}
private boolean printCacheDebugMessages = false;
//request (read or write or line-forward from another cache)
// - read (*reads++)
// - line found in cache (hits++)
// - line not in cache
// - entry exists in MSHR for same addr (halfmisses++)
// - no MSHR entry (misses++)
// - write (*writes++)
// - line found in cache (hits++)
// - line not in cache
// - entry exists in MSHR for same addr (halfmisses++)
// - latest MSHR entry for that addr is a write (combinedWrites++)
// - no MSHR entry (misses++)
ArrayList<Event> halfmissList;
public void handleEvent(EventQueue eventQ, Event e) {
AddressCarryingEvent event = (AddressCarryingEvent) e;
printCacheDebugMessage(event);
long addr = ((AddressCarryingEvent) event).getAddress();
RequestType requestType = event.getRequestType();
noOfAccesses++;
if(mshr.isAddrInMSHR(addr) &&
(requestType==RequestType.Cache_Read || requestType==RequestType.Cache_Write || requestType==RequestType.EvictCacheLine)) {
if(requestType==RequestType.Cache_Read || requestType==RequestType.Cache_Write)
{
halfmisses++;
noOfRequests++;
// if(this.cacheName.contains("L1"))
// {
// System.out.println("half miss event added to mshr : " + e.serializationID);
// halfmissList.add(event);
// if(event.serializationID == 4385)
// {
// System.out.println(event.serializationID);
// }
// }
}
mshr.addToMSHR(event);
return;
}
switch (event.getRequestType()) {
case Cache_Read:
case Cache_Write: {
noOfRequests++;
handleAccess(addr, requestType, event);
break;
}
case Mem_Response: {
handleMemResponse(event);
break;
}
case EvictCacheLine: {
updateStateOfCacheLine(addr, MESI.INVALID);
break;
}
case AckEvictCacheLine: {
processEventsInMSHR(addr);
break;
}
case DirectoryCachelineForwardRequest: {
noOfRequests++;
handleDirectoryCachelineForwardRequest(addr, (Cache) (((AddressCarryingEvent) event).getPayloadElement()));
break;
}
case DirectorySharedToExclusive: {
handleDirectorySharedToExclusive(addr);
break;
}
case AckDirectoryWriteHit: {
handleAckDirectoryWriteHit(event);
break;
}
}
}
protected void handleAckDirectoryWriteHit(AddressCarryingEvent event) {
//This function just ensures that the writeHit event gets a line
long addr = event.getAddress();
CacheLine cl = accessValid(addr);
if(cl==null) {
misc.Error.showErrorAndExit("Ack write hit expects cache line");
// writehit expects a line to be present
if(isThereAnUnlockedOrInvalidEntryInCacheSet(addr)) {
fillAndSatisfyRequests(addr);
return;
} else {
event.setEventTime(event.getEventTime() + 1);
return;
}
} else {
processEventsInMSHR(addr);
}
}
protected void handleDirectorySharedToExclusive(long addr) {
if(accessValid(addr)==null) {
// c1 and c2 both have address x
// both decide to evict at the same time
// c2's evict reaches directory first. directory asks c1 to change state from shared to exclusive
// c1 however does not have the line
noteInvalidState("shared to exclusive for a line that does not exist. addr : " + addr + ". cache : " + this);
}
updateStateOfCacheLine(addr, MESI.EXCLUSIVE);
}
protected void handleDirectoryCachelineForwardRequest(long addr, Cache cache) {
AddressCarryingEvent event = new AddressCarryingEvent(
cache.getEventQueue(), 0, this, cache,
RequestType.Mem_Response, addr);
updateStateOfCacheLine(addr, MESI.SHARED);
this.sendEvent(event);
}
protected void printCacheDebugMessage(Event event) {
if (printCacheDebugMessages == true) {
if (event.getClass() == AddressCarryingEvent.class) {
System.out.println("CACHE : globalTime = "
+ GlobalClock.getCurrentTime() + "\teventTime = "
+ event.getEventTime() + "\t" + event.getRequestType()
+ "\trequestingElelement = "
+ event.getRequestingElement() + "\taddress = "
+ ((AddressCarryingEvent) event).getAddress() + "\t"
+ this + "\t" + ((AddressCarryingEvent) event).dn_status);
}
}
}
public void handleAccess(long addr, RequestType requestType,
AddressCarryingEvent event) {
if (requestType == RequestType.Cache_Write) {
noOfWritesReceived++;
}
if(toCountCompulsoryMisses
&& addressesAccessedSoFar.contains(getLineAddress(addr)) == false)
{
numberOfCompulsoryMisses++;
addressesAccessedSoFar.add(getLineAddress(addr));
}
CacheLine cl = this.accessAndMark(addr);
// IF HIT
if (cl != null) {
hits++;
cacheHit(addr, requestType, cl, event);
} else {
misses++;
if (this.mycoherence != null) {
if (requestType == RequestType.Cache_Write) {
mycoherence.writeMiss(addr, this);
} else if (requestType == RequestType.Cache_Read) {
mycoherence.readMiss(addr, this);
}
} else {
sendRequestToNextLevel(addr, RequestType.Cache_Read);
}
mshr.addToMSHR(event);
if(this.myprefetcher != null)
{
this.myprefetcher.handleMissAtAddress(addr);
}
}
}
protected void cacheHit(long addr, RequestType requestType, CacheLine cl,
AddressCarryingEvent event) {
if (requestType == RequestType.Cache_Read) {
sendAcknowledgement(event);
} else if (requestType == RequestType.Cache_Write) {
if(event.getRequestingElement() != this
&& getPort().getWriteLatencyOfConnectedElement() - getPort().getReadLatencyOfConnectedElement() > 0)
{
//this case refers to when the line to be written to is found in the cache
//time for line searching has already been spent
//now spend time for writing
event.update(0);
event.update(this, this);
this.getPort().put(event);
//to correct the double counting of stats
noOfAccesses--;
noOfRequests--;
noOfWritesReceived--;
hits--;
}
else
{
if(this.writePolicy == WritePolicy.WRITE_THROUGH) {
sendRequestToNextLevel(addr, RequestType.Cache_Write);
}
if( (cl.getState() == MESI.SHARED || cl.getState() == MESI.EXCLUSIVE) &&
(mycoherence!=null)) {
handleCleanToModified(addr, event);
}
}
} else {
misc.Error.showErrorAndExit("cache hit unknown event type\n" + event + "\ncache : " + this);
}
}
protected void handleMemResponse(AddressCarryingEvent memResponseEvent) {
long addr = memResponseEvent.getAddress();
if(isThereAnUnlockedOrInvalidEntryInCacheSet(addr)) {
noOfResponsesReceived++;
this.fillAndSatisfyRequests(addr);
} else {
memResponseEvent.setEventTime(GlobalClock.getCurrentTime()+1);
this.getEventQueue().addEvent(memResponseEvent);
}
}
public void sendRequestToNextLevel(long addr, RequestType requestType) {
Cache c = this.nextLevel;
AddressCarryingEvent event = null;
if (c != null) {
if(c.AMAT != -1 && requestType == RequestType.Cache_Read)
{
event = new AddressCarryingEvent(c.getEventQueue(), c.AMAT*c.stepSize, c, this,
RequestType.Mem_Response, addr);
this.getPort().put(event);
}
else
{
if(c.nucaType != NucaType.NONE)
{
// String nextLevelName = null;
// if(nextLevel.cacheName.contains("["))
// {
// nextLevelName = nextLevel.cacheName.substring(0, nextLevel.cacheName.indexOf('['));
// }
// else
// {
// nextLevelName = nextLevel.cacheName;
// }
//
// NucaCache nuca = ArchitecturalComponent.nucaList.get(nextLevelName);
c = ((NucaCache)c).getBank(((NocInterface)this.getComInterface()).getId(),addr);
}
event = new AddressCarryingEvent(c.getEventQueue(), 0, this, c,
requestType, addr);
addEventAtLowerCache(event, c);
}
} else {
Core core0 = ArchitecturalComponent.getCores()[0];
//added later by kush
MainMemoryDRAMController memController;
if(SystemConfig.memControllerToUse==true){
int chan=findChannelNumber(addr);
memController = getComInterface()
.getNearestMemoryController(chan);
}
else{
memController = getComInterface()
.getNearestMemoryController(0);
}
event = new AddressCarryingEvent(core0.getEventQueue(), 0, this,
memController, requestType, addr);
sendEvent(event);
}
}
//added by kush
public static int findChannelNumber(long physicalAddress){
long tempA,tempB;
int channelBits = log2(SystemConfig.mainMemoryConfig.numChans);
int DataBusBytesOffest = log2(SystemConfig.mainMemoryConfig.DATA_BUS_BYTES); //for 64 bit bus -> 8 bytes -> lower 3 bits of address irrelevant
int ColBytesOffset = log2(SystemConfig.mainMemoryConfig.BL);
//these are the bits we need to throw away because of "bursts". The column address is incremented internally on bursts
//So for a burst length of 4, 8 bytes of data are transferred on each burst
//Each consecutive 8 byte chunk comes for the "next" column
//So we traverse 4 columns in 1 request. Thus the lower log2(4) bits become irrelevant for us. Throw them away
//Finally we get 8 bytes * 4 = 32 bytes of data for a 64 bit data bus and BL = 4.
//This is equal to a cache line
//For clarity
//Throw away bits to account for data bus size in bytes
//and for burst length
physicalAddress >>>= (DataBusBytesOffest + ColBytesOffset); //using >>> for unsigned right shift
//System.out.println("Shifted address by " + (DataBusBytesOffest + ColBytesOffset) + " bits");
//By the same logic, need to remove the burst-related column bits from the column bit width to be decoded
//colEffectiveBits = colBits - ColBytesOffset;
//row:rank:bank:col:chan
tempA = physicalAddress;
physicalAddress = physicalAddress >>> channelBits; //always unsigned shifting
tempB = physicalAddress << channelBits;
//System.out.println("Shifted address by " + rankBits + " bits");
int decodedChan = (int) (tempA ^ tempB);
return decodedChan;
}
public static int log2(int a)
{
return (int) (Math.log(a)/Math.log(2));
}
private boolean isTopLevelCache() {
return this.cacheConfig.firstLevel;
}
public boolean isL2cache() {
// I am not a first level cache.
// But a cache connected on top of me is a first level cache
return (this.cacheConfig.firstLevel == false && this.prevLevel.get(0).cacheConfig.firstLevel == true);
}
public boolean isIcache() {
return (this.cacheConfig.firstLevel == true && (this.cacheConfig.cacheDataType == CacheDataType.Instruction || this.cacheConfig.cacheDataType == CacheDataType.Unified));
}
public boolean isL1cache() {
return (this.cacheConfig.firstLevel == true && (this.cacheConfig.cacheDataType == CacheDataType.Data || this.cacheConfig.cacheDataType == CacheDataType.Unified));
}
private boolean isSharedCache = false;
public boolean isSharedCache() {
return isSharedCache;
}
public boolean isPrivateCache() {
return !isSharedCache();
}
public boolean addEventAtLowerCache(AddressCarryingEvent event, Cache c) {
if (c.isBusy(event.getAddress()) == false) {
sendEvent(event);
c.workingSetUpdate();
return true;
} else {
// Slight approximation used. MSHR full is a rare event.
// On occurrence of such events, we just add this event to the pending events list of the lower level cache.
// The network congestion and the port occupancy of the next level is not modelled in such cases.
// It must be noted that the MSHR full event of the first level caches is being modelled correctly.
// This approximation applies only to non-firstlevel caches.
c.eventsWaitingOnMSHR.add(event);
// System.out.println();
return false;
}
}
public void fillAndSatisfyRequests(long addr) {
CacheLine evictedLine = this.fill(addr, MESI.SHARED);
handleEvictedLine(evictedLine);
processEventsInMSHR(addr);
}
protected void processEventsInMSHR(long addr) {
LinkedList<AddressCarryingEvent> missList = mshr.removeEventsFromMSHR(addr);
AddressCarryingEvent writeEvent = null;
for(AddressCarryingEvent event : missList) {
switch(event.getRequestType()) {
case Cache_Read: {
sendAcknowledgement(event);
// if(this.cacheName.contains("L1"))
// {
// System.out.println("process read miss : " + event.serializationID);
// halfmissList.remove(event);
// }
break;
}
case Cache_Write: {
// if(this.cacheName.contains("L1"))
// {
// System.out.println("process write miss : " + event.serializationID);
// halfmissList.remove(event);
// }
CacheLine cl = accessValid(addr);
if(cl!=null) {
updateStateOfCacheLine(addr, MESI.MODIFIED);
writeEvent = event;
} else {
misc.Error.showErrorAndExit("Cache write expects a line here : " + event);
}
break;
}
case DirectoryEvictedFromCoherentCache:
case EvictCacheLine: {
updateStateOfCacheLine(addr, MESI.INVALID);
addUnprocessedEventsToEventQueue(missList);
processEventsInPendingList();
return;
}
}
}
if(writeEvent!=null && writePolicy==WritePolicy.WRITE_THROUGH) {
sendRequestToNextLevel(addr, RequestType.Cache_Write);
}
processEventsInPendingList();
}
private void processEventsInPendingList() {
int size = eventsWaitingOnMSHR.size();
for(int i = 0; i < size; i++)
{
if(eventsWaitingOnMSHR.isEmpty())
{
break;
}
AddressCarryingEvent event = eventsWaitingOnMSHR.get(i);
if(mshr.isMSHRFull(event.getAddress()))
{
continue;
}
event.getProcessingElement().handleEvent(event.getEventQ(), event);
eventsWaitingOnMSHR.remove(event);
i--;
size--;
}
}
protected void handleEvictedLine(CacheLine evictedLine) {
if (evictedLine != null && evictedLine.getState() != MESI.INVALID) {
if(mshr.isAddrInMSHR(evictedLine.getAddress())) {
misc.Error.showErrorAndExit("evicting locked line : " + evictedLine + ". cache : " + this);
}
if (mycoherence != null) {
AddressCarryingEvent evictEvent = mycoherence.evictedFromCoherentCache(evictedLine.getAddress(), this);
mshr.addToMSHR(evictEvent);
} else if (evictedLine.isModified() && writePolicy == WritePolicy.WRITE_BACK) {
sendRequestToNextLevel(evictedLine.getAddress(), RequestType.Cache_Write);
}
}
}
private void handleCleanToModified(long addr, AddressCarryingEvent event) {
if(mycoherence!=null) {
mycoherence.writeHit(addr, this);
mshr.addToMSHR(event);
} else {
sendRequestToNextLevel(addr, RequestType.Cache_Write);
}
}
private void addUnprocessedEventsToEventQueue(LinkedList<AddressCarryingEvent> missList) {
int timeToSet = missList.size() * -1;
boolean startAddition = false;
for(AddressCarryingEvent event : missList) {
if(startAddition == true) {
event.setEventTime(timeToSet);
getEventQueue().addEvent(event);
timeToSet++;
}
if(event.getRequestType()==RequestType.EvictCacheLine
|| event.getRequestType()==RequestType.DirectoryEvictedFromCoherentCache) {
startAddition = true;
}
}
}
public void sendAcknowledgement(AddressCarryingEvent event) {
RequestType returnType = null;
if(event.getRequestType()==RequestType.Cache_Read) {
returnType = RequestType.Mem_Response;
} else {
misc.Error.showErrorAndExit("sendAcknowledgement is meant for cache read operation only : " + event);
}
AddressCarryingEvent memResponseEvent = new AddressCarryingEvent(
event.getEventQ(), 0, event.getProcessingElement(),
event.getRequestingElement(), returnType,
event.getAddress());
sendEvent(memResponseEvent);
noOfResponsesSent++;
// if(ArchitecturalComponent.getCores()[1].getNoOfInstructionsExecuted()
// > 6000000l)
// System.out.println("sending mem response from " +
// event.getProcessingElement() + " to " + event.getRequestingElement()
// + " for addr : " + event.getAddress());
}
public long computeTag(long addr) {
long tag = addr >>> (numSetsBits + blockSizeBits);
return tag;
}
public int getSetIdx(long addr) {
int startIdx = getStartIdx(addr);
return startIdx / assoc;
}
public int getStartIdx(long addr) {
long SetMask = (1 << (numSetsBits)) - 1;
int startIdx = (int) ((addr >>> blockSizeBits) & (SetMask));
return startIdx;
}
public int getNextIdx(int startIdx, int idx) {
int index = startIdx + (idx << numSetsBits);
return index;
}
public CacheLine accessValid(long addr) {
CacheLine cl = access(addr);
if (cl != null && cl.getState() != MESI.INVALID) {
return cl;
} else {
return null;
}
}
public CacheLine access(long addr) {
/* compute startIdx and the tag */
int startIdx = getStartIdx(addr);
long tag = computeTag(addr);
/* search in a set */
for (int idx = 0; idx < assoc; idx++) {
// calculate the index
int index = getNextIdx(startIdx, idx);
// fetch the cache line
CacheLine ll = this.lines[index];
// If the tag is matching, we have a hit
if (ll.hasTagMatch(tag)) {
return ll;
}
}
return null;
}
protected void mark(CacheLine ll, long tag) {
ll.setTag(tag);
mark(ll);
}
private void mark(CacheLine ll) {
ll.setTimestamp(timestamp);
timestamp += 1.0;
}
private void makeCache(boolean isDirectory) {
lines = new CacheLine[numLines];
for (int i = 0; i < numLines; i++) {
lines[i] = new CacheLine(isDirectory);
}
}
private int getNumLines() {
long totSize = size;
return (int) (totSize / (long) (blockSize));
}
protected CacheLine accessAndMark(long addr) {
CacheLine cl = accessValid(addr);
if (cl != null) {
mark(cl);
}
return cl;
}
public CacheLine fill(long addr, MESI stateToSet) // Returns a copy of the
// evicted line
{
CacheLine evictedLine = null;
/* compute startIdx and the tag */
int startIdx = getStartIdx(addr);
long tag = computeTag(addr);
boolean addressAlreadyPresent = false;
/* find any invalid lines -- no eviction */
CacheLine fillLine = null;
boolean evicted = false;
// ------- Check if address is in cache ---------
for (int idx = 0; idx < assoc; idx++) {
int nextIdx = getNextIdx(startIdx, idx);
CacheLine ll = this.lines[nextIdx];
if (ll.getTag() == tag) {
addressAlreadyPresent = true;
fillLine = ll;
break;
}
}
// ------- Check if there's an invalid line ---------
for (int idx = 0; !addressAlreadyPresent && idx < assoc; idx++) {
int nextIdx = getNextIdx(startIdx, idx);
CacheLine ll = this.lines[nextIdx];
if (ll.isValid() == false && mshr.isAddrInMSHR(ll.getAddress())==false
|| (this.nucaType!= NucaType.NONE && ll.isValid() == false)) {
fillLine = ll;
break;
}
}
// ------- Check if there's an unlocked valid line ---------
if (fillLine == null) {
evicted = true; // We need eviction in this case
double minTimeStamp = Double.MAX_VALUE;
for (int idx = 0; idx < assoc; idx++) {
int index = getNextIdx(startIdx, idx);
CacheLine ll = this.lines[index];
if(mshr.isAddrInMSHR(ll.getAddress())==true) {
continue;
}
if (minTimeStamp > ll.getTimestamp()) {
minTimeStamp = ll.getTimestamp();
fillLine = ll;
}
}
}
if (fillLine == null) {
misc.Error.showErrorAndExit("Unholy mess !!");
}
/* if there has been an eviction */
if (evicted) {
evictedLine = (CacheLine) fillLine.clone();
long evictedLinetag = evictedLine.getTag();
evictedLinetag = (evictedLinetag << numSetsBits)
+ (startIdx / assoc);
evictedLine.setTag(evictedLinetag);
this.evictions++;
}
/* This is the new fill line */
fillLine.setState(stateToSet);
fillLine.setAddress(addr);
mark(fillLine, tag);
return evictedLine;
}
public LinkedList<AddressCarryingEvent> eventsWaitingOnMSHR = new LinkedList<AddressCarryingEvent>();
public String toString() {
return cacheName;
}
public EnergyConfig calculateAndPrintEnergy(FileWriter outputFileWriter,
String componentName) throws IOException {
EnergyConfig newPower = new EnergyConfig(energy.leakageEnergy,
energy.readDynamicEnergy);
EnergyConfig cachePower = new EnergyConfig(newPower, noOfAccesses);
cachePower.printEnergyStats(outputFileWriter, componentName);
return cachePower;
}
public void updateStateOfCacheLine(long addr, MESI newState) {
CacheLine cl = this.access(addr);
if (cl != null) {
cl.setState(newState);
if(newState==MESI.INVALID && mshr.isAddrInMSHR(addr)) {
misc.Error.showErrorAndExit("Cannot invalidate a locked line. Addr : " + addr + ". Cache : " + this);
}
if (newState == MESI.INVALID) {
if (isBelowCoherenceLevel()) {
getPrevLevelCoherence().evictedFromSharedCache(addr, this);
} else {
for (Cache c : prevLevel) {
sendAnEventFromMeToCache(addr, c, RequestType.EvictCacheLine);
}
}
} else {
// If you are not below coherence, then keep the same state in the previous level caches
// This ensures that the caches in the same core have the same MESI state
if(isBelowCoherenceLevel()==false && this.isTopLevelCache()==false) {
for(Cache c : prevLevel) {
c.updateStateOfCacheLine(addr, newState);
}
}
}
}
}
public EventQueue getEventQueue() {
if (containingMemSys != null) {
return containingMemSys.getCore().eventQueue;
} else {
return (ArchitecturalComponent.getCores()[0]).eventQueue;
}
}
public Cache getNextLevelCache(long addr) {
return nextLevel;
}
public void workingSetUpdate() {
// Clear the working set data after every x instructions
if (this.containingMemSys != null && this.workingSet != null) {
if (isIcache()) {
long numInsn = containingMemSys.getiCache().hits
+ containingMemSys.getiCache().misses;
long numWorkingSets = numInsn / workingSetChunkSize;
if (numWorkingSets > containingMemSys.numInstructionSetChunksNoted) {
this.clearWorkingSet();
containingMemSys.numInstructionSetChunksNoted++;
}
} else if (isL1cache()) {
long numInsn = containingMemSys.getiCache().hits
+ containingMemSys.getiCache().misses;
long numWorkingSets = numInsn / workingSetChunkSize;
if (numWorkingSets > containingMemSys.numDataSetChunksNoted) {
this.clearWorkingSet();
containingMemSys.numDataSetChunksNoted++;
}
}
}
}
TreeSet<Long> workingSet = null;
long workingSetChunkSize = 0;
public long numWorkingSetHits = 0;
public long numWorkingSetMisses = 0;
public long numFlushesInWorkingSet = 0;
public long totalWorkingSetSize = 0;
public long maxWorkingSetSize = Long.MIN_VALUE;
public long minWorkingSetSize = Long.MAX_VALUE;
void addToWorkingSet(long addr) {
long lineAddr = addr >>> blockSizeBits;
if (workingSet != null) {
if (workingSet.contains(lineAddr) == true) {
numWorkingSetHits++;
return;
} else {
numWorkingSetMisses++;
workingSet.add(lineAddr);
}
}
}
float getWorkingSetHitrate() {
if (numWorkingSetHits == 0 && numWorkingSetMisses == 0) {
return 0.0f;
} else {
return (float) numWorkingSetHits
/ (float) (numWorkingSetHits + numWorkingSetMisses);
}
}
void clearWorkingSet() {
numFlushesInWorkingSet++;
totalWorkingSetSize += workingSet.size();
if (workingSet.size() > maxWorkingSetSize) {
maxWorkingSetSize = workingSet.size();
}
if (workingSet.size() < minWorkingSetSize) {
minWorkingSetSize = workingSet.size();
}
// System.out.println(this + " : For chunk " +
// (numFlushesInWorkingSet-1) +
// "\tworkSet = " + workingSet.size() +
// "\tminSet = " + minWorkingSetSize +
// "\tavgSet = " +
// (float)totalWorkingSetSize/(float)numFlushesInWorkingSet +
// "\tmaxSet = " + maxWorkingSetSize +
// "\tworkSetHitrate = " + getWorkingSetHitrate());
if (workingSet != null) {
workingSet.clear();
}
}
public long getLineAddress(long addr) {
return addr >>> blockSizeBits;
}
protected AddressCarryingEvent sendAnEventFromMeToCache(long addr, Cache c,
RequestType request) {
// Create an event
AddressCarryingEvent event = new AddressCarryingEvent(
c.getEventQueue(), 0, this, c, request, addr);
// 2. Send event to cache
this.sendEvent(event);
return event;
}
private Coherence getPrevLevelCoherence() {
return prevLevel.get(0).mycoherence;
}
private boolean isBelowCoherenceLevel() {
if (prevLevel != null && prevLevel.size() > 0
&& prevLevel.get(0).mycoherence != null) {
return true;
} else {
return false;
}
}
protected boolean isThereAnUnlockedOrInvalidEntryInCacheSet(long addr) {
/* compute startIdx and the tag */
int startIdx = getStartIdx(addr);
/* search in a set */
for (int idx = 0; idx < assoc; idx++) {
// calculate the index
int index = getNextIdx(startIdx, idx);
// fetch the cache line
CacheLine ll = lines[index];
// If the tag is matching, we have a hit
if(ll.getAddress()==addr) {
return true;
}
if ((ll.isValid() == false && mshr.isAddrInMSHR(ll.getAddress())==false
|| (this.nucaType!= NucaType.NONE && ll.isValid() == false))) {
return true;
}
if(mshr.isAddrInMSHR(ll.getAddress())==false) {
return true;
}
// else if (ll.getState() == MESI.INVALID) {
// return true;
// }
}
return false;
}
public int numberOfLinesOfSetInMSHR(long addr)
{
int count = 0;
int startIdx = getStartIdx(addr);
for (int idx = 0; idx < assoc; idx++)
{
int index = getNextIdx(startIdx, idx);
CacheLine ll = lines[index];
if(mshr.isAddrInMSHR(ll.getAddress()))
{
count++;
}
}
return count;
}
public void printMSHR() {
mshr.printMSHR();
}
protected void noteInvalidState(String msg) {
invalidAccesses++;
//System.err.println(msg);
}
public void noteMSHRStats() {
mshr.noteMSHRStats();
}
public double getAvgNumEventsPendingInMSHR() {
return mshr.getAvgNumEventsPendingInMSHR();
}
public double getAvgNumEventsPendingInMSHREntry() {
return mshr.getAvgNumEventsPendingInMSHREntry();
}
public Prefetcher getMyprefetcher() {
return myprefetcher;
}
public void setMyprefetcher(Prefetcher myprefetcher) {
this.myprefetcher = myprefetcher;
}
}