# HG changeset patch # User mgronlun # Date 1572461032 -3600 # Node ID c16ac7a2eba4e73cb4f7ee9294dd647860eebff0 # Parent 2c3cc4b018809697439cf420e87c34c733105247 8226511: Implement JFR Event Streaming Reviewed-by: egahlin, mseledtsov, mgronlun Contributed-by: erik.gahlin@oracle.com, mikhailo.seledtsov@oracle.com, markus.gronlund@oracle.com diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/gc/g1/g1Trace.cpp --- a/src/hotspot/share/gc/g1/g1Trace.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/gc/g1/g1Trace.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -59,10 +59,10 @@ }; static void register_jfr_type_constants() { - JfrSerializer::register_serializer(TYPE_G1HEAPREGIONTYPE, false, true, + JfrSerializer::register_serializer(TYPE_G1HEAPREGIONTYPE, true, new G1HeapRegionTypeConstant()); - JfrSerializer::register_serializer(TYPE_G1YCTYPE, false, true, + JfrSerializer::register_serializer(TYPE_G1YCTYPE, true, new G1YCTypeConstant()); } diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -47,7 +47,6 @@ void ShenandoahJFRSupport::register_jfr_type_serializers() { JfrSerializer::register_serializer(TYPE_SHENANDOAHHEAPREGIONSTATE, - false, true, new ShenandoahHeapRegionStateConstant()); } diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/gc/z/zTracer.cpp --- a/src/hotspot/share/gc/z/zTracer.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/gc/z/zTracer.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -59,11 +59,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 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/dcmd/jfrDcmds.cpp --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -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_interval("flush-interval", "Minimum time before flushing buffers, measured in (s)econds, e.g. 4 s, or 0 for flushing when a recording ends", "NANOTIME", false, "1s"), _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_interval); _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_interval = NULL; + if (_flush_interval.is_set()) { + flush_interval = JfrJavaSupport::new_java_lang_Long(_flush_interval.value()._nanotime, CHECK); + } jobject duration = NULL; if (_duration.is_set()) { duration = JfrJavaSupport::new_java_lang_Long(_duration.value()._nanotime, CHECK); @@ -464,7 +470,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); @@ -478,6 +484,7 @@ execute_args.push_jobject(filename); execute_args.push_jobject(maxage); execute_args.push_jobject(maxsize); + execute_args.push_jobject(flush_interval); execute_args.push_jobject(dump_on_exit); execute_args.push_jobject(path_to_gc_roots); diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/dcmd/jfrDcmds.hpp --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp Wed Oct 30 19:43:52 2019 +0100 @@ -90,6 +90,7 @@ DCmdArgument _filename; DCmdArgument _maxage; DCmdArgument _maxsize; + DCmdArgument _flush_interval; DCmdArgument _dump_on_exit; DCmdArgument _path_to_gc_roots; diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/jfr.cpp --- a/src/hotspot/share/jfr/jfr.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/jfr.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -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 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/jfr.hpp --- a/src/hotspot/share/jfr/jfr.hpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/jfr.hpp Wed Oct 30 19:43:52 2019 +0100 @@ -53,6 +53,9 @@ static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter); static bool on_start_flight_recording_option(const JavaVMOption** option, char* delimiter); static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f); + static void exclude_thread(Thread* thread); + static bool is_excluded(Thread* thread); + static void include_thread(Thread* thread); }; #endif // SHARE_JFR_JFR_HPP diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/jni/jfrJavaSupport.cpp --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -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 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/jni/jfrJavaSupport.hpp --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp Wed Oct 30 19:43:52 2019 +0100 @@ -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 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/jni/jfrJniMethod.cpp --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -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)) + JfrRepository::flush(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 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/jni/jfrJniMethod.hpp --- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp Wed Oct 30 19:43:52 2019 +0100 @@ -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); 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 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp --- a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -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*)"()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 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -259,6 +259,7 @@ assert(leak_context_edge->parent() == NULL, "invariant"); if (1 == length) { + store_gc_root_id_in_leak_context_edge(leak_context_edge, leak_context_edge); return; } diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.cpp --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -34,6 +34,7 @@ #include "memory/resourceArea.hpp" #include "oops/markWord.hpp" #include "oops/oop.inline.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" @@ -51,8 +52,8 @@ } void EventEmitter::emit(ObjectSampler* sampler, int64_t cutoff_ticks, bool emit_all) { + assert(JfrStream_lock->owned_by_self(), "invariant"); assert(sampler != NULL, "invariant"); - ResourceMark rm; EdgeStore edge_store; if (cutoff_ticks <= 0) { @@ -68,6 +69,7 @@ } size_t EventEmitter::write_events(ObjectSampler* object_sampler, EdgeStore* edge_store, bool emit_all) { + assert_locked_or_safepoint(JfrStream_lock); assert(_thread == Thread::current(), "invariant"); assert(_thread->jfr_thread_local() == _jfr_thread_local, "invariant"); assert(object_sampler != NULL, "invariant"); diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -37,6 +37,7 @@ #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/utilities/jfrHashtable.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.hpp" #include "utilities/growableArray.hpp" @@ -271,7 +272,7 @@ } const JfrStackTrace* const stack_trace = resolve(sample); DEBUG_ONLY(validate_stack_trace(sample, stack_trace)); - JfrCheckpointWriter writer(false, true, Thread::current()); + JfrCheckpointWriter writer; writer.write_type(TYPE_STACKTRACE); writer.write_count(1); ObjectSampleCheckpoint::write_stacktrace(stack_trace, writer); @@ -291,6 +292,7 @@ // 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"); install_stack_traces(sampler, stack_trace_repo); @@ -388,7 +390,7 @@ static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thread* thread) { // sample set is predicated on time of last sweep const jlong last_sweep = emit_all ? max_jlong : sampler->last_sweep().value(); - JfrCheckpointWriter writer(false, false, thread); + JfrCheckpointWriter writer(thread, false); BlobWriter cbw(sampler, writer, last_sweep); iterate_samples(cbw, true); // reset blob write states @@ -397,13 +399,14 @@ } void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread) { + assert_locked_or_safepoint(JfrStream_lock); assert(sampler != NULL, "invariant"); assert(edge_store != NULL, "invariant"); assert(thread != NULL, "invariant"); write_sample_blobs(sampler, emit_all, thread); // write reference chains if (!edge_store->is_empty()) { - JfrCheckpointWriter writer(false, true, thread); + JfrCheckpointWriter writer(thread); ObjectSampleWriter osw(writer, edge_store); edge_store->iterate(osw); } diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -355,10 +355,6 @@ static traceid get_gc_root_description_info_id(const Edge& edge, traceid id) { assert(edge.is_root(), "invariant"); - if (EdgeUtils::is_leak_edge(edge)) { - return 0; - } - if (root_infos == NULL) { root_infos = new RootDescriptionInfo(); } @@ -606,8 +602,8 @@ static void register_serializers() { static bool is_registered = false; if (!is_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()); is_registered = true; } } diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -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" @@ -36,7 +37,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" @@ -256,8 +256,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 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp --- a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -31,6 +31,7 @@ #include "jfr/recorder/service/jfrOptionSet.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" @@ -92,6 +93,7 @@ if (!is_running()) { return; } + MutexLocker lock(JfrStream_lock); // exclusive access to object sampler instance ObjectSampler* const sampler = ObjectSampler::acquire(); assert(sampler != NULL, "invariant"); diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp --- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -110,6 +110,9 @@ } const JfrThreadLocal* const tl = thread->jfr_thread_local(); assert(tl != NULL, "invariant"); + if (tl->is_excluded()) { + return 0; + } if (!tl->has_thread_blob()) { JfrCheckpointManager::create_thread_blob(thread); } diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/metadata/jfrSerializer.hpp --- a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp Wed Oct 30 19:43:52 2019 +0100 @@ -70,7 +70,8 @@ class JfrSerializer : public CHeapObj { public: virtual ~JfrSerializer() {} - static bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer); + virtual void on_rotation() {} + static bool register_serializer(JfrTypeId id, bool permit_cache, JfrSerializer* serializer); virtual void serialize(JfrCheckpointWriter& writer) = 0; }; diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/metadata/metadata.xml --- a/src/hotspot/share/jfr/metadata/metadata.xml Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/metadata/metadata.xml Wed Oct 30 19:43:52 2019 +0100 @@ -154,7 +154,7 @@ - + @@ -162,27 +162,27 @@ - + - + - + - + @@ -442,7 +442,7 @@ - + @@ -484,7 +484,7 @@ - + @@ -585,21 +585,21 @@ - - - @@ -1004,6 +1004,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1183,35 +1219,40 @@ - + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -1223,5 +1264,5 @@ - + diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp --- a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -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 @@ -39,7 +39,7 @@ traceid id; uint64_t bytes_in; uint64_t bytes_out; - bool in_use; + mutable bool written; }; static GrowableArray* _interfaces = NULL; @@ -71,7 +71,7 @@ entry.id = ++interface_id; 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)); } @@ -108,6 +108,39 @@ return ((current - old) * NANOSECS_PER_SEC) / interval.nanoseconds(); } +class JfrNetworkInterfaceName : public JfrSerializer { + public: + void serialize(JfrCheckpointWriter& writer) {} // we write each constant lazily + + void on_rotation() { + for (int i = 0; i < _interfaces->length(); ++i) { + const InterfaceEntry& entry = _interfaces->at(i); + if (entry.written) { + entry.written = false; + } + } + } +}; + +static bool register_network_interface_name_serializer() { + assert(_interfaces != NULL, "invariant"); + return JfrSerializer::register_serializer(TYPE_NETWORKINTERFACENAME, + false, // disallow caching; we want a callback every rotation + new JfrNetworkInterfaceName()); +} + +static void write_interface_constant(const InterfaceEntry& entry) { + if (entry.written) { + return; + } + JfrCheckpointWriter writer; + writer.write_type(TYPE_NETWORKINTERFACENAME); + writer.write_count(1); + writer.write_key(entry.id); + writer.write(entry.name); + entry.written = true; +} + static bool get_interfaces(NetworkInterface** network_interfaces) { const int ret_val = JfrOSInterface::network_utilization(network_interfaces); if (ret_val == OS_ERR) { @@ -117,39 +150,6 @@ return ret_val != FUNCTIONALITY_NOT_IMPLEMENTED; } -class JfrNetworkInterfaceName : public JfrSerializer { - public: - void serialize(JfrCheckpointWriter& writer) { - assert(_interfaces != NULL, "invariant"); - 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) { - entry.in_use = false; - writer.write_key(entry.id); - writer.write(entry.name); - ++active_interfaces; - } - } - if (active_interfaces == 0) { - // nothing to write, restore context - writer.set_context(ctx); - return; - } - writer.write_count(active_interfaces, count_offset); - } -}; - -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()); -} - void JfrNetworkUtilization::send_events() { ResourceMark rm; NetworkInterface* network_interfaces; @@ -169,7 +169,7 @@ const uint64_t read_rate = rate_per_second(current_bytes_in, entry.bytes_in, interval); const uint64_t write_rate = rate_per_second(current_bytes_out, entry.bytes_out, interval); if (read_rate > 0 || write_rate > 0) { - entry.in_use = true; + write_interface_constant(entry); EventNetworkUtilization event(UNTIMED); event.set_starttime(cur_time); event.set_endtime(cur_time); diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/periodic/jfrPeriodic.cpp --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -44,6 +44,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" @@ -56,7 +57,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" @@ -410,13 +410,12 @@ 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(); ) { - allocated.append(jt->cooked_allocated_bytes()); - thread_ids.append(JFR_THREAD_ID(jt)); - } + 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)); } // Write allocation statistics to buffer. diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp --- a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -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 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -30,6 +30,7 @@ #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/support/jfrThreadId.hpp" +#include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrTime.hpp" #include "logging/log.hpp" #include "runtime/frame.inline.hpp" @@ -352,9 +353,14 @@ } } +static bool is_excluded(JavaThread* thread) { + assert(thread != NULL, "invariant"); + return thread->is_hidden_from_external_view() || thread->in_deopt_handler() || thread->jfr_thread_local()->is_excluded(); +} + bool JfrThreadSampleClosure::do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, JfrSampleType type) { assert(Threads_lock->owned_by_self(), "Holding the thread table lock."); - if (thread->is_hidden_from_external_view() || thread->in_deopt_handler()) { + if (is_excluded(thread)) { return false; } diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -37,11 +37,14 @@ #include "jfr/recorder/storage/jfrMemorySpace.inline.hpp" #include "jfr/recorder/storage/jfrStorageUtils.inline.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/mutex.hpp" #include "runtime/orderAccess.hpp" #include "runtime/os.inline.hpp" #include "runtime/safepoint.hpp" @@ -168,7 +171,7 @@ } bool JfrCheckpointManager::use_epoch_transition_mspace(const Thread* thread) const { - return _service_thread != thread && OrderAccess::load_acquire(&_checkpoint_epoch_state) != JfrTraceIdEpoch::epoch(); + return _service_thread != thread && _checkpoint_epoch_state != JfrTraceIdEpoch::epoch(); } static const size_t lease_retry = 10; @@ -181,12 +184,24 @@ return lease_free(size, manager._free_list_mspace, lease_retry, thread); } +JfrCheckpointMspace* JfrCheckpointManager::lookup(BufferPtr old) const { + assert(old != NULL, "invariant"); + return _free_list_mspace->in_free_list(old) ? _free_list_mspace : _epoch_transition_mspace; +} + +BufferPtr JfrCheckpointManager::lease_buffer(BufferPtr old, Thread* thread, size_t size /* 0 */) { + assert(old != NULL, "invariant"); + JfrCheckpointMspace* mspace = instance().lookup(old); + assert(mspace != NULL, "invariant"); + return lease_free(size, mspace, lease_retry, thread); +} + /* -* If the buffer was a "lease" from the free list, release back. -* -* The buffer is effectively invalidated for the thread post-return, -* and the caller should take means to ensure that it is not referenced. -*/ + * If the buffer was a lease, release back. + * + * The buffer is effectively invalidated for the thread post-return, + * and the caller should take means to ensure that it is not referenced. + */ static void release(BufferPtr const buffer, Thread* thread) { DEBUG_ONLY(assert_release(buffer);) buffer->clear_lease(); @@ -202,7 +217,7 @@ return NULL; } // migration of in-flight information - BufferPtr const new_buffer = lease_buffer(thread, used + requested); + BufferPtr const new_buffer = lease_buffer(old, thread, used + requested); if (new_buffer != NULL) { migrate_outstanding_writes(old, new_buffer, used, requested); } @@ -213,8 +228,8 @@ // offsets into the JfrCheckpointEntry static const juint starttime_offset = sizeof(jlong); static const juint duration_offset = starttime_offset + sizeof(jlong); -static const juint flushpoint_offset = duration_offset + sizeof(jlong); -static const juint types_offset = flushpoint_offset + sizeof(juint); +static const juint checkpoint_type_offset = duration_offset + sizeof(jlong); +static const juint types_offset = checkpoint_type_offset + sizeof(juint); static const juint payload_offset = types_offset + sizeof(juint); template @@ -234,21 +249,21 @@ return read_data(data + duration_offset); } -static bool is_flushpoint(const u1* data) { - return read_data(data + flushpoint_offset) == (juint)1; +static u1 checkpoint_type(const u1* data) { + return read_data(data + checkpoint_type_offset); } static juint number_of_types(const u1* data) { return read_data(data + types_offset); } -static void write_checkpoint_header(JfrChunkWriter& cw, int64_t offset_prev_cp_event, const u1* data) { +static void write_checkpoint_header(JfrChunkWriter& cw, int64_t delta_to_last_checkpoint, const u1* data) { cw.reserve(sizeof(u4)); cw.write(EVENT_CHECKPOINT); cw.write(starttime(data)); cw.write(duration(data)); - cw.write(offset_prev_cp_event); - cw.write(is_flushpoint(data)); + cw.write(delta_to_last_checkpoint); + cw.write(checkpoint_type(data)); cw.write(number_of_types(data)); } @@ -261,9 +276,9 @@ assert(data != NULL, "invariant"); const int64_t event_begin = cw.current_offset(); const int64_t last_checkpoint_event = cw.last_checkpoint_offset(); - const int64_t delta = last_checkpoint_event == 0 ? 0 : last_checkpoint_event - event_begin; + const int64_t delta_to_last_checkpoint = last_checkpoint_event == 0 ? 0 : last_checkpoint_event - event_begin; const int64_t checkpoint_size = total_size(data); - write_checkpoint_header(cw, delta, data); + write_checkpoint_header(cw, delta_to_last_checkpoint, data); write_checkpoint_content(cw, data, checkpoint_size); const int64_t event_size = cw.current_offset() - event_begin; cw.write_padded_at_offset(event_size, event_begin); @@ -305,13 +320,13 @@ typedef CheckpointWriteOp WriteOperation; typedef ReleaseOp CheckpointReleaseOperation; -template