--- /dev/null 2018-05-14 10:15:02.574213890 -0700 +++ new/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java 2018-05-21 10:49:51.417497429 -0700 @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package vm.runtime.defmeth; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import nsk.share.TestFailure; +import nsk.share.test.StressOptions; +import nsk.share.test.Stresser; +import vm.runtime.defmeth.shared.Constants; +import vm.runtime.defmeth.shared.DefMethTest; +import vm.runtime.defmeth.shared.ExecutionMode; +import vm.runtime.defmeth.shared.builder.TestBuilder; +import vm.share.options.Option; +import vm.share.options.OptionSupport; +import vm.share.options.Options; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +/* + * Stress test for default methods implementation. + * + * Stress scenario is the following: + * - in multiple threads ... + * - ... continuously run random tests ... + * - ... in random configuration ... + * - ... until predefined period of time is over... + * - ... or any failures occured. + */ +public class StressTest implements Runnable { + @Options + private StressOptions opts = new StressOptions(); + + @Option(name="seed", default_value="0", description="force deterministic behavior") + private int seed; + + @Option(name="redefine", default_value="false", description="use scenarios w/ class redefinition") + private boolean doRedefine; + + @Option(name="ver", default_value="49", description="minimum class file version to be used in the tests") + private int minMajorVer; + + @Option(name="ignoreTestFailures", default_value="false", description="ignore failures of the executed tests") + private boolean ignoreTestFailures; + + class Worker extends Thread { + private final Random rand; + + private volatile DefMethTest failedTest; + private Throwable reason; + private volatile long executedTests = 0; + + public Worker(String id, int seed) { + setName(id); + this.rand = new Random(seed); + } + + @Override + public void run() { + while (!Thread.interrupted()) { + int idx = rand.nextInt(testlist.size()); + DefMethTest test = testlist.get(idx); + try { + test.run(); + executedTests++; + if (test.isFailed()) { + throw new TestFailure(test.toString()); + } + } catch (Throwable e) { + if (!ignoreTestFailures) { + failedTest = test; + reason = e; + break; + } + } + } + } + + public boolean isFailed() { return failedTest != null; } + public Throwable getReason() { return reason; } + public DefMethTest getFailedTest() { return failedTest; } + public long getExecutedTests() { return executedTests; } + } + + private List testlist; + + private Worker[] workers; + + Stresser stresser; + + public static void main(String[] args) { + StressTest test = new StressTest(); + OptionSupport.setupAndRun(test, args); + } + + @Override + public void run() { + configureTests(); + startWorkers(); + + stresser = new Stresser(opts); + try { + stresser.start(0); + while (workersAlive() && stresser.continueExecution()) { + printStats(); + + try { + Thread.sleep(1000); + } catch (InterruptedException ex) {} + } + } finally { + interruptWorkers(); + joinWorkers(); + + stresser.finish(); + } + } + + private void configureTests() { + int[] majorVerValues = new int[52 - minMajorVer + 1]; + for (int i = 0; i< majorVerValues.length; i++) { + majorVerValues[i] = minMajorVer + i; + } + + int[] flagsValues = new int[] { + 0, + ACC_STRICT, + ACC_SYNCHRONIZED, + ACC_STRICT | ACC_SYNCHRONIZED + }; + + boolean[] doRedefineValues; + if (doRedefine) { + doRedefineValues = new boolean[] { true, false}; + } else { + doRedefineValues = new boolean[] { false }; + } + + // Upper limit for test count + int testCount = DefMethTest.getTests().size() * majorVerValues.length + * flagsValues.length * doRedefineValues.length; + + testlist = new ArrayList<>(testCount); + + // Enumerate all tests in all possible modes + for (Class testClass : DefMethTest.getTests()) { + for (ExecutionMode mode : ExecutionMode.values()) { + // Skip REDEFINITION execmode, the top README file indicates that it isn't a + // valid execution mode and there's also no code supporting this in the test generator. + if ("REDEFINITION".equals(mode.toString())) { + continue; + } + + for (int majorVer : majorVerValues) { + for (int flags : flagsValues ) { + for (boolean redefine : doRedefineValues) { + // RedefineTest isn't applicable to reflection-based execution scenario (REDEFINE & INVOKE_WITH_ARGS) + if (testClass == RedefineTest.class && mode.isReflectionBased()) { + continue; + } + + // Only run the RedefineTest tests when redefining + if (!redefine && testClass == RedefineTest.class) { + continue; + } + + try { + DefMethTest test = testClass.newInstance(); + + OptionSupport.setup(test, new String[] { + "-execMode", mode.toString(), + "-ver", Integer.toString(majorVer), + "-flags", Integer.toString(flags), + "-redefine", Boolean.toString(redefine), + "-ignoreCrashes", + "-ignoreKnownFailures", + "-silent", + "-failfast"}); + + testlist.add(test); + } catch (InstantiationException | IllegalAccessException ex) { + throw new TestFailure(ex); + } + } + } + } + } + } + + System.out.printf("Testlist size: %d\n", testlist.size()); + } + + private void startWorkers() { + Random rand; + if (seed == 0) { + seed = (new Random()).nextInt(); + } + + System.out.printf("Seed: %d\n", seed); + rand = new Random(seed); + + //Workaround for the deadlock caused by + // JDK-7122142: "(ann) Race condition between isAnnotationPresent and getAnnotations" + try { + // Do a warm-up cycle + for (Class testClass : DefMethTest.getTests()) { + DefMethTest test = testClass.newInstance(); + + OptionSupport.setupAndRun(test, + new String[] { "-silent", "-ignoreKnownFailures"}); + } + } catch(InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + + int threadsCount = opts.getThreadsFactor(); + if (threadsCount == 1) { + threadsCount = 5; + } + + workers = new Worker[threadsCount]; + + System.out.printf("Spawning %d workers...\n", workers.length); + + for (int i = 0; i < workers.length; i++) { + workers[i] = new Worker( + String.format("Worker #%d/%d", i+1, workers.length), + rand.nextInt()); + } + + for (Worker worker : workers) { + worker.start(); + } + } + + private void interruptWorkers() { + for (Worker worker : workers) { + worker.interrupt(); + } + } + + private void joinWorkers() { + boolean isFailed = false; + + for (Worker worker : workers) { + while (worker.isAlive()) { + try { + worker.join(); + } catch (InterruptedException e) {} + } + + System.out.printf("%s: %s (executed: %d)\n", + worker.getName(), + worker.isFailed() ? "FAILED: " + worker.getFailedTest() : "PASSED", + worker.getExecutedTests()); + + if (worker.isFailed()) { + if (Constants.PRINT_STACK_TRACE) { + worker.getReason().printStackTrace(); + } + + isFailed = true; + } + } + + if (isFailed) { + throw new TestFailure("Some of the worker threads failed."); + } + } + + private boolean workersAlive() { + for (Worker worker : workers) { + if (!worker.isAlive()) { + return false; + } + } + + return true; + } + + private void printStats() { + long[] counts = new long[workers.length]; + for (int i = 0; i < counts.length; i++) { + counts[i] = workers[i].executedTests; + } + + StringBuilder msg = new StringBuilder(); + msg.append(stresser.getTimeLeft() / 1000).append("s left: "); + msg.append(Arrays.toString(counts)); + + System.out.println(msg); + } +}