/** * **************************************************************************** * 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.replacement.deadBlockPrediction; import archimulator.util.math.NoThresholdSaturatingCounter; import java.util.ArrayList; import java.util.List; /** * Dead block predictor. * * @author Min Cai */ public class DeadBlockPredictor { private static final int numPredictionTables = 3; private static final int threshold = 8; private int numPredictorIndexBits; private List<List<NoThresholdSaturatingCounter>> tables; /** * Create a dead block predictor. */ public DeadBlockPredictor(int counterMax, int numPredictorIndexBits) { this.numPredictorIndexBits = numPredictorIndexBits; this.tables = new ArrayList<>(); for (int i = 0; i < numPredictionTables; i++) { List<NoThresholdSaturatingCounter> table = new ArrayList<>(); for (int j = 0; j < 1 << numPredictorIndexBits; j++) { table.add(new NoThresholdSaturatingCounter(0, counterMax, 0)); } this.tables.add(table); } } /** * Hash a trace, thread ID, and prediction table number into a predictor table index. * * @param threadId the thread ID * @param trace the trace * @param table the prediction table number * @return the corresponding table index for the specified thread ID, trace and prediction table number */ private int getTableIndex(int threadId, int trace, int table) { int x = fi(trace ^ (threadId << 2), table); return x & ((1 << this.numPredictorIndexBits) - 1); } /** * Update the predictor when a block, either dead or not, is encountered. * * @param threadId the thread ID * @param trace the trace * @param dead a value indicating whether the block is dead or not */ public void update(int threadId, int trace, boolean dead) { for (int i = 0; i < numPredictionTables; i++) { NoThresholdSaturatingCounter c = tables.get(i).get(getTableIndex(threadId, trace, i)); if (dead) { c.increment(); } else { if (i % 2 == 1) { c.decrementExponentially(); } else { c.decrement(); } } } } /** * Get a value indicating whether the specified block is predicted to be dead or not. * * @param threadId the thread ID * @param trace the trace * @return a value indicating whether the specified block is predicted to be dead or not */ public boolean predict(int threadId, int trace) { return this.tables.stream().mapToInt( table -> table.get(getTableIndex(threadId, trace, this.tables.indexOf(table))).get() ).sum() >= threshold; } /** * hash three numbers into one. * * @param a the a * @param b the b * @param c the c * @return the hash of the specified three numbers */ private static int mix(int a, int b, int c) { a = a - b; a = a - c; a = a ^ (c >> 13); b = b - c; b = b - a; b = b ^ (a << 8); c = c - a; c = c - b; c = c ^ (b >> 13); return c; } /** * The first hash function. * * @param x the x * @return the hash of the x */ private static int f1(int x) { return mix(0xfeedface, 0xdeadb10c, x); } /** * The second hash function. * * @param x the x * @return the hash of the x */ private static int f2(int x) { return mix(0xc001d00d, 0xfade2b1c, x); } /** * The generalized hash function. * * @param x the x * @param i the i * @return the generalized hash of x with i */ private static int fi(int x, int i) { return f1(x) + (f2(x) >> i); } }