/**
* ****************************************************************************
* Copyright (c) 2010-2016 by Min Cai (min.cai.china@gmail.com).
* <p>
* This file is part of the Archimulator multicore architectural simulator.
* <p>
* Archimulator is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p>
* Archimulator is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License
* along with Archimulator. If not, see <http://www.gnu.org/licenses/>.
* ****************************************************************************
*/
package archimulator.uncore.cache.stackDistanceProfile;
import archimulator.common.Simulation;
import archimulator.common.SimulationEvent;
import archimulator.common.report.ReportNode;
import archimulator.common.report.Reportable;
import archimulator.uncore.MemoryHierarchyAccess;
import archimulator.uncore.coherence.event.GeneralCacheControllerServiceNonblockingRequestEvent;
import archimulator.uncore.coherence.msi.controller.DirectoryController;
import archimulator.uncore.coherence.msi.controller.GeneralCacheController;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Stack;
import java.util.TreeMap;
/**
* Stack distance profiling helper.
*
* @author Min Cai
*/
public class StackDistanceProfilingHelper implements Reportable {
private DirectoryController l2Controller;
private Map<Integer, Stack<Integer>> l2LruStacks;
private StackDistanceProfile l2StackDistanceProfile;
/**
* Create a stack distance profiling helper.
*
* @param simulation the simulation
*/
public StackDistanceProfilingHelper(Simulation simulation) {
this.l2Controller = simulation.getProcessor().getMemoryHierarchy().getL2Controller();
this.l2LruStacks = new TreeMap<>();
this.l2StackDistanceProfile = new StackDistanceProfile(this.l2Controller.getCache().getAssociativity());
simulation.getBlockingEventDispatcher().addListener(GeneralCacheControllerServiceNonblockingRequestEvent.class, event -> {
if (event.getCacheController() == l2Controller) {
profileStackDistance(event.isHitInCache(), event.getWay(), event.getAccess());
}
});
}
/**
* Profile the stack distance for an access.
*
* @param hitInCache a value indicating whether the access hits in the cache or not
* @param way the way
* @param access the memory hierarchy access
*/
private void profileStackDistance(boolean hitInCache, int way, MemoryHierarchyAccess access) {
int tag = access.getPhysicalTag();
int set = this.l2Controller.getCache().getSet(tag);
Stack<Integer> lruStack = getLruStack(set);
int stackDistance = lruStack.search(tag);
if (stackDistance != -1) {
lruStack.remove((Integer) tag);
stackDistance--;
}
lruStack.push(tag);
if (lruStack.size() > this.l2Controller.getCache().getAssociativity()) {
lruStack.remove(lruStack.size() - 1);
}
this.l2Controller.getBlockingEventDispatcher().dispatch(new StackDistanceProfiledEvent(this.l2Controller, access, hitInCache, set, way, stackDistance));
if (stackDistance == -1) {
this.l2StackDistanceProfile.incrementMissCounter();
} else {
this.l2StackDistanceProfile.incrementHitCounter(stackDistance);
}
}
@Override
public void dumpStats(ReportNode reportNode) {
reportNode.getChildren().add(new ReportNode(reportNode, "stackDistanceProfilingHelper") {{
for (int i = 0; i < getL2StackDistanceProfile().getHitCounters().size(); i++) {
getChildren().add(
new ReportNode(
this,
String.format("l2StackDistanceProfile/hitCounters/%d", i),
String.format("%s", getL2StackDistanceProfile().getHitCounters().get(i))
)
);
}
getChildren().add(
new ReportNode(
this,
"l2StackDistanceProfile/missCounter",
String.format("%d", getL2StackDistanceProfile().getMissCounter())
)
);
for (int i : getAssumedNumMissesDistribution().keySet()) {
getChildren().add(
new ReportNode(
this,
String.format("assumedNumMissesDistribution/%d", i),
String.format("%s", getAssumedNumMissesDistribution().get(i))
)
);
}
}});
}
/**
* Get the LRU stack for the specified set in the L2 cache.
*
* @param set the set index
* @return the LRU stack for the specified set in the L2 cache
*/
private Stack<Integer> getLruStack(int set) {
if (!this.l2LruStacks.containsKey(set)) {
this.l2LruStacks.put(set, new Stack<>());
}
return this.l2LruStacks.get(set);
}
/**
* Get the number of misses for the assumed associativity.
*
* @param associativity the assumed associativity
* @return the number of misses for the assumed associativity
*/
public int getAssumedNumMisses(int associativity) {
if (associativity > this.l2Controller.getCache().getAssociativity()) {
throw new IllegalArgumentException();
}
int numMisses = 0;
for (int i = associativity - 1; i < this.l2Controller.getCache().getAssociativity(); i++) {
numMisses += this.l2StackDistanceProfile.getHitCounters().get(i);
}
numMisses += this.l2StackDistanceProfile.getMissCounter();
return numMisses;
}
/**
* Get the distribution of the number of misses for the assumed associativities.
*
* @return the distribution of the number of misses for the assumed associativities
*/
public Map<Integer, Integer> getAssumedNumMissesDistribution() {
Map<Integer, Integer> result = new LinkedHashMap<>();
for (int associativity = 1; associativity <= this.l2Controller.getCache().getAssociativity(); associativity++) {
result.put(associativity, this.getAssumedNumMisses(associativity));
}
return result;
}
/**
* Get the stack distance profile for the L2 cache.
*
* @return the stack distance profile for the L2 cache
*/
public StackDistanceProfile getL2StackDistanceProfile() {
return l2StackDistanceProfile;
}
/**
* An event when a stack distance is profiled.
*/
public class StackDistanceProfiledEvent extends SimulationEvent {
private GeneralCacheController cacheController;
private MemoryHierarchyAccess access;
private boolean hitInCache;
private int set;
private int way;
private int stackDistance;
/**
* Create an event when a stack distance is profiled.
*
* @param cacheController the cache controller
* @param access the memory hierarchy access
* @param hitInCache a value indicating whether the access hits in the cache or not
* @param set the set index
* @param way the way
* @param stackDistance the stack distance
*/
public StackDistanceProfiledEvent(GeneralCacheController cacheController, MemoryHierarchyAccess access, boolean hitInCache, int set, int way, int stackDistance) {
super(cacheController);
this.cacheController = cacheController;
this.access = access;
this.hitInCache = hitInCache;
this.set = set;
this.way = way;
this.stackDistance = stackDistance;
}
/**
* Get the cache controller.
*
* @return the cache controller
*/
public GeneralCacheController<?, ?> getCacheController() {
return cacheController;
}
/**
* Get the memory hierarchy access.
*
* @return the memory hierarchy access
*/
public MemoryHierarchyAccess getAccess() {
return access;
}
/**
* Get a value indicating whether the access hits in the cache or not.
*
* @return a value indicating whether the access hits in the cache or not
*/
public boolean isHitInCache() {
return hitInCache;
}
/**
* Get the set index.
*
* @return the set index
*/
public int getSet() {
return set;
}
/**
* Get the way.
*
* @return the way
*/
public int getWay() {
return way;
}
/**
* Get the stack distance.
*
* @return the stack position
*/
public int getStackDistance() {
return stackDistance;
}
}
}