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 * @key stress 28 * @summary Test checks that behavior of Adaptive and Static IHOP at concurrent cycle initiation 29 * @requires vm.gc.G1 30 * @requires !vm.flightRecorder 31 * @requires vm.opt.ExplicitGCInvokesConcurrent != true 32 * @requires vm.opt.MaxGCPauseMillis == "null" 33 * @library /test/lib / 34 * @modules java.base/jdk.internal.misc 35 * @modules java.management 36 * @run driver/timeout=480 gc.g1.ihop.TestIHOPErgo 37 */ 38 package gc.g1.ihop; 39 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.LinkedList; 43 import java.util.List; 44 45 import jdk.test.lib.process.OutputAnalyzer; 46 import jdk.test.lib.process.ProcessTools; 47 48 import gc.g1.ihop.lib.IhopUtils; 49 50 /** 51 * The test starts the AppIHOP multiple times varying settings of MaxHeapSize. 52 * The test parses GC log from AppIHOP to check: 53 * - occupancy is not less than threshold for Adaptive and Static IHOP at 54 * concurrent cycle initiation 55 * - Adaptive IHOP prediction was started during AppIHOP executing 56 * - log contains ergonomic messages in log 57 */ 58 public class TestIHOPErgo { 59 60 // Common GC tune and logging options for test. 61 private final static String[] COMMON_OPTIONS = { 62 "-XX:+UnlockExperimentalVMOptions", 63 "-XX:G1MixedGCLiveThresholdPercent=100", 64 "-XX:G1HeapWastePercent=0", 65 "-XX:MaxGCPauseMillis=30000", 66 "-XX:G1MixedGCCountTarget=1", 67 "-XX:+UseG1GC", 68 "-XX:G1HeapRegionSize=1m", 69 "-XX:+G1UseAdaptiveIHOP", 70 "-Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug", 71 "-XX:+AlwaysTenure", 72 "-XX:G1AdaptiveIHOPNumInitialSamples=1", 73 "-XX:InitiatingHeapOccupancyPercent=30" 74 }; 75 76 public static void main(String[] args) throws Throwable { 77 78 // heap size MB, sleep time for allocator, true/false for adaptive/static 79 runTest(64, 0, false); 80 runTest(64, 100, false); 81 runTest(128, 100, false); 82 runTest(256, 50, false); 83 runTest(512, 30, false); 84 runTest(64, 50, true); 85 runTest(128, 200, true); 86 runTest(256, 100, true); 87 runTest(512, 50, true); 88 } 89 90 /** 91 * Runs AppIHOP in separate VM and checks GC log. 92 * 93 * @param heapSize heap size 94 * @param sleepTime sleep time between memory allocations. 95 * @param isIhopAdaptive true forAdaptive IHOP, false for Static 96 * 97 * @throws Throwable 98 */ 99 private static void runTest(int heapSize, int sleepTime, boolean isIhopAdaptive) throws Throwable { 100 System.out.println("IHOP test:"); 101 System.out.println(" MaxHeapSize : " + heapSize); 102 103 List<String> options = new ArrayList<>(); 104 Collections.addAll(options, 105 "-Dheap.size=" + heapSize, 106 "-Dsleep.time=" + sleepTime, 107 "-XX:MaxHeapSize=" + heapSize + "M", 108 "-XX:NewSize=" + heapSize / 8 + "M", 109 "-XX:MaxNewSize=" + heapSize / 8 + "M", 110 "-XX:InitialHeapSize=" + heapSize + "M", 111 "-XX:" + (isIhopAdaptive ? "+" : "-") + "G1UseAdaptiveIHOP" 112 ); 113 114 Collections.addAll(options, COMMON_OPTIONS); 115 options.add(AppIHOP.class.getName()); 116 OutputAnalyzer out = executeTest(options); 117 118 // Checks that log contains message which indicates that IHOP prediction is active 119 if (isIhopAdaptive) { 120 IhopUtils.checkAdaptiveIHOPWasActivated(out); 121 } 122 // Checks that log contains messages which indicates that VM initiates/checks heap occupancy 123 // and tries to start concurrent cycle. 124 IhopUtils.checkErgoMessagesExist(out); 125 126 // Checks threshold and occupancy values 127 IhopUtils.checkIhopLogValues(out); 128 } 129 130 private static OutputAnalyzer executeTest(List<String> options) throws Throwable, RuntimeException { 131 OutputAnalyzer out; 132 out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()])); 133 if (out.getExitValue() != 0) { 134 System.out.println(out.getOutput()); 135 throw new RuntimeException("AppIHOP failed with exit code" + out.getExitValue()); 136 } 137 return out; 138 } 139 140 /** 141 * The AppIHOP fills 60% of heap and allocates and frees 30% of existing 142 * heap 'iterations' times to achieve IHOP activation. To be executed in 143 * separate VM. Expected properties: 144 * heap.size - heap size which is used to calculate amount of memory 145 * to be allocated and freed 146 * sleep.time - short pause between filling each MB 147 */ 148 public static class AppIHOP { 149 150 public final static LinkedList<Object> GARBAGE = new LinkedList<>(); 151 152 private final int ITERATIONS = 10; 153 private final int OBJECT_SIZE = 100000; 154 // 60% of the heap will be filled before test cycles. 155 // 30% of the heap will be filled and freed during test cycle. 156 private final long HEAP_PREALLOC_PCT = 60; 157 private final long HEAP_ALLOC_PCT = 30; 158 private final long HEAP_SIZE; 159 // Amount of memory to be allocated before iterations start 160 private final long HEAP_PREALLOC_SIZE; 161 // Amount of memory to be allocated and freed during iterations 162 private final long HEAP_ALLOC_SIZE; 163 private final int SLEEP_TIME; 164 165 public static void main(String[] args) throws InterruptedException { 166 new AppIHOP().start(); 167 } 168 169 AppIHOP() { 170 HEAP_SIZE = Integer.getInteger("heap.size") * 1024 * 1024; 171 SLEEP_TIME = Integer.getInteger("sleep.time"); 172 173 HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_PREALLOC_PCT / 100; 174 HEAP_ALLOC_SIZE = HEAP_SIZE * HEAP_ALLOC_PCT / 100; 175 } 176 177 public void start() throws InterruptedException { 178 fill(HEAP_PREALLOC_SIZE); 179 fillAndFree(HEAP_ALLOC_SIZE, ITERATIONS); 180 } 181 182 /** 183 * Fills allocationSize bytes of garbage. 184 * 185 * @param allocationSize amount of garbage 186 */ 187 private void fill(long allocationSize) { 188 long allocated = 0; 189 while (allocated < allocationSize) { 190 GARBAGE.addFirst(new byte[OBJECT_SIZE]); 191 allocated += OBJECT_SIZE; 192 } 193 } 194 195 /** 196 * Allocates allocationSize bytes of garbage. Performs a short pauses 197 * during allocation. Frees allocated garbage. 198 * 199 * @param allocationSize amount of garbage per iteration 200 * @param iterations iteration count 201 * 202 * @throws InterruptedException 203 */ 204 private void fillAndFree(long allocationSize, int iterations) throws InterruptedException { 205 206 for (int i = 0; i < iterations; ++i) { 207 System.out.println("Iteration:" + i); 208 long allocated = 0; 209 long counter = 0; 210 while (allocated < allocationSize) { 211 GARBAGE.addFirst(new byte[OBJECT_SIZE]); 212 allocated += OBJECT_SIZE; 213 counter += OBJECT_SIZE; 214 if (counter > 1024 * 1024) { 215 counter = 0; 216 if (SLEEP_TIME != 0) { 217 Thread.sleep(SLEEP_TIME); 218 } 219 } 220 } 221 long removed = 0; 222 while (removed < allocationSize) { 223 GARBAGE.removeLast(); 224 removed += OBJECT_SIZE; 225 } 226 } 227 } 228 } 229 }