1 /* 2 * Copyright (c) 2018, 2019, Red Hat, Inc. and/or its affiliates. 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 package gc.stress; 25 26 import java.util.Random; 27 28 import gc.CriticalNative; 29 30 /* 31 * @test CriticalNativeStressEpsilon 32 * @key gc 33 * @bug 8199868 34 * @library / 35 * @requires (os.arch =="x86_64" | os.arch == "amd64" | os.arch=="x86" | os.arch=="i386") & vm.gc.Epsilon & !vm.graal.enabled 36 * @summary test argument pinning by nmethod wrapper of critical native method 37 * @run main/othervm/native -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xcomp -Xmx1G -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 38 */ 39 40 /* 41 * @test CriticalNativeStressShenandoah 42 * @key gc 43 * @bug 8199868 44 * @library / 45 * @requires (os.arch =="x86_64" | os.arch == "amd64" | os.arch=="x86" | os.arch=="i386") & vm.gc.Shenandoah & !vm.graal.enabled 46 * @summary test argument pinning by nmethod wrapper of critical native method 47 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive -XX:-ShenandoahDegeneratedGC -Xcomp -Xmx512M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 48 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive -XX:+ShenandoahDegeneratedGC -Xcomp -Xmx512M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 49 * 50 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive -Xcomp -Xmx512M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 51 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xcomp -Xmx256M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 52 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -Xcomp -Xmx512M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 53 * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive -Xcomp -Xmx512M -XX:+CriticalJNINatives gc.stress.CriticalNativeStress 54 */ 55 public class CriticalNativeStress { 56 private static Random rand = new Random(); 57 58 // CYCLES and THREAD_PER_CASE are used to tune the tests for different GC settings, 59 // so that they can execrise enough GC cycles and not OOM 60 private static int CYCLES = Integer.getInteger("cycles", 3); 61 private static int THREAD_PER_CASE = Integer.getInteger("threadPerCase", 1); 62 63 static long sum(long[] a) { 64 long sum = 0; 65 for (int index = 0; index < a.length; index ++) { 66 sum += a[index]; 67 } 68 return sum; 69 } 70 71 static long sum(int[] a) { 72 long sum = 0; 73 for (int index = 0; index < a.length; index ++) { 74 sum += a[index]; 75 } 76 return sum; 77 } 78 79 private static volatile String garbage_array[]; 80 81 // GC potentially moves arrays passed to critical native methods 82 // if they are not pinned correctly. 83 // Create enough garbages to exercise GC cycles, verify 84 // the arrays are pinned correctly. 85 static void create_garbage(int len) { 86 len = Math.max(len, 1024); 87 String array[] = new String[len]; 88 for (int index = 0; index < len; index ++) { 89 array[index] = "String " + index; 90 } 91 garbage_array = array; 92 } 93 94 // Two test cases with different method signatures: 95 // Tests generate arbitrary length of arrays with 96 // arbitrary values, then calcuate sum of the array 97 // elements with critical native JNI methods and java 98 // methods, and compare the results for correctness. 99 static void run_test_case1() { 100 // Create testing arary with arbitrary length and 101 // values 102 int length = rand.nextInt(50) + 1; 103 long[] arr = new long[length]; 104 for (int index = 0; index < length; index ++) { 105 arr[index] = rand.nextLong() % 1002; 106 } 107 108 // Generate garbages to trigger GCs 109 for (int index = 0; index < length; index ++) { 110 create_garbage(index); 111 } 112 113 // Compare results for correctness. 114 long native_sum = CriticalNative.sum1(arr); 115 long java_sum = sum(arr); 116 if (native_sum != java_sum) { 117 StringBuffer sb = new StringBuffer("Sums do not match: native = ") 118 .append(native_sum).append(" java = ").append(java_sum); 119 120 throw new RuntimeException(sb.toString()); 121 } 122 } 123 124 static void run_test_case2() { 125 // Create testing arary with arbitrary length and 126 // values 127 int index; 128 long a1 = rand.nextLong() % 1025; 129 130 int a2_length = rand.nextInt(50) + 1; 131 int[] a2 = new int[a2_length]; 132 for (index = 0; index < a2_length; index ++) { 133 a2[index] = rand.nextInt(106); 134 } 135 136 int a3_length = rand.nextInt(150) + 1; 137 int[] a3 = new int[a3_length]; 138 for (index = 0; index < a3_length; index ++) { 139 a3[index] = rand.nextInt(3333); 140 } 141 142 int a4_length = rand.nextInt(200) + 1; 143 long[] a4 = new long[a4_length]; 144 for (index = 0; index < a4_length; index ++) { 145 a4[index] = rand.nextLong() % 122; 146 } 147 148 int a5_length = rand.nextInt(350) + 1; 149 int[] a5 = new int[a5_length]; 150 for (index = 0; index < a5_length; index ++) { 151 a5[index] = rand.nextInt(333); 152 } 153 154 // Generate garbages to trigger GCs 155 for (index = 0; index < a1; index ++) { 156 create_garbage(index); 157 } 158 159 // Compare results for correctness. 160 long native_sum = CriticalNative.sum2(a1, a2, a3, a4, a5); 161 long java_sum = a1 + sum(a2) + sum(a3) + sum(a4) + sum(a5); 162 if (native_sum != java_sum) { 163 StringBuffer sb = new StringBuffer("Sums do not match: native = ") 164 .append(native_sum).append(" java = ").append(java_sum); 165 166 throw new RuntimeException(sb.toString()); 167 } 168 } 169 170 static class Case1Runner extends Thread { 171 public Case1Runner() { 172 start(); 173 } 174 175 public void run() { 176 for (int index = 0; index < CYCLES; index ++) { 177 run_test_case1(); 178 } 179 } 180 } 181 182 static class Case2Runner extends Thread { 183 public Case2Runner() { 184 start(); 185 } 186 187 public void run() { 188 for (int index = 0; index < CYCLES; index ++) { 189 run_test_case2(); 190 } 191 } 192 } 193 194 public static void main(String[] args) { 195 Thread[] thrs = new Thread[THREAD_PER_CASE * 2]; 196 for (int index = 0; index < thrs.length; index = index + 2) { 197 thrs[index] = new Case1Runner(); 198 thrs[index + 1] = new Case2Runner(); 199 } 200 201 for (int index = 0; index < thrs.length; index ++) { 202 try { 203 thrs[index].join(); 204 } catch (Exception e) { 205 e.printStackTrace(); 206 } 207 } 208 } 209 }