/*******************************************************************************
* openDLX - A DLX/MIPS processor simulator.
* Copyright (C) 2013 The openDLX project, University of Augsburg, Germany
* Project URL: <https://sourceforge.net/projects/opendlx>
* Development branch: <https://github.com/smetzlaff/openDLX>
*
*
* 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
* 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, see <LICENSE>. If not, see
* <http://www.gnu.org/licenses/>.
******************************************************************************/
package openDLX.util;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import openDLX.PipelineConstants;
import openDLX.datatypes.BranchPredictorType;
import openDLX.datatypes.BranchTargetBufferLookupResult;
import openDLX.datatypes.CacheReplacementPolicy;
import openDLX.datatypes.CacheType;
import openDLX.datatypes.DCacheWritePolicy;
import openDLX.datatypes.uint32;
import openDLX.exception.CacheException;
import org.apache.log4j.Logger;
public class Statistics
{
// Logger
private static Logger logger = Logger.getLogger("openDLX");
// Singleton
private static final Statistics instance = new Statistics();
private int cycles;
private int instructions;
private int fetches;
private int jumps_taken;
private int jumps_nottaken;
private int jumps_likely;
private int jumps_link;
private int jumps_correctly_predicted;
private int jumps_mispredicted;
private int memory_reads;
private int memory_writes;
private int alu_forward_from_wb;
private int alu_forward_from_mem;
private int alu_forward_from_ex;
private int bcrtl_forward_from_wb;
private int bcrtl_forward_from_mem;
private int bcrtl_forward_from_ex;
private int store_forward_from_wb;
private int store_forward_from_mem;
private int store_forward_from_ex;
private int btb_size;
private BranchPredictorType btb_predictor;
private int btb_hits;
private int btb_misses;
private boolean icache = false;
private int icache_accesses;
private int icache_hits;
private int icache_misses;
private int icache_words_loaded;
private int icache_line_size;
private int icache_line_no;
private int icache_associativity;
private CacheReplacementPolicy icache_replacement_policy = CacheReplacementPolicy.UNKNOWN;
private int icache_size;
private boolean dcache = false;
private int dcache_accesses;
private int dcache_hits;
private int dcache_misses;
private int dcache_words_loaded;
private int dcache_line_size;
private int dcache_line_no;
private int dcache_associativity;
private CacheReplacementPolicy dcache_replacement_policy = CacheReplacementPolicy.UNKNOWN;
private DCacheWritePolicy dcache_write_policy = DCacheWritePolicy.UNKNOWN;
private int dcache_size;
private Map<uint32,BranchStat>branches_map;
private Properties config;
private Statistics()
{
config = null;
setBranches_map(new HashMap<uint32,BranchStat>());
}
/*
* obtain a reference to the object anywhere using:
* Statistics stat = Statistics.getInstance();
*/
public static Statistics getInstance()
{
return instance;
}
public int getCycles()
{
return cycles;
}
public int getInstructions()
{
return instructions;
}
public int getFetches()
{
return fetches;
}
public int getJumps_taken()
{
return jumps_taken;
}
public int getJumps_likely()
{
return jumps_likely;
}
public int getJumps_link()
{
return jumps_link;
}
public int getJumps_nottaken()
{
return jumps_nottaken;
}
public int getJumps_correctly_predicted()
{
return jumps_correctly_predicted;
}
public int getJumps_mispredicted()
{
return jumps_mispredicted;
}
public int getMemory_reads()
{
return memory_reads;
}
public int getMemory_writes()
{
return memory_writes;
}
public int getForward_from_wb()
{
return (alu_forward_from_wb + bcrtl_forward_from_wb + store_forward_from_wb);
}
public int getForward_from_mem()
{
return (alu_forward_from_mem + bcrtl_forward_from_mem + store_forward_from_mem);
}
public int getForward_from_ex()
{
return (alu_forward_from_ex + bcrtl_forward_from_ex + store_forward_from_ex);
}
public int getAlu_forward_from_wb()
{
return alu_forward_from_wb;
}
public int getAlu_forward_from_mem()
{
return alu_forward_from_mem;
}
public int getAlu_forward_from_ex()
{
return alu_forward_from_ex;
}
public int getBcrtl_forward_from_wb()
{
return bcrtl_forward_from_wb;
}
public int getBcrtl_forward_from_mem()
{
return bcrtl_forward_from_mem;
}
public int getBcrtl_forward_from_ex()
{
return bcrtl_forward_from_ex;
}
public int getStore_forward_from_wb()
{
return store_forward_from_wb;
}
public int getStore_forward_from_mem()
{
return store_forward_from_mem;
}
public int getStore_forward_from_ex()
{
return store_forward_from_ex;
}
/*
* Implement count functions.
*/
public void countCycle()
{
cycles++;
}
public void countInstruction()
{
instructions++;
}
public void countFetch()
{
fetches++;
}
public void countJumpTaken()
{
jumps_taken++;
}
public void countJumpNotTaken()
{
jumps_nottaken++;
}
public void countJumpLikely()
{
jumps_likely++;
}
public void countJumpLink()
{
jumps_link++;
}
public void countMemRead()
{
memory_reads++;
}
public void countMemWrite()
{
memory_writes++;
}
private void countALUForwardFromEX()
{
alu_forward_from_ex++;
}
private void countALUForwardFromMEM()
{
alu_forward_from_mem++;
}
private void countALUForwardFromWB()
{
alu_forward_from_wb++;
}
public void countALUForward(boolean forwarded_ex, boolean forwared_mem, boolean forwarded_wb)
{
if ((config != null) && (config.containsKey("statistic_count_also_masked_forwardings")) && (Integer.decode(config.getProperty("statistic_count_also_masked_forwardings")) == 1))
{
if(forwarded_ex)
{
countALUForwardFromEX();
}
if(forwared_mem)
{
countALUForwardFromMEM();
}
if(forwarded_wb)
{
countALUForwardFromWB();
}
}
else
{
// count the forwarding only once! And use the most recent value
if(forwarded_ex)
{
countALUForwardFromEX();
}
else if(forwared_mem)
{
countALUForwardFromMEM();
}
else if(forwarded_wb)
{
countALUForwardFromWB();
}
}
}
private void countBCRTLForwardFromEX()
{
bcrtl_forward_from_ex++;
}
private void countBCRTLForwardFromMEM()
{
bcrtl_forward_from_mem++;
}
private void countBCRTLForwardFromWB()
{
bcrtl_forward_from_wb++;
}
public void countBCRTLForward(boolean forwarded_ex, boolean forwared_mem, boolean forwarded_wb)
{
if ((config != null) && (config.containsKey("statistic_count_also_masked_forwardings")) && (Integer.decode(config.getProperty("statistic_count_also_masked_forwardings")) == 1))
{
if (forwarded_ex)
{
countBCRTLForwardFromEX();
}
if (forwared_mem)
{
countBCRTLForwardFromMEM();
}
if (forwarded_wb)
{
countBCRTLForwardFromWB();
}
}
else
{
// count the forwarding only once! And use the most recent value
if (forwarded_ex)
{
countBCRTLForwardFromEX();
}
else if (forwared_mem)
{
countBCRTLForwardFromMEM();
}
else if (forwarded_wb)
{
countBCRTLForwardFromWB();
}
}
}
private void countSTOREForwardFromEX()
{
store_forward_from_ex++;
}
private void countSTOREForwardFromMEM()
{
store_forward_from_mem++;
}
private void countSTOREForwardFromWB()
{
store_forward_from_wb++;
}
public void countSTOREForward(boolean forwarded_ex, boolean forwared_mem, boolean forwarded_wb)
{
if ((config != null) && (config.containsKey("statistic_count_also_masked_forwardings")) && (Integer.decode(config.getProperty("statistic_count_also_masked_forwardings")) == 1))
{
if (forwarded_ex)
{
countSTOREForwardFromEX();
}
if (forwared_mem)
{
countSTOREForwardFromMEM();
}
if (forwarded_wb)
{
countSTOREForwardFromWB();
}
}
else
{
// count the forwarding only once! And use the most recent value
if (forwarded_ex)
{
countSTOREForwardFromEX();
}
else if (forwared_mem)
{
countSTOREForwardFromMEM();
}
else if (forwarded_wb)
{
countSTOREForwardFromWB();
}
}
}
/*
* Print the aggregated performance/statistic counter values.
*/
public void printStats()
{
String stats = toString();
String[] lines = stats.split("\n");
for(int i = 0; i < lines.length; i++)
{
logger.info(lines[i]);
}
}
public String toString()
{
String stats = "";
DecimalFormat f = new DecimalFormat("###.##");
stats += "-------- SIMULATION STATISTICS --------\n";
stats += "Cycles: " + getCycles() + "\n";
stats += "Executed instructions: " + getInstructions() + "\n";
stats += "Performed fetches: " + getFetches() + "\n";
if(icache || dcache)
{
stats += "Cache statistics:\n";
stats += "Icache: " + ((icache)?("used"):("not used")) + " rpol: " + icache_replacement_policy + " lines: " + icache_line_no + " associativity: " + icache_associativity + " line_size: " + icache_line_size + " total size: " + icache_size + "\n";
if(icache)
{
stats += "Accesses:" + icache_accesses + " hits: " + icache_hits + " misses: " + icache_misses;
if(icache_accesses > 0)
{
stats += " hit rate: " + f.format((double)icache_hits/(double)icache_accesses * (double)100) + "%";
}
stats += " loaded words: " + icache_words_loaded + "\n";
}
stats += "Dcache: " + ((dcache)?("used"):("not used")) + " rpol: " + dcache_replacement_policy + " wpol: " + dcache_write_policy + " lines: " + dcache_line_no + " associativity: " + dcache_associativity + " line_size: " + dcache_line_size + " total size: " + dcache_size + "\n";
if(dcache)
{
stats += "Accesses: " + dcache_accesses + " hits: " + dcache_hits + " misses: " + dcache_misses;
if(dcache_accesses > 0)
{
stats += " hit rate: " + f.format((double)dcache_hits/(double)dcache_accesses * (double)100) + "%";
}
stats += " loaded words: " + dcache_words_loaded + "\n";
}
}
stats += "Jumps: " + (getJumps_taken()+getJumps_nottaken()) + " (taken: " + getJumps_taken() + ", not taken: " + getJumps_nottaken() + ") branches_likely: " + getJumps_likely() + " branches_and_link: " + getJumps_link() + "\n";
stats += "Branch Target Buffer (" + getBtb_size() + ", " + getBtb_predictor() + "): hits: " + getBtb_hits() + " misses: " + getBtb_misses() + "\n";
stats += "Jumps correctly predicted: " + getJumps_correctly_predicted() + " mispredicted: " + getJumps_mispredicted();
if(getJumps_correctly_predicted()+getJumps_mispredicted()>0)
{
stats += " misprediction rate: " + f.format(((double)getJumps_mispredicted())/((double)(getJumps_correctly_predicted()+getJumps_mispredicted()))*100) + "%";
}
stats += "\n";
stats += "Number of unique jumps: " + getBranches_map().size() + "\n";
stats += printBranchInformation(0);
stats += "Memory accesses: " + (getMemory_reads() + getMemory_writes()) + " (reads: " + getMemory_reads() + ", writes: " + getMemory_writes() + ")\n";
stats += "ALU forwarded values: " + (getAlu_forward_from_ex() + getAlu_forward_from_mem() + getAlu_forward_from_wb()) + " (from execute: " + getAlu_forward_from_ex() + ", memory stage: " + getAlu_forward_from_mem() + ", write back: " + getAlu_forward_from_wb() + ")\n";
stats += "BCRTL forwarded values: " + (getBcrtl_forward_from_ex() + getBcrtl_forward_from_mem() + getBcrtl_forward_from_wb()) + " (from execute: " + getBcrtl_forward_from_ex() + ", memory stage: " + getBcrtl_forward_from_mem() + ", write back: " + getBcrtl_forward_from_wb() + ")\n";
stats += "STORE forwarded values: " + (getStore_forward_from_ex() + getStore_forward_from_mem() + getStore_forward_from_wb()) + " (from execute: " + getStore_forward_from_ex() + ", memory stage: " + getStore_forward_from_mem() + ", write back: " + getStore_forward_from_wb() + ")\n";
stats += "Total forwarded values: " + (getForward_from_ex() + getForward_from_mem() + getForward_from_wb()) + " (from execute: " + getForward_from_ex() + ", memory stage: " + getForward_from_mem() + ", write back: " + getForward_from_wb() + ")\n";
stats += "-------- SIMULATION STATISTICS --------\n";
return stats;
}
public void setConfig(Properties config)
{
this.config = config;
}
public void setBTBConfig(int size, BranchPredictorType predictor)
{
setBtb_size(size);
setBtb_predictor(predictor);
}
public void countBTBAccesses(BranchTargetBufferLookupResult btb_result)
{
if((btb_result == BranchTargetBufferLookupResult.HIT_PREDICT_TAKEN) || (btb_result == BranchTargetBufferLookupResult.HIT_PREDICT_NOT_TAKEN))
{
setBtb_hits(getBtb_hits() + 1);
}
else if(btb_result == BranchTargetBufferLookupResult.MISS)
{
setBtb_misses(getBtb_misses() + 1);
}
}
public void countPredictions(boolean correctPrediction)
{
if(correctPrediction)
{
jumps_correctly_predicted++;
}
else
{
jumps_mispredicted++;
}
}
public void countBranchInformation(uint32 branch_addr, int btbIdx, uint32 branch_tgt, boolean branching, BranchTargetBufferLookupResult btb_result, boolean correctPrediction)
{
if(!getBranches_map().containsKey(branch_addr))
{
getBranches_map().put(new uint32(branch_addr), new BranchStat(branch_addr, btbIdx, branch_tgt, branching, correctPrediction));
}
else
{
getBranches_map().get(branch_addr).update(branch_tgt, branching, correctPrediction);
}
}
public String printBranchInformation(int number)
{
List<BranchStat> list_branches = new ArrayList<BranchStat>();
list_branches.addAll(getBranches_map().values());
Comparator<BranchStat> c = new Comparator<BranchStat>()
{
public int compare(BranchStat a, BranchStat b)
{
if(b.getAccesses() - a.getAccesses() != 0)
{
return (b.getAccesses() - a.getAccesses());
}
else
{
return (a.getBranchAddr().getValue() - b.getBranchAddr().getValue());
}
}
};
Collections.sort(list_branches, c);
if(number == 0)
{
number = getBranches_map().size();
}
String tempString="";
String retString="";
for(int i = 0; i < number; i ++)
{
tempString=list_branches.get(i).toString();
retString+=tempString + "\n";
}
return retString;
}
public void countCacheHit(CacheType type) throws CacheException
{
switch(type)
{
case ICACHE:
icache_hits++;
icache_accesses++;
break;
case DCACHE:
dcache_hits++;
dcache_accesses++;
break;
default:
throw new CacheException("Unknown cache replacement policy: " + type);
}
}
public void countCacheMiss(CacheType type) throws CacheException
{
switch(type)
{
case ICACHE:
icache_misses++;
icache_accesses++;
icache_words_loaded += icache_line_size / PipelineConstants.WORD_SIZE;
break;
case DCACHE:
dcache_misses++;
dcache_accesses++;
dcache_words_loaded += dcache_line_size / PipelineConstants.WORD_SIZE;
break;
default:
throw new CacheException("Unknown cache replacement policy: " + type);
}
}
public void setCacheParameters(CacheType type, CacheReplacementPolicy rpol, int lineSize, int lineNo, int associativity, DCacheWritePolicy wpol) throws CacheException
{
switch(type)
{
case ICACHE:
icache = true;
icache_line_size = lineSize;
icache_line_no = lineNo;
icache_associativity = associativity;
icache_replacement_policy = rpol;
icache_size = icache_line_no * icache_line_size;
break;
case DCACHE:
dcache = true;
dcache_line_size = lineSize;
dcache_line_no = lineNo;
dcache_associativity = associativity;
dcache_replacement_policy = rpol;
dcache_write_policy = wpol;
dcache_size = dcache_line_no * dcache_line_size;
break;
default:
throw new CacheException("Unknown cache replacement policy: " + type);
}
}
public int getBtb_size() {
return btb_size;
}
public void setBtb_size(int btb_size) {
this.btb_size = btb_size;
}
public BranchPredictorType getBtb_predictor() {
return btb_predictor;
}
public void setBtb_predictor(BranchPredictorType btb_predictor) {
this.btb_predictor = btb_predictor;
}
public int getBtb_hits() {
return btb_hits;
}
public void setBtb_hits(int btb_hits) {
this.btb_hits = btb_hits;
}
public int getBtb_misses() {
return btb_misses;
}
public void setBtb_misses(int btb_misses) {
this.btb_misses = btb_misses;
}
public Map<uint32,BranchStat> getBranches_map() {
return branches_map;
}
public void setBranches_map(Map<uint32,BranchStat> branches_map) {
this.branches_map = branches_map;
}
public void reset()
{
cycles = 0;
instructions = 0;
fetches = 0;
jumps_taken = 0;
jumps_nottaken = 0;
jumps_likely = 0;
jumps_link = 0;
jumps_correctly_predicted = 0;
jumps_mispredicted = 0;
memory_reads = 0;
memory_writes = 0;
alu_forward_from_wb = 0;
alu_forward_from_mem = 0;
alu_forward_from_ex = 0;
bcrtl_forward_from_wb = 0;
bcrtl_forward_from_mem = 0;
bcrtl_forward_from_ex = 0;
store_forward_from_wb = 0;
store_forward_from_mem = 0;
store_forward_from_ex = 0;
btb_size = 0;
btb_predictor = BranchPredictorType.UNKNOWN;
btb_hits = 0;
btb_misses = 0;
icache = false;
icache_accesses = 0;
icache_hits = 0;
icache_misses = 0;
icache_words_loaded = 0;
icache_line_size = 0;
icache_line_no = 0;
icache_associativity = 0;
icache_replacement_policy = CacheReplacementPolicy.UNKNOWN;
icache_size = 0;
dcache = false;
dcache_accesses = 0;
dcache_hits = 0;
dcache_misses = 0;
dcache_words_loaded = 0;
dcache_line_size = 0;
dcache_line_no = 0;
dcache_associativity = 0;
dcache_replacement_policy = CacheReplacementPolicy.UNKNOWN;
dcache_write_policy = DCacheWritePolicy.UNKNOWN;
dcache_size = 0;
setBranches_map(new HashMap<uint32,BranchStat>());
}
}