/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2008, Martin Schoeberl (martin@jopdesign.com) 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.tools; import java.util.*; /** * Extension of JopSim to simulation real-time transactional memory (RTTM) * * @author Martin Schoeberl * */ public class TMSim extends JopSim { final static int MAGIC = -10000; final static boolean LOG = false; TMSim(String fn, IOSimMin ioSim, int max) { super(fn, ioSim, max); } int trCnt; int retryCnt; int maxRead; int maxWrite; int maxSum; int nestingCnt; int savedPc; LinkedHashSet<Integer> readSet = new LinkedHashSet<Integer>(); LinkedHashMap<Integer, Integer> writeSet = new LinkedHashMap<Integer, Integer>(); // TODO: we should earlier abort the transaction as we // can read inconsistent data from another commited transaction // TODO: we're still having constants and method table loads in // the read set, but cache load uses readInstrMem(). int readMem(int addr, Access type) { // TODO: use access type switch (type) { case MTAB: break; default: // Transaction active and not an I/O address if (nestingCnt > 0 && addr >= 0) { Integer addrInt = new Integer(addr); readSet.add(addrInt); if (writeSet.containsKey(addrInt)) { return writeSet.get(addrInt).intValue(); } } break; } return super.readMem(addr, type); } void writeMem(int addr, int data, Access type) { if (addr == MAGIC) { if (data != 0) { startTransaction(); } else { endTransaction(); } return; } // Transaction active and not an I/O address if (nestingCnt > 0 && addr >= 0) { writeSet.put(new Integer(addr), new Integer(data)); } else { super.writeMem(addr, data, type); } } void commit() { if (LOG) System.out.print("Commiting TR " + trCnt + " on CPU " + io.cpuId); if (LOG) System.out.println(" - write set " + writeSet.size() + " read set " + readSet.size()); if (writeSet.size() > maxWrite) maxWrite = writeSet.size(); if (readSet.size() > maxRead) maxRead = readSet.size(); Collection<Integer> keys = writeSet.keySet(); for (Iterator<Integer> iterator = keys.iterator(); iterator.hasNext();) { Integer addr = iterator.next(); int thisAddr = addr; int val = writeSet.get(addr); // TODO: type lost super.writeMem(thisAddr, val, Access.INTERN); // test for conflict for (int i = 0; i < nrCpus; ++i) { if (i == io.cpuId) continue; TMSim otherSim = (TMSim) js[i]; if (otherSim.abort) continue; for (Iterator<Integer> other = otherSim.readSet.iterator(); other .hasNext();) { int otherAddr = other.next(); if (otherAddr == thisAddr) { otherSim.abort = true; if (LOG) System.out.println("Transaction on CPU " + i + " aborted"); break; } } } } // find the sum of different addresses for (Iterator<Integer> it = readSet.iterator(); it.hasNext();) { int addr = it.next(); writeSet.put(addr, 0); } if (writeSet.size() > maxSum) maxSum = writeSet.size(); writeSet.clear(); readSet.clear(); } void retry() { abort = false; pc = savedPc; // also restore the stack for the write stack[++sp] = 1; stack[++sp] = MAGIC; writeSet.clear(); readSet.clear(); if (LOG) System.out.println("Retry TR " + trCnt + " on CPU " + io.cpuId); --trCnt; ++retryCnt; } /** * The single commit token. 0 means free otherwise it contains the CPU ID + * 1. */ static int commitingCpu; boolean abort; void startTransaction() { ++trCnt; if (LOG) System.out.println("Start TR " + trCnt + " on CPU " + io.cpuId); if (nestingCnt == 0) { savedPc = pc - 1; } ++nestingCnt; } void endTransaction() { if (LOG) System.out.println("End TR " + trCnt + " on CPU " + io.cpuId); --nestingCnt; if (nestingCnt == 0) { // do the commit or retry if (abort) { retry(); } else { if (commitingCpu != 0) { // wait for commit token --pc; stack[++sp] = 0; stack[++sp] = MAGIC; System.out.println("wait for token"); } else { commitingCpu = io.cpuId + 1; commit(); commitingCpu = 0; } } } } void stat() { super.stat(); System.out.println("TM statistics"); System.out.println("Nr of transactions: " + trCnt); System.out.println("Nr of retries: " + retryCnt); System.out.println("Max write set " + maxWrite + " max read set " + maxRead + " max sum " + maxSum); } /** * @param args */ public static void main(String args[]) { IOSimMin io; int maxInstr = getArgs(args); String ioDevice = System.getProperty("ioclass"); if(ioDevice != null) { System.out.println("Using IO Class: " + ioDevice); } else { System.out.println("Using IO Class: IOSimMin"); } for (int i = 0; i < nrCpus; ++i) { // select the IO simulation if (ioDevice!=null) { try { io = (IOSimMin) Class.forName("com.jopdesign.tools."+ioDevice).newInstance(); } catch (Exception e) { e.printStackTrace(); io = new IOSimMin(); } } else { io = new IOSimMin(); } io.setCpuId(i); js[i] = new TMSim(args[0], io, maxInstr); io.setJopSimRef(js[i]); } runSimulation(); } }