54 #include "runtime/safepoint.hpp" |
54 #include "runtime/safepoint.hpp" |
55 #include "runtime/thread.inline.hpp" |
55 #include "runtime/thread.inline.hpp" |
56 #include "runtime/vmOperations.hpp" |
56 #include "runtime/vmOperations.hpp" |
57 #include "runtime/vmThread.hpp" |
57 #include "runtime/vmThread.hpp" |
58 |
58 |
59 // set data iff *dest == NULL |
|
60 static bool try_set(void* const data, void** dest, bool clear) { |
|
61 assert(data != NULL, "invariant"); |
|
62 const void* const current = *dest; |
|
63 if (current != NULL) { |
|
64 if (current != data) { |
|
65 // already set |
|
66 return false; |
|
67 } |
|
68 assert(current == data, "invariant"); |
|
69 if (!clear) { |
|
70 // recursion disallowed |
|
71 return false; |
|
72 } |
|
73 } |
|
74 return Atomic::cmpxchg(clear ? NULL : data, dest, current) == current; |
|
75 } |
|
76 |
|
77 static void* rotation_thread = NULL; |
|
78 static const int rotation_try_limit = 1000; |
|
79 static const int rotation_retry_sleep_millis = 10; |
|
80 |
|
81 // incremented on each flushpoint |
59 // incremented on each flushpoint |
82 static u8 flushpoint_id = 0; |
60 static u8 flushpoint_id = 0; |
83 |
|
84 class RotationLock : public StackObj { |
|
85 private: |
|
86 Thread* const _thread; |
|
87 bool _acquired; |
|
88 |
|
89 void log(bool recursion) { |
|
90 assert(!_acquired, "invariant"); |
|
91 const char* error_msg = NULL; |
|
92 if (recursion) { |
|
93 error_msg = "Unable to issue rotation due to recursive calls."; |
|
94 } |
|
95 else { |
|
96 error_msg = "Unable to issue rotation due to wait timeout."; |
|
97 } |
|
98 log_info(jfr)( // For user, should not be "jfr, system" |
|
99 "%s", error_msg); |
|
100 } |
|
101 public: |
|
102 RotationLock(Thread* thread) : _thread(thread), _acquired(false) { |
|
103 assert(_thread != NULL, "invariant"); |
|
104 if (_thread == rotation_thread) { |
|
105 // recursion not supported |
|
106 log(true); |
|
107 return; |
|
108 } |
|
109 |
|
110 // limited to not spin indefinitely |
|
111 for (int i = 0; i < rotation_try_limit; ++i) { |
|
112 if (try_set(_thread, &rotation_thread, false)) { |
|
113 _acquired = true; |
|
114 assert(_thread == rotation_thread, "invariant"); |
|
115 return; |
|
116 } |
|
117 if (_thread->is_Java_thread()) { |
|
118 // in order to allow the system to move to a safepoint |
|
119 MutexLocker msg_lock(JfrMsg_lock); |
|
120 JfrMsg_lock->wait(rotation_retry_sleep_millis); |
|
121 } |
|
122 else { |
|
123 os::naked_short_sleep(rotation_retry_sleep_millis); |
|
124 } |
|
125 } |
|
126 log(false); |
|
127 } |
|
128 |
|
129 ~RotationLock() { |
|
130 assert(_thread != NULL, "invariant"); |
|
131 if (_acquired) { |
|
132 assert(_thread == rotation_thread, "invariant"); |
|
133 while (!try_set(_thread, &rotation_thread, true)); |
|
134 } |
|
135 } |
|
136 bool not_acquired() const { return !_acquired; } |
|
137 }; |
|
138 |
61 |
139 template <typename E, typename Instance, size_t(Instance::*func)()> |
62 template <typename E, typename Instance, size_t(Instance::*func)()> |
140 class Content { |
63 class Content { |
141 private: |
64 private: |
142 Instance& _instance; |
65 Instance& _instance; |
436 bool JfrRecorderService::is_recording() { |
359 bool JfrRecorderService::is_recording() { |
437 return recording; |
360 return recording; |
438 } |
361 } |
439 |
362 |
440 void JfrRecorderService::start() { |
363 void JfrRecorderService::start() { |
441 RotationLock rl(Thread::current()); |
364 MutexLocker lock(JfrStream_lock); |
442 if (rl.not_acquired()) { |
|
443 return; |
|
444 } |
|
445 log_debug(jfr, system)("Request to START recording"); |
365 log_debug(jfr, system)("Request to START recording"); |
446 assert(!is_recording(), "invariant"); |
366 assert(!is_recording(), "invariant"); |
447 clear(); |
367 clear(); |
448 set_recording_state(true); |
368 set_recording_state(true); |
449 assert(is_recording(), "invariant"); |
369 assert(is_recording(), "invariant"); |
458 invoke_safepoint_clear(); |
378 invoke_safepoint_clear(); |
459 post_safepoint_clear(); |
379 post_safepoint_clear(); |
460 } |
380 } |
461 |
381 |
462 void JfrRecorderService::pre_safepoint_clear() { |
382 void JfrRecorderService::pre_safepoint_clear() { |
463 _stack_trace_repository.clear(); |
|
464 _string_pool.clear(); |
383 _string_pool.clear(); |
465 _storage.clear(); |
384 _storage.clear(); |
|
385 _stack_trace_repository.clear(); |
466 } |
386 } |
467 |
387 |
468 void JfrRecorderService::invoke_safepoint_clear() { |
388 void JfrRecorderService::invoke_safepoint_clear() { |
469 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_clear> safepoint_task(*this); |
389 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_clear> safepoint_task(*this); |
470 VMThread::execute(&safepoint_task); |
390 VMThread::execute(&safepoint_task); |
471 } |
391 } |
472 |
392 |
473 void JfrRecorderService::safepoint_clear() { |
393 void JfrRecorderService::safepoint_clear() { |
474 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
394 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
475 _stack_trace_repository.clear(); |
|
476 _string_pool.clear(); |
395 _string_pool.clear(); |
477 _storage.clear(); |
396 _storage.clear(); |
478 _checkpoint_manager.shift_epoch(); |
397 _checkpoint_manager.shift_epoch(); |
479 _chunkwriter.set_time_stamp(); |
398 _chunkwriter.set_time_stamp(); |
|
399 _stack_trace_repository.clear(); |
480 } |
400 } |
481 |
401 |
482 void JfrRecorderService::post_safepoint_clear() { |
402 void JfrRecorderService::post_safepoint_clear() { |
483 _checkpoint_manager.clear(); |
403 _checkpoint_manager.clear(); |
484 } |
404 } |
498 set_recording_state(false); |
418 set_recording_state(false); |
499 assert(!JfrRecorderService::is_recording(), "invariant"); |
419 assert(!JfrRecorderService::is_recording(), "invariant"); |
500 } |
420 } |
501 |
421 |
502 void JfrRecorderService::prepare_for_vm_error_rotation() { |
422 void JfrRecorderService::prepare_for_vm_error_rotation() { |
|
423 assert(JfrStream_lock->owned_by_self(), "invariant"); |
503 if (!_chunkwriter.is_valid()) { |
424 if (!_chunkwriter.is_valid()) { |
504 open_new_chunk(true); |
425 open_new_chunk(true); |
505 } |
426 } |
506 _checkpoint_manager.register_service_thread(Thread::current()); |
427 _checkpoint_manager.register_service_thread(Thread::current()); |
507 } |
428 } |
508 |
429 |
509 void JfrRecorderService::vm_error_rotation() { |
430 void JfrRecorderService::vm_error_rotation() { |
|
431 assert(JfrStream_lock->owned_by_self(), "invariant"); |
510 if (_chunkwriter.is_valid()) { |
432 if (_chunkwriter.is_valid()) { |
511 Thread* const t = Thread::current(); |
433 Thread* const t = Thread::current(); |
512 _storage.flush_regular_buffer(t->jfr_thread_local()->native_buffer(), t); |
434 _storage.flush_regular_buffer(t->jfr_thread_local()->native_buffer(), t); |
513 invoke_flush(t); |
435 invoke_flush(); |
514 _chunkwriter.set_time_stamp(); |
436 _chunkwriter.set_time_stamp(); |
515 _repository.close_chunk(); |
437 _repository.close_chunk(); |
516 assert(!_chunkwriter.is_valid(), "invariant"); |
438 assert(!_chunkwriter.is_valid(), "invariant"); |
517 _repository.on_vm_error(); |
439 _repository.on_vm_error(); |
518 } |
440 } |
519 } |
441 } |
520 |
442 |
521 void JfrRecorderService::rotate(int msgs) { |
443 void JfrRecorderService::rotate(int msgs) { |
522 RotationLock rl(Thread::current()); |
444 assert(!JfrStream_lock->owned_by_self(), "invariant"); |
523 if (rl.not_acquired()) { |
445 MutexLocker lock(JfrStream_lock); |
524 return; |
|
525 } |
|
526 static bool vm_error = false; |
446 static bool vm_error = false; |
527 if (msgs & MSGBIT(MSG_VM_ERROR)) { |
447 if (msgs & MSGBIT(MSG_VM_ERROR)) { |
528 vm_error = true; |
448 vm_error = true; |
529 prepare_for_vm_error_rotation(); |
449 prepare_for_vm_error_rotation(); |
530 } |
450 } |
539 stop(); |
459 stop(); |
540 } |
460 } |
541 } |
461 } |
542 |
462 |
543 void JfrRecorderService::in_memory_rotation() { |
463 void JfrRecorderService::in_memory_rotation() { |
|
464 assert(JfrStream_lock->owned_by_self(), "invariant"); |
544 // currently running an in-memory recording |
465 // currently running an in-memory recording |
545 assert(!_storage.control().to_disk(), "invariant"); |
466 assert(!_storage.control().to_disk(), "invariant"); |
546 open_new_chunk(); |
467 open_new_chunk(); |
547 if (_chunkwriter.is_valid()) { |
468 if (_chunkwriter.is_valid()) { |
548 // dump all in-memory buffer data to the newly created chunk |
469 // dump all in-memory buffer data to the newly created chunk |
549 write_storage(_storage, _chunkwriter); |
470 write_storage(_storage, _chunkwriter); |
550 } |
471 } |
551 } |
472 } |
552 |
473 |
553 void JfrRecorderService::chunk_rotation() { |
474 void JfrRecorderService::chunk_rotation() { |
|
475 assert(JfrStream_lock->owned_by_self(), "invariant"); |
554 finalize_current_chunk(); |
476 finalize_current_chunk(); |
555 open_new_chunk(); |
477 open_new_chunk(); |
556 } |
478 } |
557 |
479 |
558 void JfrRecorderService::finalize_current_chunk() { |
480 void JfrRecorderService::finalize_current_chunk() { |
568 post_safepoint_write(); |
490 post_safepoint_write(); |
569 } |
491 } |
570 |
492 |
571 void JfrRecorderService::pre_safepoint_write() { |
493 void JfrRecorderService::pre_safepoint_write() { |
572 assert(_chunkwriter.is_valid(), "invariant"); |
494 assert(_chunkwriter.is_valid(), "invariant"); |
573 if (_stack_trace_repository.is_modified()) { |
|
574 write_stacktrace(_stack_trace_repository, _chunkwriter, false); |
|
575 } |
|
576 if (_string_pool.is_modified()) { |
|
577 write_stringpool(_string_pool, _chunkwriter); |
|
578 } |
|
579 if (LeakProfiler::is_running()) { |
495 if (LeakProfiler::is_running()) { |
580 // Exclusive access to the object sampler instance. |
496 // Exclusive access to the object sampler instance. |
581 // The sampler is released (unlocked) later in post_safepoint_write. |
497 // The sampler is released (unlocked) later in post_safepoint_write. |
582 ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire(), _stack_trace_repository); |
498 ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire(), _stack_trace_repository); |
583 } |
499 } |
|
500 if (_string_pool.is_modified()) { |
|
501 write_stringpool(_string_pool, _chunkwriter); |
|
502 } |
584 write_storage(_storage, _chunkwriter); |
503 write_storage(_storage, _chunkwriter); |
|
504 if (_stack_trace_repository.is_modified()) { |
|
505 write_stacktrace(_stack_trace_repository, _chunkwriter, false); |
|
506 } |
585 } |
507 } |
586 |
508 |
587 void JfrRecorderService::invoke_safepoint_write() { |
509 void JfrRecorderService::invoke_safepoint_write() { |
588 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this); |
510 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this); |
589 VMThread::execute(&safepoint_task); |
511 VMThread::execute(&safepoint_task); |
590 } |
512 } |
591 |
513 |
592 void JfrRecorderService::safepoint_write() { |
514 void JfrRecorderService::safepoint_write() { |
593 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
515 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
594 write_stacktrace(_stack_trace_repository, _chunkwriter, true); |
|
595 if (_string_pool.is_modified()) { |
516 if (_string_pool.is_modified()) { |
596 write_stringpool_safepoint(_string_pool, _chunkwriter); |
517 write_stringpool_safepoint(_string_pool, _chunkwriter); |
597 } |
518 } |
|
519 _checkpoint_manager.on_rotation(); |
598 _storage.write_at_safepoint(); |
520 _storage.write_at_safepoint(); |
599 _checkpoint_manager.on_rotation(); |
521 _checkpoint_manager.shift_epoch(); |
600 _chunkwriter.set_time_stamp(); |
522 _chunkwriter.set_time_stamp(); |
|
523 write_stacktrace(_stack_trace_repository, _chunkwriter, true); |
601 } |
524 } |
602 |
525 |
603 void JfrRecorderService::post_safepoint_write() { |
526 void JfrRecorderService::post_safepoint_write() { |
604 assert(_chunkwriter.is_valid(), "invariant"); |
527 assert(_chunkwriter.is_valid(), "invariant"); |
605 // During the safepoint tasks just completed, the system transitioned to a new epoch. |
528 // During the safepoint tasks just completed, the system transitioned to a new epoch. |
641 reset_buffer(buffer, t); |
564 reset_buffer(buffer, t); |
642 } |
565 } |
643 } |
566 } |
644 |
567 |
645 size_t JfrRecorderService::flush() { |
568 size_t JfrRecorderService::flush() { |
|
569 assert(JfrStream_lock->owned_by_self(), "invariant"); |
646 size_t total_elements = flush_metadata(_chunkwriter); |
570 size_t total_elements = flush_metadata(_chunkwriter); |
647 const size_t storage_elements = flush_storage(_storage, _chunkwriter); |
571 const size_t storage_elements = flush_storage(_storage, _chunkwriter); |
648 if (0 == storage_elements) { |
572 if (0 == storage_elements) { |
649 return total_elements; |
573 return total_elements; |
650 } |
574 } |
651 total_elements += storage_elements; |
575 total_elements += storage_elements; |
|
576 if (_string_pool.is_modified()) { |
|
577 total_elements += flush_stringpool(_string_pool, _chunkwriter); |
|
578 } |
652 if (_stack_trace_repository.is_modified()) { |
579 if (_stack_trace_repository.is_modified()) { |
653 total_elements += flush_stacktrace(_stack_trace_repository, _chunkwriter); |
580 total_elements += flush_stacktrace(_stack_trace_repository, _chunkwriter); |
654 } |
|
655 if (_string_pool.is_modified()) { |
|
656 total_elements += flush_stringpool(_string_pool, _chunkwriter); |
|
657 } |
581 } |
658 if (_checkpoint_manager.is_type_set_required()) { |
582 if (_checkpoint_manager.is_type_set_required()) { |
659 total_elements += flush_typeset(_checkpoint_manager, _chunkwriter); |
583 total_elements += flush_typeset(_checkpoint_manager, _chunkwriter); |
660 } else if (_checkpoint_manager.is_static_type_set_required()) { |
584 } else if (_checkpoint_manager.is_static_type_set_required()) { |
661 // don't tally this, it is only in order to flush the waiting constants |
585 // don't tally this, it is only in order to flush the waiting constants |
665 } |
589 } |
666 |
590 |
667 typedef Content<EventFlush, JfrRecorderService, &JfrRecorderService::flush> FlushFunctor; |
591 typedef Content<EventFlush, JfrRecorderService, &JfrRecorderService::flush> FlushFunctor; |
668 typedef WriteContent<FlushFunctor> Flush; |
592 typedef WriteContent<FlushFunctor> Flush; |
669 |
593 |
670 void JfrRecorderService::invoke_flush(Thread* t) { |
594 void JfrRecorderService::invoke_flush() { |
671 assert(t != NULL, "invariant"); |
595 assert(JfrStream_lock->owned_by_self(), "invariant"); |
672 assert(_chunkwriter.is_valid(), "invariant"); |
596 assert(_chunkwriter.is_valid(), "invariant"); |
|
597 Thread* const t = Thread::current(); |
673 ResourceMark rm(t); |
598 ResourceMark rm(t); |
674 HandleMark hm(t); |
599 HandleMark hm(t); |
675 ++flushpoint_id; |
600 ++flushpoint_id; |
676 reset_thread_local_buffer(t); |
601 reset_thread_local_buffer(t); |
677 FlushFunctor flushpoint(*this); |
602 FlushFunctor flushpoint(*this); |
680 write_thread_local_buffer(_chunkwriter, t); |
605 write_thread_local_buffer(_chunkwriter, t); |
681 _repository.flush_chunk(); |
606 _repository.flush_chunk(); |
682 } |
607 } |
683 |
608 |
684 void JfrRecorderService::flushpoint() { |
609 void JfrRecorderService::flushpoint() { |
685 Thread* const t = Thread::current(); |
610 MutexLocker lock(JfrStream_lock); |
686 RotationLock rl(t); |
611 invoke_flush(); |
687 if (rl.not_acquired() || !_chunkwriter.is_valid()) { |
|
688 return; |
|
689 } |
|
690 invoke_flush(t); |
|
691 } |
612 } |
692 |
613 |
693 void JfrRecorderService::process_full_buffers() { |
614 void JfrRecorderService::process_full_buffers() { |
694 if (_chunkwriter.is_valid()) { |
615 if (_chunkwriter.is_valid()) { |
695 _storage.write_full(); |
616 _storage.write_full(); |