mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8081317: [NEWTEST] documented GC ratio tuning and new size options should be covered by regression tests
Reviewed-by: iignatyev, dfazunen
This commit is contained in:
parent
187c7c2b58
commit
6814a6121a
10 changed files with 1842 additions and 0 deletions
|
@ -55,6 +55,7 @@
|
||||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||||
#include "gc/g1/heapRegionRemSet.hpp"
|
#include "gc/g1/heapRegionRemSet.hpp"
|
||||||
#include "gc/parallel/parallelScavengeHeap.inline.hpp"
|
#include "gc/parallel/parallelScavengeHeap.inline.hpp"
|
||||||
|
#include "gc/parallel/adjoiningGenerations.hpp"
|
||||||
#endif // INCLUDE_ALL_GCS
|
#endif // INCLUDE_ALL_GCS
|
||||||
#if INCLUDE_NMT
|
#if INCLUDE_NMT
|
||||||
#include "services/mallocSiteTable.hpp"
|
#include "services/mallocSiteTable.hpp"
|
||||||
|
@ -296,6 +297,11 @@ WB_ENTRY(jlong, WB_GetObjectSize(JNIEnv* env, jobject o, jobject obj))
|
||||||
return p->size() * HeapWordSize;
|
return p->size() * HeapWordSize;
|
||||||
WB_END
|
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
|
#if INCLUDE_ALL_GCS
|
||||||
WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj))
|
WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj))
|
||||||
G1CollectedHeap* g1 = G1CollectedHeap::heap();
|
G1CollectedHeap* g1 = G1CollectedHeap::heap();
|
||||||
|
@ -334,6 +340,17 @@ WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o))
|
||||||
return (jint)HeapRegion::GrainBytes;
|
return (jint)HeapRegion::GrainBytes;
|
||||||
WB_END
|
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))
|
WB_ENTRY(jobject, WB_G1AuxiliaryMemoryUsage(JNIEnv* env))
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||||
|
@ -1332,6 +1349,7 @@ static JNINativeMethod methods[] = {
|
||||||
{CC"getVMPageSize", CC"()I", (void*)&WB_GetVMPageSize },
|
{CC"getVMPageSize", CC"()I", (void*)&WB_GetVMPageSize },
|
||||||
{CC"getVMAllocationGranularity", CC"()J", (void*)&WB_GetVMAllocationGranularity },
|
{CC"getVMAllocationGranularity", CC"()J", (void*)&WB_GetVMAllocationGranularity },
|
||||||
{CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize},
|
{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"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive },
|
||||||
{CC"parseCommandLine0",
|
{CC"parseCommandLine0",
|
||||||
CC"(Ljava/lang/String;C[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
|
CC"(Ljava/lang/String;C[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
|
||||||
|
@ -1356,6 +1374,8 @@ static JNINativeMethod methods[] = {
|
||||||
{CC"g1StartConcMarkCycle", CC"()Z", (void*)&WB_G1StartMarkCycle },
|
{CC"g1StartConcMarkCycle", CC"()Z", (void*)&WB_G1StartMarkCycle },
|
||||||
{CC"g1AuxiliaryMemoryUsage", CC"()Ljava/lang/management/MemoryUsage;",
|
{CC"g1AuxiliaryMemoryUsage", CC"()Ljava/lang/management/MemoryUsage;",
|
||||||
(void*)&WB_G1AuxiliaryMemoryUsage },
|
(void*)&WB_G1AuxiliaryMemoryUsage },
|
||||||
|
{CC"psVirtualSpaceAlignment",CC"()J", (void*)&WB_PSVirtualSpaceAlignment},
|
||||||
|
{CC"psHeapGenerationAlignment",CC"()J", (void*)&WB_PSHeapGenerationAlignment},
|
||||||
#endif // INCLUDE_ALL_GCS
|
#endif // INCLUDE_ALL_GCS
|
||||||
#if INCLUDE_NMT
|
#if INCLUDE_NMT
|
||||||
{CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc },
|
{CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc },
|
||||||
|
|
115
hotspot/test/gc/arguments/GCTypes.java
Normal file
115
hotspot/test/gc/arguments/GCTypes.java
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
299
hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java
Normal file
299
hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
182
hotspot/test/gc/arguments/TestNewRatioFlag.java
Normal file
182
hotspot/test/gc/arguments/TestNewRatioFlag.java
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
296
hotspot/test/gc/arguments/TestNewSizeFlags.java
Normal file
296
hotspot/test/gc/arguments/TestNewSizeFlags.java
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
182
hotspot/test/gc/arguments/TestSurvivorRatioFlag.java
Normal file
182
hotspot/test/gc/arguments/TestSurvivorRatioFlag.java
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
319
hotspot/test/gc/arguments/TestTargetSurvivorRatioFlag.java
Normal file
319
hotspot/test/gc/arguments/TestTargetSurvivorRatioFlag.java
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
116
hotspot/test/testlibrary/jdk/test/lib/AllocationHelper.java
Normal file
116
hotspot/test/testlibrary/jdk/test/lib/AllocationHelper.java
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
107
hotspot/test/testlibrary/jdk/test/lib/HeapRegionUsageTool.java
Normal file
107
hotspot/test/testlibrary/jdk/test/lib/HeapRegionUsageTool.java
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue