mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +02:00
8231125
: Improve testing of parallel loading of shared classes by the boot class loader
Reviewed-by: ccheung, coleenp, dholmes
This commit is contained in:
parent
83f41d2736
commit
9c92ecba04
4 changed files with 75 additions and 31 deletions
|
@ -1270,6 +1270,7 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
|
|
||||||
if (ik != NULL) {
|
if (ik != NULL) {
|
||||||
|
assert(!ik->is_unshareable_info_restored(), "shared class can be loaded only once");
|
||||||
Symbol* class_name = ik->name();
|
Symbol* class_name = ik->name();
|
||||||
|
|
||||||
bool visible = is_shared_class_visible(
|
bool visible = is_shared_class_visible(
|
||||||
|
|
|
@ -524,6 +524,18 @@ protected:
|
||||||
virtual void remove_java_mirror();
|
virtual void remove_java_mirror();
|
||||||
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
|
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
|
||||||
|
|
||||||
|
bool is_unshareable_info_restored() const {
|
||||||
|
assert(is_shared(), "use this for shared classes only");
|
||||||
|
if (has_raw_archived_mirror()) {
|
||||||
|
// _java_mirror is not a valid OopHandle but rather an encoded reference in the shared heap
|
||||||
|
return false;
|
||||||
|
} else if (_java_mirror.ptr_raw() == NULL) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// subclass accessor (here for convenience; undefined for non-klass objects)
|
// subclass accessor (here for convenience; undefined for non-klass objects)
|
||||||
virtual bool is_leaf_class() const { fatal("not a class"); return false; }
|
virtual bool is_leaf_class() const { fatal("not a class"); return false; }
|
||||||
|
|
|
@ -36,10 +36,34 @@
|
||||||
public class ParallelLoadTest {
|
public class ParallelLoadTest {
|
||||||
public static final int MAX_CLASSES = 40;
|
public static final int MAX_CLASSES = 40;
|
||||||
|
|
||||||
|
/* For easy stress testing, do this:
|
||||||
|
|
||||||
|
i=0; while jtreg -DParallelLoadTest.app.loops=100 -DParallelLoadTest.boot.loops=100 \
|
||||||
|
ParallelLoadTest.java; do i=$(expr $i + 1); echo =====$i; done
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static final int APP_LOOPS = Integer.parseInt(System.getProperty("ParallelLoadTest.app.loops", "1"));
|
||||||
|
private static final int BOOT_LOOPS = Integer.parseInt(System.getProperty("ParallelLoadTest.boot.loops", "1"));
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
JarBuilder.build("parallel_load", getClassList(true));
|
JarBuilder.build("parallel_load", getClassList(true));
|
||||||
String appJar = TestCommon.getTestJar("parallel_load.jar");
|
String testJar = TestCommon.getTestJar("parallel_load.jar");
|
||||||
TestCommon.test(appJar, getClassList(false), "ParallelLoad");
|
|
||||||
|
// (1) Load the classes from app class loader
|
||||||
|
TestCommon.testDump(testJar, getClassList(false));
|
||||||
|
for (int i = 0; i < APP_LOOPS; i++) {
|
||||||
|
TestCommon.run("-cp", testJar, "ParallelLoad").assertNormalExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// (2) Load the classes from boot class loader
|
||||||
|
String bootcp = "-Xbootclasspath/a:" + testJar;
|
||||||
|
TestCommon.testDump(null, getClassList(false), bootcp);
|
||||||
|
for (int i = 0; i < BOOT_LOOPS; i++) {
|
||||||
|
TestCommon.run(bootcp,
|
||||||
|
// "-Xlog:class+load=debug",
|
||||||
|
"ParallelLoad").assertNormalExit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] getClassList(boolean includeWatchdog) {
|
private static String[] getClassList(boolean includeWatchdog) {
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
|
||||||
// This test helper is parameterized by:
|
// This test helper is parameterized by:
|
||||||
|
@ -128,8 +129,13 @@ class ParallelLoadWatchdog extends Thread {
|
||||||
|
|
||||||
|
|
||||||
class ParallelLoadThread extends Thread {
|
class ParallelLoadThread extends Thread {
|
||||||
static int num_ready[] = new int[ParallelLoad.MAX_CLASSES];
|
static AtomicInteger num_ready[];
|
||||||
static Object lock = new Object();
|
static {
|
||||||
|
num_ready = new AtomicInteger[ParallelLoad.MAX_CLASSES];
|
||||||
|
for (int i = 0; i < ParallelLoad.MAX_CLASSES; i++) {
|
||||||
|
num_ready[i] = new AtomicInteger();
|
||||||
|
}
|
||||||
|
}
|
||||||
static String transformMode =
|
static String transformMode =
|
||||||
System.getProperty("appcds.parallel.transform.mode", "none");
|
System.getProperty("appcds.parallel.transform.mode", "none");
|
||||||
|
|
||||||
|
@ -154,20 +160,20 @@ class ParallelLoadThread extends Thread {
|
||||||
|
|
||||||
private void run0() throws Throwable {
|
private void run0() throws Throwable {
|
||||||
for (int i = 0; i < ParallelLoad.MAX_CLASSES; i++) {
|
for (int i = 0; i < ParallelLoad.MAX_CLASSES; i++) {
|
||||||
synchronized(lock) {
|
|
||||||
num_ready[i] ++;
|
|
||||||
while (num_ready[i] < ParallelLoad.NUM_THREADS) {
|
|
||||||
lock.wait();
|
|
||||||
}
|
|
||||||
lock.notifyAll();
|
|
||||||
}
|
|
||||||
log("this = %s %d", this, i);
|
|
||||||
String className = "ParallelClass" + i;
|
String className = "ParallelClass" + i;
|
||||||
if (transformMode.equals("cflh"))
|
if (transformMode.equals("cflh")) {
|
||||||
className = "ParallelClassTr" + i;
|
className = "ParallelClassTr" + i;
|
||||||
|
}
|
||||||
Class clazz = null;
|
Class clazz = null;
|
||||||
|
|
||||||
|
// Spin until every thread is ready to proceed
|
||||||
|
num_ready[i].incrementAndGet();
|
||||||
|
while (num_ready[i].intValue() < ParallelLoad.NUM_THREADS) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Avoid logging in this block so the threads can proceed without
|
||||||
|
// waiting for the stdout lock, etc.
|
||||||
switch (ParallelLoad.loaderType) {
|
switch (ParallelLoad.loaderType) {
|
||||||
case ParallelLoad.SYSTEM_LOADER:
|
case ParallelLoad.SYSTEM_LOADER:
|
||||||
clazz = Class.forName(className);
|
clazz = Class.forName(className);
|
||||||
|
@ -179,10 +185,11 @@ class ParallelLoadThread extends Thread {
|
||||||
clazz = ParallelLoad.classLoaders[thread_id].loadClass(className);
|
clazz = ParallelLoad.classLoaders[thread_id].loadClass(className);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
log("clazz = %s", clazz);
|
|
||||||
testTransformation(clazz);
|
testTransformation(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log("thread[%d] t = %s, c = %s, l = %s", thread_id, this, clazz, clazz.getClassLoader());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testTransformation(Class c) throws Exception {
|
private void testTransformation(Class c) throws Exception {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue