-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Runtime] Dumphooks for QuickStart framework
Summary: Add dumphooks for QuickStart framework: hooks will be called after application startup finishes Test Plan: test/jdk/com/alibaba/quickstart/TestQuickStartHooks.java
- Loading branch information
1 parent
6641997
commit 7bf80a2
Showing
13 changed files
with
348 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
src/java.base/share/classes/com/alibaba/util/QuickStart.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package com.alibaba.util; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class QuickStart { | ||
|
||
private QuickStart(){} | ||
|
||
private static native void registerNatives(); | ||
|
||
static { | ||
registerNatives(); | ||
} | ||
|
||
/** | ||
* The enumeration is the same as VM level `enum QuickStart::QuickStartRole` | ||
*/ | ||
public enum QuickStartRole { NORMAL, TRACER, REPLAYER } | ||
|
||
private static QuickStartRole role = QuickStartRole.NORMAL; | ||
|
||
private final static List<Runnable> dumpHooks = new ArrayList<>(); | ||
|
||
// JVM will set these fields | ||
protected static String resourcePath; | ||
|
||
// called by JVM | ||
private static void initialize(boolean isTracer, String resourcePath) { | ||
role = isTracer ? QuickStartRole.TRACER : QuickStartRole.REPLAYER; | ||
QuickStart.resourcePath = resourcePath; | ||
|
||
Runtime.getRuntime().addShutdownHook(new Thread(QuickStart::notifyDump)); | ||
} | ||
|
||
/** | ||
* Detect whether this Java process is a normal one. | ||
* Has the same semantics as VM level `!QuickStart::is_enabled()` | ||
* @return true if this Java process is a normal process. | ||
*/ | ||
public static boolean isNormal() { | ||
return role == QuickStartRole.NORMAL; | ||
} | ||
|
||
/** | ||
* Detect whether this Java process is a tracer. | ||
* Has the same semantics as VM level `QuickStart::is_tracer()` | ||
* @return true if this Java process is a tracer. | ||
*/ | ||
public static boolean isTracer() { | ||
return role == QuickStartRole.TRACER; | ||
} | ||
|
||
/** | ||
* Detect whether this Java process is a replayer. | ||
* Has the same semantics as VM level `QuickStart::is_replayer()` | ||
* @return true if this Java process is replayer. | ||
*/ | ||
public static boolean isReplayer() { | ||
return role == QuickStartRole.REPLAYER; | ||
} | ||
|
||
public static String resourcePath() { | ||
return resourcePath; | ||
} | ||
|
||
public static synchronized void addDumpHook(Runnable runnable) { | ||
if (notifyCompleted) { | ||
return; | ||
} | ||
dumpHooks.add(runnable); | ||
} | ||
|
||
public static synchronized void notifyDump() { | ||
if (notifyCompleted) { | ||
return; | ||
} | ||
for (Runnable dumpHook : dumpHooks) { | ||
dumpHook.run(); | ||
} | ||
notifyDump0(); | ||
notifyCompleted = true; | ||
} | ||
|
||
private static boolean notifyCompleted = false; | ||
|
||
private static native void notifyDump0(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#include "jni.h" | ||
#include "jni_util.h" | ||
#include "jvm.h" | ||
#include "jmm.h" | ||
#include "com_alibaba_util_QuickStart.h" | ||
#define THREAD "Ljava/lang/Thread;" | ||
#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0])) | ||
static JNINativeMethod methods[] = { | ||
{"notifyDump0", "()V", (void *)&JVM_NotifyDump } | ||
}; | ||
JNIEXPORT void JNICALL | ||
Java_com_alibaba_util_QuickStart_registerNatives(JNIEnv *env, jclass cls) | ||
{ | ||
(*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import com.alibaba.util.QuickStart; | ||
|
||
import java.lang.management.ClassLoadingMXBean; | ||
import java.lang.management.ManagementFactory; | ||
import java.lang.management.RuntimeMXBean; | ||
import java.security.AccessController; | ||
import java.security.PrivilegedAction; | ||
import java.util.List; | ||
import java.util.Properties; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
public class TestDump { | ||
|
||
private static long CHECK_INTERVAL_MS; | ||
private static long CLASS_INC_COUNT; | ||
private static long MAX_START_SECONDS; | ||
private static ClassLoadingMXBean mxbean = ManagementFactory.getClassLoadingMXBean(); | ||
|
||
static { | ||
Properties p = AccessController.doPrivileged((PrivilegedAction<Properties>)System::getProperties); | ||
CHECK_INTERVAL_MS = parsePositiveLongParameter(p, "-DcheckIntervalMS", 200); | ||
CLASS_INC_COUNT = parsePositiveLongParameter(p, "-DclassIncCount", 200); | ||
MAX_START_SECONDS = parsePositiveLongParameter(p, "-DmaxStartSeconds", 300); | ||
} | ||
|
||
private static long parsePositiveLongParameter(Properties p, String key, long defaultVal) { | ||
String value; | ||
if ((value = p.getProperty(key)) == null) { | ||
return defaultVal; | ||
} | ||
long res; | ||
try { | ||
res = Integer.parseInt(value); | ||
} catch (NumberFormatException e) { | ||
return defaultVal; | ||
} | ||
return res <= 0 ? defaultVal : res; | ||
} | ||
|
||
private static Policy policy = null; | ||
|
||
interface Policy { | ||
boolean check(); | ||
} | ||
|
||
static class ClassLoadingPolicy implements Policy { | ||
private final static long STARTING_MIN_INC = CLASS_INC_COUNT / | ||
TimeUnit.SECONDS.toMillis(1) * CHECK_INTERVAL_MS; | ||
private long lastLoadedClasses = 0; | ||
|
||
@Override | ||
public boolean check() { | ||
long cnt = mxbean.getLoadedClassCount(); | ||
if (cnt - lastLoadedClasses <= STARTING_MIN_INC) { | ||
return true; | ||
} | ||
lastLoadedClasses = cnt; | ||
return false; | ||
} | ||
} | ||
|
||
static class WatcherThread extends Thread { | ||
|
||
public WatcherThread() { | ||
super("QuickStart-WatcherThread"); | ||
} | ||
|
||
@Override | ||
public void run() { | ||
System.out.println("Watcher Thread begins..."); | ||
long start = System.currentTimeMillis(); | ||
|
||
do { | ||
try { | ||
Thread.sleep(CHECK_INTERVAL_MS); | ||
} catch (InterruptedException e) { | ||
return; | ||
} | ||
} while (System.currentTimeMillis() - start < TimeUnit.SECONDS.toMillis(MAX_START_SECONDS) | ||
&& !policy.check()); | ||
QuickStart.notifyDump(); | ||
} | ||
} | ||
|
||
public static boolean checkDumpUsingAPI() { | ||
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); | ||
List<String> arguments = runtimeMxBean.getInputArguments(); | ||
for (String arg : arguments) { | ||
if (arg.contains("-DtestHooks=true")) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
public static final long SLEEP_MILLIS = 5000; | ||
public static final String ANCHOR = "QuickStart startup finish detected!"; | ||
|
||
public static void main(String[] args) { | ||
if (checkDumpUsingAPI()) { | ||
policy = new ClassLoadingPolicy(); | ||
WatcherThread thread = new WatcherThread(); | ||
thread.setDaemon(true); | ||
thread.start(); | ||
} | ||
QuickStart.addDumpHook(() -> { | ||
System.out.println(ANCHOR); | ||
}); | ||
try { | ||
Thread.sleep(SLEEP_MILLIS); | ||
} catch (InterruptedException e) { | ||
e.printStackTrace(); | ||
} finally { | ||
System.out.println("finished"); | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.