Hi, This is just a backport from jdk9 to jdk8u. Could someone please review and push them?
The bug that needs to be fixed is: https://bugs.openjdk.java.net/browse/JDK-8030628 That patch depends on another patch that also has to be backported. I have added both patches in this review. Both patches were imported without changes. They are exactly as in jdk9. Webrevs: http://cr.openjdk.java.net/~ykantser/8029346/webrev.00/ http://cr.openjdk.java.net/~ykantser/8030628/webrev.00/ Bugs: https://bugs.openjdk.java.net/browse/JDK-8029346 https://bugs.openjdk.java.net/browse/JDK-8030628 I have attached the patches. Patch 8029346 must be applied before 8030628. Mattias
# HG changeset patch # User mtobiass # Date 1400083775 -7200 # Node ID ae9d0ba07243fb215f6f06b58d4d7661fdf6981e # Parent def6553ecc32f5664a5dfc3ee92a06099cb3bf31 8029346: LowMemoryTestConcMarkSweepGC.sh fails intermittently with timeout Summary: Backport from jdk 9 diff --git a/test/java/lang/management/MemoryMXBean/LowMemoryTest.java b/test/java/lang/management/MemoryMXBean/LowMemoryTest.java --- a/test/java/lang/management/MemoryMXBean/LowMemoryTest.java +++ b/test/java/lang/management/MemoryMXBean/LowMemoryTest.java @@ -32,17 +32,21 @@ * * @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 */ import java.lang.management.*; import java.util.*; +import java.util.concurrent.Phaser; import javax.management.*; import javax.management.openmbean.CompositeData; public class LowMemoryTest { - private static MemoryMXBean mm = ManagementFactory.getMemoryMXBean(); - private static List pools = ManagementFactory.getMemoryPoolMXBeans(); - private static List managers = ManagementFactory.getMemoryManagerMXBeans(); + private static final MemoryMXBean mm = ManagementFactory.getMemoryMXBean(); + private static final List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans(); + private static final Phaser phaser = new Phaser(2); private static MemoryPoolMXBean mpool = null; private static boolean trace = false; private static boolean testFailed = false; @@ -50,8 +54,9 @@ private static final int NUM_CHUNKS = 2; private static long chunkSize; - private static boolean listenerInvoked = false; + private static volatile boolean listenerInvoked = false; static class SensorListener implements NotificationListener { + @Override public void handleNotification(Notification notif, Object handback) { String type = notif.getType(); if (type.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED) || @@ -69,8 +74,9 @@ static class TestListener implements NotificationListener { private int triggers = 0; - private long[] count = new long[NUM_TRIGGERS * 2]; - private long[] usedMemory = new long[NUM_TRIGGERS * 2]; + private final long[] count = new long[NUM_TRIGGERS * 2]; + private final long[] usedMemory = new long[NUM_TRIGGERS * 2]; + @Override public void handleNotification(Notification notif, Object handback) { MemoryNotificationInfo minfo = MemoryNotificationInfo. from((CompositeData) notif.getUserData()); @@ -148,15 +154,20 @@ newThreshold); } + 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) { - e.printStackTrace(); - System.out.println("Unexpected exception."); + System.out.println("Unexpected exception:" + e); testFailed = true; } @@ -173,45 +184,17 @@ try { Thread.sleep(ms); } catch (InterruptedException e) { - e.printStackTrace(); - System.out.println("Unexpected exception."); + System.out.println("Unexpected exception:" + e); testFailed = true; } } - private static Object go = new Object(); - private static boolean waiting = false; // No thread is waiting. - - // Synchronizes two thread. If no thread is waiting then wait - // for notification from a different thread and if it is - // is waiting then send notification. - // In this test case this method is used to synchronize sweeper - // thread and alocater thread to reach a particular point. - private static void wait_or_notify() { - synchronized (go) { - if (waiting == false) { - waiting = true; - System.out.println(" Waiting "); - try { - go.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - testFailed = true; - } - waiting = false; - } else { - System.out.println(" Notify "); - go.notify(); - } - } - } - - private static List objectPool = new ArrayList(); + private static final List<Object> objectPool = new ArrayList<>(); static class AllocatorThread extends Thread { public void doTask() { int iterations = 0; int numElements = (int) (chunkSize / 4); // minimal object size - while (!listenerInvoked) { + while (!listenerInvoked || mpool.getUsage().getUsed() < mpool.getUsageThreshold()) { iterations++; if (trace) { System.out.println(" Iteration " + iterations + @@ -234,23 +217,25 @@ goSleep(100); } } + @Override public void run() { for (int i = 1; i <= NUM_TRIGGERS; i++) { - System.out.println("AllocatorThread is doing task " + i); + // Sync with SweeperThread's second phase. + phaser.arriveAndAwaitAdvance(); + System.out.println("AllocatorThread is doing task " + i + + " phase " + phaser.getPhase()); doTask(); - synchronized (sweep) { - sweep.notify(); + // Sync with SweeperThread's first phase. + phaser.arriveAndAwaitAdvance(); + System.out.println("AllocatorThread done task " + i + + " phase " + phaser.getPhase()); + if (testFailed) { + return; } - // System.out.print(" Allocater Thread "); - // If sweeper thread is waiting then send notify - // else wait for notification from sweeper thread. - wait_or_notify(); - if (testFailed) return; } } } - private static Object sweep = new Object(); static class SweeperThread extends Thread { private void doTask() { for (; mpool.getUsage().getUsed() >= @@ -261,28 +246,21 @@ goSleep(100); } } + @Override public void run() { for (int i = 1; i <= NUM_TRIGGERS; i++) { - synchronized (sweep) { - while (!listenerInvoked) { - try { - sweep.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - System.out.println("Unexpected exception."); - testFailed = true; - } - } - } - System.out.println("SweepThread is doing task " + i); + // Sync with AllocatorThread's first phase. + phaser.arriveAndAwaitAdvance(); + System.out.println("SweepThread is doing task " + i + + " phase " + phaser.getPhase()); doTask(); listenerInvoked = false; - // System.out.print(" Sweeper Thread "); - // If Allocater thread is waiting wait send notify - // else wait for notfication from allocater thread. - wait_or_notify(); + // Sync with AllocatorThread's second phase. + phaser.arriveAndAwaitAdvance(); + System.out.println("SweepThread done task " + i + + " phase " + phaser.getPhase()); if (testFailed) return; } } diff --git a/test/java/lang/management/MemoryMXBean/LowMemoryTestConcMarkSweepGC.sh b/test/java/lang/management/MemoryMXBean/LowMemoryTestConcMarkSweepGC.sh deleted file mode 100644 --- a/test/java/lang/management/MemoryMXBean/LowMemoryTestConcMarkSweepGC.sh +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright (c) 2003, 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 -# @bug 4530538 -# @summary Test LowMemoryTest with concurrent mark sweep GC -# @author Mandy Chung -# -# @run build LowMemoryTest -# @run shell/timeout=600 LowMemoryTestConcMarkSweepGC.sh -# - -#Set appropriate jdk - -if [ ! -z "${TESTJAVA}" ] ; then - jdk="$TESTJAVA" -else - echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test." - exit 1 -fi - -runOne() -{ - echo "runOne $@" - $TESTJAVA/bin/java ${TESTVMOPTS} -classpath $TESTCLASSES $@ || exit 2 -} - -# Test LowMemoryTest with concurrent collector -runOne -XX:+UseConcMarkSweepGC LowMemoryTest - -exit 0 diff --git a/test/java/lang/management/MemoryMXBean/LowMemoryTestParallelGC.sh b/test/java/lang/management/MemoryMXBean/LowMemoryTestParallelGC.sh deleted file mode 100644 --- a/test/java/lang/management/MemoryMXBean/LowMemoryTestParallelGC.sh +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright (c) 2003, 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 -# @bug 4530538 -# @summary Test LowMemoryTest with parallel GC -# @author Mandy Chung -# -# @run build LowMemoryTest -# @run shell/timeout=600 LowMemoryTestParallelGC.sh -# - -#Set appropriate jdk - -if [ ! -z "${TESTJAVA}" ] ; then - jdk="$TESTJAVA" -else - echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test." - exit 1 -fi - -runOne() -{ - echo "runOne $@" - $TESTJAVA/bin/java ${TESTVMOPTS} -classpath $TESTCLASSES $@ || exit 2 -} - -# Test LowMemoryTest with parallel scavenger collector -runOne -XX:+UseParallelGC LowMemoryTest - -exit 0 diff --git a/test/java/lang/management/MemoryMXBean/LowMemoryTestSerialGC.sh b/test/java/lang/management/MemoryMXBean/LowMemoryTestSerialGC.sh deleted file mode 100644 --- a/test/java/lang/management/MemoryMXBean/LowMemoryTestSerialGC.sh +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright (c) 2003, 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 -# @bug 4530538 -# @summary Test LowMemoryTest with Serial GC -# @author Mandy Chung -# -# @run build LowMemoryTest -# @run shell/timeout=600 LowMemoryTestSerialGC.sh -# - -#Set appropriate jdk - -if [ ! -z "${TESTJAVA}" ] ; then - jdk="$TESTJAVA" -else - echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test." - exit 1 -fi - -runOne() -{ - echo "runOne $@" - $TESTJAVA/bin/java ${TESTVMOPTS} -classpath $TESTCLASSES $@ || exit 2 -} - -# Test LowMemoryTest with serial collector -runOne -XX:+UseSerialGC LowMemoryTest - -exit 0
# HG changeset patch # User mtobiass # Date 1400084454 -7200 # Node ID a68d97a9718daf22e4c728bf5572edd307d6cab6 # Parent ae9d0ba07243fb215f6f06b58d4d7661fdf6981e 8030628: Update java/lang/management/MemoryMXBean tests to ignore GC setting by jtreg Summary: Run tests in separate JVM with controlled GC command line options. diff --git a/test/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java b/test/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java --- a/test/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java +++ b/test/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java @@ -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<MemoryPoolMXBean> pools = getMemoryPoolMXBeans(); + List<MemoryManagerMXBean> managers = getMemoryManagerMXBeans(); + + 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; + } + } + } + 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); } - List<MemoryPoolMXBean> pools = getMemoryPoolMXBeans(); - List<MemoryManagerMXBean> managers = getMemoryManagerMXBeans(); - if (trace) { - MemoryUtil.printMemoryPools(pools); - MemoryUtil.printMemoryManagers(managers); - } + private static void invokeGC() { + System.out.println("Calling System.gc()"); + numGCs++; + mm.gc(); - // 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++; + if (trace) { + for (PoolRecord pr : result.values()) { + System.out.println("Usage after GC for: " + pr.getPool().getName()); + MemoryUtil.printMemoryUsage(pr.getPool().getUsage()); } - 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"); - } - - 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("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()); } } } diff --git a/test/java/lang/management/MemoryMXBean/LowMemoryTest.java b/test/java/lang/management/MemoryMXBean/LowMemoryTest.java --- a/test/java/lang/management/MemoryMXBean/LowMemoryTest.java +++ b/test/java/lang/management/MemoryMXBean/LowMemoryTest.java @@ -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 && + private static class TestMain { + 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); + mpool = p; + if (trace) { + System.out.println("Selected memory pool for low memory " + + "detection."); + MemoryUtil.printMemoryPool(mpool); + } + break; } - break; } - } - TestListener listener = new TestListener(); - SensorListener l2 = new SensorListener(); - NotificationEmitter emitter = (NotificationEmitter) mm; - emitter.addNotificationListener(listener, null, null); - emitter.addNotificationListener(l2, null, null); + 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(); + Thread allocator = new AllocatorThread(); + Thread sweeper = new SweeperThread(); - // Now set threshold - MemoryUsage mu = mpool.getUsage(); - chunkSize = (mu.getMax() - mu.getUsed()) / 20; - newThreshold = mu.getUsed() + (chunkSize * NUM_CHUNKS); + // Now set threshold + MemoryUsage mu = mpool.getUsage(); + chunkSize = (mu.getMax() - mu.getUsed()) / 20; + newThreshold = mu.getUsed() + (chunkSize * NUM_CHUNKS); - System.out.println("Setting threshold for " + mpool.getName() + - " from " + mpool.getUsageThreshold() + " to " + newThreshold + - ". Current used = " + mu.getUsed()); - mpool.setUsageThreshold(newThreshold); + 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: " + + 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(); + + + 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); + } - - - 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; - } - - listener.checkResult(); - - if (testFailed) - throw new RuntimeException("TEST FAILED."); - - System.out.println("Test passed."); - } private static void goSleep(long ms) { diff --git a/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java b/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java --- a/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java +++ b/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java @@ -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 --git a/test/java/lang/management/MemoryMXBean/RunUtil.java b/test/java/lang/management/MemoryMXBean/RunUtil.java new file mode 100644 --- /dev/null +++ b/test/java/lang/management/MemoryMXBean/RunUtil.java @@ -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<String> 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 --git a/test/lib/testlibrary/jdk/testlibrary/Utils.java b/test/lib/testlibrary/jdk/testlibrary/Utils.java --- a/test/lib/testlibrary/jdk/testlibrary/Utils.java +++ b/test/lib/testlibrary/jdk/testlibrary/Utils.java @@ -118,6 +118,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<String> removeGcOpts(List<String> opts) { + List<String> optsWithoutGC = new ArrayList<String>(); + 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.