Skip to content
Permalink
Browse files
8245113: JFR Recorder Thread to run in thread state "_thread_in_native"
Reviewed-by: egahlin
  • Loading branch information
Markus Grönlund committed Jun 11, 2020
1 parent b9ce3b4 commit 0228a5c7677130b3a52598e8a347b1055df10c71
Showing 14 changed files with 154 additions and 90 deletions.
@@ -723,18 +723,20 @@ static bool check_exclusion_state_on_thread_start(JavaThread* jt) {
return true;
}

jlong JfrJavaSupport::jfr_thread_id(jobject thread) {
static JavaThread* get_native(jobject thread) {
ThreadsListHandle tlh;
JavaThread* native_thread = NULL;
(void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
return native_thread;
}

jlong JfrJavaSupport::jfr_thread_id(jobject thread) {
JavaThread* native_thread = get_native(thread);
return native_thread != NULL ? JFR_THREAD_ID(native_thread) : 0;
}

void JfrJavaSupport::exclude(jobject thread) {
HandleMark hm;
ThreadsListHandle tlh;
JavaThread* native_thread = NULL;
(void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
JavaThread* native_thread = get_native(thread);
if (native_thread != NULL) {
JfrThreadLocal::exclude(native_thread);
} else {
@@ -744,10 +746,7 @@ void JfrJavaSupport::exclude(jobject thread) {
}

void JfrJavaSupport::include(jobject thread) {
HandleMark hm;
ThreadsListHandle tlh;
JavaThread* native_thread = NULL;
(void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
JavaThread* native_thread = get_native(thread);
if (native_thread != NULL) {
JfrThreadLocal::include(native_thread);
} else {
@@ -757,10 +756,7 @@ void JfrJavaSupport::include(jobject thread) {
}

bool JfrJavaSupport::is_excluded(jobject thread) {
HandleMark hm;
ThreadsListHandle tlh;
JavaThread* native_thread = NULL;
(void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
JavaThread* native_thread = get_native(thread);
return native_thread != NULL ? native_thread->jfr_thread_local()->is_excluded() : is_thread_excluded(thread);
}

@@ -179,6 +179,12 @@ NO_TRANSITION(jboolean, jfr_should_rotate_disk(JNIEnv* env, jobject jvm))
return JfrChunkRotation::should_rotate() ? JNI_TRUE : JNI_FALSE;
NO_TRANSITION_END

NO_TRANSITION(jlong, jfr_get_type_id_from_string(JNIEnv * env, jobject jvm, jstring type))
const char* type_name = env->GetStringUTFChars(type, NULL);
jlong id = JfrType::name_to_id(type_name);
env->ReleaseStringUTFChars(type, type_name);
return id;
NO_TRANSITION_END
/*
* JVM_ENTRY_NO_ENV entries
*
@@ -350,11 +356,3 @@ JVM_END
JVM_ENTRY_NO_ENV(jboolean, jfr_set_handler(JNIEnv * env, jobject jvm, jobject clazz, jobject handler))
return JfrJavaSupport::set_handler(clazz, handler, thread);
JVM_END

NO_TRANSITION(jlong, jfr_get_type_id_from_string(JNIEnv * env, jobject jvm, jstring type))
const char* type_name= env->GetStringUTFChars(type, NULL);
jlong id = JfrType::name_to_id(type_name);
env->ReleaseStringUTFChars(type, type_name);
return id;
NO_TRANSITION_END

@@ -24,6 +24,7 @@

#include "precompiled.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/leakprofiler/chains/edgeStore.hpp"
#include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
@@ -40,10 +41,12 @@
#include "jfr/utilities/jfrHashtable.hpp"
#include "jfr/utilities/jfrPredicate.hpp"
#include "jfr/utilities/jfrRelation.hpp"
#include "memory/resourceArea.inline.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/thread.hpp"
#include "runtime/thread.inline.hpp"

const int initial_array_size = 64;

@@ -248,17 +251,21 @@ static void install_stack_traces(const ObjectSampler* sampler, JfrStackTraceRepo
assert(sampler != NULL, "invariant");
const ObjectSample* const last = sampler->last();
if (last != sampler->last_resolved()) {
ResourceMark rm;
JfrKlassUnloading::sort();
StackTraceBlobInstaller installer(stack_trace_repo);
iterate_samples(installer);
}
}

// caller needs ResourceMark
void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) {
assert(JfrStream_lock->owned_by_self(), "invariant");
assert(sampler != NULL, "invariant");
assert(LeakProfiler::is_running(), "invariant");
Thread* const thread = Thread::current();
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread);)
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)thread);
MutexLocker lock(ClassLoaderDataGraph_lock);
// the lock is needed to ensure the unload lists do not grow in the middle of inspection.
install_stack_traces(sampler, stack_trace_repo);
@@ -416,6 +423,7 @@ static void save_type_set_blob(JfrCheckpointWriter& writer, bool copy = false) {

void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) {
assert(LeakProfiler::is_running(), "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(Thread::current());)
const ObjectSample* last = ObjectSampler::sampler()->last();
if (writer.has_data() && last != NULL) {
save_type_set_blob(writer);
@@ -24,6 +24,7 @@

#include "precompiled.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
@@ -48,6 +49,7 @@
#include "memory/resourceArea.hpp"
#include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/mutex.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/safepoint.hpp"
@@ -325,6 +327,7 @@ void JfrCheckpointManager::end_epoch_shift() {
}

size_t JfrCheckpointManager::write() {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
assert(_mspace->free_list_is_empty(), "invariant");
WriteOperation wo(_chunkwriter);
MutexedWriteOperation mwo(wo);
@@ -357,15 +360,19 @@ size_t JfrCheckpointManager::write_static_type_set(Thread* thread) {

size_t JfrCheckpointManager::write_threads(Thread* thread) {
assert(thread != NULL, "invariant");
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)thread);
ResetNoHandleMark rnhm;
ResourceMark rm(thread);
HandleMark hm(thread);
JfrCheckpointWriter writer(true, thread, THREADS);
JfrTypeManager::write_threads(writer);
return writer.used_size();
}

size_t JfrCheckpointManager::write_static_type_set_and_threads() {
Thread* const thread = Thread::current();
ResourceMark rm(thread);
HandleMark hm(thread);
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread));
write_static_type_set(thread);
write_threads(thread);
return write();
@@ -380,29 +387,35 @@ void JfrCheckpointManager::on_rotation() {
void JfrCheckpointManager::clear_type_set() {
assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
assert(!JfrRecorder::is_recording(), "invariant");
Thread* t = Thread::current();
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(t));
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)t);
ResetNoHandleMark rnhm;
MutexLocker cld_lock(ClassLoaderDataGraph_lock);
MutexLocker module_lock(Module_lock);
JfrTypeSet::clear();
}

void JfrCheckpointManager::write_type_set() {
assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
Thread* const thread = Thread::current();
if (LeakProfiler::is_running()) {
{
Thread* const thread = Thread::current();
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread));
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)thread);
ResetNoHandleMark rnhm;
MutexLocker cld_lock(thread, ClassLoaderDataGraph_lock);
MutexLocker module_lock(thread, Module_lock);
JfrCheckpointWriter leakp_writer(true, thread);
JfrCheckpointWriter writer(true, thread);
JfrTypeSet::serialize(&writer, &leakp_writer, false, false);
ObjectSampleCheckpoint::on_type_set(leakp_writer);
} else {
// can safepoint here
MutexLocker cld_lock(ClassLoaderDataGraph_lock);
MutexLocker module_lock(Module_lock);
JfrCheckpointWriter writer(true, thread);
JfrTypeSet::serialize(&writer, NULL, false, false);
if (LeakProfiler::is_running()) {
JfrCheckpointWriter leakp_writer(true, thread);
JfrCheckpointWriter writer(true, thread);
JfrTypeSet::serialize(&writer, &leakp_writer, false, false);
ObjectSampleCheckpoint::on_type_set(leakp_writer);
} else {
JfrCheckpointWriter writer(true, thread);
JfrTypeSet::serialize(&writer, NULL, false, false);
}
}
write();
}
@@ -416,13 +429,33 @@ void JfrCheckpointManager::on_unloading_classes() {
}
}

class JavaThreadToVM : public StackObj {
private:
JavaThread* _jt;
public:
JavaThreadToVM(Thread* thread) : _jt(thread->is_Java_thread() ? (JavaThread*)thread : NULL) {
if (_jt != NULL) {
assert(_jt->thread_state() == _thread_in_native, "invariant");
_jt->set_thread_state(_thread_in_vm);
}
}
~JavaThreadToVM() {
if (_jt != NULL) {
_jt->set_thread_state(_thread_in_native);
}
}
};

size_t JfrCheckpointManager::flush_type_set() {
size_t elements = 0;
if (JfrTraceIdEpoch::has_changed_tag_state()) {
JfrCheckpointWriter writer(Thread::current());
// can safepoint here
MutexLocker cld_lock(ClassLoaderDataGraph_lock);
MutexLocker module_lock(Module_lock);
Thread* const t = Thread::current();
// can safepoint here (if JavaThread)
JavaThreadToVM transition(t);
ResetNoHandleMark rnhm;
MutexLocker cld_lock(t, ClassLoaderDataGraph_lock);
MutexLocker module_lock(t, Module_lock);
JfrCheckpointWriter writer(t);
elements = JfrTypeSet::serialize(&writer, NULL, false, true);
}
if (is_constant_pending()) {
@@ -29,14 +29,18 @@
#include "oops/klass.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/thread.inline.hpp"

static jbyteArray metadata_blob = NULL;
static u8 metadata_id = 0;
static u8 last_metadata_id = 0;

static void write_metadata_blob(JfrChunkWriter& chunkwriter) {
static void write_metadata_blob(JfrChunkWriter& chunkwriter, Thread* thread) {
assert(chunkwriter.is_valid(), "invariant");
assert(thread != NULL, "invariant");
assert(metadata_blob != NULL, "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
const typeArrayOop arr = (typeArrayOop)JfrJavaSupport::resolve_non_null(metadata_blob);
assert(arr != NULL, "invariant");
const int length = arr->length();
@@ -47,25 +51,28 @@ static void write_metadata_blob(JfrChunkWriter& chunkwriter) {
chunkwriter.write_unbuffered(data_address, length);
}

bool JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) {
void JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) {
assert(chunkwriter.is_valid(), "invariant");
if (last_metadata_id == metadata_id && chunkwriter.has_metadata()) {
return false;
return;
}
JavaThread* const jt = (JavaThread*)Thread::current();
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
// can safepoint here
ThreadInVMfromNative transition(jt);
// header
const int64_t metadata_offset = chunkwriter.reserve(sizeof(u4));
chunkwriter.write<u8>(EVENT_METADATA); // ID 0
// time data
chunkwriter.write(JfrTicks::now());
chunkwriter.write((u8)0); // duration
chunkwriter.write(metadata_id); // metadata id
write_metadata_blob(chunkwriter); // payload
write_metadata_blob(chunkwriter, jt); // payload
// fill in size of metadata descriptor event
const int64_t size_written = chunkwriter.current_offset() - metadata_offset;
chunkwriter.write_padded_at_offset((u4)size_written, metadata_offset);
chunkwriter.set_last_metadata_offset(metadata_offset);
last_metadata_id = metadata_id;
return true;
}

void JfrMetadataEvent::update(jbyteArray metadata) {
@@ -36,7 +36,7 @@ class JfrChunkWriter;
//
class JfrMetadataEvent : AllStatic {
public:
static bool write(JfrChunkWriter& writer);
static void write(JfrChunkWriter& writer);
static void update(jbyteArray metadata);
};

@@ -1038,6 +1038,7 @@ size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* l
* Clear all tags from the previous epoch.
*/
void JfrTypeSet::clear() {
ResourceMark rm;
JfrKlassUnloading::clear();
clear_artifacts = true;
setup(NULL, NULL, false, false);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, 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
@@ -27,6 +27,7 @@
#include "jfr/recorder/repository/jfrChunkRotation.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"

static jobject chunk_monitor = NULL;
static int64_t threshold = 0;
@@ -53,6 +54,9 @@ static jobject get_chunk_monitor(Thread* thread) {

static void notify() {
Thread* const thread = Thread::current();
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)thread);
ResetNoHandleMark rnhm;
JfrJavaSupport::notify_all(get_chunk_monitor(thread), thread);
}

0 comments on commit 0228a5c

Please sign in to comment.