Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a95b881
Reject bad command-line options with a non-zero exit status
mernst Oct 7, 2026
2356213
TraceSelect: reject bad arguments, accept -h and --help, reset state …
mernst Oct 7, 2026
6380a6a
Remove stale comment in DtraceDiff
mernst Oct 7, 2026
13b29da
Merge branch 'bad-option-core' into traceselect-args
mernst Oct 7, 2026
23bf08d
Address code review: reject "- " with no short options, report instru…
mernst Oct 7, 2026
d20d9f8
Merge remote-tracking branch 'origin/bad-option-core' into bad-option…
mernst Oct 7, 2026
0242d85
Address code review: recognize -h in instrumenter, fix runcluster.pl …
mernst Oct 7, 2026
9fc85fa
Address code review: SplitterFactoryTest.mainHelper throws instead of…
mernst Oct 7, 2026
ada0caf
Provide DaikonGetopt helpers that the per-tool PRs use; leave instrum…
mernst Oct 7, 2026
2ace21b
Merge remote-tracking branch 'origin/bad-option-core' into traceselec…
mernst Oct 7, 2026
e560e3e
Merge branch 'master' of https://github.com/codespecs/daikon into bad…
mernst Oct 7, 2026
b9b22ec
Merge remote-tracking branch 'origin/bad-option-core' into traceselec…
mernst Oct 7, 2026
7a0aa92
TraceSelect: pass the random generator to MultiRandSelector so -SEED …
mernst Oct 7, 2026
7b0bd65
Address code review: make TraceSelect state local, honor -SEED, check…
mernst Oct 8, 2026
131c990
Merge remote-tracking branch 'origin/traceselect-args' into tracesele…
mernst Oct 8, 2026
1f929b4
Address code review: TraceSelect sample names, -o, in-process PrintIn…
mernst Oct 8, 2026
e82b4b5
Add a same-seed TraceSelect sampling test; skip empty invocations whe…
mernst Oct 10, 2026
166c435
Make PrintInvariants, MultiDiff, and Daikon.cleanup safe to call more…
mernst Oct 10, 2026
27efa4f
Address code review: TraceSelect argument checks, compressed traces, …
mernst Oct 10, 2026
beeb763
Merge branch 'repeatable-mainhelper' into traceselect-args
mernst Oct 10, 2026
e8abacc
Move the runtimechecker changes to the runtimechecker-options branch
mernst Oct 10, 2026
2ace4a6
Merge branch 'bad-option-core' of github.com:mernst/daikon into trace…
mernst Oct 10, 2026
bf87643
Reset more static state so that mainHelper can be called repeatedly
mernst Oct 11, 2026
2b46b30
Address code review: remove unused DaikonGetopt helpers, reject stray…
mernst Oct 11, 2026
a3de9c7
Drop PrintInvariants repeatability changes; keep only Daikon and Mult…
mernst Oct 11, 2026
50e3e2a
Simplify DaikonGetopt: one constructor, which always handles -h and -…
mernst Oct 11, 2026
84d0a60
TraceSelect calls Daikon.mainHelper, not Daikon.main; remove reinitia…
mernst Oct 11, 2026
7df7f23
Move test-driver fixes and doc spelling fixes to separate pull requests
mernst Oct 11, 2026
4f54694
Handle DaikonTerminationException in SampleTester and SplitterFactory…
mernst Oct 11, 2026
680a814
TraceSelect: catch only checked exceptions, so DaikonTerminationExcep…
mernst Oct 11, 2026
117da2e
Brevity
mernst Oct 11, 2026
3bee663
Merge branch 'master' into bad-option-core
mernst Oct 11, 2026
50fedfb
Merge branch 'bad-option-core' into traceselect-args
mernst Oct 12, 2026
fb04d1a
Merge branch 'repeatable-mainhelper' into traceselect-args
mernst Oct 12, 2026
45c4d00
Merge branch 'master' of github.com:codespecs/daikon into traceselect…
mernst Oct 12, 2026
21a3377
Add the DaikonGetopt helper that this pull request uses: argsAfterLea…
mernst Oct 12, 2026
081553d
TraceSelect: reset Daikon state before checking arguments; report tra…
mernst Oct 12, 2026
e60d34d
Comments
mernst Oct 12, 2026
930b948
DtracePartitioner: propagate I/O errors instead of printing a stack t…
mernst Oct 12, 2026
79b88be
BadOptionTest: correct the comment about resetting Daikon state
mernst Oct 12, 2026
1e0c017
Merge branch 'master' into traceselect-args
mernst Oct 13, 2026
8432498
Merge branch 'master' into traceselect-args
mernst Oct 13, 2026
427b394
Merge codespecs/daikon master into traceselect-args
mernst Oct 17, 2026
e4638cb
TraceSelect: don't treat a Daikon option's value as the trace file; r…
mernst Oct 17, 2026
52ac66c
TraceSelect: report a TraceSelect option that follows the Daikon argu…
mernst Oct 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion doc/daikon.texinfo
Original file line number Diff line number Diff line change
Expand Up @@ -2789,6 +2789,10 @@ The @var{daikon_options} are the same options that can be provided to the
The @var{options} for @command{TraceSelect} are:
@table @option

@item -SEED @var{n}
Use the integer @var{n} as the seed for random selection, so that repeated
runs select the same samples.

@item -NOCLEAN
Don't delete the temporary trace samples created by the random
selection process. This can help for debugging or for using the tool
Expand Down Expand Up @@ -8649,7 +8653,7 @@ of, or in addition to, referencing this manual and the Daikon website
@c LocalWords: fd Linux's GNUC mkdir tmp gunzip xf li dkconfig CreateSpinfo
@c LocalWords: ParameterDoclet CreateSpinfoC un biconditional addAll isFull
@c LocalWords: smallexample simpleStack currentSize jtb ParseException kmeans
@c LocalWords: runcluster xm ALG xmeans TraceSelect NOCLEAN DIFFS MergeESC pp
@c LocalWords: runcluster xm ALG xmeans TraceSelect NOCLEAN DIFFS SEED MergeESC pp
@c LocalWords: escannotated jmlannotated dbcannotated Annnotate xml INVINFO
@c LocalWords: ubs Throwable throwable rethrown WriteViolationFile MyProg
@c LocalWords: callMethod isInstrumented getInvariants INVS ijmp exin wp
Expand Down
16 changes: 13 additions & 3 deletions java/daikon/Daikon.java
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ private Daikon() {
public static final Logger debugStats = Logger.getLogger("daikon.stats");

/** The usage message for this program. */
static String usage =
public static final String usage =
StringsPlume.joinLines(
release_string,
// "Uses the Java port of GNU getopt, copyright (c) 1998 Aaron M. Renn",
Expand Down Expand Up @@ -1005,8 +1005,18 @@ public FileOptions(Set<File> decls, Set<String> dtrace, Set<File> spinfo, Set<Fi

// ///////////////////////////////////////////////////////////////////////////
// Read in the command line options
// Return {decls, dtrace, spinfo, map} files.
static FileOptions read_options(String[] args, String usage) {

/**
* Reads the command-line options, setting the corresponding static fields of Daikon and other
* classes.
*
* @param args the command-line arguments
* @param usage the usage message to print for {@code -h} and {@code --help}
* @return the {decls, dtrace, spinfo, map} files
* @throws Daikon.NormalTermination after printing the usage message, if an argument requests it
* @throws Daikon.UserError if an argument is malformed or names a nonexistent file
*/
public static FileOptions read_options(String[] args, String usage) {
if (args.length == 0) {
System.out.println("Error: no files supplied on command line.");
System.out.println(usage);
Expand Down
1 change: 1 addition & 0 deletions java/daikon/test/AllTestsSuite.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
@Suite.SuiteClasses({
daikon.chicory.RuntimeTest.class,
daikon.test.BadOptionTest.class,
daikon.test.TraceSelectTest.class,
daikon.test.TestClassOrInterfaceTypeDecorateVisitor.class,
daikon.test.TestAst.class,
daikon.test.config.ConfigurationTest.class,
Expand Down
76 changes: 74 additions & 2 deletions java/daikon/test/BadOptionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import daikon.SplitDtrace;
import daikon.UnionInvariants;
import daikon.tools.DtraceDiff;
import daikon.tools.TraceSelect;
import gnu.getopt.LongOpt;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
Expand All @@ -21,8 +22,9 @@
/**
* Tests that Daikon tools reject bad command-line options with a UserError.
*
* <p>These tests do not call {@code Daikon.mainHelper}, because it resets Daikon's global state,
* which other tests in the same JVM depend on.
* <p>These tests do not call {@code Daikon.mainHelper}, which runs Daikon. However, {@link
* #testHelpOption} passes Daikon arguments to TraceSelect, which checks them by calling {@code
* Daikon.cleanup} and {@code Daikon.read_options}. Those calls reset Daikon's global state.
*/
public class BadOptionTest {

Expand Down Expand Up @@ -149,11 +151,81 @@ public void testPrintInvariantsUnrecognizedOption() {
() -> PrintInvariants.mainHelper(new String[] {"--bogus", "foo.inv.gz"}));
}

/** Tests that TraceSelect rejects bad arguments before doing any sampling. */
@Test
public void testTraceSelectBadArguments() {
Comment thread
mernst marked this conversation as resolved.
assertBadOption(
"num_reps must be a positive integer, not 0",
() -> TraceSelect.mainHelper(new String[] {"0", "10", "x.dtrace"}));
assertBadOption(
"num_reps must be a positive integer, not -5",
() -> TraceSelect.mainHelper(new String[] {"-5", "10", "x.dtrace"}));
assertBadOption(
"sample_size must be a positive integer, not -5",
() -> TraceSelect.mainHelper(new String[] {"20", "-5", "x.dtrace"}));
assertBadOption(
"sample_size must be a positive integer, not ten",
() -> TraceSelect.mainHelper(new String[] {"20", "ten", "x.dtrace"}));
Daikon.UserError e =
assertThrows(
Daikon.UserError.class,
() -> TraceSelect.mainHelper(new String[] {"20", "10", "-NOCLAEN", "x.dtrace"}));
assertEquals(
"Unrecognized TraceSelect option -NOCLAEN; the options are -SEED, -NOCLEAN,"
+ " -INCLUDE_UNRETURNED, and -DO_DIFFS",
String.valueOf(e.getMessage()));
// TraceSelect options must precede the Daikon arguments.
e =
assertThrows(
Daikon.UserError.class,
() -> TraceSelect.mainHelper(new String[] {"20", "10", "x.dtrace", "-NOCLEAN"}));
assertEquals(
"TraceSelect option -NOCLEAN must precede the Daikon arguments, such as the .dtrace file",
String.valueOf(e.getMessage()));
// Daikon would read a compressed trace in full, in every sample run.
e =
assertThrows(
Daikon.UserError.class,
() -> TraceSelect.mainHelper(new String[] {"20", "10", "x.dtrace", "y.dtrace.gz"}));
assertEquals(
"TraceSelect cannot sample y.dtrace.gz; the trace file must be uncompressed and its name"
+ " must end with \".dtrace\"",
String.valueOf(e.getMessage()));
// TraceSelect passes -o to Daikon itself.
e =
assertThrows(
Daikon.UserError.class,
() -> TraceSelect.mainHelper(new String[] {"1", "10", "-o", "r.inv", "x.dtrace"}));
assertEquals(
"TraceSelect does not accept Daikon's -o option: it writes the invariants of each sample"
+ " to the sample's file name plus \".inv\"",
String.valueOf(e.getMessage()));
// An option's value is not the trace file, even if it ends with ".dtrace".
e =
assertThrows(
Daikon.UserError.class,
() ->
TraceSelect.mainHelper(
new String[] {"20", "10", "--ppt-select-pattern", "x.dtrace"}));
assertTrue(String.valueOf(e.getMessage()).startsWith("No .dtrace file name specified"));
e =
assertThrows(
Daikon.UserError.class,
() ->
TraceSelect.mainHelper(new String[] {"20", "10", "--ppt-select-pattern=x.dtrace"}));
assertTrue(String.valueOf(e.getMessage()).startsWith("No .dtrace file name specified"));
}

/** Tests that tools accept the {@code --help} option that their usage messages document. */
@Test
public void testHelpOption() {
assertPrintsUsage(() -> DtraceDiff.mainHelper(new String[] {"--help"}));
assertPrintsUsage(() -> UnionInvariants.mainHelper(new String[] {"--help"}));
assertPrintsUsage(() -> TraceSelect.mainHelper(new String[] {"--help"}));
assertPrintsUsage(() -> TraceSelect.mainHelper(new String[] {"20", "10", "-h", "x.dtrace"}));
assertPrintsUsage(() -> TraceSelect.mainHelper(new String[] {"20", "10", "--help"}));
assertPrintsUsage(
() -> TraceSelect.mainHelper(new String[] {"20", "10", "-NOCLEAN", "x.dtrace", "--he"}));
assertPrintsUsage(() -> SplitDtrace.mainHelper(new String[] {"-h", "x"}));
}

Expand Down
61 changes: 61 additions & 0 deletions java/daikon/test/TraceSelectTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package daikon.test;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;

import daikon.tools.TraceSelect;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Random;
import org.junit.Test;

/** Tests the TraceSelect tool. */
public class TraceSelectTest {

/** The number of invocations in the trace file created by {@link #writeTrace}. */
private static final int NUM_INVOCATIONS = 20;

/**
* Writes a trace file with {@link #NUM_INVOCATIONS} invocations of one method.
*
* @return the trace file
* @throws IOException if the file cannot be written
*/
private static Path writeTrace() throws IOException {
StringBuilder sb = new StringBuilder();
for (int nonce = 1; nonce <= NUM_INVOCATIONS; nonce++) {
for (String kind : new String[] {"ENTER", "EXIT1"}) {
sb.append("foo.Bar.baz():::")
.append(kind)
.append("\nthis_invocation_nonce\n")
.append(nonce)
.append("\nx\n")
.append(nonce)
.append("\n1\n\n");
}
}
Path trace = Files.createTempFile("TraceSelectTest", ".dtrace");
Files.writeString(trace, sb, UTF_8);
return trace;
}

/** Tests that sampling twice with the same seed selects the same invocations. */
@Test
public void testSameSeedSameSample() throws IOException {
Path trace = writeTrace();
try {
int sampleSize = 5;
List<String> sample1 =
TraceSelect.selectSample(trace.toString(), sampleSize, new Random(1000), false);
List<String> sample2 =
TraceSelect.selectSample(trace.toString(), sampleSize, new Random(1000), false);
// The sample is a proper subset of the invocations, so the test is not vacuous.
assertEquals(sampleSize, sample1.size());
assertEquals(sample1, sample2);
} finally {
Files.delete(trace);
}
}
}
17 changes: 5 additions & 12 deletions java/daikon/tools/DtracePartitioner.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,11 @@ public class DtracePartitioner implements Closeable, Partitioner<String, String>

/**
* @param filename the Daikon trace file to be partitioned
* @throws IOException if the file cannot be opened
*/
public DtracePartitioner(String filename) {
try {
this.filename = filename;
// System.out.printf("trying with file %s%n", filename);
br = FilesPlume.newBufferedFileReader(filename);

} catch (IOException e) {
e.printStackTrace();
throw new Error(e);
}
public DtracePartitioner(String filename) throws IOException {
this.filename = filename;
br = FilesPlume.newBufferedFileReader(filename);
}

/** Releases resources held by this. */
Expand All @@ -61,8 +55,7 @@ public boolean hasNext(@GuardSatisfied DtracePartitioner this) {
try {
return br.ready();
} catch (IOException e) {
e.printStackTrace();
return false;
throw new UncheckedIOException(e);
}
}

Expand Down
Loading
Loading