Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/test/gc/stress/gclocker/TestExcessGCLockerCollections.java
32285 views
/*1* Copyright (c) 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 gc.stress.gclocker;2425// Based on Kim Barrett;s test for JDK-80485562627/*28* @test TestExcessGCLockerCollections29* @key gc30* @bug 804855631* @summary Check for GC Locker initiated GCs that immediately follow another32* GC and so have very little needing to be collected.33* @library /testlibrary34* @run driver/timeout=1000 gc.stress.gclocker.TestExcessGCLockerCollections 300 4 235*/3637import java.util.HashMap;38import java.util.Map;3940import java.util.zip.Deflater;4142import java.util.ArrayList;43import java.util.Arrays;4445import javax.management.MBeanServer;46import javax.management.Notification;47import javax.management.NotificationListener;48import javax.management.openmbean.CompositeData;49import java.lang.management.ManagementFactory;50import java.lang.management.GarbageCollectorMXBean;51import java.lang.management.MemoryUsage;52import java.util.List;53import com.sun.management.GarbageCollectionNotificationInfo;54import com.sun.management.GcInfo;5556import com.oracle.java.testlibrary.Asserts;57import com.oracle.java.testlibrary.ProcessTools;58import com.oracle.java.testlibrary.OutputAnalyzer;5960class TestExcessGCLockerCollectionsStringConstants {61// Some constant strings used in both GC logging and error detection62static public final String GCLOCKER_CAUSE = "GCLocker Initiated GC";63static public final String USED_TOO_LOW = "TOO LOW";64static public final String USED_OK = "OK";65}6667class TestExcessGCLockerCollectionsAux {68static private final int LARGE_MAP_SIZE = 64 * 1024;6970static private final int MAP_ARRAY_LENGTH = 4;71static private final int MAP_SIZE = 1024;7273static private final int BYTE_ARRAY_LENGTH = 128 * 1024;7475static private void println(String str) { System.out.println(str); }76static private void println() { System.out.println(); }7778static private volatile boolean keepRunning = true;7980static Map<Integer,String> populateMap(int size) {81Map<Integer,String> map = new HashMap<Integer,String>();82for (int i = 0; i < size; i += 1) {83Integer keyInt = Integer.valueOf(i);84String valStr = "value is [" + i + "]";85map.put(keyInt,valStr);86}87return map;88}8990static private class AllocatingWorker implements Runnable {91private final Object[] array = new Object[MAP_ARRAY_LENGTH];92private int arrayIndex = 0;9394private void doStep() {95Map<Integer,String> map = populateMap(MAP_SIZE);96array[arrayIndex] = map;97arrayIndex = (arrayIndex + 1) % MAP_ARRAY_LENGTH;98}99100public void run() {101while (keepRunning) {102doStep();103}104}105}106107static private class JNICriticalWorker implements Runnable {108private int count;109110private void doStep() {111byte[] inputArray = new byte[BYTE_ARRAY_LENGTH];112for (int i = 0; i < inputArray.length; i += 1) {113inputArray[i] = (byte) (count + i);114}115116Deflater deflater = new Deflater();117deflater.setInput(inputArray);118deflater.finish();119120byte[] outputArray = new byte[2 * inputArray.length];121deflater.deflate(outputArray);122123count += 1;124}125126public void run() {127while (keepRunning) {128doStep();129}130}131}132133static class GCNotificationListener implements NotificationListener {134static private final double MIN_USED_PERCENT = 40.0;135136static private final List<String> newGenPoolNames = Arrays.asList(137"G1 Eden Space", // OpenJDK G1GC: -XX:+UseG1GC138"PS Eden Space", // OpenJDK ParallelGC: -XX:+ParallelGC139"Par Eden Space", // OpenJDK ConcMarkSweepGC: -XX:+ConcMarkSweepGC140"Eden Space" // OpenJDK SerialGC: -XX:+UseSerialGC141// OpenJDK ConcMarkSweepGC: -XX:+ConcMarkSweepGC -XX:-UseParNewGC142);143144@Override145public void handleNotification(Notification notification, Object handback) {146try {147if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {148GarbageCollectionNotificationInfo info =149GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData());150151String gc_cause = info.getGcCause();152153if (gc_cause.equals(TestExcessGCLockerCollectionsStringConstants.GCLOCKER_CAUSE)) {154Map<String, MemoryUsage> memory_before_gc = info.getGcInfo().getMemoryUsageBeforeGc();155156for (String newGenPoolName : newGenPoolNames) {157MemoryUsage usage = memory_before_gc.get(newGenPoolName);158if (usage == null) continue;159160double startTime = ((double) info.getGcInfo().getStartTime()) / 1000.0;161long used = usage.getUsed();162long committed = usage.getCommitted();163long max = usage.getMax();164double used_percent = (((double) used) / Math.max(committed, max)) * 100.0;165166System.out.printf("%6.3f: (%s) %d/%d/%d, %8.4f%% (%s)\n",167startTime, gc_cause, used, committed, max, used_percent,168((used_percent < MIN_USED_PERCENT) ? TestExcessGCLockerCollectionsStringConstants.USED_TOO_LOW169: TestExcessGCLockerCollectionsStringConstants.USED_OK));170}171}172}173} catch (RuntimeException ex) {174System.err.println("Exception during notification processing:" + ex);175ex.printStackTrace();176}177}178179public static boolean register() {180try {181MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();182183// Get the list of MX184List<GarbageCollectorMXBean> gc_mxbeans = ManagementFactory.getGarbageCollectorMXBeans();185186// Create the notification listener187GCNotificationListener gcNotificationListener = new GCNotificationListener();188189for (GarbageCollectorMXBean gcbean : gc_mxbeans) {190// Add notification listener for the MXBean191mbeanServer.addNotificationListener(gcbean.getObjectName(), gcNotificationListener, null, null);192}193} catch (Exception ex) {194System.err.println("Exception during mbean registration:" + ex);195ex.printStackTrace();196// We've failed to set up, terminate197return false;198}199200return true;201}202}203204static public Map<Integer,String> largeMap;205206static public void main(String args[]) {207long durationSec = Long.parseLong(args[0]);208int allocThreadNum = Integer.parseInt(args[1]);209int jniCriticalThreadNum = Integer.parseInt(args[2]);210211println("Running for " + durationSec + " secs");212213if (!GCNotificationListener.register()) {214println("failed to register GC notification listener");215System.exit(-1);216}217218largeMap = populateMap(LARGE_MAP_SIZE);219220println("Starting " + allocThreadNum + " allocating threads");221for (int i = 0; i < allocThreadNum; i += 1) {222new Thread(new AllocatingWorker()).start();223}224225println("Starting " + jniCriticalThreadNum + " jni critical threads");226for (int i = 0; i < jniCriticalThreadNum; i += 1) {227new Thread(new JNICriticalWorker()).start();228}229230long durationMS = (long) (1000 * durationSec);231long start = System.currentTimeMillis();232long now = start;233long soFar = now - start;234while (soFar < durationMS) {235try {236Thread.sleep(durationMS - soFar);237} catch (Exception e) {238}239now = System.currentTimeMillis();240soFar = now - start;241}242println("Done.");243keepRunning = false;244}245}246247public class TestExcessGCLockerCollections {248private static final String USED_OK_LINE =249"\\(" + TestExcessGCLockerCollectionsStringConstants.GCLOCKER_CAUSE + "\\)"250+ " .* " +251"\\(" + TestExcessGCLockerCollectionsStringConstants.USED_OK + "\\)";252private static final String USED_TOO_LOW_LINE =253"\\(" + TestExcessGCLockerCollectionsStringConstants.GCLOCKER_CAUSE + "\\)"254+ " .* " +255"\\(" + TestExcessGCLockerCollectionsStringConstants.USED_TOO_LOW + "\\)";256257private static final String[] COMMON_OPTIONS = new String[] {258"-Xmx1G", "-Xms1G", "-Xmn256M" };259260public static void main(String args[]) throws Exception {261if (args.length < 3) {262System.out.println("usage: TestExcessGCLockerCollections" +263" <duration sec> <alloc threads>" +264" <jni critical threads>");265throw new RuntimeException("Invalid arguments");266}267268ArrayList<String> finalArgs = new ArrayList<String>();269finalArgs.addAll(Arrays.asList(COMMON_OPTIONS));270finalArgs.add(TestExcessGCLockerCollectionsAux.class.getName());271finalArgs.addAll(Arrays.asList(args));272273// GC and other options obtained from test framework.274ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(275true, finalArgs.toArray(new String[0]));276OutputAnalyzer output = new OutputAnalyzer(pb.start());277output.shouldHaveExitValue(0);278//System.out.println("------------- begin stdout ----------------");279//System.out.println(output.getStdout());280//System.out.println("------------- end stdout ----------------");281output.stdoutShouldMatch(USED_OK_LINE);282output.stdoutShouldNotMatch(USED_TOO_LOW_LINE);283}284}285286287