Path: blob/master/test/hotspot/jtreg/vmTestbase/metaspace/gc/HighWaterMarkTest.java
41155 views
/*1* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package metaspace.gc;2425import java.util.Arrays;26import vm.share.VMRuntimeEnvUtils;2728/**29* Test metaspace ergonomic.30*31* <ul>32* <li>MetaspaceSize33* <li>MaxMetaspaceSize34* <li>MinMetaspaceFreeRatio35* <li>MaxMetaspaceFreeRatio36* </ul>37*38* The test loads classes until the committed metaspace achieves the certain39* level between MetaspaceSize and MaxMetaspaceSize.40* Then it counts how many times GC has been induced.41* Test verifies that MinMetaspaceFreeRatio/MaxMetaspaceFreeRatio settings42* affect the frequency of GC. (High-water mark)43*44* Quoting: Java SE 8 HotSpot[tm] Virtual Machine Garbage Collection Tuning45* <pre>46* Class metadata is deallocated when the corresponding Java class is unloaded.47* Java classes are unloaded as a results of garbage collection and garbage48* collections may be induced in order to unload classes and deallocate class49* metadata. When the space used for class metadata reaches a certain level50* (call it a high-water mark), a garbage collection is induced.51* After the garbage collection the high-water mark may be raised or lowered52* depending on the amount of space freed from class metadata. The high-water53* mark would be raised so as not to induce another garbage collection too soon.54* The high-water mark is initially set to the value of the command-line55* flag MetaspaceSize . It is raised or lowered based on the flags56* MaxMetaspaceFreeRatio and MinMetaspaceFreeRatio.57* If the committed space available for class metadata as a percentage of58* the total committed space for class metadata is greater than59* MaxMetaspaceFreeRatio, the high-water mark will be lowered.60* If it is less than MinMetaspaceFreeRatio, the high-water mark will be raised.61* </pre>62*/63public class HighWaterMarkTest extends FirstGCTest {6465public static void main(String... args) {66new HighWaterMarkTest().run(args);67}6869// value given in -XX:MetaspaceSize=<value>70private long metaspaceSize = -1;7172// value given in -XX:MaxMetaspaceSize=<value>73private long maxMetaspaceSize = -1;7475// value given in -XX:MinMetaspaceFreeRatio=<value>76private long minMetaspaceFreeRatio = -1;7778// value given in -XX:MaxMetaspaceFreeRatio=<value>79private long maxMetaspaceFreeRatio = -1;8081/**82* Parses arguments and vm options.83* Throws Fault in cases of wrong values or missed parameters.84*85* @param args command line options86*/87@Override88protected void parseArgs(String[] args) {89if (args.length > 0) {90printUsage();91throw new Fault("Illegal arguments: " + Arrays.asList(args));92}9394if (gclogFileName == null) {95printUsage();96throw new Fault("Log file name is not given");97}9899final String metaSize = "-XX:MetaspaceSize=";100final String maxMetaSize = "-XX:MaxMetaspaceSize=";101final String minRatio = "-XX:MinMetaspaceFreeRatio=";102final String maxRatio = "-XX:MaxMetaspaceFreeRatio=";103104for (String va: vmArgs) {105if (va.startsWith(metaSize)) {106metaspaceSize = parseValue(va.substring(metaSize.length()));107} else if (va.startsWith(maxMetaSize)) {108maxMetaspaceSize = parseValue(va.substring(maxMetaSize.length()));109} else if (va.startsWith(minRatio)) {110minMetaspaceFreeRatio = parseValue(va.substring(minRatio.length()));111} else if (va.startsWith(maxRatio)) {112maxMetaspaceFreeRatio = parseValue(va.substring(maxRatio.length()));113}114}115116if (metaspaceSize < 0) {117printUsage();118throw new Fault("-XX:MetaspaceSize is not specified");119} else if (maxMetaspaceSize < 0) {120printUsage();121throw new Fault("-XX:MaxMetaspaceSize is not specified");122} else if (minMetaspaceFreeRatio < 0) {123printUsage();124throw new Fault("-XX:MinMetaspaceFreeRatio is not specified");125} else if (maxMetaspaceFreeRatio < 0) {126printUsage();127throw new Fault("-XX:MaxMetaspaceFreeRatio is not specified");128}129130}131132private void printUsage() {133System.err.println("Usage: ");134System.err.println("java [-Xlog:gc:<filename>] [-XX:MetaspaceSize=..] [-XX:MaxMetaspaceSize=..] [-XX:MinMetaspaceFreeRatio=..] [-XX:MaxMetaspaceFreeRatio=..] \\");135System.err.println(" " + HighWaterMarkTest.class.getCanonicalName());136}137138/**139* Check that MinMetaspaceFreeRatio/MaxMetaspaceFreeRatio settings140* affects the moment of the next GC.141*142* Eats memory until amount of committed metaspace achieves a certain level143* (between MetaspaceSize and MaxMetaspaceSize).144* Then checks how many times GC has been invoked.145*146*/147@Override148public void doCheck() {149150// to avoid timeouts we limit the number of attempts151int attempts = 0;152int maxAttempts = 10_000;153154// in between metaspaceSize and maxMetaspaceSize155// no OOM is exepcted.156long committedLevel = (metaspaceSize + maxMetaspaceSize) / 2;157158while (getCommitted() < committedLevel && attempts < maxAttempts) {159attempts++;160loadNewClasses(9, true); // load classes and keep references161loadNewClasses(1, false); // load classes without keeping references162}163164165System.out.println("% Classes loaded: " + attempts*10);166System.out.println("% Used metaspace : " + bytes2k(getUsed()));167System.out.println("% Committed metaspce: " + bytes2k(getCommitted()));168169cleanLoadedClasses();170171if (attempts == maxAttempts) {172throw new Fault("Committed amount hasn't achieved " + bytes2k(committedLevel));173}174175int gcCount = getMetaspaceGCCount();176if (gcCount < 0) {177// perhpas, it's better to silently pass here... Let's see.178throw new Fault ("Unable to count full collections, could be an env issue");179}180System.out.println("% GC has been invoked: " + gcCount + " times");181182if (maxMetaspaceFreeRatio <= 1) {183// min/max = 0/1 boundary value184// GC should happen very often185checkGCCount(gcCount, 20, -1);186} else if (minMetaspaceFreeRatio >= 99) {187// min/max = 99/100 boundary value188// GC should happen very rare189checkGCCount(gcCount, -1, 2);190} else if (minMetaspaceFreeRatio >= 10 && maxMetaspaceFreeRatio <= 20) {191// GC should happen quite often192checkGCCount(gcCount, 3, 30);193} else if (minMetaspaceFreeRatio >= 70 && maxMetaspaceFreeRatio <= 80) {194// GC should happen quite often195checkGCCount(gcCount, 1, 3);196} else {197// hard to estimate198}199200}201/**202* Checks that count of GC fits the expected range.203* Throws Fault if count is unexpected.204*205* @param count how many times GC has happened206* @param min expected minimum, if under zero - undefined207* @param max expected maximum, if under zero - undefined208*/209void checkGCCount(int count, int min, int max) {210if (min < 0) {211if(count > max) {212throw new Fault("GC has happened too often: " + count + " times, " +213"expected count: less than " + max);214}215} else if (max < 0) {216if(count < min) {217throw new Fault("GC has happened too rare: " + count + " times, " +218"expected count greater than " + min);219}220} else if (count < min || count > max ) {221throw new Fault ("GC has happened " + count + " times, " +222"approximate count is " + min + " to " + max);223}224}225226}227228229