/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2010, Benedikt Huber (benedikt@vmars.tuwien.ac.at) This program 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. This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package com.jopdesign.wcet.analysis.cache; import com.jopdesign.wcet.jop.ObjectCache; import com.jopdesign.wcet.jop.ObjectCache.ObjectCacheCost; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import java.util.Vector; /** * Purpose: helper classes for the evaluation of the object cache * @author Benedikt Huber (benedikt@vmars.tuwien.ac.at) * */ public class ObjectCacheEvaluationResult { /* small helper for partitioning result data */ private interface Selector<S,T> { T getKey(S obj); } // The JDK 1.5 Java compiler is not as smart as eclipse :( // Also, this utility function would be way cooler if we had a reasonable type inference public static<S,T,M extends Map<T,List<S>>> Map<T,List<S>> partitionBy( Collection<S> col, Selector<S,T> select, M resultMap) { for(S r : col) { T sel = select.getKey(r); List<S> list = resultMap.get(sel); if(list == null) list = new ArrayList<S>(); list.add(r); resultMap.put(sel, list); } return resultMap; } public enum OCacheMode { BLOCK_FILL, SINGLE_FIELD }; public static class OCacheAnalysisResult { public int lineWords; public int ways; public double hitrate; public int configId; public double cyclesPerAccess; private ObjectCache.ObjectCacheCost ocCost; private int blockSize; /** * @param ways * @param lineSize * @param ocCost * @param blockSize * @param configId * @param hitRate * @param cyclesPerAccess */ public OCacheAnalysisResult(int ways, int lineSize, int blockSize, int configId, double hitRate, double cyclesPerAccess, ObjectCache.ObjectCacheCost ocCost) { this.ways = ways; this.lineWords = lineSize; this.blockSize = blockSize; this.configId = configId; this.hitrate = hitRate; this.cyclesPerAccess = cyclesPerAccess; this.ocCost = ocCost; } private long cacheSize() { return lineWords * 4 * ways; } public static Comparator<OCacheAnalysisResult> wayLineComperator() { return new Comparator<OCacheAnalysisResult>() { public int compare(OCacheAnalysisResult arg0, OCacheAnalysisResult arg1) { int cmpWays = new Integer(arg0.ways).compareTo(arg1.ways); int cmpLineSz = new Integer(arg0.lineWords).compareTo(arg1.lineWords); int cmpWordSz = new Integer(arg0.blockSize).compareTo(arg1.blockSize); int cmpConfig = new Integer(arg0.configId).compareTo(arg1.configId); if(cmpWays != 0) return cmpWays; if(cmpLineSz != 0) return cmpLineSz; if(cmpWordSz != 0) return cmpWordSz; return cmpConfig; } }; } public static Map<Integer,List<OCacheAnalysisResult>> partitionByLineSize(List<OCacheAnalysisResult> results) { return partitionBy(results, new Selector<OCacheAnalysisResult,Integer>() { public Integer getKey(OCacheAnalysisResult r) { return r.lineWords; } }, new TreeMap<Integer,List<OCacheAnalysisResult>>()); } public static Map<Integer,List<OCacheAnalysisResult>> partitionByBlockSize(List<OCacheAnalysisResult> results) { return partitionBy(results, new Selector<OCacheAnalysisResult,Integer>() { public Integer getKey(OCacheAnalysisResult r) { return r.blockSize; } }, new TreeMap<Integer,List<OCacheAnalysisResult>>()); } private static Map<Integer, List<OCacheAnalysisResult>> partitionByConfig(List<OCacheAnalysisResult> samples) { return partitionBy(samples, new Selector<OCacheAnalysisResult,Integer>() { public Integer getKey(OCacheAnalysisResult r) { return r.configId; } }, new TreeMap<Integer,List<OCacheAnalysisResult>>()); } public static void dumpBarPlot(List<OCacheAnalysisResult> samples, PrintStream out) { for(Entry<Integer, List<OCacheAnalysisResult>> entryConfig : partitionByConfig(samples).entrySet()) { int config = entryConfig.getKey(); /* Bar Plot for Blocksize=1 : Group By Line Size, Associtativity on X, CMC on Y */ out.println("# PLOT DATA for config= " + config +" with block size 1 "); for(Entry<Integer, List<OCacheAnalysisResult>> entry : partitionByLineSize(entryConfig.getValue()).entrySet()) { int lineSize = entry.getKey(); out.printf("L=%d",lineSize); List<OCacheAnalysisResult> results = entry.getValue(); Collections.sort(results, OCacheAnalysisResult.wayLineComperator()); Vector<Integer> sampleWays = new Vector<Integer>(); for(OCacheAnalysisResult r : results) { if(r.blockSize > 1) continue; out.printf(",%.2f",r.cyclesPerAccess); sampleWays.add(r.ways); } out.println(" # Ways: "+sampleWays); } out.println("# PLOT DATA for config= " + config +" with different block sizes"); List<OCacheAnalysisResult> results = entryConfig.getValue(); Collections.sort(results, OCacheAnalysisResult.wayLineComperator()); int oldWays = -1; int oldLineSize = -1; for(OCacheAnalysisResult r : results) { if(r.ways != oldWays || r.lineWords != oldLineSize) { oldWays = r.ways; oldLineSize = r.lineWords; out.printf("\nN=%d L=%d",r.ways, r.lineWords); } out.printf(",%.2f", r.cyclesPerAccess); } out.println(""); } } public static void dumpPlot(List<OCacheAnalysisResult> samples, PrintStream out) { for(Entry<Integer, List<OCacheAnalysisResult>> entryConfig : partitionByConfig(samples).entrySet()) { int config = entryConfig.getKey(); for(Entry<Integer, List<OCacheAnalysisResult>> entry : partitionByBlockSize(entryConfig.getValue()).entrySet()) { int blockSize = entry.getKey(); out.println("# PLOT DATA for config= "+config+" and block size "+blockSize); List<OCacheAnalysisResult> results = entry.getValue(); Collections.sort(results, OCacheAnalysisResult.wayLineComperator()); Iterator<OCacheAnalysisResult> it = results.iterator(); OCacheAnalysisResult oldSample = null; OCacheAnalysisResult sample; while(it.hasNext()) { sample = it.next(); if(oldSample == null || oldSample.ways != sample.ways) out.println("\n"); out.println(String.format("%-8d\t%.2f", sample.cacheSize(),sample.cyclesPerAccess)); oldSample = sample; } } } } public static void dumpLatex(List<OCacheAnalysisResult> samples, PrintStream out) { Collections.sort(samples, OCacheAnalysisResult.wayLineComperator()); Iterator<OCacheAnalysisResult> it = samples.iterator(); OCacheAnalysisResult oldSample = null; OCacheAnalysisResult sample; if(it.hasNext()) sample = it.next(); else sample = null; while(sample != null) { if(oldSample == null || oldSample.blockSize != sample.blockSize) { out.println("\\midrule "+sample.blockSize * 4); } // size, line, assoc, hitrate String comment = sample.ocCost.toString(); out.print(String.format(" & %d B",sample.cacheSize())); out.print(String.format(" & %d B",sample.lineWords*4)); out.print(String.format(" & %d way",sample.ways)); out.print(String.format(" & %.2f \\%%",sample.hitrate*100)); do { out.print(String.format(" & %.2f",sample.cyclesPerAccess)); /* Stay in the same line while linesz and ways do not change */ oldSample = sample; if(it.hasNext()) sample = it.next(); else sample = null; } while(sample != null && sample.lineWords == oldSample.lineWords && sample.ways == oldSample.ways); out.println("\\\\ %"+comment); } } } }