Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debugging reports multiple #53

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ a copy of this software and associated documentation files (the
import edu.illinois.nondex.common.Logger;
import edu.illinois.nondex.common.Utils;

import org.apache.commons.lang3.tuple.Pair;

import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.BuildPluginManager;
Expand Down Expand Up @@ -92,26 +94,40 @@ public String debug() throws MojoExecutionException {
}

private String tryDebugSeeds() {
Configuration failingOne = this.debugWithConfigurations(this.failingConfigurations);
List<Configuration> debuggedOnes = this.debugWithConfigurations(this.failingConfigurations);

if (failingOne != null) {
return failingOne.toArgLine() + String.format("%n") + "DEBUG RESULTS FOR " + failingOne.testName + " AT: "
+ failingOne.getDebugPath();
if (debuggedOnes.size() > 0) {
return makeResultString(debuggedOnes);
}

// The seeds that failed with the full test-suite no longer fail
// Searching for different seeds
Logger.getGlobal().log(Level.FINE, "TRYING NEW SEEDS");
List<Configuration> retryWOtherSeeds = this.createNewSeedsToRetry();
failingOne = this.debugWithConfigurations(retryWOtherSeeds);
debuggedOnes = this.debugWithConfigurations(retryWOtherSeeds);

if (failingOne != null) {
return failingOne.toArgLine() + String.format("%n") + "DEBUG RESULTS FOR " + failingOne.testName + " AT: "
+ failingOne.getDebugPath();
if (debuggedOnes.size() > 0) {
return makeResultString(debuggedOnes);
}

return null;
}

private String makeResultString(List<Configuration> debuggedOnes) {
StringBuilder sb = new StringBuilder();
for (Configuration config : debuggedOnes) {
sb.append(config.toArgLine());
sb.append("\nDEBUG RESULTS FOR ");
sb.append(config.testName);
sb.append(" AND SEED: ");
sb.append(config.seed);
sb.append(" AT: ");
sb.append(config.getDebugPath());
sb.append('\n');
}
return sb.toString();
}

private List<Configuration> createNewSeedsToRetry() {
Configuration someFailingConfig = this.failingConfigurations.iterator().next();
int newSeed = someFailingConfig.seed * ConfigurationDefaults.SEED_FACTOR;
Expand All @@ -128,85 +144,110 @@ private List<Configuration> createNewSeedsToRetry() {
return retryWOtherSeeds;
}

private Configuration debugWithConfigurations(List<Configuration> failingConfigurations) {
Configuration debConfig = null;
private List<Configuration> debugWithConfigurations(List<Configuration> failingConfigurations) {
//Configuration debConfig = null;
List<Configuration> allDebuggedConfigs = new LinkedList<Configuration>();
for (Configuration config : failingConfigurations) {
Configuration dryConfig;
if ((dryConfig = this.failsOnDry(config)) != null) {
Configuration failingConfig = this.startDebugBinary(dryConfig);

// If debugged down to single choice point, then go ahead and return that
if (failingConfig != null && failingConfig.numChoices() == 0) {
return failingConfig;
}
// Otherwise should go on until finding better one
if (debConfig == null || failingConfig.hasFewerChoicePoints(debConfig)) {
debConfig = failingConfig;
}
// Get all debugged points and just add them to the full list
List<Configuration> debuggedConfigs = this.startDebugBinary(dryConfig);
allDebuggedConfigs.addAll(debuggedConfigs);
}
}

return debConfig;
return allDebuggedConfigs;
}

private Configuration failsOnDry(Configuration config) {
return this.failsWithConfig(config, Integer.MIN_VALUE, Integer.MAX_VALUE);
}

public Configuration startDebugBinary(Configuration config) {
long start = 0;
long end = config.getInvocationCount();
public List<Configuration> startDebugBinary(Configuration config) {
List<Configuration> allFailingConfigurations = new LinkedList<Configuration>();

List<Pair<Pair<Long, Long>, Configuration>> pairs = new LinkedList<Pair<Pair<Long, Long>, Configuration>>();
pairs.add((Pair<Pair<Long, Long>, Configuration>)Pair.of((Pair<Long, Long>)Pair.of(0L,
(long)config.getInvocationCount()), (Configuration)null));

Configuration failingConfiguration = null;
while (start < end) {
Logger.getGlobal().log(Level.INFO, "Debugging binary for " + this.test + " " + start + " : " + end);

long midPoint = (start + end) / 2;
if ((failingConfiguration = this.failsWithConfig(config, start, midPoint)) != null) {
end = midPoint;
continue;
} else if ((failingConfiguration = this.failsWithConfig(config, midPoint + 1, end)) != null) {
start = midPoint + 1;
continue;
while (pairs.size() > 0) {
Pair<Pair<Long, Long>, Configuration> pair = pairs.remove(0);
Pair<Long, Long> range = pair.getLeft();
failingConfiguration = pair.getRight();
long start = range.getLeft();
long end = range.getRight();

if (start < end) {
Logger.getGlobal().log(Level.INFO, "Debugging binary for " + this.test + " " + start + " : " + end);

boolean binarySuccess = false;
long midPoint = (start + end) / 2;
if ((failingConfiguration = this.failsWithConfig(config, start, midPoint)) != null) {
pairs.add(Pair.of((Pair<Long, Long>)Pair.of(start, midPoint), failingConfiguration));
binarySuccess = true;
}
if ((failingConfiguration = this.failsWithConfig(config, midPoint + 1, end)) != null) {
pairs.add(Pair.of((Pair<Long, Long>)Pair.of(midPoint + 1, end), failingConfiguration));
binarySuccess = true;
}

// If both halves fail, try the entire range
if (!binarySuccess) {
Logger.getGlobal().log(Level.SEVERE, "Binary splitting did not work. Going to linear");
allFailingConfigurations.addAll(this.startDebugLinear(config, start, end));
}
} else {
Logger.getGlobal().log(Level.FINE, "Binary splitting did not work. Going to linear");
failingConfiguration = this.startDebugLinear(config, start, end);
break;
// Since start <= end is always true, this branch means start == end, so reached end
if (failingConfiguration != null) {
allFailingConfigurations.add(this.reportDebugInfo(failingConfiguration));
}
}
}
if (failingConfiguration != null) {
return this.reportDebugInfo(failingConfiguration);
}
return failingConfiguration;

return allFailingConfigurations;
}

private Configuration reportDebugInfo(Configuration failingConfiguration) {
return this.failsWithConfig(failingConfiguration, failingConfiguration.start, failingConfiguration.end, true);
}

public Configuration startDebugLinear(Configuration config, long start, long end) {
public List<Configuration> startDebugLinear(Configuration config, long start, long end) {
List<Configuration> allFailingConfigurations = new LinkedList<Configuration>();

List<Pair<Pair<Long, Long>, Configuration>> pairs = new LinkedList<Pair<Pair<Long, Long>, Configuration>>();
pairs.add((Pair<Pair<Long, Long>, Configuration>)Pair.of((Pair<Long, Long>)Pair.of(start, end),
(Configuration)null));

Configuration failingConfiguration = null;
long localStart = start;
long localEnd = end;
// Give up if range too large
if (localEnd - localStart > 50) {
return null;
}
while (localStart < localEnd) {
Logger.getGlobal().log(Level.INFO,
"Debugging linear for " + this.test + " " + localStart + " : " + localEnd);

if ((failingConfiguration = this.failsWithConfig(config, localStart, localEnd - 1)) != null) {
localEnd = localEnd - 1;
continue;
} else if ((failingConfiguration = this.failsWithConfig(config, localStart + 1, localEnd)) != null) {
localStart = localStart + 1;
continue;
} else {
Logger.getGlobal().log(Level.FINE, "Refining did not work. Does not fail with linear.");
break;
while (pairs.size() > 0) {
Pair<Pair<Long, Long>, Configuration> pair = pairs.remove(0);
Pair<Long, Long> range = pair.getLeft();
failingConfiguration = pair.getRight();
long localStart = range.getLeft();
long localEnd = range.getRight();

if (localStart < localEnd) {
Logger.getGlobal().log(Level.INFO, "Debugging linear for " + this.test + " "
+ localStart + " : " + localEnd);

boolean found = false;
if ((failingConfiguration = this.failsWithConfig(config, localStart, localEnd - 1)) != null) {
pairs.add(Pair.of((Pair<Long, Long>)Pair.of(localStart, localEnd - 1), failingConfiguration));
found = true;
}
if ((failingConfiguration = this.failsWithConfig(config, localStart + 1, localEnd)) != null) {
pairs.add(Pair.of((Pair<Long, Long>)Pair.of(localStart + 1, localEnd), failingConfiguration));
found = true;
}

if (!found) {
Logger.getGlobal().log(Level.FINE, "Refining did not work. Does not fail with linear on range "
+ localStart + " : " + localEnd + ".");
}
}
}
return failingConfiguration;
return allFailingConfigurations;
}

private Configuration failsWithConfig(Configuration config, long start, long end) {
Expand Down