1 /* 2 * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2017, SAP SE and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 package gc.stress.TestJNIBlockFullGC; 26 27 /* 28 * @test TestJNIBlockFullGC 29 * @summary Check that in G1 a Full GC to reclaim space can not be blocked out by the GC locker. 30 * @key gc randomness 31 * @requires vm.gc.G1 32 * @library /test/lib 33 * @run main/othervm/native -Xmx64m -XX:+UseG1GC -Xlog:gc=info,gc+alloc=trace -XX:MaxGCPauseMillis=10 gc.stress.TestJNIBlockFullGC.TestJNIBlockFullGC 10 10000 10000 10000 30000 10000 0.7 34 */ 35 36 import java.lang.ref.SoftReference; 37 import java.util.Random; 38 import jdk.test.lib.Utils; 39 40 public class TestJNIBlockFullGC { 41 private static final Random rng = Utils.getRandomInstance(); 42 43 static { 44 System.loadLibrary("TestJNIBlockFullGC"); 45 } 46 47 public static volatile Object tmp; 48 49 public static volatile boolean hadError = false; 50 51 private static native int TestCriticalArray0(int[] x); 52 53 public static class Node { 54 public SoftReference<Node> next; 55 long payload1; 56 long payload2; 57 long payload3; 58 long payload4; 59 60 public Node(int load) { 61 payload1 = payload2 = payload3 = payload4 = load; 62 } 63 } 64 65 public static void warmUp(long warmupEndTime, int size, long seed) { 66 Random r = new Random(seed); 67 // First let the GC assume most of our objects will die. 68 Node[] roots = new Node[size]; 69 70 while (System.currentTimeMillis() < warmupEndTime) { 71 int index = (int) (r.nextDouble() * roots.length); 72 roots[index] = new Node(1); 73 } 74 75 // Make sure the young generation is empty. 76 for (int i = 0; i < roots.length; ++i) { 77 roots[i] = null; 78 } 79 } 80 81 public static void runTest(long endTime, int size, double alive, long seed) { 82 Random r = new Random(seed); 83 final int length = 10000; 84 int[] array1 = new int[length]; 85 for (int x = 1; x < length; x++) { 86 array1[x] = x; 87 } 88 89 Node[] roots = new Node[size]; 90 try { 91 int index = 0; 92 roots[0] = new Node(0); 93 94 while (!hadError && (System.currentTimeMillis() < endTime)) { 95 int test_val1 = TestCriticalArray0(array1); 96 97 if (r.nextDouble() > alive) { 98 tmp = new Node(test_val1); 99 } else { 100 index = (int) (r.nextDouble() * roots.length); 101 102 if (roots[index] != null) { 103 Node node = new Node(test_val1); 104 node.next = new SoftReference<Node>(roots[index]); 105 roots[index] = node; 106 } else { 107 roots[index] = new Node(test_val1); 108 } 109 } 110 } 111 } catch (OutOfMemoryError e) { 112 hadError = true; 113 e.printStackTrace(); 114 } 115 } 116 117 private static void joinThreads(Thread[] threads) throws Exception { 118 for (int i = 0; i < threads.length; i++) { 119 try { 120 if (threads[i] != null) { 121 threads[i].join(); 122 } 123 } catch (InterruptedException e) { 124 e.printStackTrace(); 125 throw e; 126 } 127 } 128 } 129 130 public static void main(String[] args) throws Exception { 131 if (args.length < 7){ 132 System.out.println("Usage: java TestJNIBlockFullGC <warmupThreads> <warmup-time-in-millis> <warmup iterations> <threads> <time-in-millis> <iterations> <aliveFrac>"); 133 System.exit(0); 134 } 135 136 int warmupThreads = Integer.parseInt(args[0]); 137 System.out.println("# Warmup Threads = " + warmupThreads); 138 139 int warmupDuration = Integer.parseInt(args[1]); 140 System.out.println("WarmUp Duration = " + warmupDuration); 141 int warmupIterations = Integer.parseInt(args[2]); 142 System.out.println("# Warmup Iterations = "+ warmupIterations); 143 144 int mainThreads = Integer.parseInt(args[3]); 145 System.out.println("# Main Threads = " + mainThreads); 146 int mainDuration = Integer.parseInt(args[4]); 147 System.out.println("Main Duration = " + mainDuration); 148 int mainIterations = Integer.parseInt(args[5]); 149 System.out.println("# Main Iterations = " + mainIterations); 150 151 double liveFrac = Double.parseDouble(args[6]); 152 System.out.println("Live Fraction = " + liveFrac); 153 154 Thread threads[] = new Thread[Math.max(warmupThreads, mainThreads)]; 155 156 System.out.println("Start warm-up threads!"); 157 long warmupStartTime = System.currentTimeMillis(); 158 for (int i = 0; i < warmupThreads; i++) { 159 long seed = rng.nextLong(); 160 threads[i] = new Thread() { 161 public void run() { 162 warmUp(warmupStartTime + warmupDuration, warmupIterations, seed); 163 }; 164 }; 165 threads[i].start(); 166 } 167 168 joinThreads(threads); 169 170 System.gc(); 171 System.out.println("Keep alive a lot"); 172 173 long startTime = System.currentTimeMillis(); 174 for (int i = 0; i < mainThreads; i++) { 175 long seed = rng.nextLong(); 176 threads[i] = new Thread() { 177 public void run() { 178 runTest(startTime + mainDuration, mainIterations, liveFrac, seed); 179 }; 180 }; 181 threads[i].start(); 182 } 183 System.out.println("All threads started"); 184 185 joinThreads(threads); 186 187 if (hadError) { 188 throw new RuntimeException("Experienced an OoME during execution."); 189 } 190 } 191 }