//
// Copyright (C) 2006 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.report;
import cmu.conditional.Conditional;
import gov.nasa.jpf.ListenerAdapter;
import gov.nasa.jpf.jvm.bytecode.EXECUTENATIVE;
import gov.nasa.jpf.jvm.bytecode.FieldInstruction;
import gov.nasa.jpf.jvm.bytecode.InvokeInstruction;
import gov.nasa.jpf.jvm.bytecode.LockInstruction;
import gov.nasa.jpf.search.Search;
import gov.nasa.jpf.vm.ChoiceGenerator;
import gov.nasa.jpf.vm.ClassInfo;
import gov.nasa.jpf.vm.ElementInfo;
import gov.nasa.jpf.vm.Instruction;
import gov.nasa.jpf.vm.MethodInfo;
import gov.nasa.jpf.vm.ThreadChoiceGenerator;
import gov.nasa.jpf.vm.ThreadInfo;
import gov.nasa.jpf.vm.VM;
import java.util.List;
/**
* simple structure to hold statistics info created by Reporters/Publishers
* this is kind of a second tier SearchListener, which does not
* explicitly have to be registered
* <p/>
* <2do> this should get generic and accessible enough to replace all the
* other statistics collectors, otherwise there is too much redundancy.
* If users have special requirements, they should subclass Statistics
* and set jpf.report.statistics.class accordingly
* <p/>
* Note that Statistics might be accessed by a background thread
* reporting JPF progress, hence we have to synchronize
*/
public class Statistics extends ListenerAdapter implements Cloneable {
// we make these public since we don't want to add a gazillion of
// getters for these purely informal numbers
public long maxUsed = 0;
public long newStates = 0;
public long backtracked = 0;
public long restored = 0;
public int processed = 0;
public int constraints = 0;
public long visitedStates = 0;
public long endStates = 0;
public int maxDepth = 0;
public int gcCycles = 0;
public long insns = 0;
public int threadCGs = 0;
public int sharedAccessCGs = 0;
public int monitorCGs = 0;
public int signalCGs = 0;
public int threadApiCGs = 0;
public int breakTransitionCGs = 0;
public int dataCGs = 0;
public long nNewObjects = 0;
public long nReleasedObjects = 0;
public int maxLiveObjects = 0;
public Statistics clone() {
try {
return (Statistics) super.clone();
} catch (CloneNotSupportedException e) {
return null; // can't happen
}
}
@Override
public void gcBegin(VM vm) {
int heapSize = vm.getHeap().size();
if (heapSize > maxLiveObjects) {
maxLiveObjects = heapSize;
}
gcCycles++;
}
@Override
public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) {
insns++;
// FIXME
long m = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
if (m > maxUsed) {
maxUsed = m;
}
}
@Override
public void choiceGeneratorSet(VM vm, ChoiceGenerator<?> newCG) {
ChoiceGenerator<?> cg = VM.getVM().getChoiceGenerator();
if (cg instanceof ThreadChoiceGenerator) {
threadCGs++;
Conditional<Instruction> insnCond = cg.getInsn();
List<Instruction> insnList = insnCond.toList();
for (Instruction insn : insnList) {
if (insn instanceof FieldInstruction) {
sharedAccessCGs++;
} else if (insn instanceof LockInstruction || insn instanceof InvokeInstruction) {
monitorCGs++;
} else if (insn instanceof EXECUTENATIVE) {
MethodInfo mi = insn.getMethodInfo();
if (mi != null) {
ClassInfo ci = mi.getClassInfo();
if (ci != null) {
if (ci.isObjectClassInfo()) {
// its got to be either a wait or a notify since we know the java.lang.Object methods
signalCGs++;
} else if (ci.isThreadClassInfo()) {
threadApiCGs++;
}
} else {
// Hmm - a CG from a synthetic method?
}
} else {
// even more Hmmm - a GC from a synthesized instruction
}
} else {
breakTransitionCGs++; // e.g. max_transition_length or idleLoop breakers
}
}
} else {
dataCGs++;
}
}
@Override
public void objectCreated(VM vm, ThreadInfo ti, ElementInfo ei) {
nNewObjects++;
}
@Override
public void objectReleased(VM vm, ThreadInfo ti, ElementInfo ei) {
nReleasedObjects++;
}
@Override
public void stateAdvanced(Search search) {
long m = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
if (m > maxUsed) {
maxUsed = m;
}
if (search.isNewState()) {
newStates++;
int depth = search.getDepth();
if (depth > maxDepth) {
maxDepth = depth;
}
} else {
visitedStates++;
}
if (search.isEndState()) {
endStates++;
}
}
@Override
public void stateBacktracked(Search search) {
backtracked++;
}
@Override
public void stateProcessed(Search search) {
processed++;
}
@Override
public void stateRestored(Search search) {
restored++;
}
@Override
public void searchConstraintHit(Search search) {
constraints++;
}
@Override
public void resetInstructionCounter() {
insns = 0;
}
}