us.ihmc.simulationconstructionset.util.simulationRunner.SimulationRewindabilityVerifierWithStackTracing Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of simulation-construction-set
Show all versions of simulation-construction-set
Simulation Construction Set
package us.ihmc.simulationconstructionset.util.simulationRunner;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import us.ihmc.simulationconstructionset.SimulationConstructionSet;
import us.ihmc.yoVariables.listener.YoVariableChangedListener;
import us.ihmc.yoVariables.registry.YoRegistry;
import us.ihmc.yoVariables.variable.YoVariable;
public class SimulationRewindabilityVerifierWithStackTracing
{
private final double EPSILON = 1e-14;
private final VariablesThatShouldMatchList VariablesThatShouldMatchList;
private final YoRegistry rootRegistryOne, rootRegistryTwo;
private final LinkedHashMap> changesForSimOne = new LinkedHashMap<>();
private final LinkedHashMap> changesForSimTwo = new LinkedHashMap<>();
private boolean recordDifferencesForSimOne = false;
private boolean recordDifferencesForSimTwo = false;
public SimulationRewindabilityVerifierWithStackTracing(SimulationConstructionSet simulationOne, SimulationConstructionSet simulationTwo,
ArrayList exceptions)
{
rootRegistryOne = simulationOne.getRootRegistry();
rootRegistryTwo = simulationTwo.getRootRegistry();
VariablesThatShouldMatchList = new VariablesThatShouldMatchList(rootRegistryOne, rootRegistryTwo, exceptions);
YoVariableChangedListener variableChangedListenerForSimOne = new YoVariableChangedListener()
{
@Override
public void changed(YoVariable variableInRegistryOne)
{
if (!recordDifferencesForSimOne)
return;
YoVariable variableInRegistryTwo = VariablesThatShouldMatchList.getYoVariableInListTwo(variableInRegistryOne.getFullNameString());
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
Thread thread = Thread.currentThread();
VariableChangeAndStackTrace change = new VariableChangeAndStackTrace(thread,
variableInRegistryOne,
variableInRegistryTwo,
variableInRegistryOne.getValueAsDouble(),
stackTrace);
ArrayList changesForThread = changesForSimOne.get(thread);
if (changesForThread == null)
{
changesForThread = new ArrayList<>();
changesForSimOne.put(thread, changesForThread);
}
changesForThread.add(change);
}
};
YoVariableChangedListener variableChangedListenerForSimTwo = new YoVariableChangedListener()
{
@Override
public void changed(YoVariable variableInRegistryTwo)
{
if (!recordDifferencesForSimTwo)
return;
YoVariable variableInRegistryOne = VariablesThatShouldMatchList.getYoVariableInListOne(variableInRegistryTwo.getFullNameString());
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
Thread thread = Thread.currentThread();
VariableChangeAndStackTrace change = new VariableChangeAndStackTrace(thread,
variableInRegistryOne,
variableInRegistryTwo,
variableInRegistryTwo.getValueAsDouble(),
stackTrace);
ArrayList changesForThread = changesForSimTwo.get(thread);
if (changesForThread == null)
{
changesForThread = new ArrayList<>();
changesForSimTwo.put(thread, changesForThread);
}
changesForThread.add(change);
}
};
List variablesThatShouldMatch = VariablesThatShouldMatchList.getVariablesThatShouldMatch();
for (YoVariable[] variablesToMatch : variablesThatShouldMatch)
{
variablesToMatch[0].addListener(variableChangedListenerForSimOne);
variablesToMatch[1].addListener(variableChangedListenerForSimTwo);
}
}
public void clearChangesForSimulations()
{
changesForSimOne.clear();
changesForSimTwo.clear();
}
public void setRecordDifferencesForSimOne(boolean recordDifferencesForSimOne)
{
this.recordDifferencesForSimOne = recordDifferencesForSimOne;
}
public void setRecordDifferencesForSimTwo(boolean recordDifferencesForSimTwo)
{
this.recordDifferencesForSimTwo = recordDifferencesForSimTwo;
}
public LinkedHashMap> getVariableChangesAndStackTracesForSimulationOne()
{
return changesForSimOne;
}
public LinkedHashMap> getVariableChangesAndStackTracesForSimulationTwo()
{
return changesForSimTwo;
}
public boolean areTheVariableChangesDifferent()
{
ArrayList threadNames = getThreadNames();
for (String threadName : threadNames)
{
// System.out.println("threadName = " + threadName);
if (areTheVariableChangesDifferent(threadName))
return true;
}
return false;
}
public boolean areTheVariableChangesDifferent(String threadName)
{
Thread threadOne = getThreadWithName(threadName, changesForSimOne);
Thread threadTwo = getThreadWithName(threadName, changesForSimTwo);
ArrayList changesForSimOne = this.changesForSimOne.get(threadOne);
ArrayList changesForSimTwo = this.changesForSimTwo.get(threadTwo);
int sizeOne = changesForSimOne.size();
int sizeTwo = changesForSimTwo.size();
if (sizeOne != sizeTwo)
return true;
for (int i = 0; i < sizeOne; i++)
{
VariableChangeAndStackTrace changeOne = changesForSimOne.get(i);
VariableChangeAndStackTrace changeTwo = changesForSimTwo.get(i);
boolean variablesAreDifferent = !changeOne.variableOne.getName().equals(changeTwo.variableTwo.getName());
boolean finalValueIsDifferent = Math.abs(changeOne.variableOne.getValueAsDouble() - changeOne.variableTwo.getValueAsDouble()) > EPSILON;
boolean localChangeValuesAreDifferent = Math.abs(changeOne.variableValue - changeTwo.variableValue) > EPSILON;
if (variablesAreDifferent || finalValueIsDifferent || localChangeValuesAreDifferent)
return true;
}
return false;
}
private Thread getThreadWithName(String name, LinkedHashMap> changes)
{
Set keySet = changes.keySet();
for (Thread thread : keySet)
{
if (thread.getName().equals(name))
return thread;
}
return null;
}
private ArrayList getThreadNames()
{
ArrayList threadNamesToReturn = new ArrayList<>();
Set threadsForSimOne = changesForSimOne.keySet();
for (Thread thread : threadsForSimOne)
{
threadNamesToReturn.add(thread.getName());
}
Set threadsForSimTwo = changesForSimTwo.keySet();
for (Thread thread : threadsForSimTwo)
{
if (!threadNamesToReturn.contains(thread.getName()))
{
throw new RuntimeException("Thread named" + thread.getName() + " is in second sim but not in first!");
}
}
return threadNamesToReturn;
}
public int countNumberOfThreadsThatChangeTheVariables(ArrayList changes)
{
HashSet threads = new HashSet<>();
for (int i = 0; i < changes.size(); i++)
{
VariableChangeAndStackTrace change = changes.get(i);
Thread thread = change.thread;
threads.add(thread);
}
return threads.size();
}
public int findIndexOfFistVariableChange(String threadName)
{
Thread threadOne = getThreadWithName(threadName, changesForSimOne);
Thread threadTwo = getThreadWithName(threadName, changesForSimTwo);
ArrayList changesForSimOne = this.changesForSimOne.get(threadOne);
ArrayList changesForSimTwo = this.changesForSimTwo.get(threadTwo);
int sizeOne = changesForSimOne.size();
int sizeTwo = changesForSimTwo.size();
int minSize = Math.min(sizeOne, sizeTwo);
for (int index = 0; index < minSize; index++)
{
VariableChangeAndStackTrace changeOne = changesForSimOne.get(index);
VariableChangeAndStackTrace changeTwo = changesForSimTwo.get(index);
boolean variablesAreDifferent = !(changeOne.variableOne.getName().equals(changeTwo.variableTwo.getName()));
boolean localChangeValuesAreDifferent = Math.abs(changeOne.variableValue - changeTwo.variableValue) > EPSILON;
if (variablesAreDifferent || localChangeValuesAreDifferent)
return index;
}
return -1;
}
public void printOutStackTracesOfFirstChangedVariable()
{
ArrayList threadNames = getThreadNames();
for (String threadName : threadNames)
{
System.out.println("\n\nThread = " + threadName);
printOutStackTracesOfFirstChangedVariable(threadName);
}
}
public void printOutStackTracesOfFirstChangedVariable(String threadName)
{
Thread threadOne = getThreadWithName(threadName, changesForSimOne);
Thread threadTwo = getThreadWithName(threadName, changesForSimTwo);
ArrayList changesForSimOne = this.changesForSimOne.get(threadOne);
ArrayList changesForSimTwo = this.changesForSimTwo.get(threadTwo);
int firstChangedIndex = findIndexOfFistVariableChange(threadName);
if (firstChangedIndex < 0)
return;
System.out.println("\nFirst change index at : " + firstChangedIndex);
System.out.println("\n Local changes for change one:");
printLocalChangesBeforeAndAfterIndex(changesForSimOne, firstChangedIndex);
System.out.println("\n Local changes for change two:");
printLocalChangesBeforeAndAfterIndex(changesForSimTwo, firstChangedIndex);
System.out.println("\n Stack traces for change one:");
printStackTraceBeforeAndAfterIndex(changesForSimOne, firstChangedIndex);
System.out.println("\n Stack traces for change two:");
printStackTraceBeforeAndAfterIndex(changesForSimTwo, firstChangedIndex);
}
private static void printLocalChangesBeforeAndAfterIndex(ArrayList changesForSim, int firstChangedIndex)
{
int sizeOne = changesForSim.size();
int numberBefore = 2;
int numberAfter = 2;
int startIndex = Math.max(0, firstChangedIndex - numberBefore);
int endIndex = Math.min(sizeOne - 1, firstChangedIndex + numberAfter);
for (int i = startIndex; i <= endIndex; i++)
{
VariableChangeAndStackTrace change = changesForSim.get(i);
String highlight = "";
if (i == firstChangedIndex)
highlight = "*** ";
System.out.println(highlight + "Changed variable = " + change.variableOne.getName() + " = " + change.variableValue + ", other = "
+ change.variableTwo.getName());
}
}
private static void printStackTraceBeforeAndAfterIndex(ArrayList changesForSim, int firstChangedIndex)
{
int sizeOne = changesForSim.size();
int numberBefore = 0;
int numberAfter = 0;
int startIndex = Math.max(0, firstChangedIndex - numberBefore);
int endIndex = Math.min(sizeOne - 1, firstChangedIndex + numberAfter);
for (int i = startIndex; i <= endIndex; i++)
{
VariableChangeAndStackTrace change = changesForSim.get(i);
System.out.println("Changed variable = " + change.variableOne.getName() + " = " + change.variableValue + ", other = " + change.variableTwo.getName());
printStackTrace(change.stackTrace);
}
}
public void printOutVariableChangesStartingAtIndex(String threadName, int index)
{
Thread threadOne = getThreadWithName(threadName, changesForSimOne);
Thread threadTwo = getThreadWithName(threadName, changesForSimTwo);
ArrayList changesForSimOne = this.changesForSimOne.get(threadOne);
ArrayList changesForSimTwo = this.changesForSimTwo.get(threadTwo);
int sizeOne = changesForSimOne.size();
int sizeTwo = changesForSimTwo.size();
int minSize = Math.min(sizeOne, sizeTwo);
for (int i = 0; i < minSize; i++)
{
VariableChangeAndStackTrace changeOne = changesForSimOne.get(i);
VariableChangeAndStackTrace changeTwo = changesForSimTwo.get(i);
System.out.println("Changed variable = " + changeOne.variableOne.getName() + " = " + changeOne.variableValue + ", other = "
+ changeTwo.variableTwo.getName() + " = " + changeTwo.variableValue);
}
}
private static void printStackTrace(StackTraceElement[] stackTrace)
{
System.out.println("stack trace:");
for (StackTraceElement stackTraceElement : stackTrace)
{
System.out.println(stackTraceElement.toString());
}
}
private class VariableChangeAndStackTrace
{
private final Thread thread;
private final YoVariable variableOne;
private final YoVariable variableTwo;
private final double variableValue;
private final StackTraceElement[] stackTrace;
public VariableChangeAndStackTrace(Thread thread, YoVariable variableOne, YoVariable variableTwo, double variableValue,
StackTraceElement[] stackTrace)
{
this.thread = thread;
this.variableOne = variableOne;
this.variableTwo = variableTwo;
this.variableValue = variableValue;
this.stackTrace = stackTrace;
}
}
}