1 /* 2 * Copyright (c) 2021, Red Hat, Inc. 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 /** 25 * @test 26 * @summary Stress test for ExtentLocal 27 * @modules jdk.incubator.concurrent 28 * @compile --enable-preview -source ${jdk.version} Stress.java 29 * @run testng/othervm/timeout=300 -XX:-TieredCompilation --enable-preview Stress 30 * @run testng/othervm/timeout=300 --enable-preview Stress 31 */ 32 33 import jdk.incubator.concurrent.ExtentLocal; 34 import jdk.incubator.concurrent.StructuredTaskScope; 35 import jdk.incubator.concurrent.StructureViolationException; 36 import java.util.concurrent.ThreadFactory; 37 import org.testng.annotations.Test; 38 import static org.testng.Assert.*; 39 40 public class Stress { 41 42 ExtentLocal<Integer> sl1 = ExtentLocal.newInstance(); 43 ExtentLocal<Integer> sl2 = ExtentLocal.newInstance(); 44 45 static final ExtentLocal<ThreadFactory> factory = ExtentLocal.newInstance(); 46 static final ExtentLocal.Carrier platformFactoryCarrier = ExtentLocal.where(factory, Thread.ofPlatform().factory()); 47 static final ExtentLocal.Carrier virtualFactoryCarrier = ExtentLocal.where(factory, Thread.ofVirtual().factory()); 48 49 final ExtentLocal<Integer>[] scopeLocals; 50 51 Stress() { 52 scopeLocals = new ExtentLocal[500]; 53 for (int i = 0; i < scopeLocals.length; i++) { 54 scopeLocals[i] = ExtentLocal.newInstance(); 55 } 56 } 57 58 private class MyBanger implements Runnable { 59 final ExtentLocal.Binder binder; 60 boolean shouldRunOutOfMemory; 61 boolean failed = false; 62 63 MyBanger(ExtentLocal.Binder binder, boolean shouldRunOutOfMemory) { 64 this.binder = binder; 65 this.shouldRunOutOfMemory = shouldRunOutOfMemory; 66 } 67 68 volatile int a[][] = new int[10000][]; 69 70 public void runOutOfMemory(int base, int size) { 71 for (int i = base; i < a.length; i++) { 72 try { 73 a[i] = new int[size]; 74 } catch (OutOfMemoryError e) { 75 size /= 2; 76 if (size == 0) { 77 return; 78 } 79 } 80 } 81 } 82 83 public void run() { 84 int n = sl1.get(); 85 try { 86 ExtentLocal.where(sl1, n + 1).run(this); 87 } catch (StackOverflowError e) { 88 if (sl1.get() != n) { 89 failed = true; 90 } 91 } 92 if (shouldRunOutOfMemory) { 93 runOutOfMemory(0, 0x1000_0000); 94 } 95 96 // Trigger a StructureViolationException 97 binder.close(); 98 } 99 100 } 101 102 public void stackOverflow() { 103 ExtentLocal.Binder binder = sl2.bind(99); 104 try { 105 var myBanger = new MyBanger(binder, false); 106 try { 107 ExtentLocal.where(sl1, 0, myBanger); 108 } catch (RuntimeException e) { 109 assertFalse(sl1.isBound()); 110 } finally { 111 binder.close(); 112 } 113 assertFalse(myBanger.failed); 114 } finally { 115 binder.close(); 116 } 117 } 118 119 private int deepBindings(int depth) { 120 try { 121 if (depth > 0) { 122 try (var unused = scopeLocals[depth].bind(depth)) { 123 var vx = scopeLocals[depth].get(); 124 return ExtentLocal.where(sl1, sl1.get() + 1) 125 .where(scopeLocals[depth], scopeLocals[depth].get() * 2) 126 .call(() -> scopeLocals[depth].get() + deepBindings(depth - 1) + sl1.get()); 127 } 128 } else { 129 return sl2.get(); 130 } 131 } catch (Exception foo) { 132 return 0; 133 } 134 } 135 136 private void deepBindings() { 137 int result; 138 try { 139 result = ExtentLocal.where(sl2, 42).where(sl1, 99).call(() -> 140 deepBindings(scopeLocals.length - 1)); 141 } catch (Exception e) { 142 throw new RuntimeException(e); 143 } 144 assertEquals(result, 423693); 145 } 146 147 private int deepBindings2(int depth) throws Exception { 148 if (depth > 0) { 149 try (var unused = scopeLocals[depth].bind(depth)) { 150 try (var structuredTaskScope = new StructuredTaskScope<Integer>(null, factory.get())) { 151 var future = structuredTaskScope.fork( 152 () -> ExtentLocal.where(sl1, sl1.get() + 1) 153 .where(scopeLocals[depth], scopeLocals[depth].get() * 2) 154 .call(() -> scopeLocals[depth].get() + deepBindings2(depth - 1) + sl1.get())); 155 structuredTaskScope.join(); 156 return future.get(); 157 } 158 } 159 } else { 160 return sl2.get(); 161 } 162 } 163 164 // Serious abuse of ExtentLocals. Make sure everything still works, 165 // even with a ridiculous number of bindings. 166 @Test 167 public void manyExtentLocals() { 168 ExtentLocal<Object>[] scopeLocals = new ExtentLocal[10_000]; 169 ExtentLocal.Binder[] binders = new ExtentLocal.Binder[scopeLocals.length]; 170 171 for (int i = 0; i < scopeLocals.length; i++) { 172 scopeLocals[i] = ExtentLocal.newInstance(); 173 binders[i] = scopeLocals[i].bind(i); 174 } 175 long n = 0; 176 for (var sl : scopeLocals) { 177 n += (Integer)sl.get(); 178 } 179 for (int i = scopeLocals.length - 1; i >= 0; --i) { 180 binders[i].close(); 181 } 182 assertEquals(n, 49995000); 183 for (int i = 0; i < scopeLocals.length; i++) { 184 binders[i] = scopeLocals[i].bind(i); 185 } 186 int caught = 0; 187 // Trigger StructureViolationExceptions 188 for (int i = scopeLocals.length - 2; i >= 0; i -= 2) { 189 try { 190 binders[i].close(); 191 } catch (StructureViolationException x) { 192 caught++; 193 } 194 } 195 196 assertEquals(caught, 5000); 197 198 // They should all be closed now 199 caught = 0; 200 for (int i = scopeLocals.length - 1; i >= 0; --i) { 201 binders[i].close(); 202 try { 203 binders[i].close(); 204 } catch (StructureViolationException x) { 205 caught++; 206 } 207 } 208 assertEquals(caught, 0); 209 } 210 211 private void testDeepBindings(ExtentLocal.Carrier factoryCarrier) { 212 int val = 0; 213 try (var unused = factoryCarrier.where(sl2, 42).where(sl1, 99).bind()) { 214 val = deepBindings2(scopeLocals.length - 1); 215 } catch (Exception e) { 216 throw new RuntimeException(e); 217 } 218 assertEquals(val, 423693); 219 } 220 221 // Make sure that stack overflows are handled correctly. 222 // Run for a while to trigger JIT compilation. 223 @Test 224 public void stackOverflowTest() { 225 assertFalse(sl2.isBound()); 226 for (int i = 0; i < 200; i++) { 227 try { 228 stackOverflow(); 229 } catch (Throwable t) { 230 ; 231 } 232 assertFalse(sl2.isBound()); 233 } 234 } 235 236 @Test 237 public void platformFactorydeepBindings() { 238 testDeepBindings(platformFactoryCarrier); 239 } 240 241 @Test 242 public void virtualFactorydeepBindings() { 243 testDeepBindings(virtualFactoryCarrier); 244 } 245 246 void run() { 247 manyExtentLocals(); 248 platformFactorydeepBindings(); 249 stackOverflowTest(); 250 virtualFactorydeepBindings(); 251 } 252 253 public static void main(String[] args) { 254 new Stress().run(); 255 } 256 }