8242314: use reproducible random in vmTestbase shared code

Reviewed-by: kbarrett, lmesnik
This commit is contained in:
Igor Ignatyev 2020-04-28 20:49:28 -07:00
parent 9320f9c60a
commit 6ff66db553
7 changed files with 107 additions and 52 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,16 +21,16 @@
* questions. * questions.
*/ */
import jdk.test.lib.Platform;
import jdk.test.lib.Utils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/** /**
* Starts a new process to execute a command. * Starts a new process to execute a command.
@ -48,6 +48,10 @@ import java.util.Arrays;
* {@code --java}, i.e. 0 or 95 means pass. * {@code --java}, i.e. 0 or 95 means pass.
*/ */
public class ExecDriver { public class ExecDriver {
// copied from jdk.test.lib.Utils.TEST_CLASS_PATH
private static final String TEST_CLASS_PATH = System.getProperty("test.class.path", ".");
// copied from jdk.test.lib.Utils.TEST_CLASS_PATH
private static final String TEST_JDK = System.getProperty("test.jdk");
public static void main(String[] args) throws IOException, InterruptedException { public static void main(String[] args) throws IOException, InterruptedException {
boolean java = false; boolean java = false;
boolean launcher = false; boolean launcher = false;
@ -68,7 +72,7 @@ public class ExecDriver {
} }
args[0] = javaBin(); args[0] = javaBin();
args[1] = "-cp"; args[1] = "-cp";
args[2] = Utils.TEST_CLASS_PATH; args[2] = TEST_CLASS_PATH;
System.arraycopy(oldArgs, 1, args, count, oldArgs.length - 1); System.arraycopy(oldArgs, 1, args, count, oldArgs.length - 1);
java = true; java = true;
break; break;
@ -84,7 +88,7 @@ public class ExecDriver {
// adding 'test.vm.opts' and 'test.java.opts' // adding 'test.vm.opts' and 'test.java.opts'
if (java) { if (java) {
String[] oldArgs = args; String[] oldArgs = args;
String[] testJavaOpts = Utils.getTestJavaOpts(); String[] testJavaOpts = getTestJavaOpts();
if (testJavaOpts.length > 0) { if (testJavaOpts.length > 0) {
args = new String[args.length + testJavaOpts.length]; args = new String[args.length + testJavaOpts.length];
// bin/java goes before options // bin/java goes before options
@ -101,10 +105,11 @@ public class ExecDriver {
ProcessBuilder pb = new ProcessBuilder(args); ProcessBuilder pb = new ProcessBuilder(args);
// adding jvm.so to library path // adding jvm.so to library path
if (launcher) { if (launcher) {
Path dir = Paths.get(Utils.TEST_JDK); Path dir = Paths.get(TEST_JDK);
String value; String value;
String name = Platform.sharedLibraryPathVariableName(); String name = sharedLibraryPathVariableName();
if (Platform.isWindows()) { // if (jdk.test.lib.Platform.isWindows()) {
if (System.getProperty("os.name").toLowerCase().startsWith("win")) {
value = dir.resolve("bin") value = dir.resolve("bin")
.resolve(variant()) .resolve(variant())
.toAbsolutePath() .toAbsolutePath()
@ -125,7 +130,7 @@ public class ExecDriver {
.merge(name, value, (x, y) -> y + File.pathSeparator + x)); .merge(name, value, (x, y) -> y + File.pathSeparator + x));
System.out.println(" with CLASSPATH = " + System.out.println(" with CLASSPATH = " +
pb.environment() pb.environment()
.put("CLASSPATH", Utils.TEST_CLASS_PATH)); .put("CLASSPATH", TEST_CLASS_PATH));
} }
Process p = pb.start(); Process p = pb.start();
// inheritIO does not work as expected for @run driver // inheritIO does not work as expected for @run driver
@ -138,19 +143,52 @@ public class ExecDriver {
} }
} }
// copied from jdk.test.lib.Platform::sharedLibraryPathVariableName
private static String sharedLibraryPathVariableName() {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.startsWith("win")) {
return "PATH";
} else if (osName.startsWith("mac")) {
return "DYLD_LIBRARY_PATH";
} else if (osName.startsWith("aix")) {
return "LIBPATH";
} else {
return "LD_LIBRARY_PATH";
}
}
// copied from jdk.test.lib.Utils::getTestJavaOpts()
private static String[] getTestJavaOpts() {
List<String> opts = new ArrayList<String>();
{
String v = System.getProperty("test.vm.opts", "").trim();
if (!v.isEmpty()) {
Collections.addAll(opts, v.split("\\s+"));
}
}
{
String v = System.getProperty("test.java.opts", "").trim();
if (!v.isEmpty()) {
Collections.addAll(opts, v.split("\\s+"));
}
}
return opts.toArray(new String[0]);
}
// copied jdk.test.lib.Platform::variant
private static String variant() { private static String variant() {
if (Platform.isServer()) { String vmName = System.getProperty("java.vm.name");
if (vmName.endsWith(" Server VM")) {
return "server"; return "server";
} else if (Platform.isClient()) { } else if (vmName.endsWith(" Client VM")) {
return "client"; return "client";
} else if (Platform.isMinimal()) { } else if (vmName.endsWith(" Minimal VM")) {
return "minimal"; return "minimal";
} else { } else {
throw new Error("TESTBUG: unsuppported vm variant"); throw new Error("TESTBUG: unsuppported vm variant");
} }
} }
private static void copy(InputStream is, OutputStream os) { private static void copy(InputStream is, OutputStream os) {
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
int n; int n;
@ -165,7 +203,7 @@ public class ExecDriver {
} }
private static String javaBin() { private static String javaBin() {
return Paths.get(Utils.TEST_JDK) return Paths.get(TEST_JDK)
.resolve("bin") .resolve("bin")
.resolve("java") .resolve("java")
.toAbsolutePath() .toAbsolutePath()

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ import java.io.*;
import java.util.*; import java.util.*;
import nsk.share.test.ExecutionController; import nsk.share.test.ExecutionController;
import nsk.share.test.LocalRandom;
/** /**
* <tt>NonbranchyTree</tt> defines a tree structure. Each node of the tree * <tt>NonbranchyTree</tt> defines a tree structure. Each node of the tree
@ -38,7 +39,6 @@ public class NonbranchyTree {
/** Minimal size of each node (in bytes) */ /** Minimal size of each node (in bytes) */
public final static int MIN_NODE_SIZE = 20; public final static int MIN_NODE_SIZE = 20;
private Node root; private Node root;
private Random random;
private int numberOfNodes; private int numberOfNodes;
private float branchiness; private float branchiness;
private int size; private int size;
@ -61,21 +61,16 @@ public class NonbranchyTree {
* *
*/ */
public NonbranchyTree(int numberOfNodes, float branchiness, int size) { public NonbranchyTree(int numberOfNodes, float branchiness, int size) {
this(numberOfNodes, branchiness, size, new Random(System.currentTimeMillis()), null); this(numberOfNodes, branchiness, size, null);
initTree(); initTree();
} }
public NonbranchyTree(int numberOfNodes, float branchiness, int size, ExecutionController controller) { public NonbranchyTree(int numberOfNodes, float branchiness, int size, ExecutionController controller) {
this(numberOfNodes, branchiness, size, new Random(System.currentTimeMillis()), controller);
initTree();
}
private NonbranchyTree(int numberOfNodes, float branchiness, int size, Random random, ExecutionController controller) {
this.numberOfNodes = numberOfNodes; this.numberOfNodes = numberOfNodes;
this.branchiness = branchiness; this.branchiness = branchiness;
this.size = size; this.size = size;
this.random = random;
this.controller = controller; this.controller = controller;
initTree();
} }
private void initTree() { private void initTree() {
@ -94,6 +89,8 @@ public class NonbranchyTree {
throw new IllegalArgumentException("Illegal size of nodes: " throw new IllegalArgumentException("Illegal size of nodes: "
+ size + ", must be at least 1."); + size + ", must be at least 1.");
} }
// ensure that LocalRandom is loaded and has enough memory
LocalRandom.nextBoolean();
root = createTree(numberOfNodes, size); root = createTree(numberOfNodes, size);
} }
@ -119,7 +116,7 @@ public class NonbranchyTree {
// Create a few nodes // Create a few nodes
if (makeRightNode()) { if (makeRightNode()) {
// The node will have two sons // The node will have two sons
int leftNodes = 1 + random.nextInt(numberOfNodes - 2); int leftNodes = 1 + LocalRandom.nextInt(numberOfNodes - 2);
int rightNodes = numberOfNodes - 1 - leftNodes; int rightNodes = numberOfNodes - 1 - leftNodes;
node.left = createTree(leftNodes, size); node.left = createTree(leftNodes, size);
@ -142,7 +139,7 @@ public class NonbranchyTree {
// Define the "branchiness" of the tree // Define the "branchiness" of the tree
private boolean makeRightNode() { private boolean makeRightNode() {
return (random.nextFloat() < branchiness); return (LocalRandom.nextFloat() < branchiness);
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ import nsk.share.TestBug;
import nsk.share.jpda.AbstractDebuggeeTest; import nsk.share.jpda.AbstractDebuggeeTest;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import jdk.test.lib.Utils;
/* /*
* This class serial executes several JDI tests based on nsk.share.jdi.TestDebuggerType2 in single VM * This class serial executes several JDI tests based on nsk.share.jdi.TestDebuggerType2 in single VM
@ -192,7 +193,7 @@ public class SerialExecutionDebugger extends TestDebuggerType2 {
if (testWorkDir == null) if (testWorkDir == null)
throw new TestBug("Debugger requires -testWorkDir parameter"); throw new TestBug("Debugger requires -testWorkDir parameter");
Collections.shuffle(result); Collections.shuffle(result, Utils.getRandomInstance());
// save resulted tests sequence in file (to simplify reproducing) // save resulted tests sequence in file (to simplify reproducing)
try { try {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,13 +26,13 @@ package nsk.share.runner;
import nsk.share.log.Log; import nsk.share.log.Log;
import nsk.share.test.StressOptions; import nsk.share.test.StressOptions;
import java.io.PrintStream; import java.io.PrintStream;
import jdk.test.lib.Utils;
public class RunParams { public class RunParams {
private StressOptions stressOptions; private StressOptions stressOptions;
private long sleepTime = 500; private long sleepTime = 500;
private long iterations = 0; private long iterations = 0;
private int numberOfThreads; private int numberOfThreads;
private long seed = System.currentTimeMillis();
private boolean runGCThread = false; private boolean runGCThread = false;
private boolean runFinThread = false; private boolean runFinThread = false;
private boolean runMemDiagThread = false; private boolean runMemDiagThread = false;
@ -126,11 +126,9 @@ public class RunParams {
} }
public final long getSeed() { public final long getSeed() {
return seed; // ensure that seed got printed out
} Utils.getRandomInstance();
return Utils.SEED;
public final void setSeed(long seed) {
this.seed = seed;
} }
public final boolean isRunGCThread() { public final boolean isRunGCThread() {
@ -212,8 +210,6 @@ public class RunParams {
runFinDiagThread = true; runFinDiagThread = true;
else if (args[i].equals("-Df")) else if (args[i].equals("-Df"))
runFinDiagThread = true; runFinDiagThread = true;
else if (args[i].equals("-s"))
seed = Long.parseLong(args[++i]);
else if (args[i].equals("-t")) else if (args[i].equals("-t"))
numberOfThreads = Integer.parseInt(args[++i]); numberOfThreads = Integer.parseInt(args[++i]);
else if (args[i].equals("-it")) else if (args[i].equals("-it"))
@ -233,7 +229,6 @@ public class RunParams {
out.println("Sleep time: " + sleepTime); out.println("Sleep time: " + sleepTime);
out.println("Iterations: " + iterations); out.println("Iterations: " + iterations);
out.println("Number of threads: " + numberOfThreads); out.println("Number of threads: " + numberOfThreads);
out.println("Seed: " + seed);
out.println("Run GC thread: " + runGCThread); out.println("Run GC thread: " + runGCThread);
out.println("Run mem diag thread: " + runMemDiagThread); out.println("Run mem diag thread: " + runMemDiagThread);
out.println("Run forever: " + runForever); out.println("Run forever: " + runForever);
@ -244,7 +239,6 @@ public class RunParams {
log.debug("Sleep time: " + sleepTime); log.debug("Sleep time: " + sleepTime);
log.debug("Iterations: " + iterations); log.debug("Iterations: " + iterations);
log.debug("Number of threads: " + numberOfThreads); log.debug("Number of threads: " + numberOfThreads);
log.debug("Seed: " + seed);
log.debug("Run GC thread: " + runGCThread); log.debug("Run GC thread: " + runGCThread);
log.debug("Run mem diag thread: " + runMemDiagThread); log.debug("Run mem diag thread: " + runMemDiagThread);
log.debug("Run forever: " + runForever); log.debug("Run forever: " + runForever);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,28 +23,50 @@
package nsk.share.test; package nsk.share.test;
import java.util.concurrent.ThreadLocalRandom; import java.util.Random;
import jdk.test.lib.Utils;
import nsk.share.TestFailure; import nsk.share.TestFailure;
/** /**
* Utility class which encapsulates all useful static methods. * Utility class which encapsulates all useful static methods.
*/ */
public class LocalRandom { public class LocalRandom {
static {
// ensure seed got printed out
Utils.getRandomInstance();
}
private final static ThreadLocal<Random> random = new ThreadLocal<>() {
protected Random initialValue() {
// each thread gets its own seed independendly on the order they
// use LocalRandom, yet it depends on the order threads are created.
// main thread uses original seed
return new Random(Utils.SEED ^ (Thread.currentThread().getId() - 1));
}
};
private static int minPauseTime = 3000; private static int minPauseTime = 3000;
private static int maxPauseTime = 5000; private static int maxPauseTime = 5000;
private static int maxRandomCount = 65536; private static int maxRandomCount = 65536;
/*
* Initializes a thread-local instance to ensure that there is enough memory.
* Useful for tests that exhaust memory.
*/
public static void init() {
random.get();
}
/* /*
* Return next random double number. * Return next random double number.
* *
* @return random double * @return random double
*/ */
public static double random() { public static double random() {
return ThreadLocalRandom.current().nextDouble(); return random.get().nextDouble();
} }
public static double nextDouble() { public static double nextDouble() {
return ThreadLocalRandom.current().nextDouble(); return random.get().nextDouble();
} }
public static byte nextByte() { public static byte nextByte() {
@ -60,7 +82,7 @@ public class LocalRandom {
} }
public static boolean nextBoolean() { public static boolean nextBoolean() {
return ThreadLocalRandom.current().nextBoolean(); return random.get().nextBoolean();
} }
public static void nextBytes(byte[] arr) { public static void nextBytes(byte[] arr) {
@ -252,7 +274,7 @@ public class LocalRandom {
} }
public static int nextInt() { public static int nextInt() {
return ThreadLocalRandom.current().nextInt(); return random.get().nextInt();
} }
/** /**
@ -262,11 +284,11 @@ public class LocalRandom {
* @return random integer * @return random integer
*/ */
public static int nextInt(int n) { public static int nextInt(int n) {
return ThreadLocalRandom.current().nextInt(n); return random.get().nextInt(n);
} }
public static long nextLong() { public static long nextLong() {
return ThreadLocalRandom.current().nextLong(); return random.get().nextLong();
} }
/** /**
@ -286,7 +308,7 @@ public class LocalRandom {
* @return random double * @return random double
*/ */
public static float nextFloat() { public static float nextFloat() {
return ThreadLocalRandom.current().nextFloat(); return random.get().nextFloat();
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,12 +30,12 @@ import java.net.URLClassLoader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Random;
import nsk.share.ClassUnloader; import nsk.share.ClassUnloader;
import nsk.share.TestFailure; import nsk.share.TestFailure;
import nsk.share.gc.ThreadedGCTest; import nsk.share.gc.ThreadedGCTest;
import nsk.share.gc.gp.GarbageUtils; import nsk.share.gc.gp.GarbageUtils;
import nsk.share.test.ExecutionController; import nsk.share.test.ExecutionController;
import nsk.share.test.LocalRandom;
/** /**
* This is the base class for btree & chain tests. It is a standard GCThreaded Test. * This is the base class for btree & chain tests. It is a standard GCThreaded Test.
@ -114,7 +114,7 @@ public abstract class SysDictTest extends ThreadedGCTest {
List<String> listNames = new ArrayList<String>(classnames.length); List<String> listNames = new ArrayList<String>(classnames.length);
listNames.addAll(Arrays.asList(classnames)); listNames.addAll(Arrays.asList(classnames));
for (int i = 0; i < classnames.length; i++) { for (int i = 0; i < classnames.length; i++) {
int idx1 = new Random().nextInt(listNames.size()); int idx1 = LocalRandom.nextInt(listNames.size());
this.names[i] = listNames.remove(idx1); this.names[i] = listNames.remove(idx1);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,8 @@ import java.util.Random;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
import jdk.test.lib.Utils;
public class RandomEx extends Random { public class RandomEx extends Random {
private final Map<Class<?>, Supplier<?>> map = new HashMap<>(); private final Map<Class<?>, Supplier<?>> map = new HashMap<>();
@ -51,6 +53,7 @@ public class RandomEx extends Random {
} }
public RandomEx() { public RandomEx() {
super(Utils.getRandomInstance().nextLong());
} }
public RandomEx(long seed) { public RandomEx(long seed) {