1 /* 2 * Copyright (c) 2018, Red Hat, Inc. and/or its affiliates. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 * 22 */ 23 package gc.stress; 24 25 import java.util.Random; 26 27 import gc.CriticalNative; 28 29 /* 30 * @test CriticalNativeStressEpsilon 31 * @key gc 32 * @bug 8199868 33 * @library ../.. 34 * @requires (os.arch =="x86_64" | os.arch == "amd64") & vm.gc.Epsilon & !vm.graal.enabled 35 * @summary test argument pinning by nmethod wrapper of critical native method 36 * @run main/othervm/native -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xcomp -Xmx1G -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 37 */ 38 39 /* 40 * @test CriticalNativeStressShenandoah 41 * @key gc 42 * @bug 8199868 43 * @library ../.. 44 * @requires (os.arch =="x86_64" | os.arch == "amd64") & vm.gc.Shenandoah & !vm.graal.enabled 45 * @summary test argument pinning by nmethod wrapper of critical native method 46 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=passive -XX:-ShenandoahDegeneratedGC -Xcomp -Xmx512M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 47 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=passive -XX:+ShenandoahDegeneratedGC -Xcomp -Xmx512M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 48 * 49 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive -Xcomp -Xmx512M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 50 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xcomp -Xmx256M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 51 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=traversal -Xcomp -Xmx512M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 52 */ 53 public class CriticalNativeStress { 54 private static Random rand = new Random(); 55 56 // CYCLES and THREAD_PER_CASE are used to tune the tests for different GC settings, 57 // so that they can execrise enough GC cycles and not OOM 58 private static int CYCLES = Integer.getInteger("cycles", 3); 59 private static int THREAD_PER_CASE = Integer.getInteger("threadPerCase", 1); 60 61 static long sum(long[] a) { 62 long sum = 0; 63 for (int index = 0; index < a.length; index ++) { 64 sum += a[index]; 65 } 66 return sum; 67 } 68 69 static long sum(int[] a) { 70 long sum = 0; 71 for (int index = 0; index < a.length; index ++) { 72 sum += a[index]; 73 } 74 return sum; 75 } 76 77 private static volatile String garbage_array[]; 78 79 // GC potentially moves arrays passed to critical native methods 80 // if they are not pinned correctly. 81 // Create enough garbages to exercise GC cycles, verify 82 // the arrays are pinned correctly. 83 static void create_garbage(int len) { 84 len = Math.max(len, 1024); 85 String array[] = new String[len]; 86 for (int index = 0; index < len; index ++) { 87 array[index] = "String " + index; 88 } 89 garbage_array = array; 90 } 91 92 // Two test cases with different method signatures: 93 // Tests generate arbitrary length of arrays with 94 // arbitrary values, then calcuate sum of the array 95 // elements with critical native JNI methods and java 96 // methods, and compare the results for correctness. 97 static void run_test_case1() { 98 // Create testing arary with arbitrary length and 99 // values 100 int length = rand.nextInt(50) + 1; 101 long[] arr = new long[length]; 102 for (int index = 0; index < length; index ++) { 103 arr[index] = rand.nextLong() % 1002; 104 } 105 106 // Generate garbages to trigger GCs 107 for (int index = 0; index < length; index ++) { 108 create_garbage(index); 109 } 110 111 // Compare results for correctness. 112 long native_sum = CriticalNative.sum1(arr); 113 long java_sum = sum(arr); 114 if (native_sum != java_sum) { 115 StringBuffer sb = new StringBuffer("Sums do not match: native = ") 116 .append(native_sum).append(" java = ").append(java_sum); 117 118 throw new RuntimeException(sb.toString()); 119 } 120 } 121 122 static void run_test_case2() { 123 // Create testing arary with arbitrary length and 124 // values 125 int index; 126 long a1 = rand.nextLong() % 1025; 127 128 int a2_length = rand.nextInt(50) + 1; 129 int[] a2 = new int[a2_length]; 130 for (index = 0; index < a2_length; index ++) { 131 a2[index] = rand.nextInt(106); 132 } 133 134 int a3_length = rand.nextInt(150) + 1; 135 int[] a3 = new int[a3_length]; 136 for (index = 0; index < a3_length; index ++) { 137 a3[index] = rand.nextInt(3333); 138 } 139 140 int a4_length = rand.nextInt(200) + 1; 141 long[] a4 = new long[a4_length]; 142 for (index = 0; index < a4_length; index ++) { 143 a4[index] = rand.nextLong() % 122; 144 } 145 146 int a5_length = rand.nextInt(350) + 1; 147 int[] a5 = new int[a5_length]; 148 for (index = 0; index < a5_length; index ++) { 149 a5[index] = rand.nextInt(333); 150 } 151 152 // Generate garbages to trigger GCs 153 for (index = 0; index < a1; index ++) { 154 create_garbage(index); 155 } 156 157 // Compare results for correctness. 158 long native_sum = CriticalNative.sum2(a1, a2, a3, a4, a5); 159 long java_sum = a1 + sum(a2) + sum(a3) + sum(a4) + sum(a5); 160 if (native_sum != java_sum) { 161 StringBuffer sb = new StringBuffer("Sums do not match: native = ") 162 .append(native_sum).append(" java = ").append(java_sum); 163 164 throw new RuntimeException(sb.toString()); 165 } 166 } 167 168 static class Case1Runner extends Thread { 169 public Case1Runner() { 170 start(); 171 } 172 173 public void run() { 174 for (int index = 0; index < CYCLES; index ++) { 175 run_test_case1(); 176 } 177 } 178 } 179 180 static class Case2Runner extends Thread { 181 public Case2Runner() { 182 start(); 183 } 184 185 public void run() { 186 for (int index = 0; index < CYCLES; index ++) { 187 run_test_case2(); 188 } 189 } 190 } 191 192 public static void main(String[] args) { 193 Thread[] thrs = new Thread[THREAD_PER_CASE * 2]; 194 for (int index = 0; index < thrs.length; index = index + 2) { 195 thrs[index] = new Case1Runner(); 196 thrs[index + 1] = new Case2Runner(); 197 } 198 199 for (int index = 0; index < thrs.length; index ++) { 200 try { 201 thrs[index].join(); 202 } catch (Exception e) { 203 e.printStackTrace(); 204 } 205 } 206 } 207 }