/*******************************************************************************
 * Copyright (c) 2010-2013 by Min Cai (min.cai.china@gmail.com).
 *
 * This file is part of the Archimulator multicore architectural simulator.
 *
 * 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.
 *
 * 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.
 *
 * 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.sim.uncore.cache.replacement.mlpAwareCachePartitioning;

import archimulator.sim.uncore.MemoryHierarchyAccess;
import archimulator.sim.uncore.cache.CacheAccess;
import archimulator.sim.uncore.cache.CacheLine;
import archimulator.sim.uncore.cache.EvictableCache;
import archimulator.sim.uncore.cache.replacement.LRUPolicy;

import java.io.Serializable;

/**
 * MLP-aware cache partitioning based least recently used (LRU) policy.
 *
 * @param <StateT> the state type of the parent evictable cache
 * @author Min Cai
 */
public class MLPAwareCachePartitioningLRUPolicy<StateT extends Serializable> extends LRUPolicy<StateT> {
    /**
     * Create a MLP-aware cache partitioning based least recently used (LRU) policy for the specified evictable cache.
     *
     * @param cache the parent evictable cache
     */
    public MLPAwareCachePartitioningLRUPolicy(EvictableCache<StateT> cache) {
        super(cache);
    }

    /**
     * Handle a cache replacement.
     *
     * @param access the memory hierarchy access
     * @param set    the set index
     * @param tag    the tag
     * @return the newly created cache access object
     */
    @Override
    public CacheAccess<StateT> handleReplacement(MemoryHierarchyAccess access, int set, int tag) {
        int numUsedWays = 0;

        for (int way = 0; way < this.getCache().getAssociativity(); way++) {
            CacheLine<StateT> line = this.getCache().getLine(set, way);
            if (line.getAccess() != null && line.getAccess().getThread().getId() == access.getThread().getId()) {
                numUsedWays++;
            }
        }

        if (numUsedWays < getCache().getSimulation().getMlpAwareCachePartitioningHelper().getPartition().get(access.getThread().getId())) {
            for (int stackPosition = this.getCache().getAssociativity() - 1; stackPosition >= 0; stackPosition--) {
                int way = this.getWayInStackPosition(set, stackPosition);
                CacheLine<StateT> line = this.getCache().getLine(set, way);
                if (line.getAccess() != null && line.getAccess().getThread().getId() != access.getThread().getId()) {
                    return new CacheAccess<StateT>(this.getCache(), access, set, way, tag);
                }
            }
        } else {
            for (int stackPosition = this.getCache().getAssociativity() - 1; stackPosition >= 0; stackPosition--) {
                int way = this.getWayInStackPosition(set, stackPosition);
                CacheLine<StateT> line = this.getCache().getLine(set, way);
                if (line.getAccess() != null && line.getAccess().getThread().getId() == access.getThread().getId()) {
                    return new CacheAccess<StateT>(this.getCache(), access, set, way, tag);
                }
            }
        }

        throw new IllegalArgumentException();
    }
}

@@ -1319,16 +1319,64 @@
 lizable;
+%0Aimport java.util.Map;%0Aimport java.util.TreeMap;
 %0A%0A/**%0A *
@@ -2488,32 +2488,48 @@
 ss() != null && 
+isSamePartition(
 line.getAccess()
@@ -2540,35 +2540,33 @@
 Thread().getId()
- ==
+,
  access.getThrea
@@ -2569,32 +2569,33 @@
 hread().getId())
+)
  %7B%0A             
@@ -3083,32 +3083,49 @@
 ss() != null && 
+!isSamePartition(
 line.getAccess()
@@ -3144,19 +3144,17 @@
 .getId()
- !=
+,
  access.
@@ -3165,32 +3165,33 @@
 hread().getId())
+)
  %7B%0A             
@@ -3632,16 +3632,32 @@
 null && 
+isSamePartition(
 line.get
@@ -3688,11 +3688,9 @@
 Id()
- ==
+,
  acc
@@ -3713,16 +3713,17 @@
 getId())
+)
  %7B%0A     
@@ -3844,32 +3844,32 @@
    %7D%0A        %7D%0A%0A
-
         throw ne
@@ -3903,11 +3903,940 @@
 );%0A    %7D
+%0A%0A    private static Map%3CInteger,Integer%3E threadIds; //TODO: should not be hardcoded!!!%0A%0A    //TODO: should not be hardcoded!!!%0A    static %7B%0A        threadIds = new TreeMap%3CInteger, Integer%3E();%0A        threadIds.put(0, 0);%0A        threadIds.put(1, 0);%0A        threadIds.put(2, 1);%0A        threadIds.put(3, 1);%0A    %7D%0A%0A    /**%0A     * Get a value indicating whether the given two thread IDs are within the same partition or not.%0A     *%0A     * @param threadIdA the first thread ID%0A     * @param threadIdB the second thread ID%0A     * @return a value indicating whether the given two thread IDs are within the same partition or not%0A     */%0A    private static boolean isSamePartition(int threadIdA, int threadIdB) %7B%0A        if(!threadIds.containsKey(threadIdA) %7C%7C !threadIds.containsKey(threadIdB)) %7B%0A            throw new IllegalArgumentException();%0A        %7D%0A%0A        return threadIds.get(threadIdA) == threadIds.get(threadIdB);%0A    %7D
 %0A%7D%0A

Add method isSamePartition(..) in MLPAwareCachePartitioningLRUPolicy.