jdk-24/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java
Vladimir Ivanov 229a6e2f36 8267095: Miscellaneous cleanups in vm.runtime.defmeth tests
Reviewed-by: dholmes, hseigel
2021-06-01 11:09:35 +00:00

312 lines
10 KiB
Java

/*
* Copyright (c) 2013, 2021, 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.
*/
/*
* @test
*
* @modules java.base/jdk.internal.org.objectweb.asm:+open java.base/jdk.internal.org.objectweb.asm.util:+open
* @library /vmTestbase /test/lib
*
* @comment build retransform.jar in current dir
* @run driver vm.runtime.defmeth.shared.BuildJar
*
* @run driver jdk.test.lib.FileInstaller . .
*
* @run main/othervm/native
* -agentlib:redefineClasses
* -javaagent:retransform.jar
* vm.runtime.defmeth.StressTest
*/
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.share.options.Option;
import vm.share.options.OptionSupport;
import vm.share.options.Options;
import jdk.test.lib.Utils;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import static vm.runtime.defmeth.shared.DefMethTest.MAX_MAJOR_VER;
import static vm.runtime.defmeth.shared.DefMethTest.MIN_MAJOR_VER;
/*
* 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 long seed;
@Option(name="noredefine", default_value="false", description="skip scenarios w/ class redefinition")
private boolean noRedefine;
@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, long 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[MAX_MAJOR_VER - MIN_MAJOR_VER + 1];
for (int i = 0; i< majorVerValues.length; i++) {
majorVerValues[i] = MIN_MAJOR_VER + i;
}
int[] flagsValues = new int[] {0, ACC_SYNCHRONIZED};
boolean[] doRedefineValues;
if (noRedefine) {
doRedefineValues = new boolean[] { false };
} else {
doRedefineValues = new boolean[] { false, true };
}
// 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.getDeclaredConstructor().newInstance();
OptionSupport.setup(test, new String[] {
"-execMode", mode.toString(),
"-ver", Integer.toString(majorVer),
"-flags", Integer.toString(flags),
"-redefine", Boolean.toString(redefine),
"-silent",
"-failfast"});
testlist.add(test);
} catch (ReflectiveOperationException ex) {
throw new TestFailure(ex);
}
}
}
}
}
}
System.out.printf("Testlist size: %d\n", testlist.size());
}
private void startWorkers() {
Random rand;
if (seed == 0) {
seed = Utils.SEED;
}
System.out.printf("Seed: %d\n", seed);
rand = new Random(seed);
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.nextLong());
}
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);
}
}