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 main(String[] args)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 */ runTest(int heapSize, int sleepTime, boolean isIhopAdaptive)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 executeTest(List<String> options)130 private static OutputAnalyzer executeTest(List<String> options) throws Throwable, RuntimeException { 131 OutputAnalyzer out = ProcessTools.executeTestJvm(options); 132 if (out.getExitValue() != 0) { 133 System.out.println(out.getOutput()); 134 throw new RuntimeException("AppIHOP failed with exit code" + out.getExitValue()); 135 } 136 return out; 137 } 138 139 /** 140 * The AppIHOP fills 60% of heap and allocates and frees 30% of existing 141 * heap 'iterations' times to achieve IHOP activation. To be executed in 142 * separate VM. Expected properties: 143 * heap.size - heap size which is used to calculate amount of memory 144 * to be allocated and freed 145 * sleep.time - short pause between filling each MB 146 */ 147 public static class AppIHOP { 148 149 public final static LinkedList<Object> GARBAGE = new LinkedList<>(); 150 151 private final int ITERATIONS = 10; 152 private final int OBJECT_SIZE = 100000; 153 // 60% of the heap will be filled before test cycles. 154 // 30% of the heap will be filled and freed during test cycle. 155 private final long HEAP_PREALLOC_PCT = 60; 156 private final long HEAP_ALLOC_PCT = 30; 157 private final long HEAP_SIZE; 158 // Amount of memory to be allocated before iterations start 159 private final long HEAP_PREALLOC_SIZE; 160 // Amount of memory to be allocated and freed during iterations 161 private final long HEAP_ALLOC_SIZE; 162 private final int SLEEP_TIME; 163 main(String[] args)164 public static void main(String[] args) throws InterruptedException { 165 new AppIHOP().start(); 166 } 167 AppIHOP()168 AppIHOP() { 169 HEAP_SIZE = Integer.getInteger("heap.size") * 1024 * 1024; 170 SLEEP_TIME = Integer.getInteger("sleep.time"); 171 172 HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_PREALLOC_PCT / 100; 173 HEAP_ALLOC_SIZE = HEAP_SIZE * HEAP_ALLOC_PCT / 100; 174 } 175 start()176 public void start() throws InterruptedException { 177 fill(HEAP_PREALLOC_SIZE); 178 fillAndFree(HEAP_ALLOC_SIZE, ITERATIONS); 179 } 180 181 /** 182 * Fills allocationSize bytes of garbage. 183 * 184 * @param allocationSize amount of garbage 185 */ fill(long allocationSize)186 private void fill(long allocationSize) { 187 long allocated = 0; 188 while (allocated < allocationSize) { 189 GARBAGE.addFirst(new byte[OBJECT_SIZE]); 190 allocated += OBJECT_SIZE; 191 } 192 } 193 194 /** 195 * Allocates allocationSize bytes of garbage. Performs a short pauses 196 * during allocation. Frees allocated garbage. 197 * 198 * @param allocationSize amount of garbage per iteration 199 * @param iterations iteration count 200 * 201 * @throws InterruptedException 202 */ fillAndFree(long allocationSize, int iterations)203 private void fillAndFree(long allocationSize, int iterations) throws InterruptedException { 204 205 for (int i = 0; i < iterations; ++i) { 206 System.out.println("Iteration:" + i); 207 long allocated = 0; 208 long counter = 0; 209 while (allocated < allocationSize) { 210 GARBAGE.addFirst(new byte[OBJECT_SIZE]); 211 allocated += OBJECT_SIZE; 212 counter += OBJECT_SIZE; 213 if (counter > 1024 * 1024) { 214 counter = 0; 215 if (SLEEP_TIME != 0) { 216 Thread.sleep(SLEEP_TIME); 217 } 218 } 219 } 220 long removed = 0; 221 while (removed < allocationSize) { 222 GARBAGE.removeLast(); 223 removed += OBJECT_SIZE; 224 } 225 } 226 } 227 } 228 } 229