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 import java.util.concurrent.TimeoutException; 25 import sun.hotspot.WhiteBox; 26 27 /* 28 * @test TestStressRSetCoarsening.java 29 * @key stress 30 * @bug 8146984 8147087 31 * @requires vm.gc=="G1" | vm.gc=="null" 32 * @requires os.maxMemory > 3G 33 * 34 * @summary Stress G1 Remembered Set by creating a lot of cross region links 35 * @library /testlibrary /testlibrary/whitebox 36 * @build sun.hotspot.WhiteBox 37 * @run main ClassFileInstaller sun.hotspot.WhiteBox 38 * sun.hotspot.WhiteBox$WhiteBoxPermission 39 * @run main/othervm/timeout=300 40 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC 41 * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc 42 * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 1 0 300 43 * @run main/othervm/timeout=300 44 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC 45 * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc 46 * -Xmx500m -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 1 10 300 47 * @run main/othervm/timeout=300 48 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC 49 * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc 50 * -Xmx500m -XX:G1HeapRegionSize=32m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 42 10 300 51 * @run main/othervm/timeout=300 52 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC 53 * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc 54 * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 2 0 300 55 * @run main/othervm/timeout=1800 56 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC 57 * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc 58 * -Xmx1G -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 500 0 1800 59 * @run main/othervm/timeout=1800 60 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC 61 * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc 62 * -Xmx1G -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 10 10 1800 63 */ 64 65 /** 66 * What the test does. 67 * Preparation stage: 68 * Fill out ~90% of the heap with objects, each object is an object array. 69 * If we want to allocate K objects per region, we calculate N to meet: 70 * sizeOf(Object[N]) ~= regionSize / K 71 * Stress stage: 72 * No more allocation, so no more GC. 73 * We will perform a number of iterations. On each iteration i, 74 * for each pair of regions Rx and Ry we will set c[i] references 75 * from Rx to Ry. If c[i] less than c[i-1] at the end of iteration 76 * concurrent mark cycle will be initiated (to recalculate remembered sets). 77 * As the result RSet will be growing up and down, up and down many times. 78 * 79 * The test expects: no crash and no timeouts. 80 * 81 * Test Parameters: 82 * args[0] - number of objects per Heap Region (1 - means humongous) 83 * args[1] - number of regions to refresh to provoke GC at the end of cycle. 84 * (0 - means no GC, i.e. no reading from RSet) 85 * args[2] - timeout in seconds (to stop execution to avoid jtreg timeout) 86 */ 87 public class TestStressRSetCoarsening { 88 main(String... args)89 public static void main(String... args) throws InterruptedException { 90 if (args.length != 3) { 91 throw new IllegalArgumentException("Wrong number of arguments " + args.length); 92 } 93 int objectsPerRegion = Integer.parseInt(args[0]); // 1 means humongous 94 int regsToRefresh = Integer.parseInt(args[1]); // 0 means no regions to refresh at the end of cycle 95 int timeout = Integer.parseInt(args[2]); // in seconds, test should stop working eariler 96 new TestStressRSetCoarsening(objectsPerRegion, regsToRefresh, timeout).go(); 97 } 98 99 private static final long KB = 1024; 100 private static final long MB = 1024 * KB; 101 102 private static final WhiteBox WB = WhiteBox.getWhiteBox(); 103 104 public final Object[][] storage; 105 106 /** 107 * Number of objects per region. This is a test parameter. 108 */ 109 public final int K; 110 111 /** 112 * Length of object array: sizeOf(Object[N]) ~= regionSize / K 113 * N will be calculated as function of K. 114 */ 115 public final int N; 116 117 /** 118 * How many regions involved into testing. 119 * Will be calculated as heapFractionToAllocate * freeRegionCount. 120 */ 121 public final int regionCount; 122 123 /** 124 * How much heap to use. 125 */ 126 public final float heapFractionToAllocate = 0.9f; 127 128 /** 129 * How many regions to be refreshed at the end of cycle. 130 * This is a test parameter. 131 */ 132 public final int regsToRefresh; 133 134 /** 135 * Initial time. 136 */ 137 public final long start; 138 139 /** 140 * Time when the test should stop working. 141 */ 142 public final long finishAt; 143 144 /** 145 * Does pre-calculation and allocate necessary objects. 146 * 147 * @param objPerRegions how many objects per G1 heap region 148 */ TestStressRSetCoarsening(int objPerRegions, int regsToRefresh, int timeout)149 TestStressRSetCoarsening(int objPerRegions, int regsToRefresh, int timeout) { 150 this.K = objPerRegions; 151 this.regsToRefresh = regsToRefresh; 152 this.start = System.currentTimeMillis(); 153 this.finishAt = start + timeout * 900; // 10% ahead of jtreg timeout 154 155 long regionSize = WB.g1RegionSize(); 156 157 // How many free regions 158 Runtime rt = Runtime.getRuntime(); 159 long used = rt.totalMemory() - rt.freeMemory(); 160 long totalFree = rt.maxMemory() - used; 161 regionCount = (int) ((totalFree / regionSize) * heapFractionToAllocate); 162 long toAllocate = regionCount * regionSize; 163 System.out.println("%% Test parameters"); 164 System.out.println("%% Objects per region : " + K); 165 System.out.println("%% Heap fraction to allocate : " + (int) (heapFractionToAllocate * 100) + "%"); 166 System.out.println("%% Regions to refresh to provoke GC: " + regsToRefresh); 167 168 System.out.println("%% Memory"); 169 System.out.println("%% used : " + used / MB + "M"); 170 System.out.println("%% available : " + totalFree / MB + "M"); 171 System.out.println("%% to allocate : " + toAllocate / MB + "M"); 172 System.out.println("%% (in regs) : " + regionCount); 173 System.out.println("%% G1 Region Size: " + regionSize / MB + "M"); 174 175 int refSize = WB.getHeapOopSize(); 176 177 // Calculate N: K*sizeOf(Object[N]) ~= regionSize 178 // sizeOf(Object[N]) ~= (N+4)*refSize 179 // ==> 180 // N = regionSize / K / refSize - 4; 181 N = (int) ((regionSize / K) / refSize) - 5; 182 183 /* 184 * -------------- 185 * region0 storage[0] = new Object[N] 186 * ... 187 * storage[K-1] = new Object[N] 188 * --------------- 189 * region1 storage[K] = new Object[N] 190 * ... 191 * storage[2*K - 1] = new Object[N] 192 * -------------- 193 * ... 194 * -------------- 195 * regionX storage[X*K] = new Object[N] 196 * ... 197 * storage[(X+1)*K -1] = new Object[N] 198 * where X = HeapFraction * TotalRegions 199 * ------------- 200 */ 201 System.out.println("%% Objects"); 202 System.out.println("%% N (array length) : " + N); 203 System.out.println("%% K (objects in regions): " + K); 204 System.out.println("%% Reference size : " + refSize); 205 System.out.println("%% Approximate obj size : " + (N + 2) * refSize / KB + "K)"); 206 207 storage = new Object[regionCount * K][]; 208 for (int i = 0; i < storage.length; i++) { 209 storage[i] = new Object[N]; 210 } 211 } 212 go()213 public void go() throws InterruptedException { 214 // threshold for sparce -> fine 215 final int FINE = WB.getIntxVMFlag("G1RSetSparseRegionEntries").intValue(); 216 217 // threshold for fine -> coarse 218 final int COARSE = WB.getIntxVMFlag("G1RSetRegionEntries").intValue(); 219 220 // regToRegRefCounts - array of reference counts from region to region 221 // at the the end of iteration. 222 // The number of test iterations is array length - 1. 223 // If c[i] > c[i-1] then during the iteration i more references will 224 // be created. 225 // If c[i] < c[i-1] then some referenes will be cleaned. 226 int[] regToRegRefCounts = {0, FINE / 2, 0, FINE, (FINE + COARSE) / 2, 0, 227 COARSE, COARSE + 10, FINE + 1, FINE / 2, 0}; 228 229 // For progress tracking 230 int[] progress = new int[regToRegRefCounts.length]; 231 progress[0] = 0; 232 for (int i = 1; i < regToRegRefCounts.length; i++) { 233 progress[i] = progress[i - 1] + Math.abs(regToRegRefCounts[i] - regToRegRefCounts[i - 1]); 234 } 235 try { 236 for (int i = 1; i < regToRegRefCounts.length; i++) { 237 int pre = regToRegRefCounts[i - 1]; 238 int cur = regToRegRefCounts[i]; 239 float prog = ((float) progress[i - 1] / progress[progress.length - 1]); 240 241 System.out.println("%% step " + i 242 + " out of " + (regToRegRefCounts.length - 1) 243 + " (~" + (int) (100 * prog) + "% done)"); 244 System.out.println("%% " + pre + " --> " + cur); 245 for (int to = 0; to < regionCount; to++) { 246 // Select a celebrity object that we will install references to. 247 // The celebrity will be referred from all other regions. 248 // If the number of references after should be less than they 249 // were before, select NULL. 250 Object celebrity = cur > pre ? storage[to * K] : null; 251 for (int from = 0; from < regionCount; from++) { 252 if (to == from) { 253 continue; // no need to refer to itself 254 } 255 256 int step = cur > pre ? +1 : -1; 257 for (int rn = pre; rn != cur; rn += step) { 258 storage[getY(to, from, rn)][getX(to, from, rn)] = celebrity; 259 if (System.currentTimeMillis() > finishAt) { 260 throw new TimeoutException(); 261 } 262 } 263 } 264 } 265 if (pre > cur) { 266 // Number of references went down. 267 // Need to provoke recalculation of RSet. 268 WB.g1StartConcMarkCycle(); 269 while (WB.g1InConcurrentMark()) { 270 Thread.sleep(1); 271 } 272 } 273 274 // To force the use of rememebered set entries we need to provoke a GC. 275 // To induce some fragmentation, and some mixed GCs, we need 276 // to make a few objects unreachable. 277 for (int toClean = i * regsToRefresh; toClean < (i + 1) * regsToRefresh; toClean++) { 278 int to = toClean % regionCount; 279 // Need to remove all references from all regions to the region 'to' 280 for (int from = 0; from < regionCount; from++) { 281 if (to == from) { 282 continue; // no need to refer to itself 283 } 284 for (int rn = 0; rn <= cur; rn++) { 285 storage[getY(to, from, rn)][getX(to, from, rn)] = null; 286 } 287 } 288 // 'Refresh' storage elements for the region 'to' 289 // After that loop all 'old' objects in the region 'to' 290 // should become unreachable. 291 for (int k = 0; k < K; k++) { 292 storage[(to * K + k) % storage.length] = new Object[N]; 293 } 294 } 295 } 296 } catch (TimeoutException e) { 297 System.out.println("%% TIMEOUT!!!"); 298 } 299 long now = System.currentTimeMillis(); 300 System.out.println("%% Summary"); 301 System.out.println("%% Time spent : " + ((now - start) / 1000) + " seconds"); 302 System.out.println("%% Free memory left : " + Runtime.getRuntime().freeMemory() / KB + "K"); 303 System.out.println("%% Test passed"); 304 } 305 306 /** 307 * Returns X index in the Storage of the reference #rn from the region 308 * 'from' to the region 'to'. 309 * 310 * @param to region # to refer to 311 * @param from region # to refer from 312 * @param rn number of reference 313 * 314 * @return X index in the range: [0 ... N-1] 315 */ getX(int to, int from, int rn)316 private int getX(int to, int from, int rn) { 317 return (rn * regionCount + to) % N; 318 } 319 320 /** 321 * Returns Y index in the Storage of the reference #rn from the region 322 * 'from' to the region 'to'. 323 * 324 * @param to region # to refer to 325 * @param from region # to refer from 326 * @param rn number of reference 327 * 328 * @return Y index in the range: [0 ... K*regionCount -1] 329 */ getY(int to, int from, int rn)330 private int getY(int to, int from, int rn) { 331 return ((rn * regionCount + to) / N + from * K) % (regionCount * K); 332 } 333 } 334 335