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 TestIHOPStatic 26 * @bug 8148397 27 * @summary Test checks concurrent cycle initiation which depends on IHOP value. 28 * @requires vm.gc=="G1" | vm.gc=="null" 29 * @requires vm.opt.FlightRecorder != true 30 * @requires vm.opt.ExplicitGCInvokesConcurrent != true 31 * @library /testlibrary / 32 * @modules java.base/jdk.internal.misc 33 * @modules java.management 34 * @build gc.g1.ihop.TestIHOPStatic 35 * gc.g1.ihop.lib.IhopUtils 36 * @run driver/timeout=240 gc.g1.ihop.TestIHOPStatic 37 */ 38 package gc.g1.ihop; 39 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.List; 43 44 import jdk.test.lib.OutputAnalyzer; 45 import jdk.test.lib.ProcessTools; 46 import jdk.test.lib.Utils; 47 48 import gc.g1.ihop.lib.IhopUtils; 49 50 /** 51 * The test starts the AppIHOP multiple times varying setting of MaxHeapSize, 52 * IHOP and amount of memory to allocate. Then the test parses the GC log from 53 * the app to check that Concurrent Mark Cycle was initiated only if needed 54 * and at the right moment, defined by IHOP setting. 55 */ 56 public class TestIHOPStatic { 57 58 final static long YOUNG_SIZE = 8 * 1024 * 1024; 59 60 private final static String[] COMMON_OPTIONS = { 61 "-XX:+UseG1GC", 62 "-XX:G1HeapRegionSize=1m", 63 "-XX:-G1UseAdaptiveIHOP", 64 "-XX:NewSize=" + YOUNG_SIZE, 65 "-XX:MaxNewSize=" + YOUNG_SIZE, 66 "-Xlog:gc+ihop+ergo=debug,gc*=debug" 67 }; 68 69 public static void main(String[] args) throws Throwable { 70 71 // Test case: 72 // IHOP value, heap occupancy, heap size, expectation of message 73 // Test cases for occupancy is greater than IHOP 74 runTest(30, 35, 64, true); 75 runTest(50, 55, 256, true); 76 runTest(60, 65, 64, true); 77 runTest(70, 75, 512, true); 78 79 // Test cases for big difference between occupancy and IHOP 80 runTest(30, 50, 256, true); 81 runTest(30, 70, 512, true); 82 runTest(50, 70, 256, true); 83 84 // Test cases for occupancy is less than IHOP 85 runTest(30, 25, 64, false); 86 runTest(50, 45, 256, false); 87 runTest(70, 65, 64, false); 88 runTest(70, 65, 512, false); 89 90 // Test cases for big difference between occupancy and IHOP 91 runTest(50, 30, 300, false); 92 runTest(70, 50, 160, false); 93 94 // Cases for 0 and 100 IHOP. 95 runTest(0, 50, 256, true); 96 runTest(0, 95, 512, true); 97 runTest(100, 20, 64, false); 98 runTest(100, 100, 512, false); 99 } 100 101 /** 102 * Runs the test case. 103 * 104 * @param ihop IHOP value 105 * @param pctToFill heap percentage to be filled 106 * @param heapSize heap size for test 107 * @param expectInitiationMessage 108 * true - concurrent cycle initiation message is expected 109 * false - message is not expected 110 * 111 * @throws Throwable 112 */ 113 private static void runTest(int ihop, long pctToFill, long heapSize, boolean expectInitiationMessage) throws Throwable { 114 System.out.println(""); 115 System.out.println("IHOP test:"); 116 System.out.println(" InitiatingHeapOccupancyPercent : " + ihop); 117 System.out.println(" Part of heap to fill (percentage) : " + pctToFill); 118 System.out.println(" MaxHeapSize : " + heapSize); 119 System.out.println(" Expect for concurrent cycle initiation message : " + expectInitiationMessage); 120 List<String> options = new ArrayList<>(); 121 Collections.addAll(options, Utils.getTestJavaOpts()); 122 Collections.addAll(options, 123 "-XX:InitiatingHeapOccupancyPercent=" + ihop, 124 "-Dmemory.fill=" + (heapSize * 1024 * 1024 * pctToFill / 100), 125 "-XX:MaxHeapSize=" + heapSize + "M", 126 "-XX:InitialHeapSize=" + heapSize + "M" 127 ); 128 Collections.addAll(options, COMMON_OPTIONS); 129 options.add(AppIHOP.class.getName()); 130 131 OutputAnalyzer out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()])); 132 133 if (out.getExitValue() != 0) { 134 System.out.println(out.getOutput()); 135 throw new RuntimeException("IhopTest failed with exit code " + out.getExitValue()); 136 } 137 138 checkResult(out, expectInitiationMessage); 139 } 140 141 /** 142 * Checks execution results to ensure that concurrent cycle was initiated or 143 * was not. 144 * 145 * @param out 146 * @param expectInitiationMessage true - test expects for concurrent cycle initiation. 147 * false - test does not expect for concurrent cycle initiation 148 */ 149 private static void checkResult(OutputAnalyzer out, boolean expectInitiationMessage) { 150 // Find expected messages 151 List<String> logItems = IhopUtils.getErgoInitiationMessages(out); 152 153 // Concurrent cycle was not initiated but was expected. 154 if (logItems.isEmpty() && expectInitiationMessage) { 155 System.out.println(out.getOutput()); 156 throw new RuntimeException("Concurrent cycle was not initiated."); 157 } 158 IhopUtils.checkIhopLogValues(out); 159 } 160 161 static class AppIHOP { 162 163 /** 164 * Simple class which fills part of memory and initiates GC. 165 * To be executed in separate VM. 166 * Expect next VM properties to be set: 167 * memory.fill - amount of garbage to be created. 168 */ 169 private static final long MEMORY_TO_FILL = Integer.getInteger("memory.fill"); 170 private final static int CHUNK_SIZE = 10000; 171 172 public final static ArrayList<Object> STORAGE = new ArrayList<>(); 173 174 public static void main(String[] args) throws InterruptedException { 175 176 // Calculate part of heap to be filled to achieve expected occupancy. 177 System.out.println("Mem to fill:" + MEMORY_TO_FILL); 178 if (MEMORY_TO_FILL <= 0) { 179 throw new RuntimeException("Wrong memory size: " + MEMORY_TO_FILL); 180 } 181 try { 182 createGarbage(MEMORY_TO_FILL); 183 } catch (OutOfMemoryError oome) { 184 return; 185 } 186 // Concurrent cycle initiation should start at end of Young GC cycle. 187 // Will fill entire young gen with garbage to guarantee that Young GC was initiated. 188 try { 189 createGarbage(TestIHOPStatic.YOUNG_SIZE); 190 } catch (OutOfMemoryError oome) { 191 } 192 } 193 194 private static void createGarbage(long memToFill) { 195 for (long i = 0; i < memToFill / CHUNK_SIZE; i++) { 196 STORAGE.add(new byte[CHUNK_SIZE]); 197 } 198 } 199 } 200 }