22 * |
22 * |
23 */ |
23 */ |
24 |
24 |
25 #include "precompiled.hpp" |
25 #include "precompiled.hpp" |
26 #include "jfr/jni/jfrJavaSupport.hpp" |
26 #include "jfr/jni/jfrJavaSupport.hpp" |
|
27 #include "jfr/leakprofiler/leakProfiler.hpp" |
27 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" |
28 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" |
|
29 #include "jfr/leakprofiler/sampling/objectSampler.hpp" |
28 #include "jfr/recorder/jfrRecorder.hpp" |
30 #include "jfr/recorder/jfrRecorder.hpp" |
29 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" |
31 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" |
30 #include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp" |
32 #include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp" |
31 #include "jfr/recorder/repository/jfrChunkRotation.hpp" |
33 #include "jfr/recorder/repository/jfrChunkRotation.hpp" |
32 #include "jfr/recorder/repository/jfrChunkWriter.hpp" |
34 #include "jfr/recorder/repository/jfrChunkWriter.hpp" |
129 } |
131 } |
130 bool not_acquired() const { return !_acquired; } |
132 bool not_acquired() const { return !_acquired; } |
131 }; |
133 }; |
132 |
134 |
133 static int64_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) { |
135 static int64_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) { |
134 const int64_t prev_cp_offset = cw.previous_checkpoint_offset(); |
136 const int64_t last_cp_offset = cw.last_checkpoint_offset(); |
135 const int64_t prev_cp_relative_offset = 0 == prev_cp_offset ? 0 : prev_cp_offset - cw.current_offset(); |
137 const int64_t delta_to_last_checkpoint = 0 == last_cp_offset ? 0 : last_cp_offset - cw.current_offset(); |
136 cw.reserve(sizeof(u4)); |
138 cw.reserve(sizeof(u4)); |
137 cw.write<u8>(EVENT_CHECKPOINT); |
139 cw.write<u8>(EVENT_CHECKPOINT); |
138 cw.write(JfrTicks::now()); |
140 cw.write(JfrTicks::now()); |
139 cw.write((int64_t)0); |
141 cw.write((int64_t)0); // duration |
140 cw.write(prev_cp_relative_offset); // write previous checkpoint offset delta |
142 cw.write(delta_to_last_checkpoint); |
141 cw.write<bool>(false); // flushpoint |
143 cw.write<bool>(false); // flushpoint |
142 cw.write((u4)1); // nof types in this checkpoint |
144 cw.write((u4)1); // nof types in this checkpoint |
143 cw.write(type_id); |
145 cw.write(type_id); |
144 const int64_t number_of_elements_offset = cw.current_offset(); |
146 const int64_t number_of_elements_offset = cw.current_offset(); |
145 cw.reserve(sizeof(u4)); |
147 cw.reserve(sizeof(u4)); |
174 assert(number_of_elements > 0, "invariant"); |
176 assert(number_of_elements > 0, "invariant"); |
175 assert(_cw.current_offset() > num_elements_offset, "invariant"); |
177 assert(_cw.current_offset() > num_elements_offset, "invariant"); |
176 _cw.write_padded_at_offset<u4>(number_of_elements, num_elements_offset); |
178 _cw.write_padded_at_offset<u4>(number_of_elements, num_elements_offset); |
177 _cw.write_padded_at_offset<u4>((u4)_cw.current_offset() - current_cp_offset, current_cp_offset); |
179 _cw.write_padded_at_offset<u4>((u4)_cw.current_offset() - current_cp_offset, current_cp_offset); |
178 // update writer with last checkpoint position |
180 // update writer with last checkpoint position |
179 _cw.set_previous_checkpoint_offset(current_cp_offset); |
181 _cw.set_last_checkpoint_offset(current_cp_offset); |
180 return true; |
182 return true; |
181 } |
183 } |
182 }; |
184 }; |
183 |
185 |
184 template <typename Instance, size_t(Instance::*func)()> |
186 template <typename Instance, size_t(Instance::*func)()> |
313 static bool vm_error = false; |
315 static bool vm_error = false; |
314 if (msgs & MSGBIT(MSG_VM_ERROR)) { |
316 if (msgs & MSGBIT(MSG_VM_ERROR)) { |
315 vm_error = true; |
317 vm_error = true; |
316 prepare_for_vm_error_rotation(); |
318 prepare_for_vm_error_rotation(); |
317 } |
319 } |
|
320 if (!_storage.control().to_disk()) { |
|
321 in_memory_rotation(); |
|
322 } else if (vm_error) { |
|
323 vm_error_rotation(); |
|
324 } else { |
|
325 chunk_rotation(); |
|
326 } |
318 if (msgs & (MSGBIT(MSG_STOP))) { |
327 if (msgs & (MSGBIT(MSG_STOP))) { |
319 stop(); |
328 stop(); |
320 } |
329 } |
321 // action determined by chunkwriter state |
|
322 if (!_chunkwriter.is_valid()) { |
|
323 in_memory_rotation(); |
|
324 return; |
|
325 } |
|
326 if (vm_error) { |
|
327 vm_error_rotation(); |
|
328 return; |
|
329 } |
|
330 chunk_rotation(); |
|
331 } |
330 } |
332 |
331 |
333 void JfrRecorderService::prepare_for_vm_error_rotation() { |
332 void JfrRecorderService::prepare_for_vm_error_rotation() { |
334 if (!_chunkwriter.is_valid()) { |
333 if (!_chunkwriter.is_valid()) { |
335 open_new_chunk(true); |
334 open_new_chunk(true); |
336 } |
335 } |
337 _checkpoint_manager.register_service_thread(Thread::current()); |
336 _checkpoint_manager.register_service_thread(Thread::current()); |
|
337 JfrMetadataEvent::lock(); |
338 } |
338 } |
339 |
339 |
340 void JfrRecorderService::open_new_chunk(bool vm_error) { |
340 void JfrRecorderService::open_new_chunk(bool vm_error) { |
341 assert(!_chunkwriter.is_valid(), "invariant"); |
341 assert(!_chunkwriter.is_valid(), "invariant"); |
342 assert(!JfrStream_lock->owned_by_self(), "invariant"); |
342 assert(!JfrStream_lock->owned_by_self(), "invariant"); |
395 static void write_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) { |
395 static void write_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) { |
396 WriteStackTraceRepository write_stacktrace_repo(stack_trace_repo, chunkwriter, clear); |
396 WriteStackTraceRepository write_stacktrace_repo(stack_trace_repo, chunkwriter, clear); |
397 WriteStackTraceCheckpoint write_stack_trace_checkpoint(chunkwriter, TYPE_STACKTRACE, write_stacktrace_repo); |
397 WriteStackTraceCheckpoint write_stack_trace_checkpoint(chunkwriter, TYPE_STACKTRACE, write_stacktrace_repo); |
398 write_stack_trace_checkpoint.process(); |
398 write_stack_trace_checkpoint.process(); |
399 } |
399 } |
400 |
|
401 static void write_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
400 static void write_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
402 WriteStringPool write_string_pool(string_pool); |
401 WriteStringPool write_string_pool(string_pool); |
403 WriteStringPoolCheckpoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool); |
402 WriteStringPoolCheckpoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool); |
404 write_string_pool_checkpoint.process(); |
403 write_string_pool_checkpoint.process(); |
405 } |
404 } |
416 // lock stream lock -> |
415 // lock stream lock -> |
417 // write non-safepoint dependent types -> |
416 // write non-safepoint dependent types -> |
418 // write checkpoint epoch transition list-> |
417 // write checkpoint epoch transition list-> |
419 // write stack trace checkpoint -> |
418 // write stack trace checkpoint -> |
420 // write string pool checkpoint -> |
419 // write string pool checkpoint -> |
421 // write storage -> |
420 // write object sample stacktraces -> |
422 // release stream lock |
421 // write storage -> |
|
422 // release stream lock |
423 // |
423 // |
424 void JfrRecorderService::pre_safepoint_write() { |
424 void JfrRecorderService::pre_safepoint_write() { |
425 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
425 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
426 assert(_chunkwriter.is_valid(), "invariant"); |
426 assert(_chunkwriter.is_valid(), "invariant"); |
427 _checkpoint_manager.write_types(); |
427 _checkpoint_manager.write_types(); |
428 _checkpoint_manager.write_epoch_transition_mspace(); |
428 _checkpoint_manager.write_epoch_transition_mspace(); |
429 write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, false); |
429 write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, false); |
430 write_stringpool_checkpoint(_string_pool, _chunkwriter); |
430 write_stringpool_checkpoint(_string_pool, _chunkwriter); |
|
431 if (LeakProfiler::is_running()) { |
|
432 // Exclusive access to the object sampler instance. |
|
433 // The sampler is released (unlocked) later in post_safepoint_write. |
|
434 ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire(), _stack_trace_repository); |
|
435 } |
431 _storage.write(); |
436 _storage.write(); |
432 } |
437 } |
433 |
438 |
434 void JfrRecorderService::invoke_safepoint_write() { |
439 void JfrRecorderService::invoke_safepoint_write() { |
435 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this); |
440 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this); |
436 VMThread::execute(&safepoint_task); |
441 VMThread::execute(&safepoint_task); |
437 } |
442 } |
438 |
443 |
439 static void write_object_sample_stacktrace(JfrStackTraceRepository& stack_trace_repository) { |
|
440 WriteObjectSampleStacktrace object_sample_stacktrace(stack_trace_repository); |
|
441 object_sample_stacktrace.process(); |
|
442 } |
|
443 |
|
444 // |
444 // |
445 // safepoint write sequence |
445 // safepoint write sequence |
446 // |
446 // |
447 // lock stream lock -> |
447 // lock stream lock -> |
448 // write object sample stacktraces -> |
|
449 // write stacktrace repository -> |
448 // write stacktrace repository -> |
450 // write string pool -> |
449 // write string pool -> |
451 // write safepoint dependent types -> |
450 // write safepoint dependent types -> |
452 // write storage -> |
451 // write storage -> |
453 // shift_epoch -> |
452 // shift_epoch -> |
456 // release stream lock |
455 // release stream lock |
457 // |
456 // |
458 void JfrRecorderService::safepoint_write() { |
457 void JfrRecorderService::safepoint_write() { |
459 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
458 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
460 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
459 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
461 write_object_sample_stacktrace(_stack_trace_repository); |
|
462 write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, true); |
460 write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, true); |
463 write_stringpool_checkpoint_safepoint(_string_pool, _chunkwriter); |
461 write_stringpool_checkpoint_safepoint(_string_pool, _chunkwriter); |
464 _checkpoint_manager.write_safepoint_types(); |
462 _checkpoint_manager.write_safepoint_types(); |
465 _storage.write_at_safepoint(); |
463 _storage.write_at_safepoint(); |
466 _checkpoint_manager.shift_epoch(); |
464 _checkpoint_manager.shift_epoch(); |
476 } |
474 } |
477 |
475 |
478 // |
476 // |
479 // post-safepoint write sequence |
477 // post-safepoint write sequence |
480 // |
478 // |
481 // lock stream lock -> |
479 // write type set -> |
482 // write type set -> |
480 // release object sampler -> |
483 // write checkpoints -> |
481 // lock stream lock -> |
484 // write metadata event -> |
482 // write checkpoints -> |
485 // write chunk header -> |
483 // write metadata event -> |
486 // close chunk fd -> |
484 // write chunk header -> |
487 // release stream lock |
485 // close chunk fd -> |
|
486 // release stream lock |
488 // |
487 // |
489 void JfrRecorderService::post_safepoint_write() { |
488 void JfrRecorderService::post_safepoint_write() { |
490 assert(_chunkwriter.is_valid(), "invariant"); |
489 assert(_chunkwriter.is_valid(), "invariant"); |
491 // During the safepoint tasks just completed, the system transitioned to a new epoch. |
490 // During the safepoint tasks just completed, the system transitioned to a new epoch. |
492 // Type tagging is epoch relative which entails we are able to write out the |
491 // Type tagging is epoch relative which entails we are able to write out the |
493 // already tagged artifacts for the previous epoch. We can accomplish this concurrently |
492 // already tagged artifacts for the previous epoch. We can accomplish this concurrently |
494 // with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint. |
493 // with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint. |
495 _checkpoint_manager.write_type_set(); |
494 _checkpoint_manager.write_type_set(); |
|
495 if (LeakProfiler::is_running()) { |
|
496 // The object sampler instance was exclusively acquired and locked in pre_safepoint_write. |
|
497 // Note: There is a dependency on write_type_set() above, ensure the release is subsequent. |
|
498 ObjectSampler::release(); |
|
499 } |
496 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
500 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
497 // serialize any outstanding checkpoint memory |
501 // serialize any outstanding checkpoint memory |
498 _checkpoint_manager.write(); |
502 _checkpoint_manager.write(); |
499 // serialize the metadata descriptor event and close out the chunk |
503 // serialize the metadata descriptor event and close out the chunk |
500 _repository.close_chunk(write_metadata_event(_chunkwriter)); |
504 _repository.close_chunk(write_metadata_event(_chunkwriter)); |
510 } |
514 } |
511 |
515 |
512 void JfrRecorderService::finalize_current_chunk_on_vm_error() { |
516 void JfrRecorderService::finalize_current_chunk_on_vm_error() { |
513 assert(_chunkwriter.is_valid(), "invariant"); |
517 assert(_chunkwriter.is_valid(), "invariant"); |
514 pre_safepoint_write(); |
518 pre_safepoint_write(); |
515 JfrMetadataEvent::lock(); |
|
516 // Do not attempt safepoint dependent operations during emergency dump. |
519 // Do not attempt safepoint dependent operations during emergency dump. |
517 // Optimistically write tagged artifacts. |
520 // Optimistically write tagged artifacts. |
518 _checkpoint_manager.shift_epoch(); |
521 _checkpoint_manager.shift_epoch(); |
519 _checkpoint_manager.write_type_set(); |
|
520 // update time |
522 // update time |
521 _chunkwriter.time_stamp_chunk_now(); |
523 _chunkwriter.time_stamp_chunk_now(); |
522 post_safepoint_write(); |
524 post_safepoint_write(); |
523 assert(!_chunkwriter.is_valid(), "invariant"); |
525 assert(!_chunkwriter.is_valid(), "invariant"); |
524 } |
526 } |