1 /* 2 * Copyright (c) 2015, 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 import com.sun.management.HotSpotDiagnosticMXBean; 25 import java.lang.management.ManagementFactory; 26 import java.util.Date; 27 28 /* 29 * @test TestUpAndDownRSet.java 30 * @requires vm.gc=="G1" | vm.gc=="null" 31 * @requires os.maxMemory >= 2G 32 * 33 * @summary Stress G1 Remembered Set by creating a lot of cross region links 34 * @modules jdk.management 35 * @run main/othervm -XX:+UseG1GC -Xmx2G -XX:G1HeapRegionSize=1m TestUpAndDownRSet 10000 36 * @run main/othervm -XX:+UseG1GC -Xmx2G -XX:G1HeapRegionSize=1m TestUpAndDownRSet 10 37 * @run main/othervm -XX:+UseG1GC -Xmx2G -XX:G1HeapRegionSize=1m TestUpAndDownRSet 1 38 * @run main/othervm -XX:+UseG1GC -Xmx2G -XX:G1HeapRegionSize=8m TestUpAndDownRSet 2 39 * @run main/othervm -XX:+UseG1GC -Xmx2G -XX:G1HeapRegionSize=32m TestUpAndDownRSet 42 40 */ 41 42 /** 43 * What the test does: 44 * Step1: 45 * Fill out ~90% of the heap with objects of G1HeapRegionSize*0.4 size. 46 * Two objects per region will be allocated. 47 * Step2: 48 * Link each second object to each second object. 49 * Expecting RSet will grow to a high value. 50 * Step3: 51 * Clear references created on the Step2 52 * Expecting RSet will go down. 53 * Continue Step2 and Step3 for 1000 times or until 10 seconds. 54 * 55 * The test expects: no crash and no timeouts. 56 */ 57 public class TestUpAndDownRSet { 58 59 public static void main(String... args) { 60 if (args.length != 1) { 61 throw new IllegalArgumentException("Wrong number of argument " + args.length); 62 } 63 new TestUpAndDownRSet(Integer.parseInt(args[0])).go(); 64 } 65 66 private static final long KB = 1024; 67 private static final long MB = 1024 * KB; 68 69 private static final HotSpotDiagnosticMXBean HS_MX_BEAN 70 = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); 71 72 public final Object[][] storage; 73 74 // how many objects to refer from objects 75 public final int refNumber; 76 77 // how many objects should be in each G1 heap region 78 public final int objPerRegion; 79 80 /** 81 * Does pre-calculation and allocate necessary objects. 82 * 83 * @param objPerRegions how many objects per G1 heap region 84 */ 85 TestUpAndDownRSet(int objPerRegion) { 86 this.objPerRegion = objPerRegion; 87 88 long regionSize = getG1RegionSize(); 89 90 // how many free regions 91 Runtime rt = Runtime.getRuntime(); 92 long used = rt.totalMemory() - rt.freeMemory(); 93 long totalFree = rt.maxMemory() - used; 94 long toAllocate = (long) (0.9 * totalFree); // we want to leave some free memory 95 int regionCount = (int) (toAllocate / regionSize); 96 97 System.out.println("%% Memory"); 98 System.out.println("%% used : " + used / MB + "M"); 99 System.out.println("%% available : " + totalFree / MB + "M"); 100 System.out.println("%% to allocate : " + toAllocate / MB + "M"); 101 System.out.println("%% G1 Region Size: " + regionSize / MB + "M"); 102 103 104 byte refSize = getRefSize(); 105 106 // We will fill out the heap with objects of equal size, 107 // allocating k objects per region. 108 // Each object will be an array of objects (Object[N]): 109 // storage[i] = new Object[N] 110 // We want to calculate N to meet the requirements: 111 // k * sizeOf(Object[N]) < regionSize 112 // (k+1) * sizeOf(Object[N]) > regionSize 113 // sizeOf(Object[N]) should be approximately regionSize/k 114 115 int sizeOfObjectN = (int) regionSize / objPerRegion; 116 int arrayHeaderSize = 12 + refSize; // 16 or 20 if -XX:-UseCompressedOops 117 // we need an approximate value here 118 int N = (int) ((sizeOfObjectN - arrayHeaderSize) / refSize); 119 120 // we will expect: storage[i] and storage[i+k] will be allocated in 121 // different G1 regions. 122 storage = new Object[regionCount * objPerRegion][]; 123 for (int i = 0; i < storage.length; i++) { 124 storage[i] = new Object[N]; 125 } 126 127 // in most cases refNumber == regionCount 128 // just to protect cases when: regionCount > N (a lot of very small regions) 129 refNumber = java.lang.Math.min(regionCount, N); 130 131 System.out.println("%% Objects: "); 132 System.out.println("%% Number of objects: " + storage.length); 133 System.out.println("%% objects in region: " + objPerRegion); 134 System.out.println("%% N (array length) : " + N); 135 System.out.println("%% Reference size : " + refSize); 136 System.out.println("%% Approximate size : " + N * refSize + "(" + N * refSize / KB + "K)"); 137 System.out.println("%% Reference number : " + refNumber); 138 } 139 140 141 // we don't want to execute longer than 10 seconds 142 private final long MAX_EXECUTION_TIME = 10_000; 143 144 // we don't want to perform over 1000 iterations 145 private final int MAX_ITER = 1000; 146 147 public void go() { 148 149 int iter = 0; 150 long start = new Date().getTime(); 151 long now = 0; 152 while (iter < MAX_ITER && now < start + MAX_EXECUTION_TIME) { 153 // Remembered Set UP 154 for (int i = 0; i < storage.length; i += objPerRegion) { 155 for (int j = 0; j < refNumber; j++) { 156 storage[i][j] = storage[j * objPerRegion]; 157 } 158 } 159 // Remembered Set DOWN 160 for (int i = 0; i < storage.length; i += objPerRegion) { 161 for (int j = 0; j < refNumber; j++) { 162 storage[i][j] = null; 163 } 164 } 165 iter++; 166 now = new Date().getTime(); 167 } 168 System.out.println("%% Execution:"); 169 System.out.println("%% Number of iterations: " + iter); 170 System.out.println("%% Time spent: " + ((now - start)/1000) + "seconds"); 171 System.out.println("%% Free memory left: " + Runtime.getRuntime().freeMemory()/MB + "M"); 172 System.out.println("%% Test passed"); 173 } 174 175 176 /** 177 * @return 4 unless UseCompressedOops flag is explicitely disabled. 178 */ 179 private static byte getRefSize() { 180 try { 181 if ("false".equals(HS_MX_BEAN.getVMOption("UseCompressedOops").getValue())) { 182 return 8; 183 } 184 } catch (Exception e) { 185 // UseCompressedOops is not supported flag ... 186 } 187 return 4; 188 } 189 190 /** 191 * @return G1 Heap Region Size 192 */ 193 private static long getG1RegionSize() { 194 try { 195 return Long.parseLong(HS_MX_BEAN.getVMOption("G1HeapRegionSize").getValue()); 196 } catch (Exception e) { 197 throw new RuntimeException("Unable to detect G1 HeapRegionSize " + e.getMessage(), e); 198 } 199 } 200 } 201