test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java
changeset 50243 4fac3c99487d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java	Wed May 23 17:09:49 2018 -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<DefMethTest> 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<? extends DefMethTest> 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<? extends DefMethTest> 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);
+    }
+}