/** * **************************************************************************** * 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.delinquentLoad; import archimulator.common.SimulationEvent; import archimulator.core.Thread; import archimulator.core.event.DynamicInstructionCommittedEvent; import archimulator.os.FunctionCallContext; import archimulator.uncore.coherence.event.GeneralCacheControllerServiceNonblockingRequestEvent; import archimulator.uncore.coherence.msi.controller.DirectoryController; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Stack; import java.util.stream.Collectors; /** * Delinquent load identification table. * * @author Min Cai */ public class DelinquentLoadIdentificationTable { private Thread thread; private List<DelinquentLoad> delinquentLoads; /** * Create a delinquent load identification table. * * @param thread the thread */ public DelinquentLoadIdentificationTable(final Thread thread) { this.thread = thread; this.delinquentLoads = new ArrayList<>(); thread.getBlockingEventDispatcher().addListener(DynamicInstructionCommittedEvent.class, event -> { if (event.getDynamicInstruction().getThread() == DelinquentLoadIdentificationTable.this.thread) { Stack<FunctionCallContext> functionCallContextStack = event.getDynamicInstruction().getThread().getContext().getFunctionCallContextStack(); if (functionCallContextStack.size() > 0) { boolean delinquentLoadFound = false; for (DelinquentLoad delinquentLoad : delinquentLoads) { if (delinquentLoad.getPc() == event.getDynamicInstruction().getPc() && delinquentLoad.getFunctionCallPc() == functionCallContextStack.peek().getPc()) { delinquentLoad.setNumExecutions(delinquentLoad.getNumExecutions() + 1); delinquentLoad.setNumCyclesSpentAtHeadOfReorderBuffer(delinquentLoad.getNumCyclesSpentAtHeadOfReorderBuffer() + event.getDynamicInstruction().getNumCyclesSpentAtHeadOfReorderBuffer()); delinquentLoadFound = true; break; } } if (!delinquentLoadFound && event.getDynamicInstruction().isMissedInL2() && delinquentLoads.size() < CAPACITY) { DelinquentLoad delinquentLoad = new DelinquentLoad(event.getDynamicInstruction().getPc(), functionCallContextStack.peek().getPc()); delinquentLoad.setNumExecutions(1); delinquentLoad.setNumCyclesSpentAtHeadOfReorderBuffer(event.getDynamicInstruction().getNumCyclesSpentAtHeadOfReorderBuffer()); delinquentLoads.add(delinquentLoad); } } for (Iterator<DelinquentLoad> iterator = delinquentLoads.iterator(); iterator.hasNext(); ) { DelinquentLoad delinquentLoad = iterator.next(); delinquentLoad.setNumInstructions(delinquentLoad.getNumInstructions() + 1); if (delinquentLoad.getNumInstructions() >= INSTRUCTIONS_PER_PHASE) { if (delinquentLoad.getNumExecutions() >= EXECUTION_COUNT_THRESHOLD && delinquentLoad.getNumCyclesSpentAtHeadOfReorderBuffer() / EXECUTION_COUNT_THRESHOLD >= 4) { thread.getBlockingEventDispatcher().dispatch(new DelinquentLoadIdentifiedEvent(thread, delinquentLoad)); delinquentLoad.setSteady(true); delinquentLoad.setNumInstructions(0); delinquentLoad.setNumExecutions(0); delinquentLoad.setNumCyclesSpentAtHeadOfReorderBuffer(0); } else { iterator.remove(); } } } } }); thread.getBlockingEventDispatcher().addListener(GeneralCacheControllerServiceNonblockingRequestEvent.class, event -> { if (!event.isHitInCache() && event.getAccess().getThread() == DelinquentLoadIdentificationTable.this.thread && event.getCacheController() instanceof DirectoryController && event.getAccess().getType().isRead()) { if (event.getAccess().getDynamicInstruction() != null) { event.getAccess().getDynamicInstruction().setMissedInL2(true); } } }); } /** * Remove the specified delinquent load. * * @param delinquentLoadToRemove the delinquent load to be removed */ public void removeDelinquentLoad(DelinquentLoad delinquentLoadToRemove) { this.delinquentLoads.remove(delinquentLoadToRemove); } /** * Get a value indicating whether the specified program counter (PC) is delinquent or not. * * @param pc the value of the program counter (PC) * @return a value indicating whether the specified program counter (PC) is delinquent or not */ public boolean isDelinquentPc(int pc) { for (DelinquentLoad delinquentLoad : this.delinquentLoads) { if (delinquentLoad.getPc() == pc && delinquentLoad.isSteady()) { return true; } } return false; } /** * Get the thread. * * @return the thread */ public Thread getThread() { return thread; } /** * Get the list of delinquent loads. * * @return the list of delinquent loads */ public List<DelinquentLoad> getDelinquentLoads() { return delinquentLoads; } /** * Get the list of steady delinquent loads. * * @return the list of steady delinquent loads */ public List<DelinquentLoad> getSteadyDelinquentLoads() { return this.delinquentLoads.stream().filter(DelinquentLoad::isSteady).collect(Collectors.toList()); } /** * The event fired when a delinquent load is identified. */ public class DelinquentLoadIdentifiedEvent extends SimulationEvent { private Thread thread; private DelinquentLoad delinquentLoad; /** * Create a delinquent load identified event. * * @param thread the thread * @param delinquentLoad the delinquent load */ public DelinquentLoadIdentifiedEvent(Thread thread, DelinquentLoad delinquentLoad) { super(thread); this.thread = thread; this.delinquentLoad = delinquentLoad; } /** * Get the thread. * * @return the thread */ public Thread getThread() { return thread; } /** * Get the delinquent load. * * @return the delinquent load */ public DelinquentLoad getDelinquentLoad() { return delinquentLoad; } } private static final int CAPACITY = 64; // private static final int CAPACITY = 2; private static final int INSTRUCTIONS_PER_PHASE = 128000; private static final int EXECUTION_COUNT_THRESHOLD = 100; }