提交 153c42ff 编写于 作者: I iignatyev

8039499: Add all common classes used by tests on RTM support to testlibrary

Reviewed-by: kvn, iignatyev
Contributed-by: filipp.zhinkin@oracle.com
上级 e00c70f2
/*
* Copyright (c) 2014, 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 rtm;
import java.util.Objects;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import com.oracle.java.testlibrary.Asserts;
import com.oracle.java.testlibrary.Utils;
import sun.misc.Unsafe;
/**
* Base class for different transactional execution abortion
* provokers aimed to force abort due to specified reason.
*/
public abstract class AbortProvoker implements CompilableTest {
public static final long DEFAULT_ITERATIONS = 10000L;
/**
* Inflates monitor associated with object {@code monitor}.
* Inflation is forced by entering the same monitor from
* two different threads.
*
* @param monitor monitor to be inflated.
* @return inflated monitor.
* @throws Exception if something went wrong.
*/
public static Object inflateMonitor(Object monitor) throws Exception {
Unsafe unsafe = Utils.getUnsafe();
CyclicBarrier barrier = new CyclicBarrier(2);
Runnable inflatingRunnable = () -> {
unsafe.monitorEnter(monitor);
try {
barrier.await();
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
throw new RuntimeException(
"Synchronization issue occurred.", e);
} finally {
unsafe.monitorExit(monitor);
}
};
Thread t = new Thread(inflatingRunnable);
t.start();
// Wait until thread t enters the monitor.
barrier.await();
// At this point monitor will be owned by thread t,
// so our attempt to enter the same monitor will force
// monitor inflation.
Asserts.assertFalse(unsafe.tryMonitorEnter(monitor),
"Not supposed to enter the monitor first");
barrier.await();
t.join();
return monitor;
}
/**
* Get instance of specified AbortProvoker, inflate associated monitor
* if needed and then invoke forceAbort method in a loop.
*
* Usage:
* AbortProvoker <AbortType name> [<inflate monitor&gt
* [<iterations> [ <delay>]]]
*
* Default parameters are:
* <ul>
* <li>inflate monitor = <b>true</b></li>
* <li>iterations = {@code AbortProvoker.DEFAULT_ITERATIONS}</li>
* <li>delay = <b>0</b></li>
* </ul>
*/
public static void main(String args[]) throws Throwable {
Asserts.assertGT(args.length, 0, "At least one argument is required.");
AbortType abortType = AbortType.lookup(Integer.valueOf(args[0]));
boolean monitorShouldBeInflated = true;
long iterations = AbortProvoker.DEFAULT_ITERATIONS;
if (args.length > 1) {
monitorShouldBeInflated = Boolean.valueOf(args[1]);
if (args.length > 2) {
iterations = Long.valueOf(args[2]);
if (args.length > 3) {
Thread.sleep(Integer.valueOf(args[3]));
}
}
}
AbortProvoker provoker = abortType.provoker();
if (monitorShouldBeInflated) {
provoker.inflateMonitor();
}
for (long i = 0; i < iterations; i++) {
provoker.forceAbort();
}
}
protected final Object monitor;
protected AbortProvoker() {
this(new Object());
}
protected AbortProvoker(Object monitor) {
this.monitor = Objects.requireNonNull(monitor);
}
/**
* Inflates monitor used by this AbortProvoker instance.
* @throws Exception
*/
public void inflateMonitor() throws Exception {
AbortProvoker.inflateMonitor(monitor);
}
/**
* Forces transactional execution abortion.
*/
public abstract void forceAbort();
/**
* Returns names of all methods that have to be compiled
* in order to successfully force transactional execution
* abortion.
*
* @return array with methods' names that have to be compiled.
*/
@Override
public String[] getMethodsToCompileNames() {
return new String[] { getMethodWithLockName() };
}
/**
* Returns name of the method that will contain monitor whose locking
* will be elided using transactional execution.
*
* @return name of the method that will contain elided lock.
*/
@Override
public String getMethodWithLockName() {
return this.getClass().getName() + "::forceAbort";
}
}
/*
* Copyright (c) 2014, 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 rtm;
import com.oracle.java.testlibrary.Asserts;
import java.util.HashMap;
import java.util.Map;
/**
* Type of transactional execution abort.
* For more details on different abort types please see
* shared/vm/runtime/rtmLocking.hpp
*/
public enum AbortType {
XABORT(0),
RETRIABLE(1),
MEM_CONFLICT(2),
BUF_OVERFLOW(3),
DEBUG_BREAKPOINT(4),
NESTED_ABORT(5);
private final int type;
private static final Map<Integer, AbortType> LOOKUP_MAP = new HashMap<>();
static {
for (AbortType abortType : AbortType.values()) {
Asserts.assertFalse(LOOKUP_MAP.containsKey(abortType.type),
"Abort type values should be unique.");
LOOKUP_MAP.put(abortType.type, abortType);
}
}
private AbortType(int type) {
this.type = type;
}
/**
* Returns AbortProvoker for aborts represented by this abort type.
*
* @return an AbortProvoker instance
*/
public AbortProvoker provoker() {
return AbortType.createNewProvoker(this);
}
public static AbortType lookup(int type) {
Asserts.assertLT(type, AbortType.values().length,
"Unknown abort type.");
return LOOKUP_MAP.get(type);
}
/**
* Returns transaction execution abort provoker for specified abortion type.
*
* @param type a type of abort which will be forced by returned
* AbortProvoker instance.
* @return AbortProvoker instance that will force abort of specified type
* @throws RuntimeException if there is no provoker for specified type
*/
private static AbortProvoker createNewProvoker(AbortType type) {
switch (type) {
case XABORT:
return new XAbortProvoker();
case MEM_CONFLICT:
return new MemoryConflictProvoker();
case BUF_OVERFLOW:
return new BufferOverflowProvoker();
case NESTED_ABORT:
return new NestedAbortProvoker();
default:
throw new RuntimeException("No provoker exists for type "
+ type.name());
}
}
@Override
public String toString() {
return Integer.toString(type);
}
}
/*
* Copyright (c) 2014, 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 rtm;
/**
* In order to provoke transactional execution abort due to
* internal's buffer overflow BufferOverflowProvoker modifies
* 1MB of BYTES during single transaction.
*/
class BufferOverflowProvoker extends AbortProvoker {
/**
* To force buffer overflow abort we modify memory region with
* size more then L1d cache size.
*/
private static final int MORE_THAN_L1D_SIZE = 1024 * 1024;
private static final byte[] DATA = new byte[MORE_THAN_L1D_SIZE];
@Override
public void forceAbort() {
synchronized(monitor) {
for (int i = 0; i < BufferOverflowProvoker.DATA.length; i++) {
BufferOverflowProvoker.DATA[i]++;
}
}
}
}
/*
* Copyright (c) 2014, 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 rtm;
import com.oracle.java.testlibrary.Utils;
import sun.misc.Unsafe;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* Test case for busy lock scenario.
* One thread enters the monitor and sleep for a while.
* Another thread is blocked on the same monitor.
*/
public class BusyLock implements CompilableTest, Runnable {
private static final int DEFAULT_TIMEOUT = 1000;
private final CyclicBarrier barrier;
// Following field have to be static in order to avoid escape analysis.
@SuppressWarnings("UnsuedDeclaration")
private static int field = 0;
private static final Unsafe UNSAFE = Utils.getUnsafe();
protected final Object monitor;
protected final int timeout;
public BusyLock() {
this(BusyLock.DEFAULT_TIMEOUT);
}
public BusyLock(int timeout) {
this.timeout = timeout;
this.monitor = new Object();
this.barrier = new CyclicBarrier(2);
}
@Override
public void run() {
try {
// wait until forceAbort leave monitor
barrier.await();
if (UNSAFE.tryMonitorEnter(monitor)) {
try {
barrier.await();
Thread.sleep(timeout);
} finally {
UNSAFE.monitorExit(monitor);
}
} else {
throw new RuntimeException("Monitor should be entered by " +
"::run() first.");
}
} catch (InterruptedException | BrokenBarrierException e) {
throw new RuntimeException("Synchronization error happened.", e);
}
}
public void test() {
try {
barrier.await();
// wait until monitor is locked by a ::run method
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
throw new RuntimeException("Synchronization error happened.", e);
}
synchronized(monitor) {
BusyLock.field++;
}
}
@Override
public String getMethodWithLockName() {
return this.getClass().getName() + "::test";
}
@Override
public String[] getMethodsToCompileNames() {
return new String[] { getMethodWithLockName() };
}
/**
* Usage:
* BusyLock [ &lt;inflate monitor&gt; [ &lt;timeout&gt; ] ]
*
* Default values are:
* <ul>
* <li>inflate monitor = {@code true}</li>
* <li>timeout = {@code BusyLock.DEFAULT_TIMEOUT}</li>
* </ul>
*/
public static void main(String args[]) throws Exception {
int timeoutValue = BusyLock.DEFAULT_TIMEOUT;
boolean inflateMonitor = true;
if (args.length > 0 ) {
inflateMonitor = Boolean.valueOf(args[0]);
if (args.length > 1) {
timeoutValue = Integer.valueOf(args[1]);
}
}
BusyLock busyLock = new BusyLock(timeoutValue);
if (inflateMonitor) {
AbortProvoker.inflateMonitor(busyLock.monitor);
}
Thread t = new Thread(busyLock);
t.start();
busyLock.test();
t.join();
}
}
/*
* Copyright (c) 2014, 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 rtm;
/**
* Interface for test scenarios that contain methods
* that should be compiled.
*/
public interface CompilableTest {
/**
* @return array with methods' names that should be compiled.
*/
String[] getMethodsToCompileNames();
/**
* @return name of method with RTM-elided lock.
*/
String getMethodWithLockName();
}
/*
* Copyright (c) 2014, 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 rtm;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* To force transactional execution abort due to memory conflict
* one thread should access memory region from transactional region
* while another thread should modify the same memory region.
* Since this scenario is based on the race condition between threads
* you should not expect some particular amount of aborts.
*/
class MemoryConflictProvoker extends AbortProvoker {
// Following field have to be static in order to avoid escape analysis.
@SuppressWarnings("UnsuedDeclaration")
private static int field = 0;
private static final int INNER_ITERATIONS = 10000;
private final CyclicBarrier barrier;
/**
* This thread will access and modify memory region
* from outside of the transaction.
*/
private final Runnable conflictingThread;
public MemoryConflictProvoker() {
this(new Object());
}
public MemoryConflictProvoker(Object monitor) {
super(monitor);
barrier = new CyclicBarrier(2);
conflictingThread = () -> {
try {
barrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
for (int i = 0; i < MemoryConflictProvoker.INNER_ITERATIONS; i++) {
MemoryConflictProvoker.field++;
}
};
}
/**
* Accesses and modifies memory region from within the transaction.
*/
public void transactionalRegion() {
try {
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
throw new RuntimeException(e);
}
for (int i = 0; i < MemoryConflictProvoker.INNER_ITERATIONS; i++) {
synchronized(monitor) {
MemoryConflictProvoker.field--;
}
}
}
@Override
public void forceAbort() {
try {
Thread t = new Thread(conflictingThread);
t.start();
transactionalRegion();
t.join();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String getMethodWithLockName() {
return this.getClass().getName() + "::transactionalRegion";
}
}
/*
* Copyright (c) 2014, 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 rtm;
import java.util.Arrays;
/**
* In order to force nested transaction abort NestedAbortProvoker
* invoke BufferOverflowProvoker from transactional region.
*/
class NestedAbortProvoker extends AbortProvoker {
// Following field have to be static in order to avoid escape analysis.
@SuppressWarnings("UnsuedDeclaration")
private static int field = 0;
private final AbortProvoker nestedAbortProvoker;
public NestedAbortProvoker() {
this.nestedAbortProvoker = new XAbortProvoker(monitor);
}
@Override
public void forceAbort() {
synchronized(monitor) {
NestedAbortProvoker.field++;
nestedAbortProvoker.forceAbort();
NestedAbortProvoker.field--;
}
}
@Override
public String[] getMethodsToCompileNames() {
String nestedProvokerMethods[]
= nestedAbortProvoker.getMethodsToCompileNames();
String methods[] = Arrays.copyOf(nestedProvokerMethods,
nestedProvokerMethods.length + 1);
methods[methods.length - 1] = getMethodWithLockName();
return methods;
}
}
/*
* Copyright (c) 2014, 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 rtm;
import java.util.EnumMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
* Wrapper for +UsePreciseRTMLockingStatistics output.
*
* Example of locking statistics:
*
* java/lang/ClassLoader.loadClass@7
* # rtm locks total (estimated): 0
* # rtm lock aborts : 13
* # rtm lock aborts 0: 12
* # rtm lock aborts 1: 0
* # rtm lock aborts 2: 0
* # rtm lock aborts 3: 0
* # rtm lock aborts 4: 0
* # rtm lock aborts 5: 0
*/
public class RTMLockingStatistics {
/**
* Pattern for aborts per abort type entries.
*/
private static final Pattern ABORT_PATTERN;
/**
* Pattern for whole statistics.
*/
private static final Pattern RTM_LOCKING_STATISTICS_PATTERN;
static {
String abortRe
= "# rtm lock aborts\\s+(?<type>[0-9]+):\\s(?<count>[0-9]+)";
ABORT_PATTERN = Pattern.compile(abortRe);
RTM_LOCKING_STATISTICS_PATTERN = Pattern.compile(
"(?<className>[^.\n]+)\\." +
"(?<methodName>[^@\n]+)@(?<bci>[0-9]+)\n" +
"# rtm locks total \\(estimated\\):\\s*" +
"(?<totalLocks>[0-9]+)\n" +
"# rtm lock aborts\\s+:\\s*(?<totalAborts>[0-9]+)\n" +
"(?<abortStats>(" + abortRe + "\n)+)");
}
private final long totalLocks;
private final long totalAborts;
private final String className;
private final String methodName;
private final int bci;
private final Map<AbortType, Long> aborts = new EnumMap<>(AbortType.class);
/**
* Constructs RTMLockingStatistics from matcher captured statistics entry.
* @param matcher Matcher captured statistics entry.
*/
private RTMLockingStatistics(Matcher matcher) {
className = matcher.group("className");
methodName = matcher.group("methodName");
bci = Integer.valueOf(matcher.group("bci"));
totalLocks = Long.valueOf(matcher.group("totalLocks"));
totalAborts = Long.valueOf(matcher.group("totalAborts"));
Matcher abortMatcher = ABORT_PATTERN.matcher(matcher.
group("abortStats"));
while (abortMatcher.find()) {
int type = Integer.valueOf(abortMatcher.group("type"));
long count = Long.valueOf(abortMatcher.group("count"));
setAborts(AbortType.lookup(type), count);
}
}
/**
* Parses string and return all founded RTM locking statistics entries.
*
* @param str the string to be parsed.
* @return list with all founded RTM locking statistics entries or
* empty list if nothing was found.
*/
public static List<RTMLockingStatistics> fromString(String str) {
List<RTMLockingStatistics> statistics = new LinkedList<>();
Matcher matcher = RTM_LOCKING_STATISTICS_PATTERN.matcher(str);
while (matcher.find()) {
RTMLockingStatistics lock = new RTMLockingStatistics(matcher);
statistics.add(lock);
}
return statistics;
}
/**
* Parses string and return all founded RTM locking statistics entries
* for locks in method {@code methodName}.
*
* @param methodName a name of the method for locks from which statistics
* should be gathered.
* @param str the string to be parsed.
* @return list with all founded RTM locking statistics entries or
* empty list if nothing was found.
*/
public static List<RTMLockingStatistics> fromString(String methodName,
String str) {
String formattedMethodName = formatMethodName(methodName);
List<RTMLockingStatistics> statisticsForMethod = new LinkedList<>();
for (RTMLockingStatistics statistics : fromString(str)) {
if (statistics.getLockName().startsWith(formattedMethodName)) {
statisticsForMethod.add(statistics);
}
}
return statisticsForMethod;
}
/**
* Formats method's name so it will have the same format as
* in rtm locking statistics.
*
* <pre>
* Example:
* com/example/Klass::method =&gt; com/example/Klass.method
* com/example/Klass.method =&gt; com/example/Klass.method
* com.example.Klass::method =&gt; com/example/Klass.method
* com.example.Klass.method =&gt; com/example/Klass.method
* </pre>
*
* @param methodName method's name that should be formatted.
* @return formatted method's name.
*/
private static String formatMethodName(String methodName) {
String m[];
if (methodName.contains("::")) {
m = methodName.split("::");
} else {
int splitAt = methodName.lastIndexOf('.');
m = new String[2];
m[0] = methodName.substring(0, splitAt);
m[1] = methodName.substring(splitAt + 1);
}
return String.format("%s.%s", m[0].replaceAll("\\.", "/"), m[1]);
}
/**
* Returns name of lock for which this statistics was collected.
* Lock name has following format:
* &lt;class name&gt;.&lt;method name&gt;@&lt;bci&gt;
*
* @return name of lock.
*/
public String getLockName() {
return String.format("%s.%s@%d", className, methodName, bci);
}
/**
* Returns aborts count for specified abort type.
*
* @param type an abort type.
* @return count of aborts.
*/
public long getAborts(AbortType type) {
return aborts.getOrDefault(type, 0L);
}
/**
* Sets aborts count for specified abort type.
*
* @param type an abort type.
* @param count count of aborts.
*/
public void setAborts(AbortType type, long count) {
aborts.put(type, count);
}
public long getTotalLocks() {
return totalLocks;
}
public long getTotalAborts() {
return totalAborts;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(getLockName()).append('\n');
builder.append(String.format("# rtm locks total (estimated): %d\n",
getTotalLocks()));
builder.append(String.format("# rtm lock aborts: %d\n",
getTotalLocks()));
for (AbortType type : AbortType.values()) {
builder.append(String.format("# rtm lock aborts %s %d\n",
type.toString(), getAborts(type)));
}
return builder.toString();
}
}
/*
* Copyright (c) 2014, 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 rtm;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.LinkedList;
import java.util.Arrays;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.oracle.java.testlibrary.OutputAnalyzer;
import com.oracle.java.testlibrary.ProcessTools;
import com.oracle.java.testlibrary.Utils;
import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
/**
* Auxiliary methods used for RTM testing.
*/
public class RTMTestBase {
private static final String RTM_STATE_CHANGE_REASON = "rtm_state_change";
/**
* We don't parse compilation log as XML-document and use regular
* expressions instead, because in some cases it could be
* malformed.
*/
private static final String FIRED_UNCOMMON_TRAP_PATTERN_TEMPLATE
= "<uncommon_trap thread='[0-9]+' reason='%s'";
private static final String INSTALLED_UNCOMMON_TRAP_PATTERN_TEMPLATE
= "<uncommon_trap bci='[0-9]+' reason='%s'";
/**
* Executes RTM test in a new JVM started with {@code options} cli options.
*
* @param test test case to execute.
* @param options additional options for VM
* @throws Exception when something went wrong.
*/
public static OutputAnalyzer executeRTMTest(CompilableTest test,
String... options) throws Exception {
ProcessBuilder processBuilder
= ProcessTools.createJavaProcessBuilder(
RTMTestBase.prepareTestOptions(test, options));
OutputAnalyzer outputAnalyzer
= new OutputAnalyzer(processBuilder.start());
System.out.println(outputAnalyzer.getOutput());
return outputAnalyzer;
}
/**
* Executes test case and save compilation log to {@code logFileName}.
*
* @param logFileName a name of compilation log file
* @param test a test case to execute case to execute
* @param options additional options to VM
* @return OutputAnalyzer for started test case
* @throws Exception when something went wrong
*/
public static OutputAnalyzer executeRTMTest(String logFileName,
CompilableTest test, String... options) throws Exception {
ProcessBuilder processBuilder
= ProcessTools.createJavaProcessBuilder(
RTMTestBase.prepareTestOptions(logFileName, test, options));
OutputAnalyzer outputAnalyzer
= new OutputAnalyzer(processBuilder.start());
System.out.println(outputAnalyzer.getOutput());
return outputAnalyzer;
}
/**
* Finds count of uncommon traps with reason {@code reason} installed
* during compilation.
*
* @param compilationLogFile a path to file with LogCompilation output.
* @param reason reason of installed uncommon traps.
* @return count of installed uncommon traps with reason {@code reason}.
* @throws IOException
*/
public static int installedUncommonTraps(String compilationLogFile,
String reason)throws IOException {
String pattern = String.format(
RTMTestBase.INSTALLED_UNCOMMON_TRAP_PATTERN_TEMPLATE,
reason);
return RTMTestBase.findTraps(compilationLogFile, pattern);
}
/**
* Finds count of uncommon traps with reason <i>rtm_state_change</i>
* installed during compilation.
*
* @param compilationLogFile a path to file with LogCompilation output.
* @return count of installed uncommon traps with reason
* <i>rtm_state_change</i>.
* @throws IOException
*/
public static int installedRTMStateChangeTraps(String compilationLogFile)
throws IOException {
return RTMTestBase.installedUncommonTraps(compilationLogFile,
RTMTestBase.RTM_STATE_CHANGE_REASON);
}
/**
* Finds count of fired uncommon traps with reason {@code reason}.
*
* @param compilationLogFile a path to file with LogCompilation output.
* @param reason a reason of fired uncommon traps.
* @return count of fired uncommon traps with reason {@code reason}.
* @throws IOException
*/
public static int firedUncommonTraps(String compilationLogFile,
String reason) throws IOException {
String pattern = String.format(
RTMTestBase.FIRED_UNCOMMON_TRAP_PATTERN_TEMPLATE,
reason);
return RTMTestBase.findTraps(compilationLogFile, pattern);
}
/**
* Finds count of fired uncommon traps with reason <i>rtm_state_change</i>.
*
* @param compilationLogFile a path to file with LogCompilation output.
* @return count of fired uncommon traps with reason
* <i>rtm_state_change</i>.
* @throws IOException
*/
public static int firedRTMStateChangeTraps(String compilationLogFile)
throws IOException {
return RTMTestBase.firedUncommonTraps(compilationLogFile,
RTMTestBase.RTM_STATE_CHANGE_REASON);
}
/**
* Finds count of uncommon traps that matches regular
* expression in {@code re}.
*
* @param compilationLogFile a path to file with LogCompilation output.
* @param re regular expression to match uncommon traps.
* @throws IOException
*/
private static int findTraps(String compilationLogFile, String re)
throws IOException {
String compilationLog = RTMTestBase.fileAsString(compilationLogFile);
Pattern pattern = Pattern.compile(re);
Matcher matcher = pattern.matcher(compilationLog);
int traps = 0;
while (matcher.find()) {
traps++;
}
return traps;
}
/**
* Returns file's content as a string.
*
* @param path a path to file to operate on.
* @return string with content of file.
* @throws IOException
*/
private static String fileAsString(String path) throws IOException {
byte[] fileAsBytes = Files.readAllBytes(Paths.get(path));
return new String(fileAsBytes);
}
/**
* Prepares VM options for test execution.
* This method get test java options, filter out all RTM-related options,
* adds CompileCommand=compileonly,method_name options for each method
* from {@code methodToCompile} and finally appends all {@code vmOpts}.
*
* @param test test case whose methods that should be compiled.
* If {@code null} then no additional <i>compileonly</i>
* commands will be added to VM options.
* @param vmOpts additional options to pass to VM.
* @return Array with VM options.
*/
private static String[] prepareTestOptions(CompilableTest test,
String... vmOpts) {
return RTMTestBase.prepareFilteredTestOptions(test, null, vmOpts);
}
/**
* Prepares VM options for test execution.
* This method get test java options, filter out all RTM-related options
* and all options that matches regexps in {@code additionalFilters},
* adds CompileCommand=compileonly,method_name options for each method
* from {@code methodToCompile} and finally appends all {@code vmOpts}.
*
* @param test test case whose methods that should be compiled.
* If {@code null} then no additional <i>compileonly</i>
* commands will be added to VM options.
* @param additionalFilters array with regular expression that will be
* used to filter out test java options.
* If {@code null} then no additional filters
* will be used.
* @param vmOpts additional options to pass to VM.
* @return array with VM options.
*/
private static String[] prepareFilteredTestOptions(CompilableTest test,
String[] additionalFilters, String... vmOpts) {
List<String> finalVMOpts = new LinkedList<>();
String[] filters;
if (additionalFilters != null) {
filters = Arrays.copyOf(additionalFilters,
additionalFilters.length + 1);
} else {
filters = new String[1];
}
filters[filters.length - 1] = "RTM";
String[] filteredVMOpts = Utils.getFilteredTestJavaOpts(filters);
Collections.addAll(finalVMOpts, filteredVMOpts);
Collections.addAll(finalVMOpts, "-Xcomp", "-server",
"-XX:-TieredCompilation",
CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS,
CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
"-XX:+UseRTMLocking");
if (test != null) {
for (String method : test.getMethodsToCompileNames()) {
finalVMOpts.add("-XX:CompileCommand=compileonly," + method);
}
}
Collections.addAll(finalVMOpts, vmOpts);
return finalVMOpts.toArray(new String[finalVMOpts.size()]);
}
/**
* Adds additional options for VM required for successful execution of test.
*
* @param logFileName a name of compilation log file
* @param test a test case to execute
* @param options additional options to VM
* @return an array with VM options
*/
private static String[] prepareTestOptions(String logFileName,
CompilableTest test, String... options) {
String[] preparedOptions = RTMTestBase.prepareFilteredTestOptions(
test,
new String[] {
"LogCompilation",
"LogFile"
});
List<String> updatedOptions = new LinkedList<>();
Collections.addAll(updatedOptions, preparedOptions);
Collections.addAll(updatedOptions,
"-XX:+LogCompilation",
"-XX:LogFile=" + logFileName);
Collections.addAll(updatedOptions, options);
return updatedOptions.toArray(new String[updatedOptions.size()]);
}
}
/*
* Copyright (c) 2014, 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 rtm;
import com.oracle.java.testlibrary.Utils;
import sun.misc.Unsafe;
/**
* Current RTM locking implementation force transaction abort
* before native method call by explicit xabort(0) call.
*/
class XAbortProvoker extends AbortProvoker {
// Following field have to be static in order to avoid escape analysis.
@SuppressWarnings("UnsuedDeclaration")
private static int field = 0;
private static final Unsafe UNSAFE = Utils.getUnsafe();
public XAbortProvoker() {
this(new Object());
}
public XAbortProvoker(Object monitor) {
super(monitor);
}
@Override
public void forceAbort() {
synchronized(monitor) {
XAbortProvoker.field = UNSAFE.addressSize();
}
}
@Override
public String[] getMethodsToCompileNames() {
return new String[] {
getMethodWithLockName(),
Unsafe.class.getName() + "::addressSize"
};
}
}
/*
* Copyright (c) 2014, 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 rtm.predicate;
import sun.hotspot.cpuinfo.CPUInfo;
import java.util.function.BooleanSupplier;
public class SupportedCPU implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return CPUInfo.hasFeature("rtm");
}
}
/*
* Copyright (c) 2014, 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 rtm.predicate;
import com.oracle.java.testlibrary.Platform;
import java.util.function.BooleanSupplier;
public class SupportedVM implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return Platform.isServer() && !Platform.isEmbedded();
}
}
......@@ -23,22 +23,16 @@
package com.oracle.java.testlibrary.cli;
import sun.hotspot.cpuinfo.CPUInfo;
import com.oracle.java.testlibrary.*;
import com.oracle.java.testlibrary.cli.predicate.CPUSpecificPredicate;
/**
* Base class for command line options tests that
* requires specific CPU arch or specific CPU features.
*/
public abstract class CPUSpecificCommandLineOptionTest
extends CommandLineOptionTest {
private String cpuArchPattern;
private String supportedCPUFeatures[];
private String unsupportedCPUFeatures[];
extends CommandLineOptionTest {
/**
* Create new CPU specific test instance that does not
* Creates new CPU specific test instance that does not
* require any CPU features.
*
* @param cpuArchPattern Regular expression that should
......@@ -49,62 +43,23 @@ public abstract class CPUSpecificCommandLineOptionTest
}
/**
* Create new CPU specific test instance that does not
* Creates new CPU specific test instance that does not
* require from CPU support of {@code supportedCPUFeatures} features
* and no support of {@code unsupportedCPUFeatures}.
*
* @param cpuArchPattern Regular expression that should
* match os.arch.
* @param supportedCPUFeatures Array with names of features that
* should be supported by CPU. If <b>null</b>,
* should be supported by CPU. If {@code null},
* then no features have to be supported.
* @param unsupportedCPUFeatures Array with names of features that
* should not be supported by CPU.
* If <b>null</b>, then CPU may support any
* If {@code null}, then CPU may support any
* features.
*/
public CPUSpecificCommandLineOptionTest(String cpuArchPattern,
String supportedCPUFeatures[],
String unsupportedCPUFeatures[]) {
this.cpuArchPattern = cpuArchPattern;
this.supportedCPUFeatures = supportedCPUFeatures;
this.unsupportedCPUFeatures = unsupportedCPUFeatures;
}
/**
* Check that CPU on test box has appropriate architecture, support all
* required features and does not support all features that should not be
* supported.
*
* @return <b>true</b> if CPU on test box fulfill all requirements.
*/
@Override
public boolean checkPreconditions() {
if (!Platform.getOsArch().matches(cpuArchPattern)) {
System.out.println("CPU arch does not match " + cpuArchPattern);
return false;
}
if (supportedCPUFeatures != null) {
for (String feature : supportedCPUFeatures) {
if (!CPUInfo.hasFeature(feature)) {
System.out.println("CPU does not support " + feature +
" feature");
return false;
}
}
}
if (unsupportedCPUFeatures != null) {
for (String feature : unsupportedCPUFeatures) {
if (CPUInfo.hasFeature(feature)) {
System.out.println("CPU support " + feature + " feature");
return false;
}
}
}
return true;
String supportedCPUFeatures[], String unsupportedCPUFeatures[]) {
super(new CPUSpecificPredicate(cpuArchPattern, supportedCPUFeatures,
unsupportedCPUFeatures));
}
}
......@@ -26,6 +26,7 @@ package com.oracle.java.testlibrary.cli;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.BooleanSupplier;
import com.oracle.java.testlibrary.*;
......@@ -33,34 +34,71 @@ import com.oracle.java.testlibrary.*;
* Base class for command line option tests.
*/
public abstract class CommandLineOptionTest {
public static final String UNRECOGNIZED_OPTION_ERROR_FORMAT =
"Unrecognized VM option '[+-]?%s'";
public static final String printFlagsFinalFormat = "%s\\s*:?=\\s*%s";
public static final String UNLOCK_DIAGNOSTIC_VM_OPTIONS
= "-XX:+UnlockDiagnosticVMOptions";
public static final String UNLOCK_EXPERIMENTAL_VM_OPTIONS
= "-XX:+UnlockExperimentalVMOptions";
protected static final String UNRECOGNIZED_OPTION_ERROR_FORMAT
= "Unrecognized VM option '[+-]?%s(=.*)?'";
protected static final String EXPERIMENTAL_OPTION_ERROR_FORMAT
= "VM option '%s' is experimental and must be enabled via "
+ "-XX:\\+UnlockExperimentalVMOptions.";
protected static final String DIAGNOSTIC_OPTION_ERROR_FORMAT
= " VM option '%s' is diagnostic and must be enabled via "
+ "-XX:\\+UnlockDiagnosticVMOptions.";
private static final String PRINT_FLAGS_FINAL_FORMAT = "%s\\s*:?=\\s*%s";
/**
* Verify that JVM startup behaviour matches our expectations.
* Verifies that JVM startup behaviour matches our expectations.
*
* @param option The option that should be passed to JVM
* @param excpectedMessages Array of patterns that should occur
* in JVM output. If <b>null</b> then
* JVM output could be empty.
* @param unexpectedMessages Array of patterns that should not
* occur in JVM output. If <b>null</b> then
* @param option an option that should be passed to JVM
* @param expectedMessages an array of patterns that should occur
* in JVM output. If {@code null} then
* JVM output could be empty.
* @param unexpectedMessages an array of patterns that should not
* occur in JVM output. If {@code null} then
* JVM output could be empty.
* @param exitCode expected exit code.
* @throws Throwable if verification fails or some other issues occur.
*/
public static void verifyJVMStartup(String option,
String expectedMessages[],
String unexpectedMessages[],
ExitCode exitCode)
throws Throwable {
String expectedMessages[], String unexpectedMessages[],
ExitCode exitCode) throws Throwable {
CommandLineOptionTest.verifyJVMStartup(expectedMessages,
unexpectedMessages, exitCode, false, option);
}
OutputAnalyzer outputAnalyzer =
ProcessTools.executeTestJvm(option, "-version");
/**
* Verifies that JVM startup behaviour matches our expectations.
*
* @param expectedMessages an array of patterns that should occur
* in JVM output. If {@code null} then
* JVM output could be empty.
* @param unexpectedMessages an array of patterns that should not
* occur in JVM output. If {@code null} then
* JVM output could be empty.
* @param exitCode expected exit code.
* @param addTestVMOptions if {@code true} then test VM options will be
* passed to VM.
* @param options options that should be passed to VM in addition to mode
* flag.
* @throws Throwable if verification fails or some other issues occur.
*/
public static void verifyJVMStartup(String expectedMessages[],
String unexpectedMessages[], ExitCode exitCode,
boolean addTestVMOptions, String... options) throws Throwable {
List<String> finalOptions = new ArrayList<>();
if (addTestVMOptions) {
Collections.addAll(finalOptions, Utils.getTestJavaOpts());
}
Collections.addAll(finalOptions, options);
finalOptions.add("-version");
ProcessBuilder processBuilder
= ProcessTools.createJavaProcessBuilder(finalOptions.toArray(
new String[finalOptions.size()]));
OutputAnalyzer outputAnalyzer
= new OutputAnalyzer(processBuilder.start());
outputAnalyzer.shouldHaveExitValue(exitCode.value);
if (expectedMessages != null) {
......@@ -77,97 +115,216 @@ public abstract class CommandLineOptionTest {
}
/**
* Verify that value of specified JVM option is the same as
* Verifies that JVM startup behaviour matches our expectations when type
* of newly started VM is the same as the type of current.
*
* @param expectedMessages an array of patterns that should occur
* in JVM output. If {@code null} then
* JVM output could be empty.
* @param unexpectedMessages an array of patterns that should not
* occur in JVM output. If {@code null} then
* JVM output could be empty.
* @param exitCode expected exit code.
* @param options options that should be passed to VM in addition to mode
* flag.
* @throws Throwable if verification fails or some other issues occur.
*/
public static void verifySameJVMStartup(String expectedMessages[],
String unexpectedMessages[], ExitCode exitCode, String... options)
throws Throwable {
List<String> finalOptions = new ArrayList<>();
finalOptions.add(CommandLineOptionTest.getVMTypeOption());
Collections.addAll(finalOptions, options);
CommandLineOptionTest.verifyJVMStartup(expectedMessages,
unexpectedMessages, exitCode, false,
finalOptions.toArray(new String[finalOptions.size()]));
}
/**
* Verifies that value of specified JVM option is the same as
* expected value.
* This method filter out option with {@code optionName}
* name from test java options.
*
* @param optionName Name of tested option.
* @param expectedValue Expected value of tested option.
* @param additionalVMOpts Additonal options that should be
* @param optionName a name of tested option.
* @param expectedValue expected value of tested option.
* @param additionalVMOpts additional options that should be
* passed to JVM.
* @throws Throwable if verification fails or some other issues occur.
*/
public static void verifyOptionValue(String optionName,
String expectedValue,
String... additionalVMOpts)
throws Throwable {
String expectedValue, String... additionalVMOpts) throws Throwable {
verifyOptionValue(optionName, expectedValue, true, additionalVMOpts);
}
/**
* Verify that value of specified JVM option is the same as
* Verifies that value of specified JVM option is the same as
* expected value.
* This method filter out option with {@code optionName}
* name from test java options.
*
* @param optionName Name of tested option.
* @param expectedValue Expected value of tested option.
* @param addTestVmOptions If <b>true</b>, then test VM options
* @param optionName a name of tested option.
* @param expectedValue expected value of tested option.
* @param addTestVmOptions if {@code true}, then test VM options
* will be used.
* @param additionalVMOpts Additonal options that should be
* @param additionalVMOpts additional options that should be
* passed to JVM.
* @throws Throwable if verification fails or some other issues occur.
* @throws Throwable if verification fails or some other issues
* occur.
*/
public static void verifyOptionValue(String optionName,
String expectedValue,
boolean addTestVmOptions,
String... additionalVMOpts)
throws Throwable {
List<String> vmOpts = new ArrayList<String>();
String expectedValue, boolean addTestVmOptions,
String... additionalVMOpts) throws Throwable {
List<String> vmOpts = new ArrayList<>();
if (addTestVmOptions) {
Collections.addAll(vmOpts,
Utils.getFilteredTestJavaOpts(optionName));
}
Collections.addAll(vmOpts, additionalVMOpts);
Collections.addAll(vmOpts, new String[] {
"-XX:+PrintFlagsFinal",
"-version"
});
Collections.addAll(vmOpts, "-XX:+PrintFlagsFinal", "-version");
ProcessBuilder processBuilder =
ProcessTools.
createJavaProcessBuilder(vmOpts.
toArray(new String[vmOpts.size()]));
ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
vmOpts.toArray(new String[vmOpts.size()]));
OutputAnalyzer outputAnalyzer =
new OutputAnalyzer(processBuilder.start());
OutputAnalyzer outputAnalyzer
= new OutputAnalyzer(processBuilder.start());
outputAnalyzer.shouldHaveExitValue(0);
outputAnalyzer.shouldMatch(String.
format(printFlagsFinalFormat,
optionName,
expectedValue));
outputAnalyzer.shouldMatch(String.format(
CommandLineOptionTest.PRINT_FLAGS_FINAL_FORMAT,
optionName, expectedValue));
}
/**
* Verifies that value of specified JVM when type of newly started VM
* is the same as the type of current.
* This method filter out option with {@code optionName}
* name from test java options.
* Only mode flag will be passed to VM in addition to
* {@code additionalVMOpts}
*
* @param optionName name of tested option.
* @param expectedValue expected value of tested option.
* @param additionalVMOpts additional options that should be
* passed to JVM.
* @throws Throwable if verification fails or some other issues occur.
*/
public static void verifyOptionValueForSameVM(String optionName,
String expectedValue, String... additionalVMOpts) throws Throwable {
List<String> finalOptions = new ArrayList<>();
finalOptions.add(CommandLineOptionTest.getVMTypeOption());
Collections.addAll(finalOptions, additionalVMOpts);
CommandLineOptionTest.verifyOptionValue(optionName, expectedValue,
false, finalOptions.toArray(new String[finalOptions.size()]));
}
/**
* Run command line option test.
* Prepares boolean command line flag with name {@code name} according
* to it's {@code value}.
*
* @throws Throwable if test failed.
* @param name the name of option to be prepared
* @param value the value of option
* @return prepared command line flag
*/
public final void test() throws Throwable {
if (checkPreconditions()) {
runTestCases();
}
public static String prepareBooleanFlag(String name, boolean value) {
return String.format("-XX:%c%s", (value ? '+' : '-'), name);
}
/**
* Check that all preconditions for test execution are met.
* Prepares numeric command line flag with name {@code name} by setting
* it's value to {@code value}.
*
* @return <b>true</b> if test could be executed.
* @param name the name of option to be prepared
* @param value the value of option
* @return prepared command line flag
*/
public boolean checkPreconditions() {
return true;
public static String prepareNumericFlag(String name, Number value) {
return String.format("-XX:%s=%s", name, value.toString());
}
/**
* Run test cases.
* Returns message that should occur in VM output if option
* {@code optionName} if unrecognized.
*
* @throws Throwable if test failed.
* @param optionName the name of option for which message should be returned
* @return message saying that option {@code optionName} is unrecognized
*/
public abstract void runTestCases() throws Throwable;
}
public static String getUnrecognizedOptionErrorMessage(String optionName) {
return String.format(
CommandLineOptionTest.UNRECOGNIZED_OPTION_ERROR_FORMAT,
optionName);
}
/**
* Returns message that should occur in VM output if option
* {@code optionName} is experimental and
* -XX:+UnlockExperimentalVMOptions was not passed to VM.
*
* @param optionName the name of option for which message should be returned
* @return message saying that option {@code optionName} is experimental
*/
public static String getExperimentalOptionErrorMessage(String optionName) {
return String.format(
CommandLineOptionTest.EXPERIMENTAL_OPTION_ERROR_FORMAT,
optionName);
}
/**
* Returns message that should occur in VM output if option
* {@code optionName} is diagnostic and -XX:+UnlockDiagnosticVMOptions
* was not passed to VM.
*
* @param optionName the name of option for which message should be returned
* @return message saying that option {@code optionName} is diganostic
*/
public static String getDiagnosticOptionErrorMessage(String optionName) {
return String.format(
CommandLineOptionTest.DIAGNOSTIC_OPTION_ERROR_FORMAT,
optionName);
}
/**
* @return option required to start a new VM with the same type as current.
* @throws RuntimeException when VM type is unknown.
*/
private static String getVMTypeOption() {
if (Platform.isServer()) {
return "-server";
} else if (Platform.isClient()) {
return "-client";
} else if (Platform.isMinimal()) {
return "-minimal";
} else if (Platform.isGraal()) {
return "-graal";
}
throw new RuntimeException("Unknown VM mode.");
}
private final BooleanSupplier predicate;
/**
* Constructs new CommandLineOptionTest that will be executed only if
* predicate {@code predicate} return {@code true}.
* @param predicate a predicate responsible for test's preconditions check.
*/
public CommandLineOptionTest(BooleanSupplier predicate) {
this.predicate = predicate;
}
/**
* Runs command line option test.
*/
public final void test() throws Throwable {
if (predicate.getAsBoolean()) {
runTestCases();
}
}
/**
* @throws Throwable if some issue happened during test cases execution.
*/
protected abstract void runTestCases() throws Throwable;
}
/*
* Copyright (c) 2014, 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 com.oracle.java.testlibrary.cli.predicate;
import java.util.function.BooleanSupplier;
public class AndPredicate implements BooleanSupplier {
private final BooleanSupplier a;
private final BooleanSupplier b;
public AndPredicate(BooleanSupplier a, BooleanSupplier b) {
this.a = a;
this.b = b;
}
@Override
public boolean getAsBoolean() {
return a.getAsBoolean() && b.getAsBoolean();
}
}
/*
* Copyright (c) 2014, 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 com.oracle.java.testlibrary.cli.predicate;
import com.oracle.java.testlibrary.Platform;
import sun.hotspot.cpuinfo.CPUInfo;
import java.util.function.BooleanSupplier;
public class CPUSpecificPredicate implements BooleanSupplier {
private final String cpuArchPattern;
private final String supportedCPUFeatures[];
private final String unsupportedCPUFeatures[];
public CPUSpecificPredicate(String cpuArchPattern,
String supportedCPUFeatures[],
String unsupportedCPUFeatures[]) {
this.cpuArchPattern = cpuArchPattern;
this.supportedCPUFeatures = supportedCPUFeatures;
this.unsupportedCPUFeatures = unsupportedCPUFeatures;
}
@Override
public boolean getAsBoolean() {
if (!Platform.getOsArch().matches(cpuArchPattern)) {
System.out.println("CPU arch does not match " + cpuArchPattern);
return false;
}
if (supportedCPUFeatures != null) {
for (String feature : supportedCPUFeatures) {
if (!CPUInfo.hasFeature(feature)) {
System.out.println("CPU does not support " + feature
+ " feature");
return false;
}
}
}
if (unsupportedCPUFeatures != null) {
for (String feature : unsupportedCPUFeatures) {
if (CPUInfo.hasFeature(feature)) {
System.out.println("CPU support " + feature + " feature");
return false;
}
}
}
return true;
}
}
/*
* Copyright (c) 2014, 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 com.oracle.java.testlibrary.cli.predicate;
import java.util.function.BooleanSupplier;
public class NotPredicate implements BooleanSupplier {
private final BooleanSupplier s;
public NotPredicate(BooleanSupplier s) {
this.s = s;
}
@Override
public boolean getAsBoolean() {
return !s.getAsBoolean();
}
}
/*
* Copyright (c) 2014, 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 com.oracle.java.testlibrary.cli.predicate;
import java.util.function.BooleanSupplier;
public class OrPredicate implements BooleanSupplier {
private final BooleanSupplier a;
private final BooleanSupplier b;
public OrPredicate(BooleanSupplier a, BooleanSupplier b) {
this.a = a;
this.b = b;
}
@Override
public boolean getAsBoolean() {
return a.getAsBoolean() || b.getAsBoolean();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册