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