/* * Copyright (c) 2016, 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 TestIHOPErgo * @bug 8148397 * @summary Test checks that behavior of Adaptive and Static IHOP at concurrent cycle initiation * @requires vm.gc == "G1" | vm.gc == "null" * @requires vm.flightRecorder != true * @requires vm.opt.ExplicitGCInvokesConcurrent != true * @requires vm.opt.MaxGCPauseMillis == "null" * @library /testlibrary /test/lib / * @modules java.base/jdk.internal.misc * @modules java.management * @build gc.g1.ihop.TestIHOPErgo * gc.g1.ihop.lib.IhopUtils * @run driver/timeout=480 gc.g1.ihop.TestIHOPErgo */ package gc.g1.ihop; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import jdk.test.lib.OutputAnalyzer; import jdk.test.lib.ProcessTools; import gc.g1.ihop.lib.IhopUtils; /** * The test starts the AppIHOP multiple times varying settings of MaxHeapSize. * The test parses GC log from AppIHOP to check: * - occupancy is not less than threshold for Adaptive and Static IHOP at * concurrent cycle initiation * - Adaptive IHOP prediction was started during AppIHOP executing * - log contains ergonomic messages in log */ public class TestIHOPErgo { // Common GC tune and logging options for test. private final static String[] COMMON_OPTIONS = { "-XX:+UnlockExperimentalVMOptions", "-XX:G1MixedGCLiveThresholdPercent=100", "-XX:G1HeapWastePercent=0", "-XX:MaxGCPauseMillis=30000", "-XX:G1MixedGCCountTarget=1", "-XX:+UseG1GC", "-XX:G1HeapRegionSize=1m", "-XX:+G1UseAdaptiveIHOP", "-Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug", "-XX:+AlwaysTenure", "-XX:G1AdaptiveIHOPNumInitialSamples=1", "-XX:InitiatingHeapOccupancyPercent=30" }; public static void main(String[] args) throws Throwable { // heap size MB, sleep time for allocator, true/false for adaptive/static runTest(64, 0, false); runTest(64, 100, false); runTest(128, 100, false); runTest(256, 50, false); runTest(512, 30, false); runTest(64, 50, true); runTest(128, 200, true); runTest(256, 100, true); runTest(512, 50, true); } /** * Runs AppIHOP in separate VM and checks GC log. * * @param heapSize heap size * @param sleepTime sleep time between memory allocations. * @param isIhopAdaptive true forAdaptive IHOP, false for Static * * @throws Throwable */ private static void runTest(int heapSize, int sleepTime, boolean isIhopAdaptive) throws Throwable { System.out.println("IHOP test:"); System.out.println(" MaxHeapSize : " + heapSize); List options = new ArrayList<>(); Collections.addAll(options, "-Dheap.size=" + heapSize, "-Dsleep.time=" + sleepTime, "-XX:MaxHeapSize=" + heapSize + "M", "-XX:NewSize=" + heapSize / 8 + "M", "-XX:MaxNewSize=" + heapSize / 8 + "M", "-XX:InitialHeapSize=" + heapSize + "M", "-XX:" + (isIhopAdaptive ? "+" : "-") + "G1UseAdaptiveIHOP" ); Collections.addAll(options, COMMON_OPTIONS); options.add(AppIHOP.class.getName()); OutputAnalyzer out = executeTest(options); // Checks that log contains message which indicates that IHOP prediction is active if (isIhopAdaptive) { IhopUtils.checkAdaptiveIHOPWasActivated(out); } // Checks that log contains messages which indicates that VM initiates/checks heap occupancy // and tries to start concurrent cycle. IhopUtils.checkErgoMessagesExist(out); // Checks threshold and occupancy values IhopUtils.checkIhopLogValues(out); } private static OutputAnalyzer executeTest(List options) throws Throwable, RuntimeException { OutputAnalyzer out; out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()])); if (out.getExitValue() != 0) { System.out.println(out.getOutput()); throw new RuntimeException("AppIHOP failed with exit code" + out.getExitValue()); } return out; } /** * The AppIHOP fills 60% of heap and allocates and frees 30% of existing * heap 'iterations' times to achieve IHOP activation. To be executed in * separate VM. Expected properties: * heap.size - heap size which is used to calculate amount of memory * to be allocated and freed * sleep.time - short pause between filling each MB */ public static class AppIHOP { public final static LinkedList GARBAGE = new LinkedList<>(); private final int ITERATIONS = 10; private final int OBJECT_SIZE = 100000; // 60% of the heap will be filled before test cycles. // 30% of the heap will be filled and freed during test cycle. private final long HEAP_PREALLOC_PCT = 60; private final long HEAP_ALLOC_PCT = 30; private final long HEAP_SIZE; // Amount of memory to be allocated before iterations start private final long HEAP_PREALLOC_SIZE; // Amount of memory to be allocated and freed during iterations private final long HEAP_ALLOC_SIZE; private final int SLEEP_TIME; public static void main(String[] args) throws InterruptedException { new AppIHOP().start(); } AppIHOP() { HEAP_SIZE = Integer.getInteger("heap.size") * 1024 * 1024; SLEEP_TIME = Integer.getInteger("sleep.time"); HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_PREALLOC_PCT / 100; HEAP_ALLOC_SIZE = HEAP_SIZE * HEAP_ALLOC_PCT / 100; } public void start() throws InterruptedException { fill(HEAP_PREALLOC_SIZE); fillAndFree(HEAP_ALLOC_SIZE, ITERATIONS); } /** * Fills allocationSize bytes of garbage. * * @param allocationSize amount of garbage */ private void fill(long allocationSize) { long allocated = 0; while (allocated < allocationSize) { GARBAGE.addFirst(new byte[OBJECT_SIZE]); allocated += OBJECT_SIZE; } } /** * Allocates allocationSize bytes of garbage. Performs a short pauses * during allocation. Frees allocated garbage. * * @param allocationSize amount of garbage per iteration * @param iterations iteration count * * @throws InterruptedException */ private void fillAndFree(long allocationSize, int iterations) throws InterruptedException { for (int i = 0; i < iterations; ++i) { System.out.println("Iteration:" + i); long allocated = 0; long counter = 0; while (allocated < allocationSize) { GARBAGE.addFirst(new byte[OBJECT_SIZE]); allocated += OBJECT_SIZE; counter += OBJECT_SIZE; if (counter > 1024 * 1024) { counter = 0; if (SLEEP_TIME != 0) { Thread.sleep(SLEEP_TIME); } } } long removed = 0; while (removed < allocationSize) { GARBAGE.removeLast(); removed += OBJECT_SIZE; } } } } }