/**
* ****************************************************************************
* 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;
import archimulator.common.*;
import archimulator.uncore.cache.CacheLine;
import archimulator.uncore.coherence.msi.controller.*;
import archimulator.uncore.coherence.msi.message.CoherenceMessage;
import archimulator.uncore.dram.BasicMemoryController;
import archimulator.uncore.dram.FixedLatencyMemoryController;
import archimulator.uncore.dram.MemoryController;
import archimulator.uncore.dram.SimpleMemoryController;
import archimulator.uncore.tlb.TranslationLookasideBuffer;
import archimulator.util.event.BlockingEvent;
import archimulator.util.event.BlockingEventDispatcher;
import archimulator.util.event.CycleAccurateEventQueue;
import archimulator.util.fsm.BasicFiniteStateMachine;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
/**
* Abstract memory hierarchy.
*
* @author Min Cai
*/
public abstract class AbstractMemoryHierarchy
extends BasicSimulationObject<CPUExperiment, Simulation>
implements MemoryHierarchy {
private MemoryController memoryController;
private DirectoryController l2Controller;
private List<L1IController> l1IControllers;
private List<L1DController> l1DControllers;
private List<TranslationLookasideBuffer> itlbs;
private List<TranslationLookasideBuffer> dtlbs;
private Map<Controller, Map<Controller, PointToPointReorderBuffer>> p2pReorderBuffers;
/**
* Create an abstract memory hierarchy.
*
* @param experiment the experiment
* @param simulation the simulation
* @param blockingEventDispatcher the blocking event dispatcher
* @param cycleAccurateEventQueue the cycle accurate event queue
*/
public AbstractMemoryHierarchy(CPUExperiment experiment, Simulation simulation, BlockingEventDispatcher<BlockingEvent> blockingEventDispatcher, CycleAccurateEventQueue cycleAccurateEventQueue) {
super(experiment, simulation, blockingEventDispatcher, cycleAccurateEventQueue);
switch (getExperiment().getConfig().getMemoryControllerType()) {
case SIMPLE:
this.memoryController = new SimpleMemoryController(this);
break;
case BASIC:
this.memoryController = new BasicMemoryController(this);
break;
default:
this.memoryController = new FixedLatencyMemoryController(this);
break;
}
this.l2Controller = new DirectoryController(this, "l2");
this.l2Controller.setNext(this.memoryController);
this.l1IControllers = new ArrayList<>();
this.l1DControllers = new ArrayList<>();
this.itlbs = new ArrayList<>();
this.dtlbs = new ArrayList<>();
for (int i = 0; i < getExperiment().getConfig().getNumCores(); i++) {
L1IController l1IController = new L1IController(this, "c" + i + "/icache");
l1IController.setNext(this.l2Controller);
this.l1IControllers.add(l1IController);
L1DController l1DController = new L1DController(this, "c" + i + "/dcache");
l1DController.setNext(this.l2Controller);
this.l1DControllers.add(l1DController);
for (int j = 0; j < getExperiment().getConfig().getNumThreadsPerCore(); j++) {
this.itlbs.add(new TranslationLookasideBuffer(this, "c" + i + "t" + j + "/itlb"));
this.dtlbs.add(new TranslationLookasideBuffer(this, "c" + i + "t" + j + "/dtlb"));
}
}
this.p2pReorderBuffers = new HashMap<>();
}
/**
* Dump the cache controller finite state machine statistics.
*
* @param stats the list of statistics to be manipulated
*/
@Override
public void dumpCacheControllerFsmStats(List<ExperimentStat> stats) {
for (CacheController l1IController : this.l1IControllers) {
dumpCacheControllerFsmStats(stats, l1IController);
}
for (CacheController l1DController : this.l1DControllers) {
dumpCacheControllerFsmStats(stats, l1DController);
}
dumpCacheControllerFsmStats(stats, this.l2Controller);
}
/**
* Dump the statistics for the specified general cache controller.
*
* @param stats the list of statistics to be manipulated
* @param cacheController the general cache controller
* @param <StateT> state
* @param <ConditionT> transition
*/
@SuppressWarnings("unchecked")
private <StateT extends Serializable, ConditionT> void dumpCacheControllerFsmStats(List<ExperimentStat> stats, GeneralCacheController<StateT, ConditionT> cacheController) {
List<BasicFiniteStateMachine<StateT, ConditionT>> finiteStateMachines = new ArrayList<>();
for (int set = 0; set < cacheController.getCache().getNumSets(); set++) {
for (CacheLine<StateT> line : cacheController.getCache().getLines(set)) {
BasicFiniteStateMachine<StateT, ConditionT> fsm = (BasicFiniteStateMachine<StateT, ConditionT>) line.getStateProvider();
finiteStateMachines.add(fsm);
}
}
Map<String, String> statsMap = new LinkedHashMap<>();
cacheController.getFsmFactory().dump(PREFIX_CC_FSM + cacheController.getName(), finiteStateMachines, statsMap);
stats.addAll(statsMap.entrySet().stream().map(entry -> new ExperimentStat(getSimulation().getPrefix(), entry.getKey(), entry.getValue())).collect(Collectors.toList()));
}
/**
* Transfer a message of the specified size from the source device to the destination device.
*
* @param from the source device
* @param to the destination device
* @param size the size of the message to be transferred
* @param message the message to be transferred
*/
@Override
public void transfer(final Controller from, final Controller to, int size, final CoherenceMessage message) {
if (!this.p2pReorderBuffers.containsKey(from)) {
this.p2pReorderBuffers.put(from, new HashMap<>());
}
if (!this.p2pReorderBuffers.get(from).containsKey(to)) {
this.p2pReorderBuffers.get(from).put(to, new PointToPointReorderBuffer(from, to));
}
this.p2pReorderBuffers.get(from).get(to).transfer(message);
this.getNet(from, to).transfer(from, to, size, () -> p2pReorderBuffers.get(from).get(to).onDestinationArrived(message));
}
/**
* Get the memory controller.
*
* @return the memory controller
*/
public MemoryController getMemoryController() {
return memoryController;
}
/**
* Get the L2 cache controller.
*
* @return the L2 cache controller
*/
public DirectoryController getL2Controller() {
return l2Controller;
}
/**
* Get the list of L1I cache controllers.
*
* @return the list of L1I cache controllers
*/
public List<L1IController> getL1IControllers() {
return l1IControllers;
}
/**
* Get the list of L1D cache controllers.
*
* @return the list of L1D cache controllers
*/
public List<L1DController> getL1DControllers() {
return l1DControllers;
}
/**
* Get the list of instruction translation lookaside buffers (iTLBs).
*
* @return the list of instruction translation lookaside buffers (iTLBs)
*/
public List<TranslationLookasideBuffer> getItlbs() {
return itlbs;
}
/**
* Get the list of data translation lookaside buffers (dTLBs).
*
* @return the list of data translation lookaside buffers (dTLBs)
*/
public List<TranslationLookasideBuffer> getDtlbs() {
return dtlbs;
}
/**
* Get the name of the memory hierarchy.
*
* @return the name of the memory hierarchy
*/
@Override
public String getName() {
return "memoryHierarchy";
}
/**
* Statistics prefix for cache coherence finite state machine stuff.
*/
public static final String PREFIX_CC_FSM = "ccFsm/";
}