// // Copyright (C) 2008 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.listener; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; import gov.nasa.jpf.Config; import gov.nasa.jpf.JPF; import gov.nasa.jpf.ListenerAdapter; import gov.nasa.jpf.annotation.JPFOption; import gov.nasa.jpf.annotation.JPFOptions; import gov.nasa.jpf.report.Publisher; import gov.nasa.jpf.search.Search; import gov.nasa.jpf.vm.Instruction; import gov.nasa.jpf.vm.ThreadInfo; import gov.nasa.jpf.vm.VM; /** * Listener that implements various budget constraints */ @JPFOptions({ @JPFOption(type = "Long", key = "budget.max_time", defaultValue= "-1", comment = "stop search after specified duration [msec]"), @JPFOption(type = "Long", key = "budget.max_heap", defaultValue = "-1", comment="stop search when VM heapsize reaches specified limit"), @JPFOption(type = "Int", key = "budget.max_depth", defaultValue = "-1", comment = "stop search at specified search depth"), @JPFOption(type = "long", key = "budget.max_insn", defaultValue = "-1", comment = "stop search after specified number of intstructions"), @JPFOption(type = "Int", key = "budget.max_state", defaultValue = "-1", comment = "stop search when reaching specified number of new states"), @JPFOption(type = "Int", key = "budget.max_new_states", defaultValue = "-1", comment="stop search ater specified number of non-replayed new states") }) public class BudgetChecker extends ListenerAdapter { static final int CHECK_INTERVAL = 10000; static final int CHECK_INTERVAL1 = CHECK_INTERVAL-1; long tStart; MemoryUsage muStart; long mStart; MemoryMXBean mxb; VM vm; Search search; long insnCount; //--- the budget thresholds long maxTime; long maxHeap; int maxDepth; long maxInsn; int maxState; int maxNewStates; int newStates; // the message explaining the exceeded budget String message; public BudgetChecker (Config conf, JPF jpf) { //--- get the configured budget limits (0 means not set) maxTime = conf.getDuration("budget.max_time", 0); maxHeap = conf.getMemorySize("budget.max_heap", 0); maxDepth = conf.getInt("budget.max_depth", 0); maxInsn = conf.getLong("budget.max_insn", 0); maxState = conf.getInt("budget.max_state", 0); maxNewStates = conf.getInt("budget.max_new_states", 0); tStart = System.currentTimeMillis(); if (maxHeap > 0) { mxb = ManagementFactory.getMemoryMXBean(); muStart = mxb.getHeapMemoryUsage(); mStart = muStart.getUsed(); } search = jpf.getSearch(); vm = jpf.getVM(); } public boolean timeExceeded() { if (maxTime > 0) { long dur = System.currentTimeMillis() - tStart; if (dur > maxTime) { message = "max time exceeded: " + Publisher.formatHMS(dur) + " >= " + Publisher.formatHMS(maxTime); return true; } } return false; } public boolean heapExceeded() { if (maxHeap > 0) { MemoryUsage mu = mxb.getHeapMemoryUsage(); long used = mu.getUsed() - mStart; if (used > maxHeap) { message = "max heap exceeded: " + (used / (1024*1024)) + "MB" + " >= " + (maxHeap / (1024*1024)) + "MB" ; return true; } } return false; } public boolean depthExceeded () { if (maxDepth > 0) { int d = search.getDepth(); if (d > maxDepth) { message = "max search depth exceeded: " + maxDepth; return true; } } return false; } public boolean statesExceeded () { if (maxState > 0) { int stateId = vm.getStateId(); if (stateId > maxState) { message = "max states exceeded: " + maxState;; return true; } } return false; } public boolean insnExceeded () { if (maxInsn > 0) { if (insnCount > maxInsn) { message = "max instruction count exceeded: " + maxInsn; return true; } } return false; } public boolean newStatesExceeded(){ if (maxNewStates > 0){ if (newStates > maxNewStates) { message = "max new state count exceeded: " + maxNewStates; return true; } } return false; } @Override public void stateAdvanced (Search search) { if (timeExceeded() || heapExceeded()) { search.notifySearchConstraintHit(message); search.terminate(); } if (search.isNewState()){ if (!vm.isTraceReplay()){ newStates++; } if (statesExceeded() || depthExceeded() || newStatesExceeded()){ search.notifySearchConstraintHit(message); search.terminate(); } } } @Override public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { if ((insnCount++ % CHECK_INTERVAL) == CHECK_INTERVAL1) { if (timeExceeded() || heapExceeded() || insnExceeded()) { search.notifySearchConstraintHit(message); vm.getCurrentThread().breakTransition("budgetConstraint"); search.terminate(); } } } }