diff --git a/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index 158bbab6d..26d53a203 100644 --- a/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -372,7 +372,7 @@ size_t JfrCheckpointManager::flush() { typedef DiscardOp > DiscardOperation; size_t JfrCheckpointManager::clear() { - JfrTypeSet::clear(); + clear_type_set(); DiscardOperation discarder(mutexed); // mutexed discard mode process_free_list(discarder, _free_list_mspace); process_free_list(discarder, _epoch_transition_mspace); @@ -458,6 +458,16 @@ void JfrCheckpointManager::on_rotation() { notify_threads(); } +void JfrCheckpointManager::clear_type_set() { + assert(!SafepointSynchronize::is_at_safepoint(), "invariant"); + assert(!JfrRecorder::is_recording(), "invariant"); + // can safepoint here + // MutexLocker cld_lock(ClassLoaderDataGraph_lock); + // MutexLocker module_lock(Module_lock); + MutexLocker package_table_lock(PackageTable_lock); + JfrTypeSet::clear(); +} + void JfrCheckpointManager::write_type_set() { assert(!SafepointSynchronize::is_at_safepoint(), "invariant"); if (LeakProfiler::is_running()) { diff --git a/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.hpp b/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.hpp index 5941a807f..a1d4d49c0 100644 --- a/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.hpp +++ b/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.hpp @@ -85,6 +85,7 @@ class JfrCheckpointManager : public JfrCHeapObj { size_t write_threads(); size_t write_static_type_set_and_threads(); bool is_type_set_required(); + void clear_type_set(); void write_type_set(); static void write_type_set_for_unloaded_classes(); diff --git a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index d762a3a6b..d53ffaa00 100644 --- a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -157,6 +157,7 @@ static void set_serialized(const T* ptr) { assert(ptr != NULL, "invariant"); SET_SERIALIZED(ptr); assert(IS_SERIALIZED(ptr), "invariant"); + CLEAR_THIS_EPOCH_CLEARED_BIT(ptr); } /* @@ -390,6 +391,26 @@ static void do_previous_epoch_artifact(JfrArtifactClosure* callback, T* value) { assert(IS_NOT_SERIALIZED(value), "invariant"); } +typedef JfrArtifactCallbackHost RegistrationCallback; + +static void register_klass(Klass* klass) { + assert(klass != NULL, "invariant"); + assert(_subsystem_callback != NULL, "invariant"); + do_previous_epoch_artifact(_subsystem_callback, klass); +} + +static void do_register_klasses() { + ClassLoaderDataGraph::classes_do(®ister_klass); +} + +static void register_klasses() { + assert(!_artifacts->has_klass_entries(), "invariant"); + KlassArtifactRegistrator reg(_artifacts); + RegistrationCallback callback(®); + _subsystem_callback = &callback; + do_register_klasses(); +} + static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) { assert(cld != NULL, "invariant"); assert(!cld->is_anonymous(), "invariant"); @@ -517,6 +538,15 @@ static void write_classloaders() { _artifacts->tally(cldw); } +typedef JfrArtifactCallbackHost > ClearCLDCallback; + +static void clear_classloaders() { + ClearArtifact clear; + ClearCLDCallback callback(&clear); + _subsystem_callback = &callback; + do_class_loaders(); +} + static u1 get_visibility(MethodPtr method) { assert(method != NULL, "invariant"); return const_cast(method)->is_hidden() ? (u1)1 : (u1)0; @@ -527,6 +557,7 @@ void set_serialized(MethodPtr method) { assert(method != NULL, "invariant"); SET_METHOD_SERIALIZED(method); assert(IS_METHOD_SERIALIZED(method), "invariant"); + CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(method); } static int write_method(JfrCheckpointWriter* writer, MethodPtr method, bool leakp) { @@ -759,24 +790,23 @@ static void write_symbols() { _artifacts->tally(sw); } -static bool clear_artifacts = false; - -void JfrTypeSet::clear() { - clear_artifacts = true; -} - typedef Wrapper ClearKlassBits; typedef Wrapper ClearMethodFlag; typedef MethodIteratorHost ClearKlassAndMethods; +static bool clear_artifacts = false; + +static void clear_klasses_and_methods() { + ClearKlassAndMethods clear(_writer); + _artifacts->iterate_klasses(clear); +} + static size_t teardown() { assert(_artifacts != NULL, "invariant"); const size_t total_count = _artifacts->total_count(); if (previous_epoch()) { - assert(_writer != NULL, "invariant"); - ClearKlassAndMethods clear(_writer); - _artifacts->iterate_klasses(clear); - JfrTypeSet::clear(); + clear_klasses_and_methods(); + clear_artifacts = true; ++checkpoint_id; } return total_count; @@ -815,3 +845,16 @@ size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* l write_symbols(); return teardown(); } + +/** + * Clear all tags from the previous epoch. + */ +void JfrTypeSet::clear() { + clear_artifacts = true; + setup(NULL, NULL, false, false); + register_klasses(); + // clear_packages(); + // clear_modules(); + clear_classloaders(); + clear_klasses_and_methods(); +} diff --git a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp index 328835852..c9b844e8f 100644 --- a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -84,9 +84,10 @@ template class ClearArtifact { public: bool operator()(T const& value) { - CLEAR_METHOD_AND_CLASS_PREV_EPOCH(value); CLEAR_SERIALIZED(value); assert(IS_NOT_SERIALIZED(value), "invariant"); + SET_PREV_EPOCH_CLEARED_BIT(value); + CLEAR_METHOD_AND_CLASS_PREV_EPOCH(value); return true; } }; @@ -96,9 +97,10 @@ class ClearArtifact { public: bool operator()(const Method* method) { assert(METHOD_FLAG_USED_PREV_EPOCH(method), "invariant"); - CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method); CLEAR_METHOD_SERIALIZED(method); assert(METHOD_NOT_SERIALIZED(method), "invariant"); + SET_PREV_EPOCH_METHOD_CLEARED_BIT(method); + CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method); return true; } }; diff --git a/src/share/vm/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp b/src/share/vm/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp index 81649caa9..49fee4046 100644 --- a/src/share/vm/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp +++ b/src/share/vm/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp @@ -37,6 +37,23 @@ #include "runtime/thread.inline.hpp" #include "utilities/debug.hpp" +inline bool is_not_tagged(traceid value) { + const traceid this_epoch_bit = JfrTraceIdEpoch::in_use_this_epoch_bit(); + return (value & ((this_epoch_bit << META_SHIFT) | this_epoch_bit)) != this_epoch_bit; +} + +template +inline bool should_tag(const T* t) { + assert(t != NULL, "invariant"); + return is_not_tagged(TRACE_ID_RAW(t)); +} + +template <> +inline bool should_tag(const Method* method) { + assert(method != NULL, "invariant"); + return is_not_tagged((traceid)method->trace_flags()); +} + template inline traceid set_used_and_get(const T* type) { assert(type != NULL, "invariant"); @@ -57,14 +74,12 @@ inline traceid JfrTraceId::get(const Thread* t) { inline traceid JfrTraceId::use(const Klass* klass) { assert(klass != NULL, "invariant"); - if (SHOULD_TAG(klass)) { + if (should_tag(klass)) { SET_USED_THIS_EPOCH(klass); - assert(USED_THIS_EPOCH(klass), "invariant"); JfrTraceIdEpoch::set_changed_tag_state(); - return get(klass); } assert(USED_THIS_EPOCH(klass), "invariant"); - return TRACE_ID(klass); + return get(klass); } inline traceid JfrTraceId::use(const Method* method) { diff --git a/src/share/vm/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp b/src/share/vm/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp index 525d7d2c7..6813f7968 100644 --- a/src/share/vm/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp +++ b/src/share/vm/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp @@ -46,15 +46,19 @@ // static bits #define META_SHIFT 8 -#define LEAKP_META_BIT USED_BIT +#define EPOCH_1_CLEARED_META_BIT USED_BIT +#define EPOCH_1_CLEARED_BIT (EPOCH_1_CLEARED_META_BIT << META_SHIFT) +#define EPOCH_2_CLEARED_META_BIT (USED_BIT << 1) +#define EPOCH_2_CLEARED_BIT (EPOCH_2_CLEARED_META_BIT << META_SHIFT) +#define LEAKP_META_BIT (USED_BIT << 2) #define LEAKP_BIT (LEAKP_META_BIT << META_SHIFT) -#define TRANSIENT_META_BIT (USED_BIT << 1) +#define TRANSIENT_META_BIT (USED_BIT << 3) #define TRANSIENT_BIT (TRANSIENT_META_BIT << META_SHIFT) -#define SERIALIZED_META_BIT (USED_BIT << 2) +#define SERIALIZED_META_BIT (USED_BIT << 4) #define SERIALIZED_BIT (SERIALIZED_META_BIT << META_SHIFT) #define TRACE_ID_SHIFT 16 #define METHOD_ID_NUM_MASK ((1 << TRACE_ID_SHIFT) - 1) -#define META_BITS (SERIALIZED_BIT | TRANSIENT_BIT | LEAKP_BIT) +#define META_BITS (SERIALIZED_BIT | TRANSIENT_BIT | LEAKP_BIT | EPOCH_2_CLEARED_BIT | EPOCH_1_CLEARED_BIT) #define EVENT_BITS (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS) #define USED_BITS (METHOD_USED_EPOCH_2_BIT | METHOD_USED_EPOCH_1_BIT | USED_EPOCH_2_BIT | USED_EPOCH_1_BIT) #define ALL_BITS (META_BITS | EVENT_BITS | USED_BITS) @@ -132,12 +136,16 @@ #define SHOULD_TAG_KLASS_METHOD(ptr) (METHOD_NOT_USED_THIS_EPOCH(ptr)) #define SET_SERIALIZED(ptr) (TRACE_ID_META_TAG(ptr, SERIALIZED_META_BIT)) #define CLEAR_SERIALIZED(ptr) (TRACE_ID_META_CLEAR(ptr, META_MASK)) +#define SET_PREV_EPOCH_CLEARED_BIT(ptr) (TRACE_ID_META_TAG(ptr, IN_USE_PREV_EPOCH_BIT)) #define IS_METHOD_SERIALIZED(method) (METHOD_FLAG_PREDICATE(method, SERIALIZED_BIT)) #define IS_METHOD_LEAKP_USED(method) (METHOD_FLAG_PREDICATE(method, LEAKP_BIT)) #define METHOD_NOT_SERIALIZED(method) (!(IS_METHOD_SERIALIZED(method))) #define SET_METHOD_LEAKP(method) (METHOD_META_TAG(method, LEAKP_META_BIT)) #define SET_METHOD_SERIALIZED(method) (METHOD_META_TAG(method, SERIALIZED_META_BIT)) #define CLEAR_METHOD_SERIALIZED(method) (METHOD_META_CLEAR(method, META_MASK)) +#define SET_PREV_EPOCH_METHOD_CLEARED_BIT(ptr) (METHOD_META_TAG(ptr, IN_USE_PREV_EPOCH_BIT)) #define CLEAR_LEAKP(ptr) (TRACE_ID_META_CLEAR(ptr, (~(LEAKP_META_BIT)))) +#define CLEAR_THIS_EPOCH_CLEARED_BIT(ptr) (TRACE_ID_META_CLEAR(ptr,(~(IN_USE_THIS_EPOCH_BIT)))) +#define CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(ptr) (METHOD_META_CLEAR(ptr,(~(IN_USE_THIS_EPOCH_BIT)))) #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP diff --git a/src/share/vm/jfr/recorder/service/jfrRecorderService.cpp b/src/share/vm/jfr/recorder/service/jfrRecorderService.cpp index 0ff99b153..ad31f0da6 100644 --- a/src/share/vm/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/share/vm/jfr/recorder/service/jfrRecorderService.cpp @@ -349,26 +349,48 @@ JfrRecorderService::JfrRecorderService() : _storage(JfrStorage::instance()), _string_pool(JfrStringPool::instance()) {} -static bool recording = false; +enum RecorderState { + STOPPED, + RUNNING +}; + +static RecorderState recorder_state = STOPPED; -static void set_recording_state(bool is_recording) { +static void set_recorder_state(RecorderState from, RecorderState to) { + assert(from == recorder_state, "invariant"); OrderAccess::storestore(); - recording = is_recording; + recorder_state = to; +} + +static void start_recorder() { + set_recorder_state(STOPPED, RUNNING); + if (LogJFR) tty->print_cr("Recording service STARTED"); +} + +static void stop_recorder() { + set_recorder_state(RUNNING, STOPPED); + if (LogJFR) tty->print_cr("Recording service STOPPED"); } bool JfrRecorderService::is_recording() { - return recording; + const bool is_running = recorder_state == RUNNING; + OrderAccess::loadload(); + return is_running; } void JfrRecorderService::start() { MutexLocker lock(JfrStream_lock); - if (LogJFR) tty->print_cr("Request to START recording"); assert(!is_recording(), "invariant"); clear(); - set_recording_state(true); - assert(is_recording(), "invariant"); open_new_chunk(); - if (LogJFR) tty->print_cr("Recording STARTED"); + start_recorder(); + assert(is_recording(), "invariant"); +} + +static void stop() { + assert(JfrRecorderService::is_recording(), "invariant"); + stop_recorder(); + assert(!JfrRecorderService::is_recording(), "invariant"); } void JfrRecorderService::clear() { @@ -394,9 +416,9 @@ void JfrRecorderService::safepoint_clear() { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); _checkpoint_manager.begin_epoch_shift(); _string_pool.clear(); - _stack_trace_repository.clear(); _storage.clear(); _chunkwriter.set_time_stamp(); + _stack_trace_repository.clear(); _checkpoint_manager.end_epoch_shift(); } @@ -413,13 +435,6 @@ void JfrRecorderService::open_new_chunk(bool vm_error) { } } -static void stop() { - assert(JfrRecorderService::is_recording(), "invariant"); - if (LogJFR) tty->print_cr("Recording STOPPED"); - set_recording_state(false); - assert(!JfrRecorderService::is_recording(), "invariant"); -} - void JfrRecorderService::prepare_for_vm_error_rotation() { assert(JfrStream_lock->owned_by_self(), "invariant"); if (!_chunkwriter.is_valid()) { @@ -520,9 +535,9 @@ void JfrRecorderService::safepoint_write() { write_stringpool_safepoint(_string_pool, _chunkwriter); } _checkpoint_manager.on_rotation(); - write_stacktrace(_stack_trace_repository, _chunkwriter, true); _storage.write_at_safepoint(); _chunkwriter.set_time_stamp(); + write_stacktrace(_stack_trace_repository, _chunkwriter, true); _checkpoint_manager.end_epoch_shift(); }