# HG changeset patch # User egahlin # Date 1558101747 -7200 # Node ID 5d043a159d5c05964982d037e31ca797216e2f54 # Parent 4cab5edc2950fa450acfbbb85ecfd9808d942044 Preview diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/gc/z/zTracer.cpp --- a/src/hotspot/share/gc/z/zTracer.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/gc/z/zTracer.cpp Fri May 17 16:02:27 2019 +0200 @@ -58,11 +58,9 @@ static void register_jfr_type_serializers() { JfrSerializer::register_serializer(TYPE_ZSTATISTICSCOUNTERTYPE, - false /* require_safepoint */, true /* permit_cache */, new ZStatisticsCounterTypeConstant()); JfrSerializer::register_serializer(TYPE_ZSTATISTICSSAMPLERTYPE, - false /* require_safepoint */, true /* permit_cache */, new ZStatisticsSamplerTypeConstant()); } diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/dcmd/jfrDcmds.cpp --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp Fri May 17 16:02:27 2019 +0200 @@ -349,6 +349,7 @@ _filename("filename", "Resulting recording filename, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false), _maxage("maxage", "Maximum time to keep recorded data (on disk) in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, "0"), _maxsize("maxsize", "Maximum amount of bytes to keep (on disk) in (k)B, (M)B or (G)B, e.g. 500M, or 0 for no limit", "MEMORY SIZE", false, "0"), + _flush("flush", "Maximum time before flushing buffers, measuare in (s)econds, e.g. 4 s, or 0 for flushing when a recording ends", "NANOTIME", false, "0"), _dump_on_exit("dumponexit", "Dump running recording when JVM shuts down", "BOOLEAN", false), _path_to_gc_roots("path-to-gc-roots", "Collect path to GC roots", "BOOLEAN", false, "false") { _dcmdparser.add_dcmd_option(&_name); @@ -359,6 +360,7 @@ _dcmdparser.add_dcmd_option(&_filename); _dcmdparser.add_dcmd_option(&_maxage); _dcmdparser.add_dcmd_option(&_maxsize); + _dcmdparser.add_dcmd_option(&_flush); _dcmdparser.add_dcmd_option(&_dump_on_exit); _dcmdparser.add_dcmd_option(&_path_to_gc_roots); }; @@ -411,6 +413,10 @@ maxsize = JfrJavaSupport::new_java_lang_Long(_maxsize.value()._size, CHECK); } + jobject flush = NULL; + if (_flush.is_set()) { + flush = JfrJavaSupport::new_java_lang_Long(_flush.value()._nanotime, CHECK); + } jobject duration = NULL; if (_duration.is_set()) { duration = JfrJavaSupport::new_java_lang_Long(_duration.value()._nanotime, CHECK); @@ -458,7 +464,7 @@ static const char method[] = "execute"; static const char signature[] = "(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/Long;" "Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/String;" - "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;"; + "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;"; JfrJavaArguments execute_args(&result, klass, method, signature, CHECK); execute_args.set_receiver(h_dcmd_instance); @@ -472,6 +478,7 @@ execute_args.push_jobject(filename); execute_args.push_jobject(maxage); execute_args.push_jobject(maxsize); + execute_args.push_jobject(flush); execute_args.push_jobject(dump_on_exit); execute_args.push_jobject(path_to_gc_roots); diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/dcmd/jfrDcmds.hpp --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp Fri May 17 16:02:27 2019 +0200 @@ -90,6 +90,7 @@ DCmdArgument _filename; DCmdArgument _maxage; DCmdArgument _maxsize; + DCmdArgument _flush; DCmdArgument _dump_on_exit; DCmdArgument _path_to_gc_roots; diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp --- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp Fri May 17 16:02:27 2019 +0200 @@ -44,7 +44,6 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/array.hpp" -#include "oops/constantPool.hpp" #include "oops/instanceKlass.hpp" #include "oops/method.hpp" #include "prims/jvmtiRedefineClasses.hpp" diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/jfr.cpp --- a/src/hotspot/share/jfr/jfr.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/jfr.cpp Fri May 17 16:02:27 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -71,6 +71,18 @@ JfrThreadLocal::on_exit(t); } +void Jfr::exclude_thread(Thread* t) { + JfrThreadLocal::exclude(t); +} + +void Jfr::include_thread(Thread* t) { + JfrThreadLocal::include(t); +} + +bool Jfr::is_excluded(Thread* t) { + return t != NULL && t->jfr_thread_local()->is_excluded(); +} + void Jfr::on_java_thread_dismantle(JavaThread* jt) { if (JfrRecorder::is_recording()) { JfrCheckpointManager::write_thread_checkpoint(jt); diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/jfr.hpp --- a/src/hotspot/share/jfr/jfr.hpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/jfr.hpp Fri May 17 16:02:27 2019 +0200 @@ -48,6 +48,9 @@ static void on_unloading_classes(); static void on_thread_start(Thread* thread); static void on_thread_exit(Thread* thread); + static void exclude_thread(Thread* thread); + static bool is_excluded(Thread* thread); + static void include_thread(Thread* thread); static void on_java_thread_dismantle(JavaThread* jt); static void on_vm_shutdown(bool exception_handler = false); static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter); diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/jni/jfrJavaSupport.cpp --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Fri May 17 16:02:27 2019 +0200 @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "jni.h" #include "classfile/javaClasses.inline.hpp" #include "classfile/modules.hpp" #include "classfile/symbolTable.hpp" @@ -42,9 +41,11 @@ #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/semaphore.inline.hpp" #include "runtime/synchronizer.hpp" #include "runtime/thread.inline.hpp" #include "runtime/threadSMR.hpp" +#include "utilities/growableArray.hpp" #ifdef ASSERT void JfrJavaSupport::check_java_thread_in_vm(Thread* t) { @@ -58,6 +59,12 @@ assert(t->is_Java_thread(), "invariant"); assert(((JavaThread*)t)->thread_state() == _thread_in_native, "invariant"); } + +static void check_new_unstarted_java_thread(Thread* t) { + assert(t != NULL, "invariant"); + assert(t->is_Java_thread(), "invariant"); + assert(((JavaThread*)t)->thread_state() == _thread_new, "invariant"); +} #endif /* @@ -93,6 +100,21 @@ JNIHandles::destroy_global(handle); } +jweak JfrJavaSupport::global_weak_jni_handle(const oop obj, Thread* t) { + DEBUG_ONLY(check_java_thread_in_vm(t)); + HandleMark hm(t); + return JNIHandles::make_weak_global(Handle(t, obj)); +} + +jweak JfrJavaSupport::global_weak_jni_handle(const jobject handle, Thread* t) { + const oop obj = JNIHandles::resolve(handle); + return obj == NULL ? NULL : global_weak_jni_handle(obj, t); +} + +void JfrJavaSupport::destroy_global_weak_jni_handle(jweak handle) { + JNIHandles::destroy_weak_global(handle); +} + oop JfrJavaSupport::resolve_non_null(jobject obj) { return JNIHandles::resolve_non_null(obj); } @@ -603,9 +625,149 @@ return true; } -jlong JfrJavaSupport::jfr_thread_id(jobject target_thread) { +class ThreadExclusionListAccess : public StackObj { + private: + static Semaphore _mutex_semaphore; + public: + ThreadExclusionListAccess() { _mutex_semaphore.wait(); } + ~ThreadExclusionListAccess() { _mutex_semaphore.signal(); } +}; + +Semaphore ThreadExclusionListAccess::_mutex_semaphore(1); +static GrowableArray* exclusion_list = NULL; + +static bool equals(const jweak excluded_thread, Handle target_thread) { + return JfrJavaSupport::resolve_non_null(excluded_thread) == target_thread(); +} + +static int find_exclusion_thread_idx(Handle thread) { + if (exclusion_list != NULL) { + for (int i = 0; i < exclusion_list->length(); ++i) { + if (equals(exclusion_list->at(i), thread)) { + return i; + } + } + } + return -1; +} + +static Handle as_handle(jobject thread) { + return Handle(Thread::current(), JfrJavaSupport::resolve_non_null(thread)); +} + +static bool thread_is_not_excluded(Handle thread) { + return -1 == find_exclusion_thread_idx(thread); +} + +static bool thread_is_not_excluded(jobject thread) { + return thread_is_not_excluded(as_handle(thread)); +} + +static bool is_thread_excluded(jobject thread) { + return !thread_is_not_excluded(thread); +} + +#ifdef ASSERT +static bool is_thread_excluded(Handle thread) { + return !thread_is_not_excluded(thread); +} +#endif // ASSERT + +static int add_thread_to_exclusion_list(jobject thread) { + ThreadExclusionListAccess lock; + if (exclusion_list == NULL) { + exclusion_list = new (ResourceObj::C_HEAP, mtTracing) GrowableArray(10, true, mtTracing); + } + assert(exclusion_list != NULL, "invariant"); + assert(thread_is_not_excluded(thread), "invariant"); + jweak ref = JfrJavaSupport::global_weak_jni_handle(thread, Thread::current()); + const int idx = exclusion_list->append(ref); + assert(is_thread_excluded(thread), "invariant"); + return idx; +} + +static void remove_thread_from_exclusion_list(Handle thread) { + assert(exclusion_list != NULL, "invariant"); + assert(is_thread_excluded(thread), "invariant"); + assert(exclusion_list != NULL, "invariant"); + const int idx = find_exclusion_thread_idx(thread); + assert(idx >= 0, "invariant"); + assert(idx < exclusion_list->length(), "invariant"); + JfrJavaSupport::destroy_global_weak_jni_handle(exclusion_list->at(idx)); + exclusion_list->delete_at(idx); + assert(thread_is_not_excluded(thread), "invariant"); + if (0 == exclusion_list->length()) { + delete exclusion_list; + exclusion_list = NULL; + } +} + +static void remove_thread_from_exclusion_list(jobject thread) { + ThreadExclusionListAccess lock; + remove_thread_from_exclusion_list(as_handle(thread)); +} + +// includes removal +static bool check_exclusion_state_on_thread_start(JavaThread* jt) { + Handle h_obj(jt, jt->threadObj()); + ThreadExclusionListAccess lock; + if (thread_is_not_excluded(h_obj)) { + return false; + } + remove_thread_from_exclusion_list(h_obj); + return true; +} + +jlong JfrJavaSupport::jfr_thread_id(jobject thread) { ThreadsListHandle tlh; JavaThread* native_thread = NULL; - (void)tlh.cv_internal_thread_to_JavaThread(target_thread, &native_thread, NULL); + (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL); 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); + if (native_thread != NULL) { + JfrThreadLocal::exclude(native_thread); + } else { + // not started yet, track the thread oop + add_thread_to_exclusion_list(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); + if (native_thread != NULL) { + JfrThreadLocal::include(native_thread); + } else { + // not started yet, untrack the thread oop + remove_thread_from_exclusion_list(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); + return native_thread != NULL ? native_thread->jfr_thread_local()->is_excluded() : is_thread_excluded(thread); +} + +void JfrJavaSupport::on_thread_start(Thread* t) { + assert(t != NULL, "invariant"); + assert(Thread::current() == t, "invariant"); + if (!t->is_Java_thread()) { + return; + } + DEBUG_ONLY(check_new_unstarted_java_thread(t);) + HandleMark hm; + if (check_exclusion_state_on_thread_start((JavaThread*)t)) { + JfrThreadLocal::exclude(t); + } +} diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/jni/jfrJavaSupport.hpp --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp Fri May 17 16:02:27 2019 +0200 @@ -29,18 +29,21 @@ #include "utilities/exceptions.hpp" class Klass; -class JavaThread; class outputStream; class JfrJavaSupport : public AllStatic { public: static jobject local_jni_handle(const oop obj, Thread* t); static jobject local_jni_handle(const jobject handle, Thread* t); - static void destroy_local_jni_handle(const jobject handle); + static void destroy_local_jni_handle(jobject handle); static jobject global_jni_handle(const oop obj, Thread* t); static jobject global_jni_handle(const jobject handle, Thread* t); - static void destroy_global_jni_handle(const jobject handle); + static void destroy_global_jni_handle(jobject handle); + + static jweak global_weak_jni_handle(const oop obj, Thread* t); + static jweak global_weak_jni_handle(const jobject handle, Thread* t); + static void destroy_global_weak_jni_handle(jweak handle); static oop resolve_non_null(jobject obj); static void notify_all(jobject obj, TRAPS); @@ -85,7 +88,11 @@ static bool is_jdk_jfr_module_available(); static bool is_jdk_jfr_module_available(outputStream* stream, TRAPS); - static jlong jfr_thread_id(jobject target_thread); + static jlong jfr_thread_id(jobject thread); + static void exclude(jobject thread); + static void include(jobject thread); + static bool is_excluded(jobject thread); + static void on_thread_start(Thread* t); // critical static void abort(jstring errorMsg, TRAPS); diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/jni/jfrJniMethod.cpp --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp Fri May 17 16:02:27 2019 +0200 @@ -284,6 +284,10 @@ return JfrJavaEventWriter::flush(writer, used_size, requested_size, thread); JVM_END +JVM_ENTRY_NO_ENV(void, jfr_flush(JNIEnv* env, jobject jvm, jboolean include_metadata, jshort flush_counter)) + JfrRepository::flush(include_metadata == JNI_TRUE, thread); +JVM_END + JVM_ENTRY_NO_ENV(void, jfr_set_repository_location(JNIEnv* env, jobject repo, jstring location)) return JfrRepository::set_path(location, thread); JVM_END @@ -311,3 +315,20 @@ JVM_ENTRY_NO_ENV(void, jfr_emit_old_object_samples(JNIEnv* env, jobject jvm, jlong cutoff_ticks, jboolean emit_all)) LeakProfiler::emit_events(cutoff_ticks, emit_all == JNI_TRUE); JVM_END + +JVM_ENTRY_NO_ENV(void, jfr_exclude_thread(JNIEnv* env, jobject jvm, jobject t)) + JfrJavaSupport::exclude(t); +JVM_END + +JVM_ENTRY_NO_ENV(void, jfr_include_thread(JNIEnv* env, jobject jvm, jobject t)) + JfrJavaSupport::include(t); +JVM_END + +JVM_ENTRY_NO_ENV(jboolean, jfr_is_thread_excluded(JNIEnv* env, jobject jvm, jobject t)) + return JfrJavaSupport::is_excluded(t); +JVM_END + +JVM_ENTRY_NO_ENV(jlong, jfr_chunk_start_nanos(JNIEnv* env, jobject jvm)) + return JfrRepository::current_chunk_start_nanos(); +JVM_END + diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/jni/jfrJniMethod.hpp --- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp Fri May 17 16:02:27 2019 +0200 @@ -113,6 +113,7 @@ jboolean JNICALL jfr_event_writer_flush(JNIEnv* env, jclass cls, jobject writer, jint used_size, jint requested_size); +void JNICALL jfr_flush(JNIEnv* env, jobject jvm, jboolean include_metadata, jshort flush_counter); void JNICALL jfr_abort(JNIEnv* env, jobject jvm, jstring errorMsg); jlong JNICALL jfr_get_epoch_address(JNIEnv* env, jobject jvm); @@ -131,6 +132,13 @@ jboolean JNICALL jfr_should_rotate_disk(JNIEnv* env, jobject jvm); +void JNICALL jfr_exclude_thread(JNIEnv* env, jobject jvm, jobject t); + +void JNICALL jfr_include_thread(JNIEnv* env, jobject jvm, jobject t); + +jboolean JNICALL jfr_is_thread_excluded(JNIEnv* env, jobject jvm, jobject t); + +jlong JNICALL jfr_chunk_start_nanos(JNIEnv* env, jobject jvm); #ifdef __cplusplus } diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp --- a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp Fri May 17 16:02:27 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -70,6 +70,7 @@ (char*)"getEventWriter", (char*)"()Ljava/lang/Object;", (void*)jfr_get_event_writer, (char*)"newEventWriter", (char*)"()Ljdk/jfr/internal/EventWriter;", (void*)jfr_new_event_writer, (char*)"flush", (char*)"(Ljdk/jfr/internal/EventWriter;II)Z", (void*)jfr_event_writer_flush, + (char*)"flush", (char*)"(ZS)V", (void*)jfr_flush, (char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location, (char*)"abort", (char*)"(Ljava/lang/String;)V", (void*)jfr_abort, (char*)"getEpochAddress", (char*)"()J",(void*)jfr_get_epoch_address, @@ -79,7 +80,11 @@ (char*)"getUnloadedEventClassCount", (char*)"()J", (void*)jfr_get_unloaded_event_classes_count, (char*)"setCutoff", (char*)"(JJ)Z", (void*)jfr_set_cutoff, (char*)"emitOldObjectSamples", (char*)"(JZ)V", (void*)jfr_emit_old_object_samples, - (char*)"shouldRotateDisk", (char*)"()Z", (void*)jfr_should_rotate_disk + (char*)"shouldRotateDisk", (char*)"()Z", (void*)jfr_should_rotate_disk, + (char*)"exclude", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_exclude_thread, + (char*)"include", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_include_thread, + (char*)"isExcluded", (char*)"(Ljava/lang/Thread;)Z", (void*)jfr_is_thread_excluded, + (char*)"getChunkStartNanos", (char*)"()J", (void*)jfr_chunk_start_nanos }; const size_t method_array_length = sizeof(method) / sizeof(JNINativeMethod); diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp Fri May 17 16:02:27 2019 +0200 @@ -230,8 +230,8 @@ assert(thread != NULL, "invariant"); static bool types_registered = false; if (!types_registered) { - JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType()); - JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType()); + JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, true, new RootSystemType()); + JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, true, new RootType()); types_registered = true; } const ObjectSampler* const object_sampler = LeakProfiler::object_sampler(); diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp Fri May 17 16:02:27 2019 +0200 @@ -29,6 +29,7 @@ #include "gc/shared/strongRootsScope.hpp" #include "jfr/leakprofiler/utilities/unifiedOop.hpp" #include "jfr/leakprofiler/checkpoint/rootResolver.hpp" +#include "jfr/utilities/jfrThreadIterator.hpp" #include "memory/iterator.hpp" #include "memory/universe.hpp" #include "oops/klass.hpp" @@ -37,7 +38,6 @@ #include "prims/jvmtiThreadState.hpp" #include "runtime/frame.inline.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/threadSMR.inline.hpp" #include "runtime/vframe_hp.hpp" #include "services/management.hpp" #include "utilities/growableArray.hpp" @@ -277,8 +277,9 @@ public: ReferenceToThreadRootClosure(RootCallback& callback) :_callback(callback), _complete(false) { assert_locked_or_safepoint(Threads_lock); - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { - if (do_thread_roots(jt)) { + JfrJavaThreadIterator iter; + while (iter.has_next()) { + if (do_thread_roots(iter.next())) { return; } } diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/metadata/jfrSerializer.hpp --- a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp Fri May 17 16:02:27 2019 +0200 @@ -70,8 +70,9 @@ class JfrSerializer : public CHeapObj { public: virtual ~JfrSerializer() {} - static bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer); - virtual void serialize(JfrCheckpointWriter& writer) = 0; + static bool register_serializer(JfrTypeId id, bool permit_cache, JfrSerializer* serializer); + virtual void serialize(JfrCheckpointWriter& writer) {} + virtual void on_rotation() {} }; /* diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/metadata/metadata.xml --- a/src/hotspot/share/jfr/metadata/metadata.xml Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/metadata/metadata.xml Fri May 17 16:02:27 2019 +0200 @@ -983,6 +983,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1168,6 +1204,7 @@ + diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp --- a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp Fri May 17 16:02:27 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -40,6 +40,7 @@ uint64_t bytes_in; uint64_t bytes_out; bool in_use; + bool written; }; static GrowableArray* _interfaces = NULL; @@ -72,6 +73,7 @@ entry.bytes_in = iface->get_bytes_in(); entry.bytes_out = iface->get_bytes_out(); entry.in_use = false; + entry.written = false; return _interfaces->at(_interfaces->append(entry)); } @@ -117,17 +119,17 @@ return ret_val != FUNCTIONALITY_NOT_IMPLEMENTED; } -class JfrNetworkInterfaceName : public JfrSerializer { - public: - void serialize(JfrCheckpointWriter& writer) { +static void write_interface_types(JfrCheckpointWriter& writer) { assert(_interfaces != NULL, "invariant"); + writer.write_type(TYPE_NETWORKINTERFACENAME); const JfrCheckpointContext ctx = writer.context(); const intptr_t count_offset = writer.reserve(sizeof(u4)); // Don't know how many yet int active_interfaces = 0; for (int i = 0; i < _interfaces->length(); ++i) { InterfaceEntry& entry = _interfaces->at(i); - if (entry.in_use) { + if (entry.in_use && !entry.written) { entry.in_use = false; + entry.written = true; writer.write_key(entry.id); writer.write(entry.name); ++active_interfaces; @@ -140,12 +142,19 @@ } writer.write_count(active_interfaces, count_offset); } +class JfrNetworkInterfaceName : public JfrSerializer { + public: + void on_rotation() { + for (int i = 0; i < _interfaces->length(); ++i) { + InterfaceEntry& entry = _interfaces->at(i); + entry.written = false; + } + } }; static bool register_network_interface_name_serializer() { assert(_interfaces != NULL, "invariant"); return JfrSerializer::register_serializer(TYPE_NETWORKINTERFACENAME, - false, // require safepoint false, // disallow caching; we want a callback every rotation new JfrNetworkInterfaceName()); } @@ -161,6 +170,7 @@ const JfrTicks cur_time = JfrTicks::now(); const JfrTickspan interval = last_sample_instant == 0 ? cur_time - cur_time : cur_time - last_sample_instant; last_sample_instant = cur_time; + bool write_type = false; for (NetworkInterface *cur = network_interfaces; cur != NULL; cur = cur->next()) { InterfaceEntry& entry = get_entry(cur); if (interval.value() > 0) { @@ -177,6 +187,9 @@ event.set_readRate(8 * read_rate); event.set_writeRate(8 * write_rate); event.commit(); + if (!entry.written) { + write_type = true; + } } // update existing entry with new values entry.bytes_in = current_bytes_in; @@ -184,6 +197,10 @@ } } + if (write_type) { + JfrCheckpointWriter writer(false, true, Thread::current()); + write_interface_types(writer); + } static bool is_serializer_registered = false; if (!is_serializer_registered) { is_serializer_registered = register_network_interface_name_serializer(); diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/periodic/jfrPeriodic.cpp --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp Fri May 17 16:02:27 2019 +0200 @@ -45,6 +45,7 @@ #include "jfr/periodic/jfrNetworkUtilization.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/support/jfrThreadId.hpp" +#include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfrfiles/jfrPeriodic.hpp" #include "logging/log.hpp" @@ -57,7 +58,6 @@ #include "runtime/os.hpp" #include "runtime/os_perf.hpp" #include "runtime/thread.inline.hpp" -#include "runtime/threadSMR.hpp" #include "runtime/sweeper.hpp" #include "runtime/vmThread.hpp" #include "services/classLoadingService.hpp" @@ -416,10 +416,13 @@ GrowableArray allocated(initial_size); GrowableArray thread_ids(initial_size); JfrTicks time_stamp = JfrTicks::now(); + { - // Collect allocation statistics while holding threads lock - MutexLocker ml(Threads_lock); - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { + JfrJavaThreadIterator iter; + while (iter.has_next()) { + JavaThread* const jt = iter.next(); + assert(jt != NULL, "invariant"); + allocated.append(jt->cooked_allocated_bytes()); thread_ids.append(JFR_THREAD_ID(jt)); } diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp --- a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp Fri May 17 16:02:27 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, 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 @@ -28,11 +28,10 @@ #include "jfr/periodic/jfrThreadCPULoadEvent.hpp" #include "jfr/support/jfrThreadId.hpp" #include "jfr/support/jfrThreadLocal.hpp" +#include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" #include "utilities/globalDefinitions.hpp" #include "runtime/os.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/threadSMR.inline.hpp" jlong JfrThreadCPULoadEvent::get_wallclock_time() { return os::javaTimeNanos(); @@ -115,8 +114,12 @@ JfrTicks event_time = JfrTicks::now(); jlong cur_wallclock_time = JfrThreadCPULoadEvent::get_wallclock_time(); - JavaThreadIteratorWithHandle jtiwh; - while (JavaThread* jt = jtiwh.next()) { + JfrJavaThreadIterator iter; + int number_of_threads = 0; + while (iter.has_next()) { + JavaThread* const jt = iter.next(); + assert(jt != NULL, "invariant"); + ++number_of_threads; EventThreadCPULoad event(UNTIMED); if (JfrThreadCPULoadEvent::update_event(event, jt, cur_wallclock_time, processor_count)) { event.set_starttime(event_time); @@ -129,7 +132,7 @@ event.commit(); } } - log_trace(jfr)("Measured CPU usage for %d threads in %.3f milliseconds", jtiwh.length(), + log_trace(jfr)("Measured CPU usage for %d threads in %.3f milliseconds", number_of_threads, (double)(JfrTicks::now() - event_time).milliseconds()); // Restore this thread's thread id periodic_thread_tl->set_thread_id(periodic_thread_id); diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Fri May 17 16:02:27 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -34,9 +34,13 @@ #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/utilities/jfrBigEndian.hpp" +#include "jfr/utilities/jfrIterator.hpp" +#include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jfr/writers/jfrJavaEventWriter.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" +#include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/orderAccess.hpp" #include "runtime/os.inline.hpp" @@ -136,6 +140,8 @@ void JfrCheckpointManager::register_full(BufferPtr t, Thread* thread) { // nothing here at the moment + assert(t != NULL, "invariant"); + assert(t->acquired_by(thread), "invariant"); assert(t->retired(), "invariant"); } @@ -271,15 +277,15 @@ static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) { assert(data != NULL, "invariant"); - const intptr_t previous_checkpoint_event = cw.previous_checkpoint_offset(); - const intptr_t event_begin = cw.current_offset(); - const intptr_t offset_to_previous_checkpoint_event = 0 == previous_checkpoint_event ? 0 : previous_checkpoint_event - event_begin; - const jlong total_checkpoint_size = total_size(data); - write_checkpoint_header(cw, offset_to_previous_checkpoint_event, data); + const int64_t last_checkpoint_event = cw.last_checkpoint_offset(); + const int64_t event_begin = cw.current_offset(); + const int64_t offset_to_last_checkpoint_event = 0 == last_checkpoint_event ? 0 : last_checkpoint_event - event_begin; + const int64_t total_checkpoint_size = total_size(data); + write_checkpoint_header(cw, offset_to_last_checkpoint_event, data); write_checkpoint_content(cw, data, total_checkpoint_size - sizeof(JfrCheckpointEntry)); - const jlong checkpoint_event_size = cw.current_offset() - event_begin; + const int64_t checkpoint_event_size = cw.current_offset() - event_begin; cw.write_padded_at_offset(checkpoint_event_size, event_begin); - cw.set_previous_checkpoint_offset(event_begin); + cw.set_last_checkpoint_offset(event_begin); return (size_t)total_checkpoint_size; } @@ -336,8 +342,36 @@ return processed; } +typedef StopOnEmptyIterator > EmptyIterator; + +template +static void process_transition_mspace(Processor& processor, JfrCheckpointMspace* mspace) { + assert(mspace->is_full_empty(), "invariant"); + process_free_list_iterator_control(processor, mspace, forward); +} + +size_t JfrCheckpointManager::flush() { + WriteOperation wo(_chunkwriter); + MutexedWriteOperation mwo(wo); + process_transition_mspace(mwo, _epoch_transition_mspace); + assert(_free_list_mspace->is_full_empty(), "invariant"); + process_free_list(mwo, _free_list_mspace); + return wo.processed(); +} + +size_t JfrCheckpointManager::write_constants() { + write_types(); + return flush(); +} + size_t JfrCheckpointManager::write_epoch_transition_mspace() { - return write_mspace_exclusive(_epoch_transition_mspace, _chunkwriter); + Thread* const thread = Thread::current(); + WriteOperation wo(_chunkwriter); + MutexedWriteOperation mwo(wo); + CheckpointReleaseOperation cro(_epoch_transition_mspace, thread, false); + CheckpointWriteOperation cpwo(&mwo, &cro); + process_transition_mspace(cpwo, _epoch_transition_mspace); + return wo.processed(); } typedef DiscardOp > DiscardOperation; @@ -346,20 +380,38 @@ process_free_list(discarder, _free_list_mspace); process_free_list(discarder, _epoch_transition_mspace); synchronize_epoch(); - return discarder.processed(); + return discarder.elements(); } size_t JfrCheckpointManager::write_types() { + ResourceMark rm; + HandleMark hm; JfrCheckpointWriter writer(false, true, Thread::current()); JfrTypeManager::write_types(writer); return writer.used_size(); } -size_t JfrCheckpointManager::write_safepoint_types() { - // this is also a "flushpoint" - JfrCheckpointWriter writer(true, true, Thread::current()); - JfrTypeManager::write_safepoint_types(writer); - return writer.used_size(); +class JfrNotifyClosure : public ThreadClosure { + public: + void do_thread(Thread* t) { + assert(t != NULL, "invariant"); + assert(t->is_Java_thread(), "invariant"); + assert_locked_or_safepoint(Threads_lock); + JfrJavaEventWriter::notify((JavaThread*)t); + } +}; + +void JfrCheckpointManager::notify_threads() { + assert(SafepointSynchronize::is_at_safepoint(), "invariant"); + JfrNotifyClosure tc; + JfrJavaThreadIterator iter; + while (iter.has_next()) { + tc.do_thread(iter.next()); + } +} + +void JfrCheckpointManager::notify_types_on_rotation() { + JfrTypeManager::notify_types_on_rotation(); } void JfrCheckpointManager::write_type_set() { @@ -371,10 +423,16 @@ JfrTypeManager::write_type_set_for_unloaded_classes(); } -void JfrCheckpointManager::create_thread_checkpoint(JavaThread* jt) { - JfrTypeManager::create_thread_checkpoint(jt); +size_t JfrCheckpointManager::flush_type_set() { + const size_t elements = JfrTypeManager::flush_type_set(); + flush(); + return elements; } -void JfrCheckpointManager::write_thread_checkpoint(JavaThread* jt) { - JfrTypeManager::write_thread_checkpoint(jt); +void JfrCheckpointManager::create_thread_checkpoint(Thread* t) { + JfrTypeManager::create_thread_checkpoint(t); } + +void JfrCheckpointManager::write_thread_checkpoint(Thread* t) { + JfrTypeManager::write_thread_checkpoint(t); +} diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp Fri May 17 16:02:27 2019 +0200 @@ -73,13 +73,17 @@ size_t clear(); size_t write(); + size_t write_constants(); + size_t flush(); size_t write_epoch_transition_mspace(); size_t write_types(); - size_t write_safepoint_types(); + size_t write_metadata_event(); void write_type_set(); void shift_epoch(); void synchronize_epoch(); bool use_epoch_transition_mspace(const Thread* t) const; + void notify_threads(); + void notify_types_on_rotation(); JfrCheckpointManager(JfrChunkWriter& cw); ~JfrCheckpointManager(); @@ -91,9 +95,10 @@ public: void register_service_thread(const Thread* t); + size_t flush_type_set(); static void write_type_set_for_unloaded_classes(); - static void create_thread_checkpoint(JavaThread* jt); - static void write_thread_checkpoint(JavaThread* jt); + static void create_thread_checkpoint(Thread* t); + static void write_thread_checkpoint(Thread* t); friend class JfrRecorder; friend class JfrRecorderService; diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp Fri May 17 16:02:27 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -156,6 +156,7 @@ this->seek(ctx.offset); set_count(ctx.count); } + bool JfrCheckpointWriter::has_data() const { return this->used_size() > sizeof(JfrCheckpointEntry); } diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp Fri May 17 16:02:27 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -29,19 +29,11 @@ #include "oops/klass.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" -#include "runtime/semaphore.hpp" #include "runtime/thread.inline.hpp" static jbyteArray _metadata_blob = NULL; -static Semaphore metadata_mutex_semaphore(1); - -void JfrMetadataEvent::lock() { - metadata_mutex_semaphore.wait(); -} - -void JfrMetadataEvent::unlock() { - metadata_mutex_semaphore.signal(); -} +static u8 metadata_id = 0; +static u8 last_written_metadata_id = 0; static void write_metadata_blob(JfrChunkWriter& chunkwriter, jbyteArray metadata_blob) { if (metadata_blob != NULL) { @@ -56,34 +48,38 @@ } } -// the semaphore is assumed to be locked (was locked previous safepoint) -size_t JfrMetadataEvent::write(JfrChunkWriter& chunkwriter, jlong metadata_offset) { +void JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) { assert(chunkwriter.is_valid(), "invariant"); + const jlong metadata_offset = chunkwriter.current_offset(); assert(chunkwriter.current_offset() == metadata_offset, "invariant"); + + if (last_written_metadata_id == metadata_id && chunkwriter.has_metadata()) { + return; + } + // header chunkwriter.reserve(sizeof(u4)); chunkwriter.write(EVENT_METADATA); // ID 0 // time data chunkwriter.write(JfrTicks::now()); chunkwriter.write((u8)0); // duration - chunkwriter.write((u8)0); // metadata id + chunkwriter.write(metadata_id); // metadata id write_metadata_blob(chunkwriter, _metadata_blob); // payload - unlock(); // open up for java to provide updated metadata + last_written_metadata_id = metadata_id; // fill in size of metadata descriptor event const jlong size_written = chunkwriter.current_offset() - metadata_offset; chunkwriter.write_padded_at_offset((u4)size_written, metadata_offset); - return size_written; + chunkwriter.set_last_metadata_offset(metadata_offset); } void JfrMetadataEvent::update(jbyteArray metadata) { JavaThread* thread = (JavaThread*)Thread::current(); assert(thread->is_Java_thread(), "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread)); - lock(); if (_metadata_blob != NULL) { JfrJavaSupport::destroy_global_jni_handle(_metadata_blob); } const oop new_desc_oop = JfrJavaSupport::resolve_non_null(metadata); _metadata_blob = new_desc_oop != NULL ? (jbyteArray)JfrJavaSupport::global_jni_handle(new_desc_oop, thread) : NULL; - unlock(); + ++metadata_id; } diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp Fri May 17 16:02:27 2019 +0200 @@ -37,9 +37,7 @@ // class JfrMetadataEvent : AllStatic { public: - static void lock(); - static void unlock(); - static size_t write(JfrChunkWriter& writer, jlong metadata_offset); + static void write(JfrChunkWriter& writer); static void update(jbyteArray metadata); }; diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadGroup.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadGroup.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadGroup.cpp Fri May 17 16:02:27 2019 +0200 @@ -25,7 +25,6 @@ #include "precompiled.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfr/recorder/checkpoint/types/jfrThreadGroup.hpp" -#include "jfr/utilities/jfrResourceManager.hpp" #include "jfr/utilities/jfrTypes.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.inline.hpp" @@ -33,6 +32,8 @@ #include "runtime/semaphore.hpp" #include "utilities/growableArray.hpp" +static const int initial_array_size = 30; + class ThreadGroupExclusiveAccess : public StackObj { private: static Semaphore _mutex_semaphore; @@ -257,12 +258,10 @@ } } -JfrThreadGroup::JfrThreadGroup() : _list(NULL) { - _list = new (ResourceObj::C_HEAP, mtTracing) GrowableArray(30, true); -} +JfrThreadGroup::JfrThreadGroup() : + _list(new (ResourceObj::C_HEAP, mtTracing) GrowableArray(initial_array_size, true, mtTracing)) {} JfrThreadGroup::~JfrThreadGroup() { - assert(SafepointSynchronize::is_at_safepoint(), "invariant"); if (_list != NULL) { for (int i = 0; i < _list->length(); i++) { JfrThreadGroupEntry* e = _list->at(i); @@ -281,14 +280,11 @@ } traceid JfrThreadGroup::thread_group_id(const JavaThread* jt, Thread* current) { - ResourceMark rm(current); - HandleMark hm(current); JfrThreadGroupsHelper helper(jt, current); return helper.is_valid() ? thread_group_id_internal(helper) : 0; } traceid JfrThreadGroup::thread_group_id(JavaThread* const jt) { - assert(!JfrStream_lock->owned_by_self(), "holding stream lock but should not hold it here"); return thread_group_id(jt, jt); } @@ -396,9 +392,7 @@ ThreadGroupExclusiveAccess lock; JfrThreadGroup* tg_instance = instance(); assert(tg_instance != NULL, "invariant"); - ResourceManager tg_handle(tg_instance); - set_instance(NULL); - tg_handle->write_thread_group_entries(writer); + tg_instance->write_thread_group_entries(writer); } // for writing a particular thread group diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp Fri May 17 16:02:27 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -39,7 +39,7 @@ #include "jfr/recorder/checkpoint/types/jfrThreadState.hpp" #include "jfr/recorder/checkpoint/types/jfrTypeSet.hpp" #include "jfr/support/jfrThreadLocal.hpp" -#include "jfr/writers/jfrJavaEventWriter.hpp" +#include "jfr/utilities/jfrThreadIterator.hpp" #include "memory/metaspaceGCThresholdUpdater.hpp" #include "memory/referenceType.hpp" #include "memory/universe.hpp" @@ -93,12 +93,10 @@ // Requires a ResourceMark for get_thread_name/as_utf8 void JfrCheckpointThreadClosure::do_thread(Thread* t) { assert(t != NULL, "invariant"); - assert_locked_or_safepoint(Threads_lock); const JfrThreadLocal* const tl = t->jfr_thread_local(); assert(tl != NULL, "invariant"); - if (tl->is_dead()) { - return; - } + assert(!tl->is_dead(), "invariant"); + assert(!tl->is_excluded(), "invariant"); ++_count; _writer.write_key(tl->thread_id()); _writer.write(t->name()); @@ -110,7 +108,6 @@ _writer.write(java_lang_Thread::thread_id(jt->threadObj())); _writer.write(JfrThreadGroup::thread_group_id(jt, _curthread)); // since we are iterating threads during a safepoint, also issue notification - JfrJavaEventWriter::notify(jt); return; } _writer.write((const char*)NULL); // java name @@ -119,13 +116,18 @@ } void JfrThreadConstantSet::serialize(JfrCheckpointWriter& writer) { - assert(SafepointSynchronize::is_at_safepoint(), "invariant"); JfrCheckpointThreadClosure tc(writer); - Threads::threads_do(&tc); + JfrJavaThreadIterator javathreads; + while (javathreads.has_next()) { + tc.do_thread(javathreads.next()); + } + JfrNonJavaThreadIterator nonjavathreads; + while (nonjavathreads.has_next()) { + tc.do_thread(nonjavathreads.next()); + } } void JfrThreadGroupConstant::serialize(JfrCheckpointWriter& writer) { - assert(SafepointSynchronize::is_at_safepoint(), "invariant"); JfrThreadGroup::serialize(writer); } @@ -298,16 +300,23 @@ class TypeSetSerialization { private: + size_t _elements; bool _class_unload; + bool _flushpoint; public: - explicit TypeSetSerialization(bool class_unload) : _class_unload(class_unload) {} + explicit TypeSetSerialization(bool class_unload, bool flushpoint) : _elements(0), _class_unload(class_unload), _flushpoint(flushpoint) {} void write(JfrCheckpointWriter& writer, JfrCheckpointWriter* leakp_writer) { - JfrTypeSet::serialize(&writer, leakp_writer, _class_unload); + MutexLocker cld_lock(SafepointSynchronize::is_at_safepoint() ? NULL : ClassLoaderDataGraph_lock); + MutexLocker lock(SafepointSynchronize::is_at_safepoint() ? NULL : Module_lock); + _elements = JfrTypeSet::serialize(&writer, leakp_writer, _class_unload, _flushpoint); + } + size_t elements() const { + return _elements; } }; void ClassUnloadTypeSet::serialize(JfrCheckpointWriter& writer) { - TypeSetSerialization type_set(true); + TypeSetSerialization type_set(true, false); if (LeakProfiler::is_running()) { JfrCheckpointWriter leakp_writer(false, true, Thread::current()); type_set.write(writer, &leakp_writer); @@ -317,8 +326,19 @@ type_set.write(writer, NULL); }; +void FlushTypeSet::serialize(JfrCheckpointWriter& writer) { + assert(!SafepointSynchronize::is_at_safepoint(), "invariant"); + TypeSetSerialization type_set(false, true); + type_set.write(writer, NULL); + _elements = type_set.elements(); +} + +size_t FlushTypeSet::elements() const { + return _elements; +} + void TypeSet::serialize(JfrCheckpointWriter& writer) { - TypeSetSerialization type_set(false); + TypeSetSerialization type_set(false, false); if (LeakProfiler::is_suspended()) { JfrCheckpointWriter leakp_writer(false, true, Thread::current()); type_set.write(writer, &leakp_writer); @@ -335,20 +355,23 @@ void JfrThreadConstant::serialize(JfrCheckpointWriter& writer) { assert(_thread != NULL, "invariant"); assert(_thread == Thread::current(), "invariant"); - assert(_thread->is_Java_thread(), "invariant"); - assert(!_thread->jfr_thread_local()->has_thread_checkpoint(), "invariant"); ResourceMark rm(_thread); - const oop threadObj = _thread->threadObj(); - assert(threadObj != NULL, "invariant"); - const u8 java_lang_thread_id = java_lang_Thread::thread_id(threadObj); + HandleMark hm(_thread); const char* const thread_name = _thread->name(); - const traceid thread_group_id = JfrThreadGroup::thread_group_id(_thread); writer.write_count(1); writer.write_key(_thread->jfr_thread_local()->thread_id()); writer.write(thread_name); writer.write((traceid)_thread->osthread()->thread_id()); - writer.write(thread_name); - writer.write(java_lang_thread_id); - writer.write(thread_group_id); - JfrThreadGroup::serialize(&writer, thread_group_id); + if (_thread->is_Java_thread()) { + JavaThread* const jt = (JavaThread*)_thread; + writer.write(jt->name()); + writer.write(java_lang_Thread::thread_id(jt->threadObj())); + const traceid thread_group_id = JfrThreadGroup::thread_group_id(jt, jt); + writer.write(thread_group_id); + JfrThreadGroup::serialize(&writer, thread_group_id); + return; + } + writer.write((const char*)NULL); // java name + writer.write((traceid)0); // java thread id + writer.write((traceid)0); // java thread group } diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp Fri May 17 16:02:27 2019 +0200 @@ -42,6 +42,12 @@ void serialize(JfrCheckpointWriter& writer); }; +class FlushTypeSet : public JfrSerializer { + size_t _elements; + public: + void serialize(JfrCheckpointWriter& writer); + size_t elements() const; +}; class FlagValueOriginConstant : public JfrSerializer { public: void serialize(JfrCheckpointWriter& writer); @@ -129,9 +135,9 @@ class JfrThreadConstant : public JfrSerializer { private: - JavaThread* _thread; + Thread* _thread; public: - JfrThreadConstant(JavaThread* jt) : _thread(jt) {} + JfrThreadConstant(Thread* t) : _thread(t) {} void serialize(JfrCheckpointWriter& writer); }; diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp Fri May 17 16:02:27 2019 +0200 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "jfr/jfr.hpp" #include "jfr/metadata/jfrSerializer.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfr/recorder/checkpoint/types/jfrType.hpp" @@ -72,6 +73,8 @@ } void invoke(JfrCheckpointWriter& writer) const; + + void on_rotation() const; }; void JfrSerializerRegistration::invoke(JfrCheckpointWriter& writer) const { @@ -96,6 +99,10 @@ } } +void JfrSerializerRegistration::on_rotation() const { + _serializer->on_rotation(); +} + class SerializerRegistrationGuard : public StackObj { private: static Semaphore _mutex_semaphore; @@ -113,7 +120,6 @@ typedef JfrDoublyLinkedList List; typedef StopOnNullIterator Iterator; static List types; -static List safepoint_types; void JfrTypeManager::clear() { SerializerRegistrationGuard guard; @@ -124,12 +130,6 @@ assert(registration != NULL, "invariant"); delete registration; } - Iterator sp_type_iter(safepoint_types); - while (sp_type_iter.has_next()) { - registration = safepoint_types.remove(sp_type_iter.next()); - assert(registration != NULL, "invariant"); - delete registration; - } } void JfrTypeManager::write_types(JfrCheckpointWriter& writer) { @@ -139,54 +139,53 @@ } } -void JfrTypeManager::write_safepoint_types(JfrCheckpointWriter& writer) { - assert(SafepointSynchronize::is_at_safepoint(), "invariant"); - const Iterator iter(safepoint_types); +void JfrTypeManager::notify_types_on_rotation() { + const Iterator iter(types); while (iter.has_next()) { - iter.next()->invoke(writer); + iter.next()->on_rotation(); } } void JfrTypeManager::write_type_set() { // can safepoint here because of Module_lock - MutexLocker cld_lock(SafepointSynchronize::is_at_safepoint() ? NULL : ClassLoaderDataGraph_lock); - MutexLocker lock(SafepointSynchronize::is_at_safepoint() ? NULL : Module_lock); - + assert(!SafepointSynchronize::is_at_safepoint(), "invariant"); JfrCheckpointWriter writer(true, true, Thread::current()); TypeSet set; set.serialize(writer); } void JfrTypeManager::write_type_set_for_unloaded_classes() { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + assert(SafepointSynchronize::is_at_safepoint(), "invariant"); JfrCheckpointWriter writer(false, true, Thread::current()); ClassUnloadTypeSet class_unload_set; class_unload_set.serialize(writer); } -void JfrTypeManager::create_thread_checkpoint(JavaThread* jt) { - assert(jt != NULL, "invariant"); - JfrThreadConstant type_thread(jt); - JfrCheckpointWriter writer(false, true, jt); +size_t JfrTypeManager::flush_type_set() { + assert(!SafepointSynchronize::is_at_safepoint(), "invariant"); + JfrCheckpointWriter writer(true, true, Thread::current()); + FlushTypeSet flush; + flush.serialize(writer); + return flush.elements(); +} + +void JfrTypeManager::create_thread_checkpoint(Thread* t) { + assert(t != NULL, "invariant"); + JfrThreadConstant type_thread(t); + JfrCheckpointWriter writer(false, true, t); writer.write_type(TYPE_THREAD); type_thread.serialize(writer); // create and install a checkpoint blob - jt->jfr_thread_local()->set_thread_checkpoint(writer.checkpoint_blob()); - assert(jt->jfr_thread_local()->has_thread_checkpoint(), "invariant"); + t->jfr_thread_local()->set_thread_checkpoint(writer.checkpoint_blob()); + assert(t->jfr_thread_local()->has_thread_checkpoint(), "invariant"); } -void JfrTypeManager::write_thread_checkpoint(JavaThread* jt) { - assert(jt != NULL, "JavaThread is NULL!"); - ResourceMark rm(jt); - if (jt->jfr_thread_local()->has_thread_checkpoint()) { - JfrCheckpointWriter writer(false, false, jt); - jt->jfr_thread_local()->thread_checkpoint()->write(writer); - } else { - JfrThreadConstant type_thread(jt); - JfrCheckpointWriter writer(false, true, jt); - writer.write_type(TYPE_THREAD); - type_thread.serialize(writer); - } +void JfrTypeManager::write_thread_checkpoint(Thread* t) { + assert(t != NULL, "invariant"); + JfrThreadConstant type_thread(t); + JfrCheckpointWriter writer(false, true, t); + writer.write_type(TYPE_THREAD); + type_thread.serialize(writer); } #ifdef ASSERT @@ -198,22 +197,21 @@ } #endif -static bool register_type(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer) { +static bool register_type(JfrTypeId id, bool permit_cache, JfrSerializer* serializer) { assert(serializer != NULL, "invariant"); JfrSerializerRegistration* const registration = new JfrSerializerRegistration(id, permit_cache, serializer); if (registration == NULL) { delete serializer; return false; } - if (require_safepoint) { - assert(!safepoint_types.in_list(registration), "invariant"); - DEBUG_ONLY(assert_not_registered_twice(id, safepoint_types);) - safepoint_types.prepend(registration); - } else { - assert(!types.in_list(registration), "invariant"); - DEBUG_ONLY(assert_not_registered_twice(id, types);) - types.prepend(registration); + + assert(!types.in_list(registration), "invariant"); + DEBUG_ONLY(assert_not_registered_twice(id, types);) + if (Jfr::is_recording()) { + JfrCheckpointWriter writer(false, true, Thread::current()); + registration->invoke(writer); } + types.prepend(registration); return true; } @@ -221,31 +219,30 @@ SerializerRegistrationGuard guard; // register non-safepointing type serialization - register_type(TYPE_FLAGVALUEORIGIN, false, true, new FlagValueOriginConstant()); - register_type(TYPE_INFLATECAUSE, false, true, new MonitorInflateCauseConstant()); - register_type(TYPE_GCCAUSE, false, true, new GCCauseConstant()); - register_type(TYPE_GCNAME, false, true, new GCNameConstant()); - register_type(TYPE_GCWHEN, false, true, new GCWhenConstant()); - register_type(TYPE_G1HEAPREGIONTYPE, false, true, new G1HeapRegionTypeConstant()); - register_type(TYPE_GCTHRESHOLDUPDATER, false, true, new GCThresholdUpdaterConstant()); - register_type(TYPE_METADATATYPE, false, true, new MetadataTypeConstant()); - register_type(TYPE_METASPACEOBJECTTYPE, false, true, new MetaspaceObjectTypeConstant()); - register_type(TYPE_G1YCTYPE, false, true, new G1YCTypeConstant()); - register_type(TYPE_REFERENCETYPE, false, true, new ReferenceTypeConstant()); - register_type(TYPE_NARROWOOPMODE, false, true, new NarrowOopModeConstant()); - register_type(TYPE_COMPILERPHASETYPE, false, true, new CompilerPhaseTypeConstant()); - register_type(TYPE_CODEBLOBTYPE, false, true, new CodeBlobTypeConstant()); - register_type(TYPE_VMOPERATIONTYPE, false, true, new VMOperationTypeConstant()); - register_type(TYPE_THREADSTATE, false, true, new ThreadStateConstant()); + register_type(TYPE_THREADGROUP, false, new JfrThreadGroupConstant()); + register_type(TYPE_THREAD, false, new JfrThreadConstantSet()); + register_type(TYPE_FLAGVALUEORIGIN, true, new FlagValueOriginConstant()); + register_type(TYPE_INFLATECAUSE, true, new MonitorInflateCauseConstant()); + register_type(TYPE_GCCAUSE, true, new GCCauseConstant()); + register_type(TYPE_GCNAME, true, new GCNameConstant()); + register_type(TYPE_GCWHEN, true, new GCWhenConstant()); + register_type(TYPE_G1HEAPREGIONTYPE, true, new G1HeapRegionTypeConstant()); + register_type(TYPE_GCTHRESHOLDUPDATER, true, new GCThresholdUpdaterConstant()); + register_type(TYPE_METADATATYPE, true, new MetadataTypeConstant()); + register_type(TYPE_METASPACEOBJECTTYPE, true, new MetaspaceObjectTypeConstant()); + register_type(TYPE_G1YCTYPE, true, new G1YCTypeConstant()); + register_type(TYPE_REFERENCETYPE, true, new ReferenceTypeConstant()); + register_type(TYPE_NARROWOOPMODE, true, new NarrowOopModeConstant()); + register_type(TYPE_COMPILERPHASETYPE, true, new CompilerPhaseTypeConstant()); + register_type(TYPE_CODEBLOBTYPE, true, new CodeBlobTypeConstant()); + register_type(TYPE_VMOPERATIONTYPE, true, new VMOperationTypeConstant()); + register_type(TYPE_THREADSTATE, true, new ThreadStateConstant()); - // register safepointing type serialization - register_type(TYPE_THREADGROUP, true, false, new JfrThreadGroupConstant()); - register_type(TYPE_THREAD, true, false, new JfrThreadConstantSet()); return true; } // implementation for the static registration function exposed in the JfrSerializer api -bool JfrSerializer::register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer) { +bool JfrSerializer::register_serializer(JfrTypeId id, bool permit_cache, JfrSerializer* serializer) { SerializerRegistrationGuard guard; - return register_type(id, require_safepoint, permit_cache, serializer); + return register_type(id, permit_cache, serializer); } diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp Fri May 17 16:02:27 2019 +0200 @@ -34,11 +34,12 @@ static bool initialize(); static void clear(); static void write_types(JfrCheckpointWriter& writer); - static void write_safepoint_types(JfrCheckpointWriter& writer); + static void notify_types_on_rotation(); static void write_type_set(); static void write_type_set_for_unloaded_classes(); - static void create_thread_checkpoint(JavaThread* jt); - static void write_thread_checkpoint(JavaThread* jt); + static size_t flush_type_set(); + static void create_thread_checkpoint(Thread* t); + static void write_thread_checkpoint(Thread* t); }; #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPEMANAGER_HPP diff -r 4cab5edc2950 -r 5d043a159d5c src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp Fri May 17 15:53:21 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp Fri May 17 16:02:27 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -80,35 +80,35 @@ return cld->is_unsafe_anonymous() ? 0 : TRACE_ID(cld); } -static void tag_leakp_klass_artifacts(KlassPtr k, bool class_unload) { +static void tag_leakp_klass_artifacts(KlassPtr k, bool current_epoch) { assert(k != NULL, "invariant"); PkgPtr pkg = k->package(); if (pkg != NULL) { - tag_leakp_artifact(pkg, class_unload); + tag_leakp_artifact(pkg, current_epoch); ModPtr module = pkg->module(); if (module != NULL) { - tag_leakp_artifact(module, class_unload); + tag_leakp_artifact(module, current_epoch); } } CldPtr cld = k->class_loader_data(); assert(cld != NULL, "invariant"); if (!cld->is_unsafe_anonymous()) { - tag_leakp_artifact(cld, class_unload); + tag_leakp_artifact(cld, current_epoch); } } class TagLeakpKlassArtifact { - bool _class_unload; + bool _current_epoch; public: - TagLeakpKlassArtifact(bool class_unload) : _class_unload(class_unload) {} + TagLeakpKlassArtifact(bool current_epoch) : _current_epoch(current_epoch) {} bool operator()(KlassPtr klass) { - if (_class_unload) { + if (_current_epoch) { if (LEAKP_USED_THIS_EPOCH(klass)) { - tag_leakp_klass_artifacts(klass, _class_unload); + tag_leakp_klass_artifacts(klass, _current_epoch); } } else { if (LEAKP_USED_PREV_EPOCH(klass)) { - tag_leakp_klass_artifacts(klass, _class_unload); + tag_leakp_klass_artifacts(klass, _current_epoch); } } return true; @@ -123,11 +123,10 @@ * The weird naming is an effort to decrease the risk of name clashes. */ -int write__artifact__klass(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) { +int write__artifact__klass(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, KlassPtr klass) { assert(writer != NULL, "invariant"); assert(artifacts != NULL, "invariant"); - assert(k != NULL, "invariant"); - KlassPtr klass = (KlassPtr)k; + assert(klass != NULL, "invariant"); traceid pkg_id = 0; KlassPtr theklass = klass; if (theklass->is_objArray_klass()) { @@ -149,17 +148,33 @@ return 1; } +int write__artifact__klass__leakp(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) { + assert(k != NULL, "invariant"); + KlassPtr klass = (KlassPtr)k; + return write__artifact__klass(writer, artifacts, klass); +} + +int write__artifact__klass__serialize(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) { + assert(k != NULL, "invariant"); + KlassPtr klass = (KlassPtr)k; + int result = write__artifact__klass(writer, artifacts, klass); + if (IS_NOT_SERIALIZED(klass)) { + SET_SERIALIZED(klass); + } + assert(IS_SERIALIZED(klass), "invariant"); + return result; +} + typedef LeakPredicate LeakKlassPredicate; -typedef JfrPredicatedArtifactWriterImplHost LeakKlassWriterImpl; +typedef SerializePredicate KlassPredicate; +typedef JfrPredicatedArtifactWriterImplHost LeakKlassWriterImpl; typedef JfrArtifactWriterHost LeakKlassWriter; -typedef JfrArtifactWriterImplHost KlassWriterImpl; +typedef JfrPredicatedArtifactWriterImplHost KlassWriterImpl; typedef JfrArtifactWriterHost KlassWriter; -int write__artifact__method(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) { +int write__artifact__method(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, MethodPtr method) { assert(writer != NULL, "invariant"); assert(artifacts != NULL, "invariant"); - assert(m != NULL, "invariant"); - MethodPtr method = (MethodPtr)m; const traceid method_name_symbol_id = artifacts->mark(method->name()); assert(method_name_symbol_id > 0, "invariant"); const traceid method_sig_symbol_id = artifacts->mark(method->signature()); @@ -176,14 +191,33 @@ return 1; } -typedef JfrArtifactWriterImplHost MethodWriterImplTarget; +int write__artifact__method__leakp(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) { + assert(m != NULL, "invariant"); + MethodPtr method = (MethodPtr)m; + return write__artifact__method(writer, artifacts, method); +} + +int write__artifact__method__serialize(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) { + assert(m != NULL, "invariant"); + MethodPtr method = (MethodPtr)m; + int result = write__artifact__method(writer, artifacts, method); + if (METHOD_NOT_SERIALIZED(method)) { + SET_METHOD_SERIALIZED(method); + } + assert(IS_METHOD_SERIALIZED(method), "invariant"); + return result; +} + +typedef JfrArtifactWriterImplHost LeakpMethodWriterImplTarget; +typedef JfrArtifactWriterHost LeakpMethodWriterImpl; +typedef SerializePredicate MethodPredicate; +typedef JfrPredicatedArtifactWriterImplHost MethodWriterImplTarget; typedef JfrArtifactWriterHost MethodWriterImpl; -int write__artifact__package(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) { +int write__artifact__package(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, PkgPtr pkg) { assert(writer != NULL, "invariant"); assert(artifacts != NULL, "invariant"); - assert(p != NULL, "invariant"); - PkgPtr pkg = (PkgPtr)p; + assert(pkg != NULL, "invariant"); Symbol* const pkg_name = pkg->name(); const traceid package_name_symbol_id = pkg_name != NULL ? artifacts->mark(pkg_name) : 0; assert(package_name_symbol_id > 0, "invariant"); @@ -194,17 +228,34 @@ return 1; } +int write__artifact__package__leakp(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) { + assert(p != NULL, "invariant"); + PkgPtr pkg = (PkgPtr)p; + return write__artifact__package(writer, artifacts, pkg); +} + +int write__artifact__package__serialize(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) { + assert(p != NULL, "invariant"); + PkgPtr pkg = (PkgPtr)p; + int result = write__artifact__package(writer, artifacts, pkg); + if (IS_NOT_SERIALIZED(pkg)) { + SET_SERIALIZED(pkg); + } + assert(IS_SERIALIZED(pkg), "invariant"); + return result; +} + typedef LeakPredicate LeakPackagePredicate; -int _compare_pkg_ptr_(PkgPtr const& lhs, PkgPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; } -typedef UniquePredicate PackagePredicate; -typedef JfrPredicatedArtifactWriterImplHost LeakPackageWriterImpl; -typedef JfrPredicatedArtifactWriterImplHost PackageWriterImpl; +//int _compare_pkg_ptr_(PkgPtr const& lhs, PkgPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; } +//typedef UniquePredicate PackagePredicate; +typedef SerializePredicate PackagePredicate; +typedef JfrPredicatedArtifactWriterImplHost LeakPackageWriterImpl; +typedef JfrPredicatedArtifactWriterImplHost PackageWriterImpl; typedef JfrArtifactWriterHost LeakPackageWriter; typedef JfrArtifactWriterHost PackageWriter; -int write__artifact__module(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) { - assert( m != NULL, "invariant"); - ModPtr entry = (ModPtr)m; +int write__artifact__module(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, ModPtr entry) { + assert(entry != NULL, "invariant"); Symbol* const module_name = entry->name(); const traceid module_name_symbol_id = module_name != NULL ? artifacts->mark(module_name) : 0; Symbol* const module_version = entry->version(); @@ -219,17 +270,41 @@ return 1; } +int write__artifact__module__leakp(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) { + assert(m != NULL, "invariant"); + ModPtr entry = (ModPtr)m; + return write__artifact__module(writer, artifacts, entry); +} + +int write__artifact__module__serialize(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) { + assert(m != NULL, "invariant"); + ModPtr entry = (ModPtr)m; + int result = write__artifact__module(writer, artifacts, entry); + CldPtr cld = entry->loader_data(); + assert(cld != NULL, "invariant"); + if (IS_NOT_SERIALIZED(cld)) { + if (!cld->is_unsafe_anonymous()) { + SET_USED_PREV_EPOCH(cld); + } + } + if (IS_NOT_SERIALIZED(entry)) { + SET_SERIALIZED(entry); + } + assert(IS_SERIALIZED(entry), "invariant"); + return result; +} + typedef LeakPredicate LeakModulePredicate; -int _compare_mod_ptr_(ModPtr const& lhs, ModPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; } -typedef UniquePredicate ModulePredicate; -typedef JfrPredicatedArtifactWriterImplHost LeakModuleWriterImpl; -typedef JfrPredicatedArtifactWriterImplHost ModuleWriterImpl; +//int _compare_mod_ptr_(ModPtr const& lhs, ModPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; } +//typedef UniquePredicate ModulePredicate; +typedef SerializePredicate ModulePredicate; +typedef JfrPredicatedArtifactWriterImplHost LeakModuleWriterImpl; +typedef JfrPredicatedArtifactWriterImplHost ModuleWriterImpl; typedef JfrArtifactWriterHost LeakModuleWriter; typedef JfrArtifactWriterHost ModuleWriter; -int write__artifact__classloader(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) { - assert(c != NULL, "invariant"); - CldPtr cld = (CldPtr)c; +int write__artifact__classloader(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, CldPtr cld) { + assert(cld != NULL, "invariant"); assert(!cld->is_unsafe_anonymous(), "invariant"); const traceid cld_id = TRACE_ID(cld); // class loader type @@ -250,18 +325,40 @@ return 1; } -typedef LeakPredicate LeakCldPredicate; -int _compare_cld_ptr_(CldPtr const& lhs, CldPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; } -typedef UniquePredicate CldPredicate; -typedef JfrPredicatedArtifactWriterImplHost LeakCldWriterImpl; -typedef JfrPredicatedArtifactWriterImplHost CldWriterImpl; +int write__artifact__classloader__leakp(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) { + assert(c != NULL, "invariant"); + CldPtr cld = (CldPtr)c; + int result = write__artifact__classloader(writer, artifacts, cld); + if (IS_NOT_LEAKP_SERIALIZED(cld)) { + SET_LEAKP_SERIALIZED(cld); + } + assert(IS_LEAKP_SERIALIZED(cld), "invariant"); + return result; +} + +int write__artifact__classloader__serialize(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) { + assert(c != NULL, "invariant"); + CldPtr cld = (CldPtr)c; + int result = write__artifact__classloader(writer, artifacts, cld); + if (IS_NOT_SERIALIZED(cld)) { + SET_SERIALIZED(cld); + } + assert(IS_SERIALIZED(cld), "invariant"); + return result; +} + +typedef LeakSerializePredicate LeakCldPredicate; +//int _compare_cld_ptr_(CldPtr const& lhs, CldPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; } +//typedef UniquePredicate CldPredicate; +typedef SerializePredicate CldPredicate; +typedef JfrPredicatedArtifactWriterImplHost LeakCldWriterImpl; +typedef JfrPredicatedArtifactWriterImplHost CldWriterImpl; typedef JfrArtifactWriterHost LeakCldWriter; typedef JfrArtifactWriterHost CldWriter; typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr; -static int write__artifact__symbol__entry__(JfrCheckpointWriter* writer, - SymbolEntryPtr entry) { +static int write__artifact__symbol__entry__(JfrCheckpointWriter* writer, SymbolEntryPtr entry) { assert(writer != NULL, "invariant"); assert(entry != NULL, "invariant"); ResourceMark rm; @@ -336,12 +433,12 @@ typedef KlassPtr Type; KlassSymbolWriterImpl(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, - bool class_unload) : _writer(writer), + bool current_epoch) : _writer(writer), _artifacts(artifacts), - _predicate(class_unload), - _method_used_predicate(class_unload), - _method_flag_predicate(class_unload), - _unique_predicate(class_unload) {} + _predicate(current_epoch), + _method_used_predicate(current_epoch), + _method_flag_predicate(current_epoch), + _unique_predicate(current_epoch) {} int operator()(KlassPtr klass) { assert(klass != NULL, "invariant"); @@ -392,8 +489,7 @@ assert(pkg_name != NULL, "invariant"); SymbolEntryPtr package_symbol = this->_artifacts->map_symbol(pkg_name); assert(package_symbol != NULL, "invariant"); - return _unique_predicate(package_symbol->id()) ? - write__artifact__symbol__entry__(this->_writer, package_symbol) : 0; + return _unique_predicate(package_symbol->id()) ? write__artifact__symbol__entry__(this->_writer, package_symbol) : 0; } template