# HG changeset patch # User mchernov # Date 1441132687 -10800 # Node ID e7dadf42aa35f5dde518f044233b8a3b78e120ff # Parent d750cc39ed606b1c0fb24d88308bb05f2dae8629 8081317: [NEWTEST] documented GC ratio tuning and new size options should be covered by regression tests Reviewed-by: iignatyev, dfazunen diff -r d750cc39ed60 -r e7dadf42aa35 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Mon Sep 07 21:30:45 2015 +0400 +++ b/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 }, diff -r d750cc39ed60 -r e7dadf42aa35 test/gc/arguments/GCTypes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 getCurrentGCType(Class type) { + return ManagementFactory.getGarbageCollectorMXBeans().stream() + .map(bean -> getGCTypeByName(type, bean.getName())) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); + } + + private static T getGCTypeByName(Class type, String name) { + return Arrays.stream(type.getEnumConstants()) + .filter(e -> e.getGCName().equals(name)) + .findFirst() + .orElse(null); + } + + private static GarbageCollectorMXBean getGCBeanByType(Class 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; + } + } +} diff -r d750cc39ed60 -r e7dadf42aa35 test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 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 options) throws Exception { + + LinkedList 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 options) throws Exception { + + LinkedList 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 garbage = new LinkedList<>(); + + public static void main(String args[]) throws Exception { + if (args.length != 2) { + throw new IllegalArgumentException("Expected 2 args: "); + } + 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(); + } + } +} diff -r d750cc39ed60 -r e7dadf42aa35 test/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 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 options, + boolean useAdaptiveSizePolicy) throws Exception { + + LinkedList 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: "); + } + 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; + } + } +} diff -r d750cc39ed60 -r e7dadf42aa35 test/gc/arguments/TestNewRatioFlag.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 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 options) throws Exception { + LinkedList 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: "); + } + 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); + } + } + } +} diff -r d750cc39ed60 -r e7dadf42aa35 test/gc/arguments/TestNewSizeFlags.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 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 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 options, + boolean failureExpected) throws Exception { + LinkedList 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 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 options, + long newSize, long maxNewSize, + long heapSize, long maxHeapSize, + long expectedNewSize, long expectedMaxNewSize) throws Exception, IOException { + LinkedList 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: "); + } + 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"); + } + } + } +} diff -r d750cc39ed60 -r e7dadf42aa35 test/gc/arguments/TestSurvivorRatioFlag.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 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 options) throws Exception { + + LinkedList 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: "); + } + 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); + } + } + } +} diff -r d750cc39ed60 -r e7dadf42aa35 test/gc/arguments/TestTargetSurvivorRatioFlag.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 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 options) throws Exception { + LinkedList 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 options) throws Exception { + LinkedList 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 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 parseTestOutput(String output) { + List ratios = new LinkedList(); + 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: "); + } + 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 (ratio * maxSize / 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(); + } + } + } +} diff -r d750cc39ed60 -r e7dadf42aa35 test/testlibrary/jdk/test/lib/AllocationHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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: + *
+ * {@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();
+ * }
+ * 
+ */ +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; + } + } +} diff -r d750cc39ed60 -r e7dadf42aa35 test/testlibrary/jdk/test/lib/HeapRegionUsageTool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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); + } +}