Skip to content

Commit

Permalink
[Wisp] Support threadMxbean in AllThreadAsWisp
Browse files Browse the repository at this point in the history
Summary: Now we can use ThreadMxBean to inspect coroutine infomation.

Test Plan: Support ThreadMxBean to inspect coroutine infomation,
including getThreadInfo, dumpAllThreads,getThreadCount, getAllThreadIds.

Reviewed-by: zhengxiaolinX, yuleil, sanhongli

Issue: dragonwell-project/dragonwell8#132
  • Loading branch information
joeylee.lz authored and joeyleeeeeee97 committed Sep 29, 2020
1 parent 92cfe74 commit cb5618f
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 92 deletions.
12 changes: 0 additions & 12 deletions src/share/vm/prims/unsafe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1503,17 +1503,6 @@ JVM_ENTRY(jboolean, CoroutineSupport_stealCoroutine(JNIEnv* env, jclass klass, j
return true;
JVM_END

JVM_ENTRY (jobjectArray, CoroutineSupport_getCoroutineStack(JNIEnv* env, jclass klass, jlong coroPtr))
assert(EnableCoroutine, "pre-condition");

JvmtiVMObjectAllocEventCollector oam;

Coroutine* coro = (Coroutine*)coroPtr;

Handle stacktraces = ThreadService::dump_coroutine_stack_trace(coro, CHECK_NULL);
return (jobjectArray)JNIHandles::make_local(env, stacktraces());
JVM_END

JVM_ENTRY (void, CoroutineSupport_checkAndThrowException0(JNIEnv* env, jclass klass, jlong coroPtr))
assert(EnableCoroutine, "pre-condition");
Coroutine* coro = (Coroutine*)coroPtr;
Expand Down Expand Up @@ -1880,7 +1869,6 @@ JNINativeMethod coroutine_support_methods[] = {
{CC"getNextCoroutine", CC"(J)"COR, FN_PTR(CoroutineSupport_getNextCoroutine)},
{CC"moveCoroutine", CC"(JJ)V", FN_PTR(CoroutineSupport_moveCoroutine)},
{CC"markThreadCoroutine", CC"(J"COBA")V", FN_PTR(CoroutineSupport_markThreadCoroutine)},
{CC"getCoroutineStack", CC"(J)["STE, FN_PTR(CoroutineSupport_getCoroutineStack)},
{CC"checkAndThrowException0", CC"(J)V", FN_PTR(CoroutineSupport_checkAndThrowException0)},
};

Expand Down
14 changes: 14 additions & 0 deletions src/share/vm/runtime/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4299,6 +4299,20 @@ JavaThread* Threads::find_java_thread_from_java_tid(jlong java_tid) {
java_thread = thread;
break;
}

if (EnableCoroutine) {
for (Coroutine* co = thread->coroutine_list()->next();
co != thread->coroutine_list(); co = co->next()) {
oop wtObj = com_alibaba_wisp_engine_WispTask::get_threadWrapper(co->wisp_task());
// wtObj == 0 means coroutine is cached
if (!thread->is_exiting() &&
wtObj != NULL &&
java_tid == java_lang_Thread::thread_id(wtObj)) {
co->wisp_thread()->set_threadObj(wtObj);
return co->wisp_thread();
}
}
}
}
return java_thread;
}
Expand Down
68 changes: 45 additions & 23 deletions src/share/vm/runtime/vm_operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,25 @@ void VM_ThreadDump::doit() {
}
ThreadSnapshot* ts = snapshot_thread(jt, tcl);
_result->add_thread_snapshot(ts);

if (EnableCoroutine) {
for (Coroutine* co = jt->coroutine_list()->next();
co != jt->coroutine_list(); co = co->next()) {
oop tw = com_alibaba_wisp_engine_WispTask::get_threadWrapper(co->wisp_task());
// skip exited wisp threads
if (tw == NULL) {
continue;
}
co->wisp_thread()->set_threadObj(tw);

ThreadConcurrentLocks* wtcl = NULL;
if (_with_locked_synchronizers) {
wtcl = concurrent_locks.thread_concurrent_locks(co->wisp_thread());
}
ThreadSnapshot* wts = snapshot_coroutine(co, wtcl);
_result->add_thread_snapshot(wts);
}
}
}
} else {
// Snapshot threads in the given _threads array
Expand All @@ -336,6 +355,29 @@ void VM_ThreadDump::doit() {
continue;
}

if (EnableCoroutine) {
jlong id = java_lang_Thread::thread_id(th());
// this would traverse thread's coroutine list
JavaThread* jt = Threads::find_java_thread_from_java_tid(id);
if (jt->is_Wisp_thread()) {
Coroutine* co = ((WispThread*)jt)->coroutine();
oop tw = com_alibaba_wisp_engine_WispTask::get_threadWrapper(co->wisp_task());
// skip exited wisp threads
if (tw == NULL) {
continue;
}
co->wisp_thread()->set_threadObj(tw);

ThreadConcurrentLocks* wtcl = NULL;
if (_with_locked_synchronizers) {
wtcl = concurrent_locks.thread_concurrent_locks(co->wisp_thread());
}
ThreadSnapshot* wts = snapshot_coroutine(co, wtcl);
_result->add_thread_snapshot(wts);
return;
}
}

// Dump thread stack only if the thread is alive and not exiting
// and not VM internal thread.
JavaThread* jt = java_lang_Thread::thread(th());
Expand Down Expand Up @@ -363,33 +405,13 @@ ThreadSnapshot* VM_ThreadDump::snapshot_thread(JavaThread* java_thread, ThreadCo
return snapshot;
}

ThreadSnapshot* VM_CoroutineDump::snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl) {
ThreadSnapshot* snapshot = new ThreadSnapshot(java_thread);
snapshot->dump_stack_at_safepoint_for_coroutine(_target);
ThreadSnapshot* VM_ThreadDump::snapshot_coroutine(Coroutine* coro, ThreadConcurrentLocks* tcl) {
ThreadSnapshot* snapshot = new ThreadSnapshot(coro->wisp_thread());
snapshot->dump_stack_at_safepoint_for_coroutine(coro, _max_depth, _with_locked_monitors);
snapshot->set_concurrent_locks(tcl);
return snapshot;
}

VM_CoroutineDump::VM_CoroutineDump(ThreadDumpResult* result, Coroutine *target) {
assert(EnableCoroutine, "coroutine enabled");
_result = result;
_target = target;
}

bool VM_CoroutineDump::doit_prologue() {
assert(EnableCoroutine && Thread::current()->is_Java_thread(), "just checking");

return true;
}

void VM_CoroutineDump::doit_epilogue() {}

void VM_CoroutineDump::doit() {
ResourceMark rm;

ThreadSnapshot* ts = snapshot_thread(_target->thread(), NULL);
_result->add_thread_snapshot(ts);
}

volatile bool VM_Exit::_vm_exited = false;
Thread * VM_Exit::_shutdown_thread = NULL;
Expand Down
19 changes: 1 addition & 18 deletions src/share/vm/runtime/vm_operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
template(Dummy) \
template(ThreadStop) \
template(ThreadDump) \
template(CoroutineDump) \
template(PrintThreads) \
template(FindDeadlocks) \
template(ForceSafepoint) \
Expand Down Expand Up @@ -361,6 +360,7 @@ class VM_ThreadDump : public VM_Operation {
bool _with_locked_synchronizers;

ThreadSnapshot* snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl);
ThreadSnapshot* snapshot_coroutine(Coroutine* coro, ThreadConcurrentLocks* tcl);

public:
VM_ThreadDump(ThreadDumpResult* result,
Expand All @@ -381,23 +381,6 @@ class VM_ThreadDump : public VM_Operation {
void doit_epilogue();
};

class VM_CoroutineDump : public VM_Operation {
private:
ThreadDumpResult* _result;
Coroutine * _target;

ThreadSnapshot* snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl);

public:
VM_CoroutineDump(ThreadDumpResult* result, Coroutine *target);

VMOp_Type type() const { return VMOp_CoroutineDump; }
void doit();
bool doit_prologue();
void doit_epilogue();
};


class VM_Exit: public VM_Operation {
private:
int _exit_code;
Expand Down
71 changes: 36 additions & 35 deletions src/share/vm/services/threadService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "services/threadService.hpp"
#include "runtime/coroutine.hpp"

PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC

Expand Down Expand Up @@ -281,31 +282,6 @@ Handle ThreadService::dump_stack_traces(GrowableArray<instanceHandle>* threads,
return result_obj;
}

// Dump stack trace of Coroutine and return StackTraceElement[].
Handle ThreadService::dump_coroutine_stack_trace(Coroutine *coro, TRAPS) {

assert(EnableCoroutine, "coroutine enabled");

ThreadDumpResult dump_result;
VM_CoroutineDump op(&dump_result, coro);
VMThread::execute(&op);

// Allocate the resulting StackTraceElement[] object

ResourceMark rm(THREAD);

assert(dump_result.num_snapshots() == 1, "must only one stacktrace");
ThreadStackTrace* stacktrace = dump_result.snapshots()->get_stack_trace();
Handle stacktrace_h;
if (stacktrace == NULL) {
// No stack trace
stacktrace_h = Handle();
} else {
// Construct an array of java/lang/StackTraceElement object
stacktrace_h = stacktrace->allocate_fill_stack_trace_element_array(CHECK_NH);
}
return stacktrace_h;
}

void ThreadService::reset_contention_count_stat(JavaThread* thread) {
ThreadStatistics* stat = thread->get_thread_stat();
Expand Down Expand Up @@ -655,7 +631,7 @@ void ThreadStackTrace::add_stack_frame(javaVFrame* jvf) {
_depth++;
}

void ThreadStackTrace::dump_stack_at_safepoint_for_coroutine(Coroutine *target) {
void ThreadStackTrace::dump_stack_at_safepoint_for_coroutine(Coroutine *target, int max_depth) {
assert(SafepointSynchronize::is_at_safepoint(), "all threads are stopped");

Coroutine::CoroutineState state = target->state();
Expand All @@ -681,12 +657,18 @@ void ThreadStackTrace::dump_stack_at_safepoint_for_coroutine(Coroutine *target)
}
}

int count = 0;
while (vf) {
if (vf->is_java_frame()) {
javaVFrame* jvf = javaVFrame::cast(vf);
add_stack_frame(jvf);
count++;
}
vf = vf->sender();
if (max_depth > 0 && count == max_depth) {
// Skip frames if more than maxDepth
break;
}
}
}

Expand Down Expand Up @@ -900,9 +882,9 @@ void ThreadSnapshot::dump_stack_at_safepoint(int max_depth, bool with_locked_mon
_stack_trace->dump_stack_at_safepoint(max_depth);
}

void ThreadSnapshot::dump_stack_at_safepoint_for_coroutine(Coroutine *target) {
_stack_trace = new ThreadStackTrace(_thread, false);
_stack_trace->dump_stack_at_safepoint_for_coroutine(target);
void ThreadSnapshot::dump_stack_at_safepoint_for_coroutine(Coroutine *target, int max_depth, bool with_locked_monitors) {
_stack_trace = new ThreadStackTrace(_thread, with_locked_monitors);
_stack_trace->dump_stack_at_safepoint_for_coroutine(target, max_depth);
}


Expand Down Expand Up @@ -1016,6 +998,27 @@ ThreadsListEnumerator::ThreadsListEnumerator(Thread* cur_thread,
MutexLockerEx ml(Threads_lock);

for (JavaThread* jt = Threads::first(); jt != NULL; jt = jt->next()) {
if (!ThreadsListEnumerator::skipThread(jt, include_jvmti_agent_threads, include_jni_attaching_threads)) {
instanceHandle h(cur_thread, (instanceOop) jt->threadObj());
_threads_array->append(h);
}

if (EnableCoroutine) {
for (Coroutine* co = jt->coroutine_list()->next(); co != jt->coroutine_list(); co = co->next()) {
if (!ThreadsListEnumerator::skipThread(co->thread(), include_jvmti_agent_threads, include_jni_attaching_threads)) {
oop tw = com_alibaba_wisp_engine_WispTask::get_threadWrapper(co->wisp_task());
// skip exited wisp threads
if (tw != NULL) {
instanceHandle hc(cur_thread, (instanceOop) tw);
_threads_array->append(hc);
}
}
}
}
}
}

bool ThreadsListEnumerator::skipThread(JavaThread* jt, bool include_jvmti_agent_threads, bool include_jni_attaching_threads) {
// skips JavaThreads in the process of exiting
// and also skips VM internal JavaThreads
// Threads in _thread_new or _thread_new_trans state are included.
Expand All @@ -1024,20 +1027,18 @@ ThreadsListEnumerator::ThreadsListEnumerator(Thread* cur_thread,
jt->is_exiting() ||
!java_lang_Thread::is_alive(jt->threadObj()) ||
jt->is_hidden_from_external_view()) {
continue;
return true;
}

// skip agent threads
if (!include_jvmti_agent_threads && jt->is_jvmti_agent_thread()) {
continue;
return true;
}

// skip jni threads in the process of attaching
if (!include_jni_attaching_threads && jt->is_attaching_via_jni()) {
continue;
return true;
}

instanceHandle h(cur_thread, (instanceOop) jt->threadObj());
_threads_array->append(h);
}
return false;
}
7 changes: 3 additions & 4 deletions src/share/vm/services/threadService.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,6 @@ class ThreadService : public AllStatic {
static Handle dump_stack_traces(GrowableArray<instanceHandle>* threads,
int num_threads, TRAPS);

static Handle dump_coroutine_stack_trace(Coroutine *coro, TRAPS);

static void reset_peak_thread_count();
static void reset_contention_count_stat(JavaThread* thread);
static void reset_contention_time_stat(JavaThread* thread);
Expand Down Expand Up @@ -243,7 +241,7 @@ class ThreadSnapshot : public CHeapObj<mtInternal> {
ThreadConcurrentLocks* get_concurrent_locks() { return _concurrent_locks; }

void dump_stack_at_safepoint(int max_depth, bool with_locked_monitors);
void dump_stack_at_safepoint_for_coroutine(Coroutine *target);
void dump_stack_at_safepoint_for_coroutine(Coroutine *target, int max_depth, bool with_locked_monitors);
void set_concurrent_locks(ThreadConcurrentLocks* l) { _concurrent_locks = l; }
void oops_do(OopClosure* f);
void metadata_do(void f(Metadata*));
Expand All @@ -268,7 +266,7 @@ class ThreadStackTrace : public CHeapObj<mtInternal> {

void add_stack_frame(javaVFrame* jvf);
void dump_stack_at_safepoint(int max_depth);
void dump_stack_at_safepoint_for_coroutine(Coroutine *target);
void dump_stack_at_safepoint_for_coroutine(Coroutine *target, int max_depth);
Handle allocate_fill_stack_trace_element_array(TRAPS);
void oops_do(OopClosure* f);
void metadata_do(void f(Metadata*));
Expand Down Expand Up @@ -392,6 +390,7 @@ class DeadlockCycle : public CHeapObj<mtInternal> {
class ThreadsListEnumerator : public StackObj {
private:
GrowableArray<instanceHandle>* _threads_array;
static bool skipThread(JavaThread* jt, bool include_jvmti_agent_threads, bool include_jni_attaching_threads);
public:
ThreadsListEnumerator(Thread* cur_thread,
bool include_jvmti_agent_threads = false,
Expand Down

0 comments on commit cb5618f

Please sign in to comment.