diff --git a/jcstress-core/src/main/java/org/openjdk/jcstress/Options.java b/jcstress-core/src/main/java/org/openjdk/jcstress/Options.java index ed7316b7..bba25d36 100644 --- a/jcstress-core/src/main/java/org/openjdk/jcstress/Options.java +++ b/jcstress-core/src/main/java/org/openjdk/jcstress/Options.java @@ -66,6 +66,7 @@ public class Options { private List<String> jvmArgsPrepend; private boolean splitCompilation; private AffinityMode affinityMode; + private boolean pretouchHeap; public Options(String[] args) { this.args = args; @@ -141,6 +142,9 @@ public boolean parse() throws IOException { OptionSpec<AffinityMode> optAffinityMode = parser.accepts("af", "Use the specific affinity mode, if available.") .withOptionalArg().ofType(AffinityMode.class).describedAs("mode"); + OptionSpec<Boolean> optPretouchHeap = parser.accepts("pth", "Pre-touch Java heap, if possible.") + .withOptionalArg().ofType(Boolean.class).describedAs("bool"); + parser.accepts("v", "Be verbose."); parser.accepts("vv", "Be extra verbose."); parser.accepts("vvv", "Be extra extra verbose."); @@ -204,6 +208,7 @@ public boolean parse() throws IOException { this.forksStressMultiplier = 5; this.strideSize = 256; this.strideCount = 40; + this.pretouchHeap = true; mode = orDefault(modeStr.value(set), "default"); if (this.mode.equalsIgnoreCase("sanity")) { @@ -213,6 +218,7 @@ public boolean parse() throws IOException { this.forksStressMultiplier = 1; this.strideSize = 1; this.strideCount = 1; + this.pretouchHeap = false; } else if (this.mode.equalsIgnoreCase("quick")) { this.time = 200; this.forksStressMultiplier = 1; @@ -239,6 +245,7 @@ public boolean parse() throws IOException { this.forksStressMultiplier = orDefault(set.valueOf(forksStressMultiplier), this.forksStressMultiplier); this.strideSize = orDefault(set.valueOf(strideSize), this.strideSize); this.strideCount = orDefault(set.valueOf(strideCount), this.strideCount); + this.pretouchHeap = orDefault(set.valueOf(optPretouchHeap), this.pretouchHeap); this.heapPerFork = orDefault(set.valueOf(heapPerFork), 256); @@ -380,4 +387,9 @@ public boolean isSplitCompilation() { public AffinityMode affinityMode() { return affinityMode; } + + public boolean isPretouchHeap() { + return pretouchHeap; + } + } diff --git a/jcstress-core/src/main/java/org/openjdk/jcstress/vm/VMSupport.java b/jcstress-core/src/main/java/org/openjdk/jcstress/vm/VMSupport.java index 9c2847c5..63192fa1 100644 --- a/jcstress-core/src/main/java/org/openjdk/jcstress/vm/VMSupport.java +++ b/jcstress-core/src/main/java/org/openjdk/jcstress/vm/VMSupport.java @@ -127,6 +127,20 @@ public static void initFlags(Options opts) { GLOBAL_JVM_FLAGS, "-Xms" + heap + "M", "-Xmx" + heap + "M"); + // After heap size is set, check if we can pre-touch it. This would allow + // tests to run in fully committed heap without experiencing the occasional + // memory stalls. This also provides better safety in face of OS OOM-killers. + // On large heaps, this might take a while, so users are allowed to disable + // pre-touch for better performance. + + if (opts.isPretouchHeap()) { + detect("Enabling Java heap pre-touch", + SimpleTestMain.class, + GLOBAL_JVM_FLAGS, + "-XX:+AlwaysPreTouch" + ); + } + // The tests are usually not GC heavy. The minimum amount of threads a jcstress // test uses is 2, so we can expect the CPU affinity machinery to allocate at // least 2 CPUs per fork. This gives us the upper bound for the number of GC threads: 2,