/* * Copyright 2009 Wishnu Prasetya. * * This file is part of T2. * T2 is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License (GPL) as published by the * Free Software Foundation; either version 3 of the License, or any * later version. * * T2 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. * * A copy of the GNU General Public License can be found in T2 distribution. * If it is missing, see http://www.gnu.org/licenses. */ package Sequenic.T2ext.Instrumenter; import java.util.* ; /** * This provides some methods that act as sensors to be inserted * to instrument a target code. * * I use a different algorithm than Maaike to keep track of the paths. A code is now * injected into the a method that will assign a run-ID when each sensor * fires. For each invocation of the target method, this run-ID is unique. * This circumvents problems with recursion. Moreover, keeping track of the * paths is now simpler (you don't need to use a stack etc). * * @author Wishnu Prasetya */ public class Sensor { static public boolean debug = false ; /** * Maintain the next available runID. */ static private long IDcounter = 0 ; static public synchronized long currentRunId(){ return IDcounter ; } /** * This is where we accumulate observations generated by our sensors. */ static Map observedPaths = new HashMap() ; /** * A support data structure to allow us to quickly find which runIDs belong * to which target methods. If n is the unique name of a target method m, * the map below maps n to the list of runids that belong to it. */ static Map> observationGroups = new HashMap>() ; /** * This will reset the runID counter to 0, and clear the observations * lists (making them empty). Note that this will have side effect to * other classes that hold pointers to the observation lists. These lists * will then also be emptied for them. */ public static synchronized void resetSensor() { IDcounter = 0 ; resetObservations() ; } /** * As reset sensor, except that the runID counter is not reset to 0. */ public static synchronized void resetObservations() { recentlyAcquiredIDs.clear() ; observedPaths.clear() ; observationGroups.clear() ; } /** * This is like resetSensor, but this will release the observations * and start fresh observation lists. So, other classes that hold * pointers to these lists will experience no side effect. */ public static synchronized void ejectObservations() { IDcounter = 0 ; observedPaths = new HashMap() ; observationGroups = new HashMap>() ; } public static Map getObservedPaths() { return observedPaths ; } public static Map> getObservationGroups() { return observationGroups; } /** * Just a test-sensor that will print back its arguments. */ static void testtick(long runID, int nodeNr, String tmethodName){ System.out.println(tmethodName + " [runid: " + runID + "] node " + nodeNr) ; } private static List recentlyAcquiredIDs = new LinkedList() ; /** * Sensor method. This method is to be injected at the beginning of a target method. * The idea is that it returns a unique ID, so that when a sensor * reports it is visited, we know to which run/execution this report * belongs to. * */ public static synchronized long getRunID(){ IDcounter++; recentlyAcquiredIDs.add(IDcounter) ; if (debug) System.out.println("[acquire rid: " + IDcounter + "]") ; return IDcounter; } /** * Sensor method. This method is to be injected in a target method. When it * is called, it will record the corresponding runID, node number, and * the unique name of its host method. */ public static synchronized void tick(long runID, int nodeNr, String tmethodName){ if (debug) System.out.print("[rid: " + runID + "] " + tmethodName + " ==> " + nodeNr + "// ") ; if (recentlyAcquiredIDs.contains(runID)) { // A new run is observed: ObservedPath path = new ObservedPath(tmethodName,runID) ; path.extend(nodeNr) ; observedPaths.put(runID,path) ; recentlyAcquiredIDs.remove((Long) runID) ; // Also add runID to the observationGroups list: List otherRunIds = observationGroups.get(tmethodName) ; if (otherRunIds==null) { otherRunIds = new LinkedList() ; observationGroups.put(tmethodName, otherRunIds) ; } otherRunIds.add(runID) ; return ; } ObservedPath path = observedPaths.get(runID) ; path.extend(nodeNr) ; } /** * A simple method for printing the set of observed paths to the console. */ static public void simplePrint(){ System.out.println("\nEXECUTED paths:") ; for (Long rid : observedPaths.keySet()) { System.out.print("[rid:" + rid + "] " + observedPaths.get(rid).methodUname + " ") ; for (Integer N : observedPaths.get(rid).nodes) System.out.print(N + " -> ") ; System.out.println("EXIT") ; } } }