1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test TestIHOPErgo 26 * @bug 8148397 27 * @summary Test checks that behavior of Adaptive and Static IHOP at concurrent cycle initiation 28 * @requires vm.gc == "G1" | vm.gc == "null" 29 * @requires vm.flightRecorder != true 30 * @requires vm.opt.ExplicitGCInvokesConcurrent != true 31 * @requires vm.opt.MaxGCPauseMillis == "null" 32 * @library /testlibrary /test/lib / 33 * @modules java.base/jdk.internal.misc 34 * @modules java.management 35 * @build gc.g1.ihop.TestIHOPErgo 36 * gc.g1.ihop.lib.IhopUtils 37 * @run driver/timeout=480 gc.g1.ihop.TestIHOPErgo 38 */ 39 package gc.g1.ihop; 40 41 import java.util.ArrayList; 42 import java.util.Collections; 43 import java.util.LinkedList; 44 import java.util.List; 45 46 import jdk.test.lib.OutputAnalyzer; 47 import jdk.test.lib.ProcessTools; 48 49 import gc.g1.ihop.lib.IhopUtils; 50 51 /** 52 * The test starts the AppIHOP multiple times varying settings of MaxHeapSize. 53 * The test parses GC log from AppIHOP to check: 54 * - occupancy is not less than threshold for Adaptive and Static IHOP at 55 * concurrent cycle initiation 56 * - Adaptive IHOP prediction was started during AppIHOP executing 57 * - log contains ergonomic messages in log 58 */ 59 public class TestIHOPErgo { 60 61 // Common GC tune and logging options for test. 62 private final static String[] COMMON_OPTIONS = { 63 "-XX:+UnlockExperimentalVMOptions", 64 "-XX:G1MixedGCLiveThresholdPercent=100", 65 "-XX:G1HeapWastePercent=0", 66 "-XX:MaxGCPauseMillis=30000", 67 "-XX:G1MixedGCCountTarget=1", 68 "-XX:+UseG1GC", 69 "-XX:G1HeapRegionSize=1m", 70 "-XX:+G1UseAdaptiveIHOP", 71 "-Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug", 72 "-XX:+AlwaysTenure", 73 "-XX:G1AdaptiveIHOPNumInitialSamples=1", 74 "-XX:InitiatingHeapOccupancyPercent=30" 75 }; 76 77 public static void main(String[] args) throws Throwable { 78 79 // heap size MB, sleep time for allocator, true/false for adaptive/static 80 runTest(64, 0, false); 81 runTest(64, 100, false); 82 runTest(128, 100, false); 83 runTest(256, 50, false); 84 runTest(512, 30, false); 85 runTest(64, 50, true); 86 runTest(128, 200, true); 87 runTest(256, 100, true); 88 runTest(512, 50, true); 89 } 90 91 /** 92 * Runs AppIHOP in separate VM and checks GC log. 93 * 94 * @param heapSize heap size 95 * @param sleepTime sleep time between memory allocations. 96 * @param isIhopAdaptive true forAdaptive IHOP, false for Static 97 * 98 * @throws Throwable 99 */ 100 private static void runTest(int heapSize, int sleepTime, boolean isIhopAdaptive) throws Throwable { 101 System.out.println("IHOP test:"); 102 System.out.println(" MaxHeapSize : " + heapSize); 103 104 List<String> options = new ArrayList<>(); 105 Collections.addAll(options, 106 "-Dheap.size=" + heapSize, 107 "-Dsleep.time=" + sleepTime, 108 "-XX:MaxHeapSize=" + heapSize + "M", 109 "-XX:NewSize=" + heapSize / 8 + "M", 110 "-XX:MaxNewSize=" + heapSize / 8 + "M", 111 "-XX:InitialHeapSize=" + heapSize + "M", 112 "-XX:" + (isIhopAdaptive ? "+" : "-") + "G1UseAdaptiveIHOP" 113 ); 114 115 Collections.addAll(options, COMMON_OPTIONS); 116 options.add(AppIHOP.class.getName()); 117 OutputAnalyzer out = executeTest(options); 118 119 // Checks that log contains message which indicates that IHOP prediction is active 120 if (isIhopAdaptive) { 121 IhopUtils.checkAdaptiveIHOPWasActivated(out); 122 } 123 // Checks that log contains messages which indicates that VM initiates/checks heap occupancy 124 // and tries to start concurrent cycle. 125 IhopUtils.checkErgoMessagesExist(out); 126 127 // Checks threshold and occupancy values 128 IhopUtils.checkIhopLogValues(out); 129 } 130 131 private static OutputAnalyzer executeTest(List<String> options) throws Throwable, RuntimeException { 132 OutputAnalyzer out; 133 out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()])); 134 if (out.getExitValue() != 0) { 135 System.out.println(out.getOutput()); 136 throw new RuntimeException("AppIHOP failed with exit code" + out.getExitValue()); 137 } 138 return out; 139 } 140 141 /** 142 * The AppIHOP fills 60% of heap and allocates and frees 30% of existing 143 * heap 'iterations' times to achieve IHOP activation. To be executed in 144 * separate VM. Expected properties: 145 * heap.size - heap size which is used to calculate amount of memory 146 * to be allocated and freed 147 * sleep.time - short pause between filling each MB 148 */ 149 public static class AppIHOP { 150 151 public final static LinkedList<Object> GARBAGE = new LinkedList<>(); 152 153 private final int ITERATIONS = 10; 154 private final int OBJECT_SIZE = 100000; 155 // 60% of the heap will be filled before test cycles. 156 // 30% of the heap will be filled and freed during test cycle. 157 private final long HEAP_PREALLOC_PCT = 60; 158 private final long HEAP_ALLOC_PCT = 30; 159 private final long HEAP_SIZE; 160 // Amount of memory to be allocated before iterations start 161 private final long HEAP_PREALLOC_SIZE; 162 // Amount of memory to be allocated and freed during iterations 163 private final long HEAP_ALLOC_SIZE; 164 private final int SLEEP_TIME; 165 166 public static void main(String[] args) throws InterruptedException { 167 new AppIHOP().start(); 168 } 169 170 AppIHOP() { 171 HEAP_SIZE = Integer.getInteger("heap.size") * 1024 * 1024; 172 SLEEP_TIME = Integer.getInteger("sleep.time"); 173 174 HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_PREALLOC_PCT / 100; 175 HEAP_ALLOC_SIZE = HEAP_SIZE * HEAP_ALLOC_PCT / 100; 176 } 177 178 public void start() throws InterruptedException { 179 fill(HEAP_PREALLOC_SIZE); 180 fillAndFree(HEAP_ALLOC_SIZE, ITERATIONS); 181 } 182 183 /** 184 * Fills allocationSize bytes of garbage. 185 * 186 * @param allocationSize amount of garbage 187 */ 188 private void fill(long allocationSize) { 189 long allocated = 0; 190 while (allocated < allocationSize) { 191 GARBAGE.addFirst(new byte[OBJECT_SIZE]); 192 allocated += OBJECT_SIZE; 193 } 194 } 195 196 /** 197 * Allocates allocationSize bytes of garbage. Performs a short pauses 198 * during allocation. Frees allocated garbage. 199 * 200 * @param allocationSize amount of garbage per iteration 201 * @param iterations iteration count 202 * 203 * @throws InterruptedException 204 */ 205 private void fillAndFree(long allocationSize, int iterations) throws InterruptedException { 206 207 for (int i = 0; i < iterations; ++i) { 208 System.out.println("Iteration:" + i); 209 long allocated = 0; 210 long counter = 0; 211 while (allocated < allocationSize) { 212 GARBAGE.addFirst(new byte[OBJECT_SIZE]); 213 allocated += OBJECT_SIZE; 214 counter += OBJECT_SIZE; 215 if (counter > 1024 * 1024) { 216 counter = 0; 217 if (SLEEP_TIME != 0) { 218 Thread.sleep(SLEEP_TIME); 219 } 220 } 221 } 222 long removed = 0; 223 while (removed < allocationSize) { 224 GARBAGE.removeLast(); 225 removed += OBJECT_SIZE; 226 } 227 } 228 } 229 } 230 }