# HG changeset patch # User mtobiass # Date 1397677219 25200 # Node ID 754ee146b6238e54c4e963a8f564a45591bff650 # Parent 0c547f072113f2cac146cdab8f26c7a5f2c8d6d0 8030628: Update java/lang/management/MemoryMXBean tests to ignore GC setting by jtreg Reviewed-by: mchung, jbachorik Contributed-by: Mattias Tobiasson diff -r 0c547f072113 -r 754ee146b623 jdk/test/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java --- a/jdk/test/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java Wed Apr 16 11:56:58 2014 +0100 +++ b/jdk/test/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java Wed Apr 16 12:40:19 2014 -0700 @@ -30,11 +30,9 @@ * * @author Mandy Chung * - * @build CollectionUsageThreshold MemoryUtil - * @run main/othervm/timeout=300 -XX:+PrintGCDetails -XX:+UseSerialGC CollectionUsageThreshold - * @run main/othervm/timeout=300 -XX:+PrintGCDetails -XX:+UseParallelGC CollectionUsageThreshold - * @run main/othervm/timeout=300 -XX:+PrintGCDetails -XX:+UseG1GC CollectionUsageThreshold - * @run main/othervm/timeout=300 -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC CollectionUsageThreshold + * @library /lib/testlibrary/ + * @build CollectionUsageThreshold MemoryUtil RunUtil + * @run main/timeout=300 CollectionUsageThreshold */ import java.util.*; @@ -61,6 +59,20 @@ // finishes checking the low memory notification result private static final CyclicBarrier barrier = new CyclicBarrier(2); + /** + * Run the test multiple times with different GC versions. + * First with default command line specified by the framework. + * Then with GC versions specified by the test. + */ + public static void main(String a[]) throws Throwable { + final String main = "CollectionUsageThreshold$TestMain"; + RunUtil.runTestKeepGcOpts(main); + RunUtil.runTestClearGcOpts(main, "-XX:+UseSerialGC"); + RunUtil.runTestClearGcOpts(main, "-XX:+UseParallelGC"); + RunUtil.runTestClearGcOpts(main, "-XX:+UseG1GC"); + RunUtil.runTestClearGcOpts(main, "-XX:+UseConcMarkSweepGC"); + } + static class PoolRecord { private final MemoryPoolMXBean pool; private final AtomicInteger listenerInvoked = new AtomicInteger(0); @@ -110,88 +122,90 @@ } } - public static void main(String args[]) throws Exception { - if (args.length > 0 && args[0].equals("trace")) { - trace = true; - } + private static class TestMain { + public static void main(String args[]) throws Exception { + if (args.length > 0 && args[0].equals("trace")) { + trace = true; + } - List pools = getMemoryPoolMXBeans(); - List managers = getMemoryManagerMXBeans(); + List pools = getMemoryPoolMXBeans(); + List managers = getMemoryManagerMXBeans(); - if (trace) { - MemoryUtil.printMemoryPools(pools); - MemoryUtil.printMemoryManagers(managers); - } + if (trace) { + MemoryUtil.printMemoryPools(pools); + MemoryUtil.printMemoryManagers(managers); + } - // Find the Old generation which supports low memory detection - for (MemoryPoolMXBean p : pools) { - if (p.isUsageThresholdSupported() && p.isCollectionUsageThresholdSupported()) { - if (p.getName().toLowerCase().contains("perm")) { - // if we have a "perm gen" pool increase the number of expected - // memory pools by one. - numMemoryPools++; - } - PoolRecord pr = new PoolRecord(p); - result.put(p.getName(), pr); - if (result.size() == numMemoryPools) { - break; + // Find the Old generation which supports low memory detection + for (MemoryPoolMXBean p : pools) { + if (p.isUsageThresholdSupported() && p.isCollectionUsageThresholdSupported()) { + if (p.getName().toLowerCase().contains("perm")) { + // if we have a "perm gen" pool increase the number of expected + // memory pools by one. + numMemoryPools++; + } + PoolRecord pr = new PoolRecord(p); + result.put(p.getName(), pr); + if (result.size() == numMemoryPools) { + break; + } } } - } - if (result.size() != numMemoryPools) { - throw new RuntimeException("Unexpected number of selected pools"); + if (result.size() != numMemoryPools) { + throw new RuntimeException("Unexpected number of selected pools"); + } + + try { + // This test creates a checker thread responsible for checking + // the low memory notifications. It blocks until a permit + // from the signals semaphore is available. + Checker checker = new Checker("Checker thread"); + checker.setDaemon(true); + checker.start(); + + for (PoolRecord pr : result.values()) { + pr.getPool().setCollectionUsageThreshold(THRESHOLD); + System.out.println("Collection usage threshold of " + + pr.getPool().getName() + " set to " + THRESHOLD); + } + + SensorListener listener = new SensorListener(); + NotificationEmitter emitter = (NotificationEmitter) mm; + emitter.addNotificationListener(listener, null, null); + + // The main thread invokes GC to trigger the VM to perform + // low memory detection and then waits until the checker thread + // finishes its work to check for a low-memory notification. + // + // At GC time, VM will issue low-memory notification and invoke + // the listener which will release a permit to the signals semaphore. + // When the checker thread acquires the permit and finishes + // checking the low-memory notification, it will also call + // barrier.await() to signal the main thread to resume its work. + for (int i = 0; i < NUM_GCS; i++) { + invokeGC(); + barrier.await(); + } + } finally { + // restore the default + for (PoolRecord pr : result.values()) { + pr.getPool().setCollectionUsageThreshold(0); + } + } + System.out.println(RunUtil.successMessage); } - try { - // This test creates a checker thread responsible for checking - // the low memory notifications. It blocks until a permit - // from the signals semaphore is available. - Checker checker = new Checker("Checker thread"); - checker.setDaemon(true); - checker.start(); - for (PoolRecord pr : result.values()) { - pr.getPool().setCollectionUsageThreshold(THRESHOLD); - System.out.println("Collection usage threshold of " + - pr.getPool().getName() + " set to " + THRESHOLD); - } - - SensorListener listener = new SensorListener(); - NotificationEmitter emitter = (NotificationEmitter) mm; - emitter.addNotificationListener(listener, null, null); + private static void invokeGC() { + System.out.println("Calling System.gc()"); + numGCs++; + mm.gc(); - // The main thread invokes GC to trigger the VM to perform - // low memory detection and then waits until the checker thread - // finishes its work to check for a low-memory notification. - // - // At GC time, VM will issue low-memory notification and invoke - // the listener which will release a permit to the signals semaphore. - // When the checker thread acquires the permit and finishes - // checking the low-memory notification, it will also call - // barrier.await() to signal the main thread to resume its work. - for (int i = 0; i < NUM_GCS; i++) { - invokeGC(); - barrier.await(); - } - } finally { - // restore the default - for (PoolRecord pr : result.values()) { - pr.getPool().setCollectionUsageThreshold(0); - } - } - System.out.println("Test passed."); - } - - - private static void invokeGC() { - System.out.println("Calling System.gc()"); - numGCs++; - mm.gc(); - - if (trace) { - for (PoolRecord pr : result.values()) { - System.out.println("Usage after GC for: " + pr.getPool().getName()); - MemoryUtil.printMemoryUsage(pr.getPool().getUsage()); + if (trace) { + for (PoolRecord pr : result.values()) { + System.out.println("Usage after GC for: " + pr.getPool().getName()); + MemoryUtil.printMemoryUsage(pr.getPool().getUsage()); + } } } } diff -r 0c547f072113 -r 754ee146b623 jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java --- a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java Wed Apr 16 11:56:58 2014 +0100 +++ b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java Wed Apr 16 12:40:19 2014 -0700 @@ -30,11 +30,9 @@ * * @author Mandy Chung * - * @build LowMemoryTest MemoryUtil - * @run main/othervm/timeout=600 LowMemoryTest - * @run main/othervm/timeout=600 -XX:+UseConcMarkSweepGC LowMemoryTest - * @run main/othervm/timeout=600 -XX:+UseParallelGC LowMemoryTest - * @run main/othervm/timeout=600 -XX:+UseSerialGC LowMemoryTest + * @library /lib/testlibrary/ + * @build LowMemoryTest MemoryUtil RunUtil + * @run main/timeout=600 LowMemoryTest */ import java.lang.management.*; @@ -54,6 +52,20 @@ private static final int NUM_CHUNKS = 2; private static long chunkSize; + /** + * Run the test multiple times with different GC versions. + * First with default command line specified by the framework. + * Then with GC versions specified by the test. + */ + public static void main(String a[]) throws Throwable { + final String main = "LowMemoryTest$TestMain"; + RunUtil.runTestKeepGcOpts(main); + RunUtil.runTestClearGcOpts(main, "-XX:+UseSerialGC"); + RunUtil.runTestClearGcOpts(main, "-XX:+UseParallelGC"); + RunUtil.runTestClearGcOpts(main, "-XX:+UseG1GC"); + RunUtil.runTestClearGcOpts(main, "-XX:+UseConcMarkSweepGC"); + } + private static volatile boolean listenerInvoked = false; static class SensorListener implements NotificationListener { @Override @@ -107,77 +119,80 @@ } private static long newThreshold; - public static void main(String args[]) throws Exception { - if (args.length > 0 && args[0].equals("trace")) { - trace = true; - } - // Find the Old generation which supports low memory detection - ListIterator iter = pools.listIterator(); - while (iter.hasNext()) { - MemoryPoolMXBean p = (MemoryPoolMXBean) iter.next(); - if (p.getType() == MemoryType.HEAP && - p.isUsageThresholdSupported()) { - mpool = p; - if (trace) { - System.out.println("Selected memory pool for low memory " + - "detection."); - MemoryUtil.printMemoryPool(mpool); - } - break; + private static class TestMain { + public static void main(String args[]) throws Exception { + if (args.length > 0 && args[0].equals("trace")) { + trace = true; } - } - TestListener listener = new TestListener(); - SensorListener l2 = new SensorListener(); - NotificationEmitter emitter = (NotificationEmitter) mm; - emitter.addNotificationListener(listener, null, null); - emitter.addNotificationListener(l2, null, null); - - Thread allocator = new AllocatorThread(); - Thread sweeper = new SweeperThread(); + // Find the Old generation which supports low memory detection + ListIterator iter = pools.listIterator(); + while (iter.hasNext()) { + MemoryPoolMXBean p = (MemoryPoolMXBean) iter.next(); + if (p.getType() == MemoryType.HEAP && + p.isUsageThresholdSupported()) { + mpool = p; + if (trace) { + System.out.println("Selected memory pool for low memory " + + "detection."); + MemoryUtil.printMemoryPool(mpool); + } + break; + } + } - // Now set threshold - MemoryUsage mu = mpool.getUsage(); - chunkSize = (mu.getMax() - mu.getUsed()) / 20; - newThreshold = mu.getUsed() + (chunkSize * NUM_CHUNKS); + TestListener listener = new TestListener(); + SensorListener l2 = new SensorListener(); + NotificationEmitter emitter = (NotificationEmitter) mm; + emitter.addNotificationListener(listener, null, null); + emitter.addNotificationListener(l2, null, null); + + Thread allocator = new AllocatorThread(); + Thread sweeper = new SweeperThread(); - System.out.println("Setting threshold for " + mpool.getName() + - " from " + mpool.getUsageThreshold() + " to " + newThreshold + - ". Current used = " + mu.getUsed()); - mpool.setUsageThreshold(newThreshold); + // Now set threshold + MemoryUsage mu = mpool.getUsage(); + chunkSize = (mu.getMax() - mu.getUsed()) / 20; + newThreshold = mu.getUsed() + (chunkSize * NUM_CHUNKS); - if (mpool.getUsageThreshold() != newThreshold) { - throw new RuntimeException("TEST FAILED: " + + System.out.println("Setting threshold for " + mpool.getName() + + " from " + mpool.getUsageThreshold() + " to " + newThreshold + + ". Current used = " + mu.getUsed()); + mpool.setUsageThreshold(newThreshold); + + if (mpool.getUsageThreshold() != newThreshold) { + throw new RuntimeException("TEST FAILED: " + "Threshold for Memory pool " + mpool.getName() + "is " + mpool.getUsageThreshold() + " but expected to be" + newThreshold); - } + } - allocator.start(); - // Force Allocator start first - phaser.arriveAndAwaitAdvance(); - sweeper.start(); + allocator.start(); + // Force Allocator start first + phaser.arriveAndAwaitAdvance(); + sweeper.start(); - try { - allocator.join(); - // Wait until AllocatorThread's done - phaser.arriveAndAwaitAdvance(); - sweeper.join(); - } catch (InterruptedException e) { - System.out.println("Unexpected exception:" + e); - testFailed = true; + try { + allocator.join(); + // Wait until AllocatorThread's done + phaser.arriveAndAwaitAdvance(); + sweeper.join(); + } catch (InterruptedException e) { + System.out.println("Unexpected exception:" + e); + testFailed = true; + } + + listener.checkResult(); + + if (testFailed) + throw new RuntimeException("TEST FAILED."); + + System.out.println(RunUtil.successMessage); + } - - listener.checkResult(); - - if (testFailed) - throw new RuntimeException("TEST FAILED."); - - System.out.println("Test passed."); - } private static void goSleep(long ms) { diff -r 0c547f072113 -r 754ee146b623 jdk/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java --- a/jdk/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java Wed Apr 16 11:56:58 2014 +0100 +++ b/jdk/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java Wed Apr 16 12:40:19 2014 -0700 @@ -32,11 +32,9 @@ * @summary Basic Test for MemoryPool.resetPeakUsage() * @author Mandy Chung * - * @build ResetPeakMemoryUsage MemoryUtil - * @run main/othervm -XX:+PrintGCDetails -XX:+UseSerialGC -Xms256m -XX:MarkSweepAlwaysCompactCount=1 -Xmn8m ResetPeakMemoryUsage - * @run main/othervm -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC -Xms256m -Xmn8m ResetPeakMemoryUsage - * @run main/othervm -XX:+PrintGCDetails -XX:+UseParallelGC -Xms256m -Xmn8m ResetPeakMemoryUsage - * @run main/othervm -XX:+PrintGCDetails -XX:+UseG1GC -Xms256m -Xmn8m -XX:G1HeapRegionSize=1m ResetPeakMemoryUsage + * @library /lib/testlibrary/ + * @build ResetPeakMemoryUsage MemoryUtil RunUtil + * @run main ResetPeakMemoryUsage */ import java.lang.management.*; @@ -47,24 +45,42 @@ // make public so that it can't be optimized away easily public static Object[] obj; - public static void main(String[] argv) { - List pools = ManagementFactory.getMemoryPoolMXBeans(); - ListIterator iter = pools.listIterator(); - boolean found = false; - while (iter.hasNext()) { - MemoryPoolMXBean p = (MemoryPoolMXBean) iter.next(); - // only check heap pools that support usage threshold - // this is typically only the old generation space - // since the other spaces are expected to get filled up - if (p.getType() == MemoryType.HEAP && - p.isUsageThresholdSupported()) - { - found = true; - testPool(p); + /** + * Run the test multiple times with different GC versions. + * First with default command line specified by the framework. + * Then with all GC versions specified by the test. + */ + public static void main(String a[]) throws Throwable { + final String main = "ResetPeakMemoryUsage$TestMain"; + final String ms = "-Xms256m"; + final String mn = "-Xmn8m"; + RunUtil.runTestClearGcOpts(main, ms, mn, "-XX:+UseConcMarkSweepGC"); + RunUtil.runTestClearGcOpts(main, ms, mn, "-XX:+UseParallelGC"); + RunUtil.runTestClearGcOpts(main, ms, mn, "-XX:+UseG1GC", "-XX:G1HeapRegionSize=1m"); + RunUtil.runTestClearGcOpts(main, ms, mn, "-XX:+UseSerialGC", + "-XX:MarkSweepAlwaysCompactCount=1"); + } + + private static class TestMain { + public static void main(String[] argv) { + List pools = ManagementFactory.getMemoryPoolMXBeans(); + ListIterator iter = pools.listIterator(); + boolean found = false; + while (iter.hasNext()) { + MemoryPoolMXBean p = (MemoryPoolMXBean) iter.next(); + // only check heap pools that support usage threshold + // this is typically only the old generation space + // since the other spaces are expected to get filled up + if (p.getType() == MemoryType.HEAP && + p.isUsageThresholdSupported()) + { + found = true; + testPool(p); + } } - } - if (!found) { - throw new RuntimeException("No heap pool found"); + if (!found) { + throw new RuntimeException("No heap pool found"); + } } } @@ -142,7 +158,7 @@ formatSize("previous peak", peak2.getUsed())); } - System.out.println("Test passed."); + System.out.println(RunUtil.successMessage); } private static String INDENT = " "; diff -r 0c547f072113 -r 754ee146b623 jdk/test/java/lang/management/MemoryMXBean/RunUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/management/MemoryMXBean/RunUtil.java Wed Apr 16 12:40:19 2014 -0700 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * Utility class for launching a test in a separate JVM. + */ + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import jdk.testlibrary.OutputAnalyzer; +import jdk.testlibrary.Utils; +import jdk.testlibrary.ProcessTools; +import jdk.testlibrary.JDKToolFinder; + +public class RunUtil { + + // Used to mark that the test has passed successfully. + public static final String successMessage = "Test passed."; + + public static void runTestClearGcOpts(String main, String... testOpts) throws Throwable { + runTest(main, true, testOpts); + } + + public static void runTestKeepGcOpts(String main, String... testOpts) throws Throwable { + runTest(main, false, testOpts); + } + + /** + * Runs a test in a separate JVM. + * command line like: + * {test_jdk}/bin/java {defaultopts} -cp {test.class.path} {testopts} main + * + * {defaultopts} are the default java options set by the framework. + * Default GC options in {defaultopts} may be removed. + * This is used when the test specifies its own GC options. + * + * @param main Name of the main class. + * @param clearGcOpts true if the default GC options should be removed. + * @param testOpts java options specified by the test. + */ + private static void runTest(String main, boolean clearGcOpts, String... testOpts) + throws Throwable { + List opts = new ArrayList<>(); + opts.add(JDKToolFinder.getJDKTool("java")); + opts.addAll(Arrays.asList(Utils.getTestJavaOpts())); + opts.add("-cp"); + opts.add(System.getProperty("test.class.path", "test.class.path")); + opts.add("-XX:+PrintGCDetails"); + + if (clearGcOpts) { + opts = Utils.removeGcOpts(opts); + } + opts.addAll(Arrays.asList(testOpts)); + opts.add(main); + + OutputAnalyzer output = ProcessTools.executeProcess(opts.toArray(new String[0])); + output.shouldHaveExitValue(0); + if (output.getStdout().indexOf(successMessage) < 0) { + throw new Exception("output missing '" + successMessage + "'"); + } + } + +} diff -r 0c547f072113 -r 754ee146b623 jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java --- a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java Wed Apr 16 11:56:58 2014 +0100 +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java Wed Apr 16 12:40:19 2014 -0700 @@ -120,6 +120,26 @@ } /** + * Removes any options specifying which GC to use, for example "-XX:+UseG1GC". + * Removes any options matching: -XX:(+/-)Use*GC + * Used when a test need to set its own GC version. Then any + * GC specified by the framework must first be removed. + * @return A copy of given opts with all GC options removed. + */ + private static final Pattern useGcPattern = Pattern.compile("\\-XX\\:[\\+\\-]Use.+GC"); + public static List removeGcOpts(List opts) { + List optsWithoutGC = new ArrayList(); + for (String opt : opts) { + if (useGcPattern.matcher(opt).matches()) { + System.out.println("removeGcOpts: removed " + opt); + } else { + optsWithoutGC.add(opt); + } + } + return optsWithoutGC; + } + + /** * Splits a string by white space. * Works like String.split(), but returns an empty array * if the string is null or empty.