8081317: [NEWTEST] documented GC ratio tuning and new size options should be covered by regression tests
Reviewed-by: iignatyev, dfazunen
--- a/hotspot/src/share/vm/prims/whitebox.cpp Mon Sep 07 21:30:45 2015 +0400
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Tue Sep 01 21:38:07 2015 +0300
@@ -55,6 +55,7 @@
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/parallel/parallelScavengeHeap.inline.hpp"
+#include "gc/parallel/adjoiningGenerations.hpp"
#endif // INCLUDE_ALL_GCS
#if INCLUDE_NMT
#include "services/mallocSiteTable.hpp"
@@ -296,6 +297,11 @@
return p->size() * HeapWordSize;
WB_END
+WB_ENTRY(jlong, WB_GetHeapSpaceAlignment(JNIEnv* env, jobject o))
+ size_t alignment = Universe::heap()->collector_policy()->space_alignment();
+ return (jlong)alignment;
+WB_END
+
#if INCLUDE_ALL_GCS
WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj))
G1CollectedHeap* g1 = G1CollectedHeap::heap();
@@ -334,6 +340,17 @@
return (jint)HeapRegion::GrainBytes;
WB_END
+WB_ENTRY(jlong, WB_PSVirtualSpaceAlignment(JNIEnv* env, jobject o))
+ ParallelScavengeHeap* ps = ParallelScavengeHeap::heap();
+ size_t alignment = ps->gens()->virtual_spaces()->alignment();
+ return (jlong)alignment;
+WB_END
+
+WB_ENTRY(jlong, WB_PSHeapGenerationAlignment(JNIEnv* env, jobject o))
+ size_t alignment = ParallelScavengeHeap::heap()->generation_alignment();
+ return (jlong)alignment;
+WB_END
+
WB_ENTRY(jobject, WB_G1AuxiliaryMemoryUsage(JNIEnv* env))
ResourceMark rm(THREAD);
G1CollectedHeap* g1h = G1CollectedHeap::heap();
@@ -1332,6 +1349,7 @@
{CC"getVMPageSize", CC"()I", (void*)&WB_GetVMPageSize },
{CC"getVMAllocationGranularity", CC"()J", (void*)&WB_GetVMAllocationGranularity },
{CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize},
+ {CC"getHeapSpaceAlignment", CC"()J", (void*)&WB_GetHeapSpaceAlignment},
{CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive },
{CC"parseCommandLine0",
CC"(Ljava/lang/String;C[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
@@ -1356,6 +1374,8 @@
{CC"g1StartConcMarkCycle", CC"()Z", (void*)&WB_G1StartMarkCycle },
{CC"g1AuxiliaryMemoryUsage", CC"()Ljava/lang/management/MemoryUsage;",
(void*)&WB_G1AuxiliaryMemoryUsage },
+ {CC"psVirtualSpaceAlignment",CC"()J", (void*)&WB_PSVirtualSpaceAlignment},
+ {CC"psHeapGenerationAlignment",CC"()J", (void*)&WB_PSHeapGenerationAlignment},
#endif // INCLUDE_ALL_GCS
#if INCLUDE_NMT
{CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc },
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/arguments/GCTypes.java Tue Sep 01 21:38:07 2015 +0300
@@ -0,0 +1,115 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*/
+
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Helper class with enum representation of GC types.
+ */
+public final class GCTypes {
+
+ private static <T extends GCType> T getCurrentGCType(Class<T> type) {
+ return ManagementFactory.getGarbageCollectorMXBeans().stream()
+ .map(bean -> getGCTypeByName(type, bean.getName()))
+ .filter(Objects::nonNull)
+ .findFirst()
+ .orElse(null);
+ }
+
+ private static <T extends GCType> T getGCTypeByName(Class<T> type, String name) {
+ return Arrays.stream(type.getEnumConstants())
+ .filter(e -> e.getGCName().equals(name))
+ .findFirst()
+ .orElse(null);
+ }
+
+ private static <T extends GCType> GarbageCollectorMXBean getGCBeanByType(Class<T> type) {
+ return ManagementFactory.getGarbageCollectorMXBeans().stream()
+ .filter(bean -> Arrays.stream(type.getEnumConstants())
+ .filter(enumName -> enumName.getGCName().equals(bean.getName()))
+ .findFirst()
+ .isPresent()
+ )
+ .findFirst()
+ .orElse(null);
+ }
+
+ /**
+ * Helper interface used by GCTypes static methods
+ * to get gcTypeName field of *GCType classes.
+ */
+ private interface GCType {
+
+ String getGCName();
+ }
+
+ public static enum YoungGCType implements GCType {
+ DefNew("Copy"),
+ ParNew("ParNew"),
+ PSNew("PS Scavenge"),
+ G1("G1 Young Generation");
+
+ @Override
+ public String getGCName() {
+ return gcTypeName;
+ }
+ private final String gcTypeName;
+
+ private YoungGCType(String name) {
+ gcTypeName = name;
+ }
+
+ public static YoungGCType getYoungGCType() {
+ return GCTypes.getCurrentGCType(YoungGCType.class);
+ }
+
+ public static GarbageCollectorMXBean getYoungGCBean() {
+ return GCTypes.getGCBeanByType(YoungGCType.class);
+ }
+ }
+
+ public static enum OldGCType implements GCType {
+ Serial("MarkSweepCompact"),
+ CMS("ConcurrentMarkSweep"),
+ PSOld("PS MarkSweep"),
+ G1("G1 Old Generation");
+
+ private final String gcTypeName;
+
+ private OldGCType(String name) {
+ gcTypeName = name;
+ }
+
+ public static OldGCType getOldGCType() {
+ return GCTypes.getCurrentGCType(OldGCType.class);
+ }
+
+ @Override
+ public String getGCName() {
+ return gcTypeName;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java Tue Sep 01 21:38:07 2015 +0300
@@ -0,0 +1,299 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*/
+
+/*
+ * @test TestMaxMinHeapFreeRatioFlags
+ * @key gc
+ * @summary Verify that heap size changes according to max and min heap free ratios.
+ * @library /testlibrary
+ * @modules java.base/sun.misc
+ * java.management
+ * @build TestMaxMinHeapFreeRatioFlags
+ * @run driver/timeout=240 TestMaxMinHeapFreeRatioFlags
+ */
+
+import java.util.LinkedList;
+import java.util.Arrays;
+import java.util.Collections;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Utils;
+import jdk.test.lib.HeapRegionUsageTool;
+import sun.misc.Unsafe;
+
+public class TestMaxMinHeapFreeRatioFlags {
+
+ public static final long M = 1024 * 1024;
+ public static final long MAX_HEAP_SIZE = 200 * M;
+ public static final long HEAP_SIZE = 10 * M;
+ public static final long MAX_NEW_SIZE = 20 * M;
+ public static final long NEW_SIZE = 5 * M;
+
+ public static void main(String args[]) throws Exception {
+ LinkedList<String> options = new LinkedList<>(
+ Arrays.asList(Utils.getFilteredTestJavaOpts("-XX:[^ ]*HeapFreeRatio","-XX:\\+ExplicitGCInvokesConcurrent"))
+ );
+
+ negativeTest(20, false, 10, true, options);
+ negativeTest(100, true, 0, false, options);
+ negativeTest(101, false, 50, false, options);
+ negativeTest(49, true, 102, true, options);
+ negativeTest(-1, false, 50, false, options);
+ negativeTest(50, true, -1, true, options);
+
+ positiveTest(10, false, 90, false, options);
+ positiveTest(10, true, 80, false, options);
+ positiveTest(20, false, 70, true, options);
+ positiveTest(25, true, 65, true, options);
+ positiveTest(40, false, 50, false, options);
+ }
+
+ /**
+ * Verify that heap size will be changed to conform
+ * min and max heap free ratios.
+ *
+ * @param minRatio value of MinHeapFreeRatio option
+ * @param useXminf used Xminf option instead of MinHeapFreeRatio
+ * @param maxRatio value of MaxHeapFreeRatio option
+ * @param useXmaxf used Xmaxf option instead of MaxHeapFreeRatio
+ * @param options additional options for JVM
+ */
+ public static void positiveTest(int minRatio, boolean useXminf,
+ int maxRatio, boolean useXmaxf,
+ LinkedList<String> options) throws Exception {
+
+ LinkedList<String> vmOptions = new LinkedList<>(options);
+ Collections.addAll(vmOptions,
+ (useXminf ? "-Xminf" + minRatio / 100.0 : "-XX:MinHeapFreeRatio=" + minRatio),
+ (useXmaxf ? "-Xmaxf" + maxRatio / 100.0 : "-XX:MaxHeapFreeRatio=" + maxRatio),
+ "-Xmx" + MAX_HEAP_SIZE,
+ "-Xms" + HEAP_SIZE,
+ "-XX:NewSize=" + NEW_SIZE,
+ "-XX:MaxNewSize=" + MAX_NEW_SIZE,
+ RatioVerifier.class.getName(),
+ Integer.toString(minRatio),
+ Integer.toString(maxRatio)
+ );
+
+ ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()]));
+ OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
+ analyzer.shouldHaveExitValue(0);
+ }
+
+ /**
+ * Verify that VM will fail to start with specified ratios.
+ *
+ * @param minRatio value of MinHeapFreeRatio option
+ * @param useXminf used Xminf option instead of MinHeapFreeRatio
+ * @param maxRatio value of MaxHeapFreeRatio option
+ * @param useXmaxf used Xmaxf option instead of MaxHeapFreeRatio
+ * @param options additional options for JVM
+ */
+ public static void negativeTest(int minRatio, boolean useXminf,
+ int maxRatio, boolean useXmaxf,
+ LinkedList<String> options) throws Exception {
+
+ LinkedList<String> vmOptions = new LinkedList<>(options);
+ Collections.addAll(vmOptions,
+ (useXminf ? "-Xminf" + minRatio / 100.0 : "-XX:MinHeapFreeRatio=" + minRatio),
+ (useXmaxf ? "-Xmaxf" + maxRatio / 100.0 : "-XX:MaxHeapFreeRatio=" + maxRatio),
+ "-version"
+ );
+ ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()]));
+ OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
+ analyzer.shouldHaveExitValue(1);
+ analyzer.shouldContain("Error: Could not create the Java Virtual Machine.");
+ }
+
+ /**
+ * RatioVerifier will be executed in the tested VM.
+ * It will check that real heap usage after collection lies between MinHeapFreeRatio and MaxHeapFreeRatio.
+ */
+ public static class RatioVerifier {
+
+ private static final Unsafe unsafe = Utils.getUnsafe();
+
+ // Size of byte array that will be allocated
+ public static final int CHUNK_SIZE = 1024;
+ // Length of byte array, that will be added to "garbage" list.
+ public static final int ARRAY_LENGTH = CHUNK_SIZE - Unsafe.ARRAY_BYTE_BASE_OFFSET;
+ // Amount of tries to force heap shrinking/expansion using GC
+ public static final int GC_TRIES = 10;
+
+ // Value that will be added/substracted from expected min/max heap free ratio
+ // during memory allocation to make sure that specified limit will be exceeded.
+ public static final double OVERLOAD = 0.05;
+ // Acceptable heap free ratio limit exceedance: verification will fail if
+ // actual ratio is lower than expected min heap free ratio - VARIANCE or
+ // higher than expected max heap free ratio + VARIANCE.
+ public static final double VARIANCE = 0.025;
+
+ public static LinkedList<Object> garbage = new LinkedList<>();
+
+ public static void main(String args[]) throws Exception {
+ if (args.length != 2) {
+ throw new IllegalArgumentException("Expected 2 args: <minRatio> <maxRatio>");
+ }
+ if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.PSOld) {
+ System.out.println("Test is not applicable to parallel GC");
+ return;
+ }
+
+ double minRatio = Integer.valueOf(args[0]) / 100.0;
+ double maxRatio = Integer.valueOf(args[1]) / 100.0;
+
+ long maxHeapSize = getMax();
+
+ // commit 0.5 of total heap size to have enough space
+ // to both shink and expand
+ while (getCommitted() < maxHeapSize / 2) {
+ garbage.add(new byte[ARRAY_LENGTH]);
+ }
+
+ forceGC();
+ // Verify that current heap free ratio lies between specified limits
+ verifyRatio(minRatio, maxRatio);
+
+ // Estimate how much memory we have to allocate to force expansion
+ long memoryToFill = (long) (getCommitted() * (1 - minRatio + OVERLOAD))
+ - getUsed();
+
+ long previouslyCommitted = getCommitted();
+
+ while (memoryToFill > 0) {
+ garbage.add(new byte[CHUNK_SIZE]);
+ memoryToFill -= CHUNK_SIZE;
+ }
+
+ forceGC();
+ // Verify that after memory allocation heap free ratio is still conforming specified limits
+ verifyRatio(minRatio, maxRatio);
+ // Verify that heap was actually expanded
+ if (previouslyCommitted >= getCommitted()) {
+ throw new RuntimeException("Heap was not expanded.");
+ }
+
+ // Estimate how much memory we have to free to force shrinking
+ long memoryToFree = getUsed()
+ - (long) (getCommitted() * (1 - maxRatio - OVERLOAD));
+
+ previouslyCommitted = getCommitted();
+
+ while (memoryToFree > 0 && garbage.size() > 0) {
+ garbage.remove(garbage.size() - 1);
+ memoryToFree -= CHUNK_SIZE;
+ }
+
+ forceGC();
+ // Verify that heap free ratio is still conforming specified limits
+ verifyRatio(minRatio, maxRatio);
+ // Verify that heap was actually shrinked
+ if (previouslyCommitted <= getCommitted()) {
+ throw new RuntimeException("Heap was not shrinked.");
+ }
+
+ }
+
+ public static void forceGC() {
+ for (int i = 0; i < GC_TRIES; i++) {
+ System.gc();
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ /**
+ * Verify that heap free ratio is conforming specified limits.
+ * Actual heap free ratio may be very close to one of specified limits,
+ * but exceed for more then VARIANCE.
+ * Verification will also pass if actual ratio is not conforming limits,
+ * but it is not possible to shrink/expand heap.
+ */
+ public static void verifyRatio(double minRatio, double maxRatio) {
+ double ratio = getHeapFreeRatio();
+ System.out.println(minRatio + " " + ratio + " " + maxRatio);
+ if (minRatio - ratio > VARIANCE
+ && getCommitted() < getMax()) {
+ throw new RuntimeException("Current heap free ratio is lower than "
+ + "MinHeapFreeRatio (" + ratio + " vs " + minRatio + ").");
+ }
+ if (ratio - maxRatio > VARIANCE
+ && getUsed() > getInit()) {
+ throw new RuntimeException("Current heap free ratio is higher than "
+ + "MaxHeapFreeRatio (" + ratio + " vs " + maxRatio + ").");
+ }
+ }
+
+ /*
+ * Obtain information about heap size.
+ *
+ * For G1 information summed up for all type of regions,
+ * because tested options affect overall heap sizing.
+ *
+ * For all other GCs return information only for old gen.
+ */
+ public static long getMax() {
+ return HeapRegionUsageTool.getOldUsage().getMax();
+ }
+
+ public static long getInit() {
+ if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) {
+ return HeapRegionUsageTool.getEdenUsage().getInit()
+ + HeapRegionUsageTool.getSurvivorUsage().getInit()
+ + HeapRegionUsageTool.getOldUsage().getInit();
+ } else {
+ return HeapRegionUsageTool.getOldUsage().getInit();
+ }
+ }
+
+ public static long getUsed() {
+ if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) {
+ return HeapRegionUsageTool.getEdenUsage().getUsed()
+ + HeapRegionUsageTool.getSurvivorUsage().getUsed()
+ + HeapRegionUsageTool.getOldUsage().getUsed();
+ } else {
+ return HeapRegionUsageTool.getOldUsage().getUsed();
+ }
+ }
+
+ public static long getCommitted() {
+ if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) {
+ return HeapRegionUsageTool.getEdenUsage().getCommitted()
+ + HeapRegionUsageTool.getSurvivorUsage().getCommitted()
+ + HeapRegionUsageTool.getOldUsage().getCommitted();
+ } else {
+ return HeapRegionUsageTool.getOldUsage().getCommitted();
+ }
+ }
+
+ public static long getFree() {
+ return getCommitted() - getUsed();
+ }
+
+ public static double getHeapFreeRatio() {
+ return getFree() / (double) getCommitted();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java Tue Sep 01 21:38:07 2015 +0300
@@ -0,0 +1,206 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*/
+
+/*
+ * @test TestMinAndInitialSurvivorRatioFlags
+ * @key gc
+ * @summary Verify that MinSurvivorRatio and InitialSurvivorRatio flags work
+ * @library /testlibrary /../../test/lib
+ * @modules java.base/sun.misc
+ * java.management
+ * @build TestMinAndInitialSurvivorRatioFlags
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver TestMinAndInitialSurvivorRatioFlags
+ */
+
+import jdk.test.lib.AllocationHelper;
+import java.lang.management.MemoryUsage;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import jdk.test.lib.HeapRegionUsageTool;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Utils;
+import sun.hotspot.WhiteBox;
+
+/* Test verifies that VM can start with any GC when MinSurvivorRatio and
+ * InitialSurvivorRatio flags passed and for Parallel GC it verifies that
+ * after start up survivor ratio equal to InitialSurvivorRatio value and
+ * that actual survivor ratio will never be less than MinSurvivorRatio.
+ */
+public class TestMinAndInitialSurvivorRatioFlags {
+
+ public static final long M = 1024 * 1024;
+ public static final long HEAP_SIZE = 200 * M;
+ public static final long NEW_SIZE = 100 * M;
+
+ public static void main(String args[]) throws Exception {
+ LinkedList<String> options = new LinkedList<>(
+ Arrays.asList(Utils.getFilteredTestJavaOpts("-XX:[^ ]*SurvivorRatio=[^ ]+"))
+ );
+
+ testSurvivorRatio(5, -1, -1, options, true);
+ testSurvivorRatio(10, -1, -1, options, true);
+ testSurvivorRatio(-1, 5, 3, options, true);
+ testSurvivorRatio(-1, 15, 3, options, true);
+ testSurvivorRatio(-1, 15, 3, options, false);
+ testSurvivorRatio(-1, 10, 10, options, true);
+ testSurvivorRatio(-1, 3, 15, options, true);
+ testSurvivorRatio(-1, 3, 15, options, false);
+ }
+
+ /**
+ * Test that MinSurvivorRatio and InitialSurvivorRatio flags work.
+ *
+ * @param survivorRatio value for -XX:SurvivorRatio option, omitted if negative
+ * @param initRatio value for -XX:InitialSurvivorRatio option, omitted if negative
+ * @param minRatio value for -XX:MinSurvivorRatio option, omitted if negative
+ * @param options additional options for VM
+ * @param useAdaptiveSizePolicy turn on or off UseAdaptiveSizePolicy option
+ */
+ public static void testSurvivorRatio(int survivorRatio,
+ int initRatio,
+ int minRatio,
+ LinkedList<String> options,
+ boolean useAdaptiveSizePolicy) throws Exception {
+
+ LinkedList<String> vmOptions = new LinkedList<>(options);
+ Collections.addAll(vmOptions,
+ "-Xbootclasspath/a:.",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-XX:MaxNewSize=" + NEW_SIZE, "-XX:NewSize=" + NEW_SIZE,
+ "-Xmx" + HEAP_SIZE, "-Xms" + HEAP_SIZE,
+ (survivorRatio >= 0 ? "-XX:SurvivorRatio=" + survivorRatio : ""),
+ (initRatio >= 0 ? "-XX:InitialSurvivorRatio=" + initRatio : ""),
+ (minRatio >= 0 ? "-XX:MinSurvivorRatio=" + minRatio : ""),
+ (useAdaptiveSizePolicy ? "-XX:+UseAdaptiveSizePolicy" : "-XX:-UseAdaptiveSizePolicy"),
+ SurvivorRatioVerifier.class.getName(),
+ Integer.toString(survivorRatio),
+ Integer.toString(initRatio),
+ Integer.toString(minRatio),
+ Boolean.toString(useAdaptiveSizePolicy)
+ );
+ vmOptions.removeIf((String p) -> p.isEmpty());
+ ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()]));
+ OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
+ analyzer.shouldHaveExitValue(0);
+ }
+
+ /**
+ * Class that verifies survivor ratio.
+ * Will be executed in tested VM. Checks initial size of eden and survivor paces with alignment.
+ */
+ public static class SurvivorRatioVerifier {
+
+ public static WhiteBox wb = WhiteBox.getWhiteBox();
+
+ public static final int MAX_ITERATIONS = 10;
+ public static final int ARRAY_LENGTH = 10000;
+ public static final int CHUNK_SIZE = 10000;
+
+ public static byte garbage[][] = new byte[ARRAY_LENGTH][];
+
+ public static void main(String args[]) throws Exception {
+ if (args.length != 4) {
+ throw new IllegalArgumentException("Expected 4 args: <survivorRatio> <initRatio> <minRatio> <useAdaptiveSizePolicy>");
+ }
+ final int survivorRatio = Integer.valueOf(args[0]);
+ final int initRatio = Integer.valueOf(args[1]);
+ final int minRatio = Integer.valueOf(args[2]);
+ final boolean useAdaptiveSizePolicy = Boolean.valueOf(args[3]);
+
+ // we stop testing only here to ensure that JVM will accept
+ // both MinSurvivorRatio and InitialSurvivorRatio regardles to GC
+ if (GCTypes.YoungGCType.getYoungGCType() != GCTypes.YoungGCType.PSNew) {
+ System.out.println("Test is only applicable to Parallel GC");
+ return;
+ }
+
+ // verify initial survivor ratio
+ verifySurvivorRatio(survivorRatio, initRatio, minRatio, useAdaptiveSizePolicy, true);
+
+ // force GC
+ AllocationHelper allocator = new AllocationHelper(MAX_ITERATIONS, ARRAY_LENGTH, CHUNK_SIZE,
+ () -> (verifySurvivorRatio(survivorRatio, initRatio, minRatio, useAdaptiveSizePolicy, false)));
+ allocator.allocateMemoryAndVerify();
+ }
+
+ /**
+ * Verify actual survivor ratio.
+ *
+ * @param survivorRatio value of SurvivorRatio option, omitted if negative
+ * @param initRatio value of InitialSurvivorRatio option, omitted if negative
+ * @param minRatio value of MinSurvivorRatio option, omitted if negative
+ * @param useAdaptiveSizePolicy value of UseAdaptiveSizePolicy option
+ * @param verifyInitialRatio true if we are going to verify initial ratio
+ */
+ public static Void verifySurvivorRatio(int survivorRatio,
+ int initRatio,
+ int minRatio,
+ boolean useAdaptiveSizePolicy,
+ boolean verifyInitialRatio) {
+
+ MemoryUsage edenUsage = HeapRegionUsageTool.getEdenUsage();
+ MemoryUsage survivorUsage = HeapRegionUsageTool.getSurvivorUsage();
+
+ long alignedNewSize = edenUsage.getMax() + 2 * survivorUsage.getMax();
+ long generationAlignment = wb.psHeapGenerationAlignment();
+
+ if (survivorRatio >= 0) {
+ // -XX:SurvivorRatio was passed to JVM, actual ratio should be SurvivorRatio + 2
+ long expectedSize = HeapRegionUsageTool.alignDown(alignedNewSize / (survivorRatio + 2),
+ generationAlignment);
+
+ if (survivorUsage.getCommitted() != expectedSize) {
+ throw new RuntimeException("Expected survivor size is: " + expectedSize
+ + ", but observed size is: " + survivorUsage.getCommitted());
+ }
+ } else if (verifyInitialRatio || !useAdaptiveSizePolicy) {
+ // In case of initial ratio verification or disabled adaptive size policy
+ // ratio should be equal to InitialSurvivorRatio value
+ long expectedSize = HeapRegionUsageTool.alignDown(alignedNewSize / initRatio,
+ generationAlignment);
+ if (survivorUsage.getCommitted() != expectedSize) {
+ throw new RuntimeException("Expected survivor size is: " + expectedSize
+ + ", but observed size is: " + survivorUsage.getCommitted());
+ }
+ } else {
+ // In any other case actual survivor ratio should not be lower than MinSurvivorRatio
+ // or is should be equal to InitialSurvivorRatio
+ long expectedMinSize = HeapRegionUsageTool.alignDown(alignedNewSize / minRatio,
+ generationAlignment);
+ long expectedInitSize = HeapRegionUsageTool.alignDown(alignedNewSize / initRatio,
+ generationAlignment);
+ if (survivorUsage.getCommitted() != expectedInitSize
+ && survivorUsage.getCommitted() < expectedMinSize) {
+ throw new RuntimeException("Expected survivor size should be " + expectedMinSize
+ + " or should be greater then " + expectedMinSize
+ + ", but observer survivor size is " + survivorUsage.getCommitted());
+ }
+ }
+ return null;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/arguments/TestNewRatioFlag.java Tue Sep 01 21:38:07 2015 +0300
@@ -0,0 +1,182 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*/
+
+/*
+ * @test TestNewRatioFlag
+ * @key gc
+ * @bug 8025166
+ * @summary Verify that heap devided among generations according to NewRatio
+ * @library /testlibrary /../../test/lib
+ * @modules java.base/sun.misc
+ * java.management
+ * @build TestNewRatioFlag
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver TestNewRatioFlag
+ */
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import jdk.test.lib.HeapRegionUsageTool;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Utils;
+import sun.hotspot.WhiteBox;
+
+public class TestNewRatioFlag {
+
+ public static final long M = 1024 * 1024;
+ public static final long HEAP_SIZE = 100 * M;
+
+ public static void main(String args[]) throws Exception {
+ LinkedList<String> options = new LinkedList<>(
+ Arrays.asList(Utils.getFilteredTestJavaOpts("(-XX:[^ ]*NewSize=[^ ]+)|(-Xm[ns][^ ]+)"))
+ );
+
+ testNewRatio(4, options);
+ testNewRatio(6, options);
+ testNewRatio(10, options);
+ testNewRatio(15, options);
+ testNewRatio(20, options);
+ }
+
+ /**
+ * Verify that actual size of young gen conforms specified NewRatio
+ *
+ * @param ratio value of NewRatio option
+ * @param options additional options for VM
+ */
+ public static void testNewRatio(int ratio, LinkedList<String> options) throws Exception {
+ LinkedList<String> vmOptions = new LinkedList<>(options);
+ Collections.addAll(vmOptions,
+ "-Xbootclasspath/a:.",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-XX:GCLockerEdenExpansionPercent=0",
+ "-Xmx" + HEAP_SIZE,
+ "-Xms" + HEAP_SIZE,
+ "-XX:NewRatio=" + ratio,
+ "-XX:-UseLargePages",
+ NewRatioVerifier.class.getName(),
+ Integer.toString(ratio)
+ );
+
+ ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()]));
+ OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
+ analyzer.shouldHaveExitValue(0);
+ System.out.println(analyzer.getOutput());
+ }
+
+ public static class NewRatioVerifier {
+
+ static WhiteBox wb = WhiteBox.getWhiteBox();
+
+ public static void main(String args[]) {
+ if (args.length != 1) {
+ throw new IllegalArgumentException("Expected 1 arg: <expectedRatio>");
+ }
+ int expectedRatio = Integer.valueOf(args[0]);
+ switch (GCTypes.YoungGCType.getYoungGCType()) {
+ case DefNew:
+ case ParNew:
+ verifyDefNewNewRatio(expectedRatio);
+ break;
+ case PSNew:
+ verifyPSNewRatio(expectedRatio);
+ break;
+ case G1:
+ verifyG1NewRatio(expectedRatio);
+ break;
+ default:
+ throw new RuntimeException("Unexpected young GC type");
+ }
+ }
+
+ /**
+ * Verify NewSize for DefNew and ParNew collectors.
+ *
+ * Compare expected NewSize calculated according to sizing policies used by DefNew
+ * with NewSize value reported by MemoryPoolMXBeans.
+ */
+ public static void verifyDefNewNewRatio(int expectedRatio) {
+ long initEden = HeapRegionUsageTool.getEdenUsage().getInit();
+ long initSurv = HeapRegionUsageTool.getSurvivorUsage().getInit();
+ long initOld = HeapRegionUsageTool.getOldUsage().getInit();
+
+ long newSize = initEden + 2 * initSurv;
+
+ long expectedNewSize = HeapRegionUsageTool.alignDown(initOld / expectedRatio,
+ wb.getHeapSpaceAlignment());
+
+ if (expectedNewSize != newSize) {
+ throw new RuntimeException("Expected young gen size is: " + expectedNewSize
+ + ", but observed new size is: " + newSize);
+ }
+ }
+
+ /**
+ * Verify NewSize for PS collector.
+ * Expected NewSize calculated according to alignment policies used by PS
+ * and then compared with actual NewSize obtained from MemoryPoolMXBeans.
+ */
+ public static void verifyPSNewRatio(int expectedRatio) {
+ long initEden = HeapRegionUsageTool.getEdenUsage().getInit();
+ long initSurv = HeapRegionUsageTool.getSurvivorUsage().getInit();
+ long initOld = HeapRegionUsageTool.getOldUsage().getInit();
+
+ long newSize = initEden + 2 * initSurv;
+
+ long alignedDownNewSize = HeapRegionUsageTool.alignDown(initOld / expectedRatio,
+ wb.getHeapSpaceAlignment());
+ long expectedNewSize = HeapRegionUsageTool.alignUp(alignedDownNewSize,
+ wb.psVirtualSpaceAlignment());
+
+ if (expectedNewSize != newSize) {
+ throw new RuntimeException("Expected young gen size is: " + expectedNewSize
+ + ", but observed new size is: " + newSize);
+ }
+ }
+
+ /**
+ * Verify NewSize for G1 GC.
+ * Amount of young regions calculated according to sizing policies used by G1
+ * and then compared with actual number of young regions derived from
+ * values reported by MemoryPoolMXBeans and region size.
+ */
+ public static void verifyG1NewRatio(int expectedRatio) {
+ long initEden = HeapRegionUsageTool.getEdenUsage().getInit();
+ long initSurv = HeapRegionUsageTool.getSurvivorUsage().getInit();
+ long maxOld = HeapRegionUsageTool.getOldUsage().getMax();
+
+ int regionSize = wb.g1RegionSize();
+ int youngListLength = (int) ((initEden + initSurv) / regionSize);
+ int maxRegions = (int) (maxOld / regionSize);
+ int expectedYoungListLength = (int) (maxRegions / (double) (expectedRatio + 1));
+
+ if (youngListLength != expectedYoungListLength) {
+ throw new RuntimeException("Expected G1 young list length is: " + expectedYoungListLength
+ + ", but observed young list length is: " + youngListLength);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/arguments/TestNewSizeFlags.java Tue Sep 01 21:38:07 2015 +0300
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestNewSizeFlags
+ * @key gc
+ * @bug 8025166
+ * @summary Verify that young gen size conforms values specified by NewSize, MaxNewSize and Xmn options
+ * @library /testlibrary /../../test/lib
+ * @modules java.base/sun.misc
+ * java.management
+ * @build TestNewSizeFlags
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver/timeout=240 TestNewSizeFlags
+ */
+
+import jdk.test.lib.AllocationHelper;
+import java.io.IOException;
+import java.lang.management.MemoryUsage;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import jdk.test.lib.HeapRegionUsageTool;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Utils;
+import sun.hotspot.WhiteBox;
+
+public class TestNewSizeFlags {
+
+ public static final long M = 1024 * 1024;
+
+ public static void main(String args[]) throws Exception {
+ LinkedList<String> options = new LinkedList<>(
+ Arrays.asList(Utils.getFilteredTestJavaOpts("(-Xm[nsx][^ ]+)|"
+ + "(-XX:(Max)?((New)|"
+ + "(Heap))((Size)|"
+ + "(Ratio))=[^ ]+)"))
+ );
+
+ // Test NewSize and MaxNewSize
+ testNewSizeFlags(20 * M, 10 * M, 30 * M, 40 * M, options, false);
+ testNewSizeFlags(10 * M, 20 * M, 30 * M, 40 * M, options, false);
+ testNewSizeFlags(-1, 20 * M, 30 * M, 40 * M, options, false);
+ testNewSizeFlags(10 * M, -1, 30 * M, 40 * M, options, false);
+ testNewSizeFlags(20 * M, 20 * M, 30 * M, 40 * M, options, false);
+ testNewSizeFlags(20 * M, 30 * M, 40 * M, 50 * M, options, false);
+ testNewSizeFlags(30 * M, 100 * M, 150 * M, 200 * M, options, false);
+ testNewSizeFlags(0, -1, 30 * M, 40 * M, options, false);
+
+ // Test -Xmn
+ testXmnFlags(0, 30 * M, 40 * M, options, true);
+ testXmnFlags(20 * M, 30 * M, 40 * M, options, false);
+ testXmnFlags(50 * M, 70 * M, 100 * M, options, false);
+ }
+
+ /**
+ * Verify that NewSize and MaxNewSize flags affect young gen size.
+ *
+ * @param newSize value of NewSize option, omitted if negative
+ * @param maxNewSize value of MaxNewSize option, omitted if negative
+ * @param heapSize value of HeapSize option
+ * @param maxHeapSize value of MaxHeapSize option
+ * @param options additional options for JVM
+ * @param failureExpected true if JVM should fail with passed heap size options
+ */
+ public static void testNewSizeFlags(long newSize, long maxNewSize,
+ long heapSize, long maxHeapSize,
+ LinkedList<String> options,
+ boolean failureExpected) throws Exception {
+ testVMOptions(newSize, maxNewSize,
+ heapSize, maxHeapSize,
+ newSize, (maxNewSize >= 0 ? Math.max(maxNewSize, newSize) : maxNewSize),
+ options, failureExpected);
+ }
+
+ /**
+ * Verify that -Xmn flag affect young gen size.
+ *
+ * @param mnValue value of -Xmn option
+ * @param heapSize value of HeapSize option
+ * @param maxHeapSize value of MaxHeapSize option
+ * @param options additional options for JVM
+ * @param failureExpected true if JVM should fail with passed heap size options
+ */
+ public static void testXmnFlags(long mnValue,
+ long heapSize, long maxHeapSize,
+ LinkedList<String> options,
+ boolean failureExpected) throws Exception {
+ LinkedList<String> newOptions = new LinkedList<>(options);
+ newOptions.add("-Xmn" + mnValue);
+ testVMOptions(-1, -1,
+ heapSize, maxHeapSize,
+ mnValue, mnValue,
+ newOptions, failureExpected);
+ }
+
+ /**
+ * Verify that NewSize and MaxNewSize flags affect young gen size.
+ *
+ * @param newSize value of NewSize option, omitted if negative
+ * @param maxNewSize value of MaxNewSize option, omitted if negative
+ * @param heapSize value of HeapSize option
+ * @param maxHeapSize value of MaxHeapSize option
+ * @param expectedNewSize expected initial young gen size
+ * @param expectedMaxNewSize expected max young gen size
+ * @param options additional options for JVM
+ * @param failureExpected true if JVM should fail with passed heap size options
+ */
+ public static void testVMOptions(long newSize, long maxNewSize,
+ long heapSize, long maxHeapSize,
+ long expectedNewSize, long expectedMaxNewSize,
+ LinkedList<String> options, boolean failureExpected) throws Exception {
+ OutputAnalyzer analyzer = startVM(options, newSize, maxNewSize, heapSize, maxHeapSize, expectedNewSize, expectedMaxNewSize);
+
+ if (failureExpected) {
+ analyzer.shouldHaveExitValue(1);
+ analyzer.shouldMatch("(Error occurred during initialization of VM)|"
+ + "(Error: Could not create the Java Virtual Machine.)");
+ } else {
+ analyzer.shouldHaveExitValue(0);
+ }
+ }
+
+ private static OutputAnalyzer startVM(LinkedList<String> options,
+ long newSize, long maxNewSize,
+ long heapSize, long maxHeapSize,
+ long expectedNewSize, long expectedMaxNewSize) throws Exception, IOException {
+ LinkedList<String> vmOptions = new LinkedList<>(options);
+ Collections.addAll(vmOptions,
+ "-Xbootclasspath/a:.",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ (newSize >= 0 ? "-XX:NewSize=" + newSize : ""),
+ (maxNewSize >= 0 ? "-XX:MaxNewSize=" + maxNewSize : ""),
+ "-Xmx" + maxHeapSize,
+ "-Xms" + heapSize,
+ "-XX:GCLockerEdenExpansionPercent=0",
+ "-XX:-UseLargePages",
+ NewSizeVerifier.class.getName(),
+ Long.toString(expectedNewSize),
+ Long.toString(expectedMaxNewSize)
+ );
+ vmOptions.removeIf(String::isEmpty);
+ ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()]));
+ OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
+ return analyzer;
+ }
+
+ /**
+ * NewSizeVerifier checks that initial young gen size is equal to expected
+ * regardful to alignment and that young gen size will not be greater than
+ * expected max size.
+ * In order to verify that young gen size will not be greater then expected
+ * max size, NewSizeVerifier do some object allocation to force garbage
+ * collection and heap expansion.
+ */
+ public static class NewSizeVerifier {
+
+ static WhiteBox wb = WhiteBox.getWhiteBox();
+
+ public static final int ARRAY_LENGTH = 100;
+ public static final int CHUNK_SIZE = 1024;
+ public static final int MAX_ITERATIONS = 10;
+ public static byte garbage[][] = new byte[ARRAY_LENGTH][];
+
+ public static void main(String args[]) throws Exception {
+ if (args.length != 2) {
+ throw new IllegalArgumentException("Expected 2 args: <expectedNewSize> <expectedMaxNewSize>");
+ }
+ final long newSize = Long.valueOf(args[0]);
+ final long maxNewSize = Long.valueOf(args[1]);
+
+ // verify initial size
+ verifyNewSize(newSize, maxNewSize);
+
+ // force GC and verify that size is still correct
+ AllocationHelper allocator = new AllocationHelper(MAX_ITERATIONS, ARRAY_LENGTH, CHUNK_SIZE, () -> (verifyNewSize(newSize, maxNewSize)));
+ allocator.allocateMemoryAndVerifyNoOOME();
+ }
+
+ /**
+ * Verify that actual young gen size conforms NewSize and MaxNewSize values.
+ */
+ public static Void verifyNewSize(long newSize, long maxNewSize) {
+ long alignedNewSize = alignNewSize(newSize);
+ long alignedMaxNewSize = alignNewSize(maxNewSize);
+
+ MemoryUsage youngGenUsage = getYoungGenUsage();
+
+ if (newSize != -1) {
+ if (youngGenUsage.getInit() < alignedNewSize) {
+ throw new RuntimeException("initial new size < NewSize value: "
+ + youngGenUsage.getInit() + " < " + alignedNewSize);
+ }
+
+ if (youngGenUsage.getCommitted() < alignedNewSize) {
+ throw new RuntimeException("actual new size < NewSize value: "
+ + youngGenUsage.getCommitted() + " < " + alignedNewSize);
+ }
+
+ // for G1 max new size == committed new size
+ if (GCTypes.YoungGCType.getYoungGCType() != GCTypes.YoungGCType.G1
+ && youngGenUsage.getMax() < alignedNewSize) {
+ throw new RuntimeException("max new size < NewSize value: "
+ + youngGenUsage.getMax() + " < " + alignedNewSize);
+ }
+ }
+
+ if (maxNewSize != -1) {
+ if (youngGenUsage.getInit() > alignedMaxNewSize) {
+ throw new RuntimeException("initial new size > MaxNewSize value: "
+ + youngGenUsage.getInit() + " > " + alignedMaxNewSize);
+ }
+
+ if (youngGenUsage.getCommitted() > alignedMaxNewSize) {
+ throw new RuntimeException("actual new size > MaxNewSize value: "
+ + youngGenUsage.getCommitted() + " > " + alignedMaxNewSize);
+ }
+
+ if (GCTypes.YoungGCType.getYoungGCType() != GCTypes.YoungGCType.G1
+ && youngGenUsage.getMax() != alignedMaxNewSize) {
+ throw new RuntimeException("max new size != MaxNewSize value: "
+ + youngGenUsage.getMax() + " != " + alignedMaxNewSize);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get young gen memory usage.
+ *
+ * For G1 it is EdenUsage + SurvivorUsage,
+ * for other GCs it is EdenUsage + 2 * SurvivorUsage.
+ * For G1 max value is just LONG_MAX.
+ * For all GCs used value is 0.
+ */
+ private static MemoryUsage getYoungGenUsage() {
+ if (GCTypes.YoungGCType.getYoungGCType() == GCTypes.YoungGCType.G1) {
+ return new MemoryUsage(HeapRegionUsageTool.getEdenUsage().getInit()
+ + HeapRegionUsageTool.getSurvivorUsage().getInit(),
+ 0,
+ HeapRegionUsageTool.getEdenUsage().getCommitted()
+ + HeapRegionUsageTool.getSurvivorUsage().getCommitted(),
+ Long.MAX_VALUE);
+ } else {
+ return new MemoryUsage(HeapRegionUsageTool.getEdenUsage().getInit()
+ + HeapRegionUsageTool.getSurvivorUsage().getInit() * 2,
+ 0,
+ HeapRegionUsageTool.getEdenUsage().getCommitted()
+ + HeapRegionUsageTool.getSurvivorUsage().getCommitted() * 2,
+ HeapRegionUsageTool.getEdenUsage().getMax()
+ + HeapRegionUsageTool.getSurvivorUsage().getMax() * 2);
+ }
+ }
+
+ /**
+ * Align value regardful to used young GC.
+ */
+ public static long alignNewSize(long value) {
+ switch (GCTypes.YoungGCType.getYoungGCType()) {
+ case DefNew:
+ case ParNew:
+ return HeapRegionUsageTool.alignDown(value, wb.getHeapSpaceAlignment());
+ case PSNew:
+ return HeapRegionUsageTool.alignUp(HeapRegionUsageTool.alignDown(value,
+ wb.getHeapSpaceAlignment()),
+ wb.psVirtualSpaceAlignment());
+ case G1:
+ return HeapRegionUsageTool.alignUp(value, wb.g1RegionSize());
+ default:
+ throw new RuntimeException("Unexpected young GC type");
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/arguments/TestSurvivorRatioFlag.java Tue Sep 01 21:38:07 2015 +0300
@@ -0,0 +1,182 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*/
+
+/*
+ * @test TestSurvivorRatioFlag
+ * @key gc
+ * @summary Verify that actual survivor ratio is equal to specified SurvivorRatio value
+ * @library /testlibrary /../../test/lib
+ * @modules java.base/sun.misc
+ * java.management
+ * @build TestSurvivorRatioFlag
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver TestSurvivorRatioFlag
+ */
+
+import jdk.test.lib.AllocationHelper;
+import java.lang.management.MemoryUsage;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import jdk.test.lib.HeapRegionUsageTool;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Utils;
+import sun.hotspot.WhiteBox;
+
+public class TestSurvivorRatioFlag {
+
+ public static final long M = 1024 * 1024;
+ public static final long HEAP_SIZE = 200 * M;
+ public static final long NEW_SIZE = 100 * M;
+
+ public static void main(String args[]) throws Exception {
+ LinkedList<String> options = new LinkedList<>(
+ Arrays.asList(Utils.getFilteredTestJavaOpts("-XX:[^ ]*SurvivorRatio=[^ ]+"))
+ );
+
+ testSurvivorRatio(3, options);
+ testSurvivorRatio(6, options);
+ testSurvivorRatio(10, options);
+ testSurvivorRatio(15, options);
+ testSurvivorRatio(20, options);
+ }
+
+ /**
+ * Verify that actual survivor ratio equal to specified.
+ *
+ * @param ratio survivor ratio that be verified
+ * @param options additional options to JVM
+ */
+ public static void testSurvivorRatio(int ratio, LinkedList<String> options) throws Exception {
+
+ LinkedList<String> vmOptions = new LinkedList<>(options);
+
+ Collections.addAll(vmOptions,
+ "-Xbootclasspath/a:.",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-XX:GCLockerEdenExpansionPercent=0",
+ "-XX:MaxNewSize=" + NEW_SIZE,
+ "-XX:NewSize=" + NEW_SIZE,
+ "-Xmx" + HEAP_SIZE,
+ "-Xms" + HEAP_SIZE,
+ "-XX:SurvivorRatio=" + ratio,
+ SurvivorRatioVerifier.class.getName(),
+ Integer.toString(ratio)
+ );
+
+ ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()]));
+ OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
+ analyzer.shouldHaveExitValue(0);
+ }
+
+ /**
+ * Class that verifies survivor ratio.
+ */
+ public static class SurvivorRatioVerifier {
+
+ static WhiteBox wb = WhiteBox.getWhiteBox();
+
+ public static final int MAX_ITERATIONS = 10;
+ public static final int ARRAY_LENGTH = 10000;
+ public static final int CHUNK_SIZE = 10000;
+
+ public static void main(String args[]) throws Exception {
+ if (args.length != 1) {
+ throw new IllegalArgumentException("Expected 1 arg: <ratio>");
+ }
+ final int ratio = Integer.valueOf(args[0]);
+
+ AllocationHelper allocator = new AllocationHelper(MAX_ITERATIONS, ARRAY_LENGTH, CHUNK_SIZE, () -> (verifySurvivorRatio(ratio)));
+ allocator.allocateMemoryAndVerify();
+ }
+
+ /**
+ * Verify that actual survivor ratio is equal to expected.
+ * Depending on selected young GC we verify that:
+ * - for DefNew and ParNew: eden_size / survivor_size is close to expectedRatio;
+ * - for PSNew: survivor_size equal to young_gen_size / expectedRatio;
+ * - for G1: survivor_regions <= young_list_length / expectedRatio.
+ */
+ public static Void verifySurvivorRatio(int expectedRatio) {
+ GCTypes.YoungGCType type = GCTypes.YoungGCType.getYoungGCType();
+ switch (type) {
+ case DefNew:
+ case ParNew:
+ verifyDefNewSurvivorRatio(expectedRatio);
+ break;
+ case PSNew:
+ verifyPSSurvivorRatio(expectedRatio);
+ break;
+ case G1:
+ verifyG1SurvivorRatio(expectedRatio);
+ break;
+ default:
+ throw new RuntimeException("Unexpected young GC type");
+ }
+ return null;
+ }
+
+ private static void verifyDefNewSurvivorRatio(int expectedRatio) {
+ MemoryUsage edenUsage = HeapRegionUsageTool.getEdenUsage();
+ MemoryUsage survivorUsage = HeapRegionUsageTool.getSurvivorUsage();
+
+ int actualRatio = (int) (edenUsage.getCommitted() / survivorUsage.getCommitted());
+ if (Math.abs(actualRatio - expectedRatio) > 1) {
+ throw new RuntimeException("Expected survivor ratio is: " + expectedRatio
+ + ", but observed ratio is: " + actualRatio);
+ }
+ }
+
+ private static void verifyPSSurvivorRatio(int expectedRatio) {
+ MemoryUsage edenUsage = HeapRegionUsageTool.getEdenUsage();
+ MemoryUsage survivorUsage = HeapRegionUsageTool.getSurvivorUsage();
+
+ long youngGenSize = edenUsage.getMax() + 2 * survivorUsage.getMax();
+ // for Paralle GC Min/InitialSurvivorRatio = SurvivorRatio + 2
+ long expectedSize = HeapRegionUsageTool.alignDown(youngGenSize / (expectedRatio + 2),
+ wb.psHeapGenerationAlignment());
+
+ if (expectedSize != survivorUsage.getCommitted()) {
+ throw new RuntimeException("Expected survivor size is: " + expectedSize
+ + ", but observed size is: " + survivorUsage.getCommitted());
+ }
+ }
+
+ private static void verifyG1SurvivorRatio(int expectedRatio) {
+ MemoryUsage survivorUsage = HeapRegionUsageTool.getSurvivorUsage();
+
+ int regionSize = wb.g1RegionSize();
+ int youngListLength = (int) Math.max(NEW_SIZE / regionSize, 1);
+ int expectedSurvivorRegions = (int) Math.ceil(youngListLength / (double) expectedRatio);
+ int observedSurvivorRegions = (int) (survivorUsage.getCommitted() / regionSize);
+
+ if (expectedSurvivorRegions < observedSurvivorRegions) {
+ throw new RuntimeException("Expected amount of G1 survivor regions is "
+ + expectedSurvivorRegions + ", but observed "
+ + observedSurvivorRegions);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/arguments/TestTargetSurvivorRatioFlag.java Tue Sep 01 21:38:07 2015 +0300
@@ -0,0 +1,319 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*/
+
+/*
+ * @test TestTargetSurvivorRatioFlag
+ * @key gc
+ * @summary Verify that option TargetSurvivorRatio affects survivor space occupancy after minor GC.
+ * @library /testlibrary /../../test/lib
+ * @modules java.base/sun.misc
+ * java.management
+ * @build TestTargetSurvivorRatioFlag
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver TestTargetSurvivorRatioFlag
+ */
+
+import jdk.test.lib.AllocationHelper;
+import java.lang.management.GarbageCollectorMXBean;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import jdk.test.lib.HeapRegionUsageTool;
+import sun.misc.Unsafe;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Utils;
+import sun.hotspot.WhiteBox;
+
+/* In order to test that TargetSurvivorRatio affects survivor space occupancy
+ * we setup fixed MaxTenuringThreshold and then verifying that if size of allocated
+ * objects is lower than (survivor_size * TargetSurvivorRatio / 100) then objects
+ * will stay in survivor space until MaxTenuringThreshold minor GC cycles.
+ * If more than (survivor_size * TargetSurvivorRatio / 100) objects were allocated,
+ * then we verify that after MaxTenuringThreshold minor GC cycles survivor space
+ * is almost empty.
+ */
+public class TestTargetSurvivorRatioFlag {
+
+ public static final long M = 1024 * 1024;
+
+ // VM option values
+ public static final long MAX_NEW_SIZE = 40 * M;
+ public static final int SURVIVOR_RATIO = 8;
+ public static final int MAX_TENURING_THRESHOLD = 15;
+
+ // Value used to estimate amount of memory that should be allocated
+ // and placed in survivor space.
+ public static final double DELTA = 0.25;
+
+ // Max variance of observed ratio
+ public static double VARIANCE = 1;
+
+ // Messages used by debuggee
+ public static final String UNSUPPORTED_GC = "Unsupported GC";
+ public static final String START_TEST = "Start test";
+ public static final String END_TEST = "End test";
+
+ // Patterns used during log parsing
+ public static final String TENURING_DISTRIBUTION = "Desired survivor size";
+ public static final String AGE_TABLE_ENTRY = "-[\\s]+age[\\s]+([0-9]+):[\\s]+([0-9]+)[\\s]+bytes,[\\s]+([0-9]+)[\\s]+total";
+ public static final String MAX_SURVIVOR_SIZE = "Max survivor size: ([0-9]+)";
+
+ public static void main(String args[]) throws Exception {
+
+ LinkedList<String> options = new LinkedList<>(Arrays.asList(Utils.getTestJavaOpts()));
+
+ // Need to consider the effect of TargetPLABWastePct=1 for G1 GC
+ if (options.contains("-XX:+UseG1GC")) {
+ VARIANCE = 2;
+ } else {
+ VARIANCE = 1;
+ }
+
+ negativeTest(-1, options);
+ negativeTest(101, options);
+
+ positiveTest(20, options);
+ positiveTest(30, options);
+ positiveTest(55, options);
+ positiveTest(70, options);
+ }
+
+ /**
+ * Verify that VM will fail to start with specified TargetSurvivorRatio
+ *
+ * @param ratio value of TargetSurvivorRatio
+ * @param options additional VM options
+ */
+ public static void negativeTest(int ratio, LinkedList<String> options) throws Exception {
+ LinkedList<String> vmOptions = new LinkedList<>(options);
+ vmOptions.add("-XX:TargetSurvivorRatio=" + ratio);
+ vmOptions.add("-version");
+
+ ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()]));
+ OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
+
+ analyzer.shouldHaveExitValue(1);
+ analyzer.shouldContain("Error: Could not create the Java Virtual Machine.");
+ }
+
+ /**
+ * Verify that actual survivor space usage ratio conforms specified TargetSurvivorRatio
+ *
+ * @param ratio value of TargetSurvivorRatio
+ * @param options additional VM options
+ */
+ public static void positiveTest(int ratio, LinkedList<String> options) throws Exception {
+ LinkedList<String> vmOptions = new LinkedList<>(options);
+ Collections.addAll(vmOptions,
+ "-Xbootclasspath/a:.",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-XX:+UseAdaptiveSizePolicy",
+ "-XX:+PrintTenuringDistribution",
+ "-XX:MaxTenuringThreshold=" + MAX_TENURING_THRESHOLD,
+ "-XX:NewSize=" + MAX_NEW_SIZE,
+ "-XX:MaxNewSize=" + MAX_NEW_SIZE,
+ "-XX:InitialHeapSize=" + 2 * MAX_NEW_SIZE,
+ "-XX:MaxHeapSize=" + 2 * MAX_NEW_SIZE,
+ "-XX:SurvivorRatio=" + SURVIVOR_RATIO,
+ "-XX:TargetSurvivorRatio=" + ratio,
+ // For reducing variance of survivor size.
+ "-XX:TargetPLABWastePct=" + 1,
+ TargetSurvivorRatioVerifier.class.getName(),
+ Integer.toString(ratio)
+ );
+
+ ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()]));
+ OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
+
+ analyzer.shouldHaveExitValue(0);
+
+ String output = analyzer.getOutput();
+
+ // Test avoids verification for parallel GC
+ if (!output.contains(UNSUPPORTED_GC)) {
+ // Two tests should be done - when actual ratio is lower than TargetSurvivorRatio
+ // and when it is higher. We chech that output contains results for exactly two tests.
+ List<Double> ratios = parseTestOutput(output);
+
+ if (ratios.size() != 2) {
+ System.out.println(output);
+ throw new RuntimeException("Expected number of ratios extraced for output is 2,"
+ + " but " + ratios.size() + " ratios were extracted");
+ }
+
+ // At the end of the first test survivor space usage ratio should lies between
+ // TargetSurvivorRatio and TargetSurvivorRatio - 2*DELTA
+ if (ratio < ratios.get(0) || ratio - ratios.get(0) > VARIANCE) {
+ System.out.println(output);
+ throw new RuntimeException("Survivor space usage ratio expected to be close to "
+ + ratio + ", but observed ratio is: " + ratios.get(0));
+ }
+
+ // After second test survivor space should be almost empty.
+ if (ratios.get(1) > VARIANCE) {
+ System.out.println(output);
+ throw new RuntimeException("Survivor space expected to be empty due to "
+ + "TargetSurvivorRatio overlimit, however observed "
+ + "survivor space usage ratio is: " + ratios.get(1));
+ }
+ } else {
+ System.out.println("Selected GC does not support TargetSurvivorRatio option.");
+ }
+ }
+
+ /**
+ * Parse output produced by TargetSurvivorRatioVerifier.
+ *
+ * @param output output obtained from TargetSurvivorRatioVerifier
+ * @return list of parsed test results, where each result is an actual
+ * survivor ratio after MaxTenuringThreshold minor GC cycles.
+ */
+ public static List<Double> parseTestOutput(String output) {
+ List<Double> ratios = new LinkedList<Double>();
+ String lines[] = output.split("[\n\r]");
+ boolean testStarted = false;
+ long survivorSize = 0;
+ long survivorOccupancy = 0;
+ int gcCount = 0;
+ Pattern ageTableEntry = Pattern.compile(AGE_TABLE_ENTRY);
+ Pattern maxSurvivorSize = Pattern.compile(MAX_SURVIVOR_SIZE);
+ for (String line : lines) {
+ if (Pattern.matches(MAX_SURVIVOR_SIZE, line)) {
+ // We found estimated survivor space size
+ Matcher m = maxSurvivorSize.matcher(line);
+ m.find();
+ survivorSize = Long.valueOf(m.group(1));
+ } else if (line.contains(START_TEST) && !testStarted) {
+ // Start collecting test results
+ testStarted = true;
+ gcCount = 0;
+ } else if (testStarted) {
+ if (line.contains(TENURING_DISTRIBUTION)) {
+ // We found start of output emitted by -XX:+PrintTenuringDistribution
+ // If it is associated with "MaxTenuringThreshold" GC cycle, then it's
+ // time to report observed survivor usage ratio
+ gcCount++;
+ double survivorRatio = survivorOccupancy / (double) survivorSize;
+ if (gcCount == MAX_TENURING_THRESHOLD || gcCount == MAX_TENURING_THRESHOLD * 2) {
+ ratios.add(survivorRatio * 100.0);
+ testStarted = false;
+ }
+ survivorOccupancy = 0;
+ } else if (Pattern.matches(AGE_TABLE_ENTRY, line)) {
+ // Obtain survivor space usage from "total" age table log entry
+ Matcher m = ageTableEntry.matcher(line);
+ m.find();
+ survivorOccupancy = Long.valueOf(m.group(3));
+ } else if (line.contains(END_TEST)) {
+ // It is expected to find at least MaxTenuringThreshold GC events
+ // until test end
+ if (gcCount < MAX_TENURING_THRESHOLD) {
+ throw new RuntimeException("Observed " + gcCount + " GC events, "
+ + "while it is expected to see at least "
+ + MAX_TENURING_THRESHOLD);
+ }
+ testStarted = false;
+ }
+ }
+ }
+ return ratios;
+ }
+
+ public static class TargetSurvivorRatioVerifier {
+
+ static final WhiteBox wb = WhiteBox.getWhiteBox();
+ static final Unsafe unsafe = Utils.getUnsafe();
+
+ // Desired size of memory allocated at once
+ public static final int CHUNK_SIZE = 1024;
+ // Length of byte[] array that will have occupy CHUNK_SIZE bytes in heap
+ public static final int ARRAY_LENGTH = CHUNK_SIZE - Unsafe.ARRAY_BYTE_BASE_OFFSET;
+
+ public static void main(String args[]) throws Exception {
+ if (args.length != 1) {
+ throw new IllegalArgumentException("Expected 1 arg: <ratio>");
+ }
+ if (GCTypes.YoungGCType.getYoungGCType() == GCTypes.YoungGCType.PSNew) {
+ System.out.println(UNSUPPORTED_GC);
+ return;
+ }
+
+ int ratio = Integer.valueOf(args[0]);
+ long maxSurvivorSize = getMaxSurvivorSize();
+ System.out.println("Max survivor size: " + maxSurvivorSize);
+
+ allocateMemory(ratio - DELTA, maxSurvivorSize);
+ allocateMemory(ratio + DELTA, maxSurvivorSize);
+ }
+
+ /**
+ * Allocate (<b>ratio</b> * <b>maxSize</b> / 100) bytes of objects
+ * and force at least "MaxTenuringThreshold" minor GCs.
+ *
+ * @param ratio ratio used to calculate how many objects should be allocated
+ * @param maxSize estimated max survivor space size
+ */
+ public static void allocateMemory(double ratio, long maxSize) throws Exception {
+ GarbageCollectorMXBean youngGCBean = GCTypes.YoungGCType.getYoungGCBean();
+ long garbageSize = (long) (maxSize * (ratio / 100.0));
+ int arrayLength = (int) (garbageSize / CHUNK_SIZE);
+ AllocationHelper allocator = new AllocationHelper(1, arrayLength, ARRAY_LENGTH, null);
+
+ System.out.println(START_TEST);
+ System.gc();
+ final long initialGcId = youngGCBean.getCollectionCount();
+ // allocate memory
+ allocator.allocateMemoryAndVerify();
+
+ // force minor GC
+ while (youngGCBean.getCollectionCount() <= initialGcId + MAX_TENURING_THRESHOLD * 2) {
+ byte b[] = new byte[ARRAY_LENGTH];
+ }
+
+ allocator.release();
+ System.out.println(END_TEST);
+ }
+
+ /**
+ * Estimate max survivor space size.
+ *
+ * For non-G1 GC returns value reported by MemoryPoolMXBean
+ * associated with survivor space.
+ * For G1 GC return max number of survivor regions * region size.
+ * Number if survivor regions estimated from MaxNewSize and SurvivorRatio.
+ */
+ public static long getMaxSurvivorSize() {
+ if (GCTypes.YoungGCType.getYoungGCType() == GCTypes.YoungGCType.G1) {
+ int youngLength = (int) Math.max(MAX_NEW_SIZE / wb.g1RegionSize(), 1);
+ return (long) Math.ceil(youngLength / (double) SURVIVOR_RATIO) * wb.g1RegionSize();
+ } else {
+ return HeapRegionUsageTool.getSurvivorUsage().getMax();
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/jdk/test/lib/AllocationHelper.java Tue Sep 01 21:38:07 2015 +0300
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*/
+
+package jdk.test.lib;
+
+import java.util.LinkedList;
+import java.util.concurrent.Callable;
+
+/**
+ * Helper class which allocates memory.
+ *
+ * Typical usage:
+ * <pre>
+ * {@code
+ * AllocationHelper allocator = new AllocationHelper(MAX_ITERATIONS, ARRAY_LENGTH, CHUNK_SIZE,
+ * () -> (verifier()));
+ * // Allocate byte[CHUNK_SIZE] ARRAY_LENGTH times. Total allocated bytes will be CHUNK_SIZE * ARRAY_LENGTH + refs length.
+ * // Then invoke verifier and iterate MAX_ITERATIONS times.
+ * allocator.allocateMemoryAndVerify();
+ * }
+ * </pre>
+ */
+public final class AllocationHelper {
+
+ private final int arrayLength;
+ private final int maxIterations;
+ private final int chunkSize;
+
+ // garbageStorage is used to store link to garbage to prevent optimization.
+ private static Object garbageStorage;
+ private byte garbage[][];
+ private final Callable<?> verifierInstance;
+
+ /**
+ * Create an AllocationHelper with specified iteration count, array length, chunk size and verifier.
+ *
+ * @param maxIterations
+ * @param arrayLength
+ * @param chunkSize
+ * @param verifier - Callable instance which will be invoked after all allocation cycle. Can be null;
+ */
+ public AllocationHelper(int maxIterations, int arrayLength, int chunkSize, Callable<?> verifier) {
+ if ((arrayLength <= 0) || (maxIterations <= 0) || (chunkSize <= 0)) {
+ throw new IllegalArgumentException("maxIterations, arrayLength and chunkSize should be greater then 0.");
+ }
+ this.arrayLength = arrayLength;
+ this.maxIterations = maxIterations;
+ this.chunkSize = chunkSize;
+ verifierInstance = verifier;
+ garbage = new byte[this.arrayLength][];
+ garbageStorage = garbage;
+ }
+
+ private void allocateMemoryOneIteration() {
+ for (int j = 0; j < arrayLength; j++) {
+ garbage[j] = new byte[chunkSize];
+ }
+ }
+
+ /**
+ * Allocate memory and invoke Verifier during all iteration.
+ *
+ * @throws java.lang.Exception
+ */
+ public void allocateMemoryAndVerify() throws Exception {
+ for (int i = 0; i < maxIterations; i++) {
+ allocateMemoryOneIteration();
+ if (verifierInstance != null) {
+ verifierInstance.call();
+ }
+ }
+ }
+
+ /**
+ * The same as allocateMemoryAndVerify() but hides OOME
+ *
+ * @throws Exception
+ */
+ public void allocateMemoryAndVerifyNoOOME() throws Exception {
+ try {
+ allocateMemoryAndVerify();
+ } catch (OutOfMemoryError e) {
+ // exit on OOME
+ }
+ }
+
+ /**
+ * Release link to allocated garbage to make it available for further GC
+ */
+ public void release() {
+ if (garbage != null) {
+ garbage = null;
+ garbageStorage = null;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/jdk/test/lib/HeapRegionUsageTool.java Tue Sep 01 21:38:07 2015 +0300
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*/
+
+package jdk.test.lib;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.management.MemoryUsage;
+
+/**
+ * Utility class used by tests to get heap region usage.
+ */
+public final class HeapRegionUsageTool {
+
+ /**
+ * Get MemoryUsage from MemoryPoolMXBean which name matches passed string.
+ *
+ * @param name
+ * @return MemoryUsage
+ */
+ private static MemoryUsage getUsage(String name){
+ for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
+ if (pool.getName().matches(name)) {
+ return pool.getUsage();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get MemoryUsage of Eden space.
+ *
+ * @return MemoryUsage
+ */
+ public static MemoryUsage getEdenUsage() {
+ return getUsage(".*Eden.*");
+ }
+
+ /**
+ * Get MemoryUsage of Survivor space.
+ *
+ * @return MemoryUsage
+ */
+ public static MemoryUsage getSurvivorUsage() {
+ return getUsage(".*Survivor.*");
+ }
+
+ /**
+ * Get memory usage of Tenured space
+ *
+ * @return MemoryUsage
+ */
+ public static MemoryUsage getOldUsage() {
+ return getUsage(".*(Old|Tenured).*");
+ }
+
+ /**
+ * Get heap usage.
+ *
+ * @return MemoryUsage
+ */
+ public static MemoryUsage getHeapUsage() {
+ return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
+ }
+
+ /**
+ * Helper function to align up.
+ *
+ * @param value
+ * @param alignment
+ * @return aligned value
+ */
+ public static long alignUp(long value, long alignment) {
+ return (value + alignment - 1) & ~(alignment - 1);
+ }
+
+ /**
+ * Helper function to align down.
+ *
+ * @param value
+ * @param alignment
+ * @return aligned value
+ */
+ public static long alignDown(long value, long alignment) {
+ return value & ~(alignment - 1);
+ }
+}