/**
* ****************************************************************************
* 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.helperThread.hotspot;
import archimulator.analysis.BasicBlock;
import archimulator.analysis.Function;
import archimulator.common.Simulation;
import archimulator.common.report.ReportNode;
import archimulator.common.report.Reportable;
import archimulator.core.DynamicInstruction;
import archimulator.isa.StaticInstructionType;
import archimulator.isa.event.FunctionCallEvent;
import archimulator.os.Process;
import archimulator.uncore.MemoryHierarchyAccess;
import archimulator.uncore.cache.stackDistanceProfile.StackDistanceProfilingHelper;
import archimulator.uncore.coherence.event.GeneralCacheControllerServiceNonblockingRequestEvent;
import archimulator.uncore.coherence.msi.controller.DirectoryController;
import archimulator.uncore.helperThread.HelperThreadL2RequestProfilingHelper;
import archimulator.uncore.helperThread.HelperThreadL2RequestState;
import archimulator.uncore.helperThread.HelperThreadingHelper;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* Hotspot profiling helper.
*
* @author Min Cai
*/
public class HotspotProfilingHelper implements Reportable {
private DirectoryController l2Controller;
private Map<String, Map<String, Long>> numCallsPerFunctions;
private Map<Integer, LoadInstructionEntry> loadsInHotspotFunction;
private SummaryStatistics statL2HitStackDistances;
private SummaryStatistics statL2MissStackDistances;
private SummaryStatistics statL2HitHotspotInterThreadStackDistances;
private SummaryStatistics statL2MissHotspotStackDistances;
/**
* Create a hotpot profiling helper.
*
* @param simulation the simulation object
*/
public HotspotProfilingHelper(Simulation simulation) {
this.l2Controller = simulation.getProcessor().getMemoryHierarchy().getL2Controller();
this.numCallsPerFunctions = new TreeMap<>();
this.loadsInHotspotFunction = new TreeMap<>();
this.statL2HitStackDistances = new SummaryStatistics();
this.statL2MissStackDistances = new SummaryStatistics();
this.statL2HitHotspotInterThreadStackDistances = new SummaryStatistics();
this.statL2MissHotspotStackDistances = new SummaryStatistics();
if (simulation.getProcessor().getCores().get(0).getThreads().get(0).getContext() == null) {
return;
}
this.scanLoadInstructionsInHotspotFunctions(simulation.getProcessor().getCores().get(0).getThreads().get(0).getContext().getProcess());
simulation.getBlockingEventDispatcher().addListener(FunctionCallEvent.class, event -> {
String callerFunctionName = event.getContext().getProcess().getFunctionNameFromPc(event.getFunctionCallContext().getPc());
String calleeFunctionName = event.getContext().getProcess().getFunctionNameFromPc(event.getFunctionCallContext().getTargetPc());
if (callerFunctionName != null) {
if (!numCallsPerFunctions.containsKey(callerFunctionName)) {
numCallsPerFunctions.put(callerFunctionName, new TreeMap<>());
}
if (!numCallsPerFunctions.get(callerFunctionName).containsKey(calleeFunctionName)) {
numCallsPerFunctions.get(callerFunctionName).put(calleeFunctionName, 0L);
}
numCallsPerFunctions.get(callerFunctionName).put(calleeFunctionName, numCallsPerFunctions.get(callerFunctionName).get(calleeFunctionName) + 1);
}
});
simulation.getBlockingEventDispatcher().addListener(GeneralCacheControllerServiceNonblockingRequestEvent.class, event -> {
DynamicInstruction dynamicInstruction = event.getAccess().getDynamicInstruction();
if (dynamicInstruction != null && dynamicInstruction.getThread().getContext().getThreadId() == HelperThreadingHelper.getMainThreadId()) {
if (loadsInHotspotFunction.containsKey(dynamicInstruction.getPc())) {
LoadInstructionEntry loadInstructionEntry = loadsInHotspotFunction.get(dynamicInstruction.getPc());
if (event.getCacheController().getName().equals("c0/dcache")) {
loadInstructionEntry.setL1DAccesses(loadInstructionEntry.getL1DAccesses() + 1);
if (event.isHitInCache()) {
loadInstructionEntry.setL1DHits(loadInstructionEntry.getL1DHits() + 1);
}
} else if (event.getCacheController() == l2Controller) {
loadInstructionEntry.setL2Accesses(loadInstructionEntry.getL2Accesses() + 1);
if (event.isHitInCache()) {
loadInstructionEntry.setL2Hits(loadInstructionEntry.getL2Hits() + 1);
}
}
}
}
});
//TODO: to be removed out of HotspotProfilingHelper!!!
simulation.getBlockingEventDispatcher().addListener(StackDistanceProfilingHelper.StackDistanceProfiledEvent.class, event -> {
if (event.getCacheController() == l2Controller) {
MemoryHierarchyAccess access = event.getAccess();
if (event.isHitInCache() && HelperThreadingHelper.isMainThread(access.getThread())) {
HelperThreadL2RequestProfilingHelper helperThreadL2RequestProfilingHelper = l2Controller.getSimulation().getHelperThreadL2RequestProfilingHelper();
if (helperThreadL2RequestProfilingHelper != null) {
HelperThreadL2RequestState helperThreadL2RequestState =
helperThreadL2RequestProfilingHelper.getHelperThreadL2RequestStates().get(event.getSet()).get(event.getWay());
if (HelperThreadingHelper.isHelperThread(helperThreadL2RequestState.getThreadId())) {
l2Controller.getBlockingEventDispatcher().dispatch(new L2HitHotspotInterThreadStackDistanceMeterEvent(
l2Controller,
access.getVirtualPc(),
access.getPhysicalAddress(),
access.getThread().getId(),
access.getThread().getContext().getProcess().getFunctionNameFromPc(access.getVirtualPc()),
new L2HitHotspotInterThreadStackDistanceMeterEvent.L2HitHotspotInterThreadStackDistanceMeterEventValue(helperThreadL2RequestState, event.getStackDistance())
));
}
}
}
if (!event.isHitInCache() && HelperThreadingHelper.isMainThread(access.getThread())) {
l2Controller.getBlockingEventDispatcher().dispatch(new L2MissHotspotStackDistanceMeterEvent(
l2Controller,
access.getVirtualPc(),
access.getPhysicalAddress(),
access.getThread().getId(),
access.getThread().getContext().getProcess().getFunctionNameFromPc(access.getVirtualPc()),
new L2MissHotspotStackDistanceMeterEvent.L2MissHotspotStackDistanceMeterEventValue(event.getStackDistance())
));
}
if (event.isHitInCache()) {
statL2HitStackDistances.addValue(event.getStackDistance());
} else {
statL2MissStackDistances.addValue(event.getStackDistance());
}
}
});
simulation.getBlockingEventDispatcher().addListener(
L2HitHotspotInterThreadStackDistanceMeterEvent.class,
event -> statL2HitHotspotInterThreadStackDistances.addValue(event.getValue().getStackDistance())
);
simulation.getBlockingEventDispatcher().addListener(
L2MissHotspotStackDistanceMeterEvent.class,
event -> statL2MissHotspotStackDistances.addValue(event.getValue().getStackDistance())
);
}
/**
* Scan the load instructions in all the identified hotspot functions in the specified process.
*
* @param process the process
*/
private void scanLoadInstructionsInHotspotFunctions(Process process) {
List<Function> hotspotFunctions = process.getHotspotFunctions();
for (Function hotspotFunction : hotspotFunctions) {
for (BasicBlock basicBlock : hotspotFunction.getBasicBlocks()) {
basicBlock.getInstructions().stream()
.filter(instruction -> instruction.getStaticInstruction().getMnemonic().getType() == StaticInstructionType.LOAD)
.forEach(instruction -> this.loadsInHotspotFunction.put(instruction.getPc(), new LoadInstructionEntry(instruction)));
}
}
}
@Override
public void dumpStats(ReportNode reportNode) {
reportNode.getChildren().add(new ReportNode(reportNode, "hotspot") {{
for(String function : getNumCallsPerFunctions().keySet()) {
Map<String, Long> calls = getNumCallsPerFunctions().get(function);
for(String callee : calls.keySet()) {
getChildren().add(
new ReportNode(
this,
String.format("numCallsPerFunctions/%s/%s", function, callee),
String.format("%s", calls.get(callee))
)
);
}
}
for(int pc : getLoadsInHotspotFunction().keySet()) {
LoadInstructionEntry loadInstructionEntry = getLoadsInHotspotFunction().get(pc);
getChildren().add(
new ReportNode(
this,
String.format("loadsInHotspotFunction/0x%08x/instruction", pc),
String.format("%s", loadInstructionEntry.getInstruction())
)
);
getChildren().add(
new ReportNode(
this,
String.format("loadsInHotspotFunction/0x%08x/l1DAccesses", pc),
String.format("%s", loadInstructionEntry.getL1DAccesses())
)
);
getChildren().add(
new ReportNode(
this,
String.format("loadsInHotspotFunction/0x%08x/l1DHitRatio", pc),
String.format("%s", loadInstructionEntry.getL1DHitRatio())
)
);
getChildren().add(
new ReportNode(
this,
String.format("loadsInHotspotFunction/0x%08x/l1DHits", pc),
String.format("%s", loadInstructionEntry.getL1DHits())
)
);
getChildren().add(
new ReportNode(
this,
String.format("loadsInHotspotFunction/0x%08x/l1DMisses", pc),
String.format("%s", loadInstructionEntry.getL1DMisses())
)
);
getChildren().add(
new ReportNode(
this,
String.format("loadsInHotspotFunction/0x%08x/l2Accesses", pc),
String.format("%s", loadInstructionEntry.getL2Accesses())
)
);
getChildren().add(
new ReportNode(
this,
String.format("loadsInHotspotFunction/0x%08x/l2HitRatio", pc),
String.format("%s", loadInstructionEntry.getL2HitRatio())
)
);
getChildren().add(
new ReportNode(
this,
String.format("loadsInHotspotFunction/0x%08x/l2Hits", pc),
String.format("%s", loadInstructionEntry.getL2Hits())
)
);
getChildren().add(
new ReportNode(
this,
String.format("loadsInHotspotFunction/0x%08x/l2Misses", pc),
String.format("%s", loadInstructionEntry.getL2Misses())
)
);
}
getChildren().add(
new ReportNode(
this,
"statL2HitStackDistances",
String.format("%s", getStatL2HitStackDistances())
)
);
getChildren().add(
new ReportNode(
this,
"statL2MissStackDistances",
String.format("%s", getStatL2MissStackDistances())
)
);
getChildren().add(
new ReportNode(
this,
"statL2HitHotspotInterThreadStackDistances",
String.format("%s", getStatL2HitHotspotInterThreadStackDistances())
)
);
getChildren().add(
new ReportNode(
this,
"statL2MissHotspotStackDistances",
String.format("%s", getStatL2MissStackDistances())
)
);
}});
}
/**
* Get the number of calls per functions.
*
* @return the number of calls per functions
*/
public Map<String, Map<String, Long>> getNumCallsPerFunctions() {
return numCallsPerFunctions;
}
/**
* Get the loads in the first identified hotspot function in the first context/process.
*
* @return the loads in the first identified hotspot function in the first context/process
*/
public Map<Integer, LoadInstructionEntry> getLoadsInHotspotFunction() {
return loadsInHotspotFunction;
}
/**
* Get the summary statistics on the L2 cache hit stack distances.
*
* @return the summary statistics on the L2 cache hit stack distances
*/
public SummaryStatistics getStatL2HitStackDistances() {
return statL2HitStackDistances;
}
/**
* Get the summary statistics on the L2 cache miss stack distances.
*
* @return the summary statistics on the L2 cache miss stack distances
*/
public SummaryStatistics getStatL2MissStackDistances() {
return statL2MissStackDistances;
}
/**
* Get the summary statistics on the L2 cache hit hotspot inter-thread stack distances.
*
* @return the summary statistics on the L2 cache hit hotspot inter-thread stack distances
*/
public SummaryStatistics getStatL2HitHotspotInterThreadStackDistances() {
return statL2HitHotspotInterThreadStackDistances;
}
/**
* Get the summary statistics on the L2 cache miss hotspot stack distances.
*
* @return the summary statistics on the L2 cache miss hotspot stack distances
*/
public SummaryStatistics getStatL2MissHotspotStackDistances() {
return statL2MissHotspotStackDistances;
}
}