Skip to content

Commit fe85fb7

Browse files
authored
Allow debug to report multiple invocations (#168)
Squashed four commits
1 parent d191e05 commit fe85fb7

2 files changed

Lines changed: 108 additions & 60 deletions

File tree

nondex-maven-plugin/src/main/java/edu/illinois/nondex/plugin/DebugTask.java

Lines changed: 107 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ a copy of this software and associated documentation files (the
3737
import edu.illinois.nondex.common.Logger;
3838
import edu.illinois.nondex.common.Utils;
3939

40+
import org.apache.commons.lang3.tuple.Pair;
41+
4042
import org.apache.maven.execution.MavenSession;
4143
import org.apache.maven.model.Plugin;
4244
import org.apache.maven.plugin.BuildPluginManager;
@@ -92,26 +94,43 @@ public String debug() throws MojoExecutionException {
9294
}
9395

9496
private String tryDebugSeeds() {
95-
Configuration failingOne = this.debugWithConfigurations(this.failingConfigurations);
97+
List<Configuration> debuggedOnes = this.debugWithConfigurations(this.failingConfigurations);
9698

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

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

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

112113
return null;
113114
}
114115

116+
private String makeResultString(List<Configuration> debuggedOnes) {
117+
StringBuilder sb = new StringBuilder();
118+
for (Configuration config : debuggedOnes) {
119+
if (config == null) {
120+
continue;
121+
}
122+
sb.append(config.toArgLine());
123+
sb.append("\nDEBUG RESULTS FOR ");
124+
sb.append(config.testName);
125+
sb.append(" AND SEED: ");
126+
sb.append(config.seed);
127+
sb.append(" AT: ");
128+
sb.append(config.getDebugPath());
129+
sb.append('\n');
130+
}
131+
return sb.toString();
132+
}
133+
115134
private List<Configuration> createNewSeedsToRetry() {
116135
Configuration someFailingConfig = this.failingConfigurations.iterator().next();
117136
int newSeed = someFailingConfig.seed * ConfigurationDefaults.SEED_FACTOR;
@@ -128,85 +147,114 @@ private List<Configuration> createNewSeedsToRetry() {
128147
return retryWOtherSeeds;
129148
}
130149

131-
private Configuration debugWithConfigurations(List<Configuration> failingConfigurations) {
132-
Configuration debConfig = null;
150+
private List<Configuration> debugWithConfigurations(List<Configuration> failingConfigurations) {
151+
List<Configuration> allDebuggedConfigs = new LinkedList<Configuration>();
133152
for (Configuration config : failingConfigurations) {
134153
Configuration dryConfig;
135154
if ((dryConfig = this.failsOnDry(config)) != null) {
136-
Configuration failingConfig = this.startDebugBinary(dryConfig);
137-
138-
// If debugged down to single choice point, then go ahead and return that
139-
if (failingConfig != null && failingConfig.numChoices() == 0) {
140-
return failingConfig;
141-
}
142-
// Otherwise should go on until finding better one
143-
if (debConfig == null || failingConfig.hasFewerChoicePoints(debConfig)) {
144-
debConfig = failingConfig;
145-
}
155+
// Get all debugged points and just add them to the full list
156+
List<Configuration> debuggedConfigs = this.startDebugBinary(dryConfig);
157+
allDebuggedConfigs.addAll(debuggedConfigs);
146158
}
147159
}
148160

149-
return debConfig;
161+
return allDebuggedConfigs;
150162
}
151163

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

156-
public Configuration startDebugBinary(Configuration config) {
157-
long start = 0;
158-
long end = config.getInvocationCount();
168+
public List<Configuration> startDebugBinary(Configuration config) {
169+
List<Configuration> allFailingConfigurations = new LinkedList<Configuration>();
170+
171+
List<Pair<Pair<Long, Long>, Configuration>> pairs = new LinkedList<Pair<Pair<Long, Long>, Configuration>>();
172+
pairs.add((Pair<Pair<Long, Long>, Configuration>)Pair.of((Pair<Long, Long>)Pair.of(0L,
173+
(long)config.getInvocationCount()), config));
174+
159175
Configuration failingConfiguration = null;
160-
while (start < end) {
161-
Logger.getGlobal().log(Level.INFO, "Debugging binary for " + this.test + " " + start + " : " + end);
176+
while (pairs.size() > 0) {
177+
Pair<Pair<Long, Long>, Configuration> pair = pairs.remove(0);
178+
Pair<Long, Long> range = pair.getLeft();
179+
failingConfiguration = pair.getRight();
180+
long start = range.getLeft();
181+
long end = range.getRight();
182+
183+
if (start < end) {
184+
Logger.getGlobal().log(Level.INFO, "Debugging binary for " + this.test + " " + start + " : " + end);
185+
186+
boolean binarySuccess = false;
187+
long midPoint = (start + end) / 2;
188+
if ((failingConfiguration = this.failsWithConfig(config, start, midPoint)) != null) {
189+
pairs.add(Pair.of((Pair<Long, Long>)Pair.of(start, midPoint), failingConfiguration));
190+
binarySuccess = true;
191+
}
192+
if ((failingConfiguration = this.failsWithConfig(config, midPoint + 1, end)) != null) {
193+
pairs.add(Pair.of((Pair<Long, Long>)Pair.of(midPoint + 1, end), failingConfiguration));
194+
binarySuccess = true;
195+
}
162196

163-
long midPoint = (start + end) / 2;
164-
if ((failingConfiguration = this.failsWithConfig(config, start, midPoint)) != null) {
165-
end = midPoint;
166-
continue;
167-
} else if ((failingConfiguration = this.failsWithConfig(config, midPoint + 1, end)) != null) {
168-
start = midPoint + 1;
169-
continue;
197+
// If both halves fail, try the entire range
198+
if (!binarySuccess) {
199+
Logger.getGlobal().log(Level.SEVERE, "Binary splitting did not work. Going to linear");
200+
allFailingConfigurations.addAll(this.startDebugLinear(config, start, end));
201+
}
170202
} else {
171-
Logger.getGlobal().log(Level.FINE, "Binary splitting did not work. Going to linear");
172-
failingConfiguration = this.startDebugLinear(config, start, end);
173-
break;
203+
// Since start <= end is always true, this branch means start == end, so reached end
204+
if (failingConfiguration != null) {
205+
allFailingConfigurations.add(this.reportDebugInfo(failingConfiguration));
206+
}
174207
}
175208
}
176-
if (failingConfiguration != null) {
177-
return this.reportDebugInfo(failingConfiguration);
178-
}
179-
return failingConfiguration;
209+
210+
return allFailingConfigurations;
180211
}
181212

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

186-
public Configuration startDebugLinear(Configuration config, long start, long end) {
217+
public List<Configuration> startDebugLinear(Configuration config, long start, long end) {
218+
List<Configuration> allFailingConfigurations = new LinkedList<Configuration>();
219+
220+
List<Pair<Pair<Long, Long>, Configuration>> pairs = new LinkedList<Pair<Pair<Long, Long>, Configuration>>();
221+
pairs.add((Pair<Pair<Long, Long>, Configuration>)Pair.of((Pair<Long, Long>)Pair.of(start, end),
222+
config));
223+
187224
Configuration failingConfiguration = null;
188-
long localStart = start;
189-
long localEnd = end;
190-
// Give up if range too large
191-
if (localEnd - localStart > 50) {
192-
return null;
193-
}
194-
while (localStart < localEnd) {
195-
Logger.getGlobal().log(Level.INFO,
196-
"Debugging linear for " + this.test + " " + localStart + " : " + localEnd);
225+
while (pairs.size() > 0) {
226+
Pair<Pair<Long, Long>, Configuration> pair = pairs.remove(0);
227+
Pair<Long, Long> range = pair.getLeft();
228+
failingConfiguration = pair.getRight();
229+
long localStart = range.getLeft();
230+
long localEnd = range.getRight();
231+
232+
if (localStart < localEnd) {
233+
Logger.getGlobal().log(Level.INFO, "Debugging linear for " + this.test + " "
234+
+ localStart + " : " + localEnd);
235+
236+
boolean found = false;
237+
if ((failingConfiguration = this.failsWithConfig(config, localStart, localEnd - 1)) != null) {
238+
pairs.add(Pair.of((Pair<Long, Long>)Pair.of(localStart, localEnd - 1), failingConfiguration));
239+
found = true;
240+
}
241+
if ((failingConfiguration = this.failsWithConfig(config, localStart + 1, localEnd)) != null) {
242+
pairs.add(Pair.of((Pair<Long, Long>)Pair.of(localStart + 1, localEnd), failingConfiguration));
243+
found = true;
244+
}
197245

198-
if ((failingConfiguration = this.failsWithConfig(config, localStart, localEnd - 1)) != null) {
199-
localEnd = localEnd - 1;
200-
continue;
201-
} else if ((failingConfiguration = this.failsWithConfig(config, localStart + 1, localEnd)) != null) {
202-
localStart = localStart + 1;
203-
continue;
246+
if (!found) {
247+
Logger.getGlobal().log(Level.FINE, "Refining did not work. Does not fail with linear on range "
248+
+ localStart + " : " + localEnd + ".");
249+
}
204250
} else {
205-
Logger.getGlobal().log(Level.FINE, "Refining did not work. Does not fail with linear.");
206-
break;
251+
// Since start <= end is always true, this branch means start == end, so reached end
252+
if (failingConfiguration != null) {
253+
allFailingConfigurations.add(this.reportDebugInfo(failingConfiguration));
254+
}
207255
}
208256
}
209-
return failingConfiguration;
257+
return allFailingConfigurations;
210258
}
211259

212260
private Configuration failsWithConfig(Configuration config, long start, long end) {

nondex-maven-plugin/src/main/java/edu/illinois/nondex/plugin/NonDexMojo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ a copy of this software and associated documentation files (the
6262
public class NonDexMojo extends AbstractNonDexMojo {
6363

6464
private List<NonDexSurefireExecution> executions = new LinkedList<>();
65-
private ArrayList<CleanSurefireExecution> executionsWithoutShuffling =
65+
private ArrayList<CleanSurefireExecution> executionsWithoutShuffling =
6666
new ArrayList<CleanSurefireExecution>();
6767

6868
@Override

0 commit comments

Comments
 (0)