|
1 /* |
|
2 * Copyright (c) 2013, 2018, 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 package vm.runtime.defmeth; |
|
25 |
|
26 import java.util.ArrayList; |
|
27 import java.util.Arrays; |
|
28 import java.util.List; |
|
29 import java.util.Random; |
|
30 import nsk.share.TestFailure; |
|
31 import nsk.share.test.StressOptions; |
|
32 import nsk.share.test.Stresser; |
|
33 import vm.runtime.defmeth.shared.Constants; |
|
34 import vm.runtime.defmeth.shared.DefMethTest; |
|
35 import vm.runtime.defmeth.shared.ExecutionMode; |
|
36 import vm.runtime.defmeth.shared.builder.TestBuilder; |
|
37 import vm.share.options.Option; |
|
38 import vm.share.options.OptionSupport; |
|
39 import vm.share.options.Options; |
|
40 import static jdk.internal.org.objectweb.asm.Opcodes.*; |
|
41 |
|
42 /* |
|
43 * Stress test for default methods implementation. |
|
44 * |
|
45 * Stress scenario is the following: |
|
46 * - in multiple threads ... |
|
47 * - ... continuously run random tests ... |
|
48 * - ... in random configuration ... |
|
49 * - ... until predefined period of time is over... |
|
50 * - ... or any failures occured. |
|
51 */ |
|
52 public class StressTest implements Runnable { |
|
53 @Options |
|
54 private StressOptions opts = new StressOptions(); |
|
55 |
|
56 @Option(name="seed", default_value="0", description="force deterministic behavior") |
|
57 private int seed; |
|
58 |
|
59 @Option(name="redefine", default_value="false", description="use scenarios w/ class redefinition") |
|
60 private boolean doRedefine; |
|
61 |
|
62 @Option(name="ver", default_value="49", description="minimum class file version to be used in the tests") |
|
63 private int minMajorVer; |
|
64 |
|
65 @Option(name="ignoreTestFailures", default_value="false", description="ignore failures of the executed tests") |
|
66 private boolean ignoreTestFailures; |
|
67 |
|
68 class Worker extends Thread { |
|
69 private final Random rand; |
|
70 |
|
71 private volatile DefMethTest failedTest; |
|
72 private Throwable reason; |
|
73 private volatile long executedTests = 0; |
|
74 |
|
75 public Worker(String id, int seed) { |
|
76 setName(id); |
|
77 this.rand = new Random(seed); |
|
78 } |
|
79 |
|
80 @Override |
|
81 public void run() { |
|
82 while (!Thread.interrupted()) { |
|
83 int idx = rand.nextInt(testlist.size()); |
|
84 DefMethTest test = testlist.get(idx); |
|
85 try { |
|
86 test.run(); |
|
87 executedTests++; |
|
88 if (test.isFailed()) { |
|
89 throw new TestFailure(test.toString()); |
|
90 } |
|
91 } catch (Throwable e) { |
|
92 if (!ignoreTestFailures) { |
|
93 failedTest = test; |
|
94 reason = e; |
|
95 break; |
|
96 } |
|
97 } |
|
98 } |
|
99 } |
|
100 |
|
101 public boolean isFailed() { return failedTest != null; } |
|
102 public Throwable getReason() { return reason; } |
|
103 public DefMethTest getFailedTest() { return failedTest; } |
|
104 public long getExecutedTests() { return executedTests; } |
|
105 } |
|
106 |
|
107 private List<DefMethTest> testlist; |
|
108 |
|
109 private Worker[] workers; |
|
110 |
|
111 Stresser stresser; |
|
112 |
|
113 public static void main(String[] args) { |
|
114 StressTest test = new StressTest(); |
|
115 OptionSupport.setupAndRun(test, args); |
|
116 } |
|
117 |
|
118 @Override |
|
119 public void run() { |
|
120 configureTests(); |
|
121 startWorkers(); |
|
122 |
|
123 stresser = new Stresser(opts); |
|
124 try { |
|
125 stresser.start(0); |
|
126 while (workersAlive() && stresser.continueExecution()) { |
|
127 printStats(); |
|
128 |
|
129 try { |
|
130 Thread.sleep(1000); |
|
131 } catch (InterruptedException ex) {} |
|
132 } |
|
133 } finally { |
|
134 interruptWorkers(); |
|
135 joinWorkers(); |
|
136 |
|
137 stresser.finish(); |
|
138 } |
|
139 } |
|
140 |
|
141 private void configureTests() { |
|
142 int[] majorVerValues = new int[52 - minMajorVer + 1]; |
|
143 for (int i = 0; i< majorVerValues.length; i++) { |
|
144 majorVerValues[i] = minMajorVer + i; |
|
145 } |
|
146 |
|
147 int[] flagsValues = new int[] { |
|
148 0, |
|
149 ACC_STRICT, |
|
150 ACC_SYNCHRONIZED, |
|
151 ACC_STRICT | ACC_SYNCHRONIZED |
|
152 }; |
|
153 |
|
154 boolean[] doRedefineValues; |
|
155 if (doRedefine) { |
|
156 doRedefineValues = new boolean[] { true, false}; |
|
157 } else { |
|
158 doRedefineValues = new boolean[] { false }; |
|
159 } |
|
160 |
|
161 // Upper limit for test count |
|
162 int testCount = DefMethTest.getTests().size() * majorVerValues.length |
|
163 * flagsValues.length * doRedefineValues.length; |
|
164 |
|
165 testlist = new ArrayList<>(testCount); |
|
166 |
|
167 // Enumerate all tests in all possible modes |
|
168 for (Class<? extends DefMethTest> testClass : DefMethTest.getTests()) { |
|
169 for (ExecutionMode mode : ExecutionMode.values()) { |
|
170 // Skip REDEFINITION execmode, the top README file indicates that it isn't a |
|
171 // valid execution mode and there's also no code supporting this in the test generator. |
|
172 if ("REDEFINITION".equals(mode.toString())) { |
|
173 continue; |
|
174 } |
|
175 |
|
176 for (int majorVer : majorVerValues) { |
|
177 for (int flags : flagsValues ) { |
|
178 for (boolean redefine : doRedefineValues) { |
|
179 // RedefineTest isn't applicable to reflection-based execution scenario (REDEFINE & INVOKE_WITH_ARGS) |
|
180 if (testClass == RedefineTest.class && mode.isReflectionBased()) { |
|
181 continue; |
|
182 } |
|
183 |
|
184 // Only run the RedefineTest tests when redefining |
|
185 if (!redefine && testClass == RedefineTest.class) { |
|
186 continue; |
|
187 } |
|
188 |
|
189 try { |
|
190 DefMethTest test = testClass.newInstance(); |
|
191 |
|
192 OptionSupport.setup(test, new String[] { |
|
193 "-execMode", mode.toString(), |
|
194 "-ver", Integer.toString(majorVer), |
|
195 "-flags", Integer.toString(flags), |
|
196 "-redefine", Boolean.toString(redefine), |
|
197 "-ignoreCrashes", |
|
198 "-ignoreKnownFailures", |
|
199 "-silent", |
|
200 "-failfast"}); |
|
201 |
|
202 testlist.add(test); |
|
203 } catch (InstantiationException | IllegalAccessException ex) { |
|
204 throw new TestFailure(ex); |
|
205 } |
|
206 } |
|
207 } |
|
208 } |
|
209 } |
|
210 } |
|
211 |
|
212 System.out.printf("Testlist size: %d\n", testlist.size()); |
|
213 } |
|
214 |
|
215 private void startWorkers() { |
|
216 Random rand; |
|
217 if (seed == 0) { |
|
218 seed = (new Random()).nextInt(); |
|
219 } |
|
220 |
|
221 System.out.printf("Seed: %d\n", seed); |
|
222 rand = new Random(seed); |
|
223 |
|
224 //Workaround for the deadlock caused by |
|
225 // JDK-7122142: "(ann) Race condition between isAnnotationPresent and getAnnotations" |
|
226 try { |
|
227 // Do a warm-up cycle |
|
228 for (Class<? extends DefMethTest> testClass : DefMethTest.getTests()) { |
|
229 DefMethTest test = testClass.newInstance(); |
|
230 |
|
231 OptionSupport.setupAndRun(test, |
|
232 new String[] { "-silent", "-ignoreKnownFailures"}); |
|
233 } |
|
234 } catch(InstantiationException | IllegalAccessException e) { |
|
235 throw new RuntimeException(e); |
|
236 } |
|
237 |
|
238 int threadsCount = opts.getThreadsFactor(); |
|
239 if (threadsCount == 1) { |
|
240 threadsCount = 5; |
|
241 } |
|
242 |
|
243 workers = new Worker[threadsCount]; |
|
244 |
|
245 System.out.printf("Spawning %d workers...\n", workers.length); |
|
246 |
|
247 for (int i = 0; i < workers.length; i++) { |
|
248 workers[i] = new Worker( |
|
249 String.format("Worker #%d/%d", i+1, workers.length), |
|
250 rand.nextInt()); |
|
251 } |
|
252 |
|
253 for (Worker worker : workers) { |
|
254 worker.start(); |
|
255 } |
|
256 } |
|
257 |
|
258 private void interruptWorkers() { |
|
259 for (Worker worker : workers) { |
|
260 worker.interrupt(); |
|
261 } |
|
262 } |
|
263 |
|
264 private void joinWorkers() { |
|
265 boolean isFailed = false; |
|
266 |
|
267 for (Worker worker : workers) { |
|
268 while (worker.isAlive()) { |
|
269 try { |
|
270 worker.join(); |
|
271 } catch (InterruptedException e) {} |
|
272 } |
|
273 |
|
274 System.out.printf("%s: %s (executed: %d)\n", |
|
275 worker.getName(), |
|
276 worker.isFailed() ? "FAILED: " + worker.getFailedTest() : "PASSED", |
|
277 worker.getExecutedTests()); |
|
278 |
|
279 if (worker.isFailed()) { |
|
280 if (Constants.PRINT_STACK_TRACE) { |
|
281 worker.getReason().printStackTrace(); |
|
282 } |
|
283 |
|
284 isFailed = true; |
|
285 } |
|
286 } |
|
287 |
|
288 if (isFailed) { |
|
289 throw new TestFailure("Some of the worker threads failed."); |
|
290 } |
|
291 } |
|
292 |
|
293 private boolean workersAlive() { |
|
294 for (Worker worker : workers) { |
|
295 if (!worker.isAlive()) { |
|
296 return false; |
|
297 } |
|
298 } |
|
299 |
|
300 return true; |
|
301 } |
|
302 |
|
303 private void printStats() { |
|
304 long[] counts = new long[workers.length]; |
|
305 for (int i = 0; i < counts.length; i++) { |
|
306 counts[i] = workers[i].executedTests; |
|
307 } |
|
308 |
|
309 StringBuilder msg = new StringBuilder(); |
|
310 msg.append(stresser.getTimeLeft() / 1000).append("s left: "); |
|
311 msg.append(Arrays.toString(counts)); |
|
312 |
|
313 System.out.println(msg); |
|
314 } |
|
315 } |