128 } |
132 } |
129 } |
133 } |
130 bool not_acquired() const { return !_acquired; } |
134 bool not_acquired() const { return !_acquired; } |
131 }; |
135 }; |
132 |
136 |
|
137 template <typename E, typename Instance, size_t(Instance::*func)()> |
|
138 class ServiceFunctor { |
|
139 private: |
|
140 Instance& _instance; |
|
141 u4 _elements; |
|
142 public: |
|
143 typedef E EventType; |
|
144 ServiceFunctor(Instance& instance) : _instance(instance), _elements(0) {} |
|
145 bool process() { |
|
146 _elements = (u4)(_instance.*func)(); |
|
147 return true; |
|
148 } |
|
149 u4 elements() const { return _elements; } |
|
150 }; |
|
151 |
|
152 template <typename ContentFunctor> |
|
153 class WriteSubsystem : public StackObj { |
|
154 protected: |
|
155 const JfrTicks _start_time; |
|
156 JfrTicks _end_time; |
|
157 JfrChunkWriter& _cw; |
|
158 ContentFunctor& _content_functor; |
|
159 const int64_t _start_offset; |
|
160 public: |
|
161 typedef typename ContentFunctor::EventType EventType; |
|
162 |
|
163 WriteSubsystem(JfrChunkWriter& cw, ContentFunctor& functor) : |
|
164 _start_time(JfrTicks::now()), |
|
165 _end_time(), |
|
166 _cw(cw), |
|
167 _content_functor(functor), |
|
168 _start_offset(_cw.current_offset()) { |
|
169 assert(_cw.is_valid(), "invariant"); |
|
170 } |
|
171 |
|
172 bool process() { |
|
173 // invocation |
|
174 _content_functor.process(); |
|
175 _end_time = JfrTicks::now(); |
|
176 return 0 != _content_functor.elements(); |
|
177 } |
|
178 |
|
179 const JfrTicks& start_time() const { |
|
180 return _start_time; |
|
181 } |
|
182 |
|
183 const JfrTicks& end_time() const { |
|
184 return _end_time; |
|
185 } |
|
186 |
|
187 int64_t start_offset() const { |
|
188 return _start_offset; |
|
189 } |
|
190 |
|
191 int64_t end_offset() const { |
|
192 return current_offset(); |
|
193 } |
|
194 |
|
195 int64_t current_offset() const { |
|
196 return _cw.current_offset(); |
|
197 } |
|
198 |
|
199 u4 elements() const { |
|
200 return (u4) _content_functor.elements(); |
|
201 } |
|
202 |
|
203 u4 size() const { |
|
204 return (u4)(end_offset() - start_offset()); |
|
205 } |
|
206 |
|
207 static bool is_event_enabled() { |
|
208 return EventType::is_enabled(); |
|
209 } |
|
210 |
|
211 static u8 event_id() { |
|
212 return EventType::eventId; |
|
213 } |
|
214 |
|
215 void write_elements(int64_t offset) { |
|
216 _cw.write_padded_at_offset<u4>(elements(), offset); |
|
217 } |
|
218 |
|
219 void write_size() { |
|
220 _cw.write_padded_at_offset<u4>(size(), start_offset()); |
|
221 } |
|
222 |
|
223 void set_last_checkpoint() { |
|
224 _cw.set_last_checkpoint_offset(start_offset()); |
|
225 } |
|
226 |
|
227 void rewind() { |
|
228 _cw.seek(start_offset()); |
|
229 } |
|
230 |
|
231 }; |
|
232 |
133 static int64_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) { |
233 static int64_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) { |
134 const int64_t prev_cp_offset = cw.previous_checkpoint_offset(); |
234 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(); |
235 const int64_t last_cp_relative_offset = 0 == last_cp_offset ? 0 : last_cp_offset - cw.current_offset(); |
136 cw.reserve(sizeof(u4)); |
236 cw.reserve(sizeof(u4)); |
137 cw.write<u8>(EVENT_CHECKPOINT); |
237 cw.write<u8>(EVENT_CHECKPOINT); |
138 cw.write(JfrTicks::now()); |
238 cw.write(JfrTicks::now()); |
139 cw.write((int64_t)0); |
239 cw.write<int64_t>((int64_t)0); |
140 cw.write(prev_cp_relative_offset); // write previous checkpoint offset delta |
240 cw.write(last_cp_relative_offset); // write last checkpoint offset delta |
141 cw.write<bool>(false); // flushpoint |
241 cw.write<bool>(false); // flushpoint |
142 cw.write((u4)1); // nof types in this checkpoint |
242 cw.write<u4>((u4)1); // nof types in this checkpoint |
143 cw.write(type_id); |
243 cw.write<u8>(type_id); |
144 const int64_t number_of_elements_offset = cw.current_offset(); |
244 const int64_t number_of_elements_offset = cw.current_offset(); |
145 cw.reserve(sizeof(u4)); |
245 cw.reserve(sizeof(u4)); |
146 return number_of_elements_offset; |
246 return number_of_elements_offset; |
147 } |
247 } |
148 |
248 |
149 template <typename ContentFunctor> |
249 template <typename ContentFunctor> |
150 class WriteCheckpointEvent : public StackObj { |
250 class WriteSubsystemCheckpointEvent : public WriteSubsystem<ContentFunctor> { |
151 private: |
251 private: |
152 JfrChunkWriter& _cw; |
252 const u8 _type_id; |
153 u8 _type_id; |
|
154 ContentFunctor& _content_functor; |
|
155 public: |
253 public: |
156 WriteCheckpointEvent(JfrChunkWriter& cw, u8 type_id, ContentFunctor& functor) : |
254 WriteSubsystemCheckpointEvent(JfrChunkWriter& cw, ContentFunctor& functor, u8 type_id) : |
157 _cw(cw), |
255 WriteSubsystem<ContentFunctor>(cw, functor), _type_id(type_id) {} |
158 _type_id(type_id), |
256 |
159 _content_functor(functor) { |
|
160 assert(_cw.is_valid(), "invariant"); |
|
161 } |
|
162 bool process() { |
257 bool process() { |
163 // current_cp_offset is also offset for the event size header field |
258 const int64_t num_elements_offset = write_checkpoint_event_prologue(this->_cw, _type_id); |
164 const int64_t current_cp_offset = _cw.current_offset(); |
259 if (!WriteSubsystem<ContentFunctor>::process()) { |
165 const int64_t num_elements_offset = write_checkpoint_event_prologue(_cw, _type_id); |
|
166 // invocation |
|
167 _content_functor.process(); |
|
168 const u4 number_of_elements = (u4)_content_functor.processed(); |
|
169 if (number_of_elements == 0) { |
|
170 // nothing to do, rewind writer to start |
260 // nothing to do, rewind writer to start |
171 _cw.seek(current_cp_offset); |
261 this->rewind(); |
172 return true; |
262 assert(this->current_offset() == this->start_offset(), "invariant"); |
|
263 return false; |
173 } |
264 } |
174 assert(number_of_elements > 0, "invariant"); |
265 assert(this->elements() > 0, "invariant"); |
175 assert(_cw.current_offset() > num_elements_offset, "invariant"); |
266 assert(this->current_offset() > num_elements_offset, "invariant"); |
176 _cw.write_padded_at_offset<u4>(number_of_elements, num_elements_offset); |
267 this->write_elements(num_elements_offset); |
177 _cw.write_padded_at_offset<u4>((u4)_cw.current_offset() - current_cp_offset, current_cp_offset); |
268 this->write_size(); |
178 // update writer with last checkpoint position |
269 this->set_last_checkpoint(); |
179 _cw.set_previous_checkpoint_offset(current_cp_offset); |
|
180 return true; |
270 return true; |
181 } |
271 } |
182 }; |
272 }; |
183 |
273 |
184 template <typename Instance, size_t(Instance::*func)()> |
274 template <typename Functor> |
185 class ServiceFunctor { |
275 static void write_flush_event(Functor& f) { |
186 private: |
276 if (!Functor::is_event_enabled()) { |
187 Instance& _instance; |
277 return; |
188 size_t _processed; |
278 } |
189 public: |
279 typename Functor::EventType e(UNTIMED); |
190 ServiceFunctor(Instance& instance) : _instance(instance), _processed(0) {} |
280 e.set_starttime(f.start_time()); |
191 bool process() { |
281 e.set_endtime(f.end_time()); |
192 _processed = (_instance.*func)(); |
282 e.set_flushId(flushpoint_id); |
193 return true; |
283 e.set_elements(f.elements()); |
194 } |
284 e.set_size(f.size()); |
195 size_t processed() const { return _processed; } |
285 e.commit(); |
196 }; |
286 } |
|
287 |
|
288 template <typename Functor> |
|
289 static u4 invoke(Functor& f) { |
|
290 f.process(); |
|
291 return f.elements(); |
|
292 } |
|
293 |
|
294 template <typename Functor> |
|
295 static u4 invoke_with_flush_event(Functor& f) { |
|
296 const u4 elements = invoke(f); |
|
297 if (elements != 0) { |
|
298 write_flush_event(f); |
|
299 } |
|
300 return elements; |
|
301 } |
197 |
302 |
198 template <typename Instance, void(Instance::*func)()> |
303 template <typename Instance, void(Instance::*func)()> |
199 class JfrVMOperation : public VM_Operation { |
304 class JfrVMOperation : public VM_Operation { |
200 private: |
305 private: |
201 Instance& _instance; |
306 Instance& _instance; |
336 } |
454 } |
337 _checkpoint_manager.register_service_thread(Thread::current()); |
455 _checkpoint_manager.register_service_thread(Thread::current()); |
338 } |
456 } |
339 |
457 |
340 void JfrRecorderService::open_new_chunk(bool vm_error) { |
458 void JfrRecorderService::open_new_chunk(bool vm_error) { |
341 assert(!_chunkwriter.is_valid(), "invariant"); |
|
342 assert(!JfrStream_lock->owned_by_self(), "invariant"); |
|
343 JfrChunkRotation::on_rotation(); |
459 JfrChunkRotation::on_rotation(); |
344 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
460 const bool valid_chunk = _repository.open_chunk(vm_error); |
345 if (!_repository.open_chunk(vm_error)) { |
461 _storage.control().set_to_disk(valid_chunk); |
346 assert(!_chunkwriter.is_valid(), "invariant"); |
462 if (valid_chunk) { |
347 _storage.control().set_to_disk(false); |
463 _checkpoint_manager.write_constants(); |
348 return; |
464 } |
349 } |
|
350 assert(_chunkwriter.is_valid(), "invariant"); |
|
351 _storage.control().set_to_disk(true); |
|
352 } |
465 } |
353 |
466 |
354 void JfrRecorderService::in_memory_rotation() { |
467 void JfrRecorderService::in_memory_rotation() { |
355 assert(!_chunkwriter.is_valid(), "invariant"); |
|
356 // currently running an in-memory recording |
468 // currently running an in-memory recording |
|
469 assert(!_storage.control().to_disk(), "invariant"); |
357 open_new_chunk(); |
470 open_new_chunk(); |
358 if (_chunkwriter.is_valid()) { |
471 if (_chunkwriter.is_valid()) { |
359 // dump all in-memory buffer data to the newly created chunk |
472 // dump all in-memory buffer data to the newly created chunk |
360 serialize_storage_from_in_memory_recording(); |
473 serialize_storage_from_in_memory_recording(); |
361 } |
474 } |
362 } |
475 } |
363 |
476 |
364 void JfrRecorderService::serialize_storage_from_in_memory_recording() { |
477 void JfrRecorderService::serialize_storage_from_in_memory_recording() { |
365 assert(!JfrStream_lock->owned_by_self(), "not holding stream lock!"); |
|
366 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
|
367 _storage.write(); |
478 _storage.write(); |
368 } |
479 } |
369 |
480 |
370 void JfrRecorderService::chunk_rotation() { |
481 void JfrRecorderService::chunk_rotation() { |
371 finalize_current_chunk(); |
482 finalize_current_chunk(); |
373 } |
484 } |
374 |
485 |
375 void JfrRecorderService::finalize_current_chunk() { |
486 void JfrRecorderService::finalize_current_chunk() { |
376 assert(_chunkwriter.is_valid(), "invariant"); |
487 assert(_chunkwriter.is_valid(), "invariant"); |
377 write(); |
488 write(); |
378 assert(!_chunkwriter.is_valid(), "invariant"); |
|
379 } |
489 } |
380 |
490 |
381 void JfrRecorderService::write() { |
491 void JfrRecorderService::write() { |
382 ResourceMark rm; |
492 ResourceMark rm; |
383 HandleMark hm; |
493 HandleMark hm; |
384 pre_safepoint_write(); |
494 pre_safepoint_write(); |
385 invoke_safepoint_write(); |
495 invoke_safepoint_write(); |
386 post_safepoint_write(); |
496 post_safepoint_write(); |
387 } |
497 } |
388 |
498 |
389 typedef ServiceFunctor<JfrStringPool, &JfrStringPool::write> WriteStringPool; |
499 typedef ServiceFunctor<EventFlushStringPool, JfrStringPool, &JfrStringPool::write> FlushStringPoolFunctor; |
390 typedef ServiceFunctor<JfrStringPool, &JfrStringPool::write_at_safepoint> WriteStringPoolSafepoint; |
500 typedef ServiceFunctor<EventFlushStringPool, JfrStringPool, &JfrStringPool::write_at_safepoint> FlushStringPoolSafepointFunctor; |
391 typedef WriteCheckpointEvent<WriteStackTraceRepository> WriteStackTraceCheckpoint; |
501 typedef WriteSubsystemCheckpointEvent<FlushStackTraceRepository> FlushStackTraceCheckpoint; |
392 typedef WriteCheckpointEvent<WriteStringPool> WriteStringPoolCheckpoint; |
502 typedef WriteSubsystemCheckpointEvent<FlushStringPoolFunctor> FlushStringPoolCheckpoint; |
393 typedef WriteCheckpointEvent<WriteStringPoolSafepoint> WriteStringPoolCheckpointSafepoint; |
503 typedef WriteSubsystemCheckpointEvent<FlushStringPoolSafepointFunctor> FlushStringPoolCheckpointSafepoint; |
394 |
504 |
395 static void write_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) { |
505 static u4 flush_stacktrace(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) { |
396 WriteStackTraceRepository write_stacktrace_repo(stack_trace_repo, chunkwriter, clear); |
506 FlushStackTraceRepository flush_stacktrace_repo(stack_trace_repo, chunkwriter, clear); |
397 WriteStackTraceCheckpoint write_stack_trace_checkpoint(chunkwriter, TYPE_STACKTRACE, write_stacktrace_repo); |
507 FlushStackTraceCheckpoint flush_stack_trace_checkpoint(chunkwriter, flush_stacktrace_repo, TYPE_STACKTRACE); |
398 write_stack_trace_checkpoint.process(); |
508 return invoke_with_flush_event(flush_stack_trace_checkpoint); |
399 } |
509 } |
400 |
510 |
401 static void write_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
511 static u4 flush_stacktrace(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter) { |
402 WriteStringPool write_string_pool(string_pool); |
512 return flush_stacktrace(stack_trace_repo, chunkwriter, false); |
403 WriteStringPoolCheckpoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool); |
513 } |
404 write_string_pool_checkpoint.process(); |
514 |
405 } |
515 static u4 flush_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) { |
406 |
516 FlushStackTraceRepository flush_stacktrace_repo(stack_trace_repo, chunkwriter, clear); |
407 static void write_stringpool_checkpoint_safepoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
517 FlushStackTraceCheckpoint flush_stack_trace_checkpoint(chunkwriter, flush_stacktrace_repo, TYPE_STACKTRACE); |
408 WriteStringPoolSafepoint write_string_pool(string_pool); |
518 return invoke(flush_stack_trace_checkpoint); |
409 WriteStringPoolCheckpointSafepoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool); |
519 } |
410 write_string_pool_checkpoint.process(); |
520 |
|
521 static u4 flush_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
|
522 FlushStringPoolFunctor flush_string_pool(string_pool); |
|
523 FlushStringPoolCheckpoint flush_string_pool_checkpoint(chunkwriter, flush_string_pool, TYPE_STRING); |
|
524 return invoke_with_flush_event(flush_string_pool_checkpoint); |
|
525 } |
|
526 |
|
527 static u4 flush_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
|
528 FlushStringPoolFunctor flush_string_pool(string_pool); |
|
529 FlushStringPoolCheckpoint flush_string_pool_checkpoint(chunkwriter, flush_string_pool, TYPE_STRING); |
|
530 return invoke(flush_string_pool_checkpoint); |
|
531 } |
|
532 |
|
533 static u4 flush_stringpool_checkpoint_safepoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
|
534 FlushStringPoolSafepointFunctor flush_string_pool(string_pool); |
|
535 FlushStringPoolCheckpointSafepoint flush_string_pool_checkpoint(chunkwriter, flush_string_pool, TYPE_STRING); |
|
536 return invoke(flush_string_pool_checkpoint); |
|
537 } |
|
538 |
|
539 typedef ServiceFunctor<EventFlushTypeSet, JfrCheckpointManager, &JfrCheckpointManager::flush_type_set> FlushTypeSetFunctor; |
|
540 typedef WriteSubsystem<FlushTypeSetFunctor> FlushTypeSet; |
|
541 |
|
542 static u4 flush_typeset(JfrCheckpointManager& checkpoint_manager, JfrChunkWriter& chunkwriter) { |
|
543 FlushTypeSetFunctor flush_type_set(checkpoint_manager); |
|
544 FlushTypeSet fts(chunkwriter, flush_type_set); |
|
545 return invoke_with_flush_event(fts); |
|
546 } |
|
547 |
|
548 typedef WriteSubsystem<FlushMetadataEvent> FlushMetadata; |
|
549 |
|
550 static u4 flush_metadata_event(JfrChunkWriter& chunkwriter) { |
|
551 assert(chunkwriter.is_valid(), "invariant"); |
|
552 FlushMetadataEvent fme(chunkwriter); |
|
553 FlushMetadata fm(chunkwriter, fme); |
|
554 return invoke_with_flush_event(fm); |
|
555 } |
|
556 |
|
557 static u4 flush_metadata_event_checkpoint(JfrChunkWriter& chunkwriter) { |
|
558 assert(chunkwriter.is_valid(), "invariant"); |
|
559 FlushMetadataEvent wme(chunkwriter); |
|
560 FlushMetadata wm(chunkwriter, wme); |
|
561 return invoke(wm); |
|
562 } |
|
563 |
|
564 static JfrBuffer* thread_local_buffer() { |
|
565 return Thread::current()->jfr_thread_local()->native_buffer(); |
|
566 } |
|
567 |
|
568 static void reset_buffer(JfrBuffer* buffer) { |
|
569 assert(buffer != NULL, "invariant"); |
|
570 assert(buffer == thread_local_buffer(), "invariant"); |
|
571 buffer->set_pos(const_cast<u1*>(buffer->top())); |
|
572 assert(buffer->empty(), "invariant"); |
|
573 } |
|
574 |
|
575 static void reset_thread_local_buffer() { |
|
576 reset_buffer(thread_local_buffer()); |
|
577 } |
|
578 |
|
579 static void write_thread_local_buffer(JfrChunkWriter& chunkwriter) { |
|
580 JfrBuffer * const buffer = thread_local_buffer(); |
|
581 assert(buffer != NULL, "invariant"); |
|
582 if (!buffer->empty()) { |
|
583 chunkwriter.write_unbuffered(buffer->top(), buffer->pos() - buffer->top()); |
|
584 reset_buffer(buffer); |
|
585 } |
|
586 assert(buffer->empty(), "invariant"); |
|
587 } |
|
588 |
|
589 typedef ServiceFunctor<EventFlushStorage, JfrStorage, &JfrStorage::write> FlushStorageFunctor; |
|
590 typedef WriteSubsystem<FlushStorageFunctor> FlushStorage; |
|
591 |
|
592 static size_t flush_storage(JfrStorage& storage, JfrChunkWriter& chunkwriter) { |
|
593 assert(chunkwriter.is_valid(), "invariant"); |
|
594 FlushStorageFunctor fsf(storage); |
|
595 FlushStorage fs(chunkwriter, fsf); |
|
596 return invoke_with_flush_event(fs); |
|
597 } |
|
598 |
|
599 typedef ServiceFunctor<EventFlush, JfrRecorderService, &JfrRecorderService::flush> FlushFunctor; |
|
600 typedef WriteSubsystem<FlushFunctor> Flush; |
|
601 |
|
602 static bool write_metadata_in_flushpoint = false; |
|
603 |
|
604 size_t JfrRecorderService::flush() { |
|
605 size_t total_elements = 0; |
|
606 if (write_metadata_in_flushpoint) { |
|
607 total_elements = flush_metadata_event(_chunkwriter); |
|
608 } |
|
609 const size_t storage_elements = flush_storage(_storage, _chunkwriter); |
|
610 if (0 == storage_elements) { |
|
611 return total_elements; |
|
612 } |
|
613 total_elements += storage_elements; |
|
614 total_elements += flush_stacktrace(_stack_trace_repository, _chunkwriter); |
|
615 if (_string_pool.modified()) { |
|
616 total_elements += flush_stringpool(_string_pool, _chunkwriter); |
|
617 } |
|
618 total_elements += flush_typeset(_checkpoint_manager, _chunkwriter); |
|
619 return total_elements; |
|
620 } |
|
621 |
|
622 void JfrRecorderService::flush(int msgs) { |
|
623 assert(_chunkwriter.is_valid(), "invariant"); |
|
624 ResourceMark rm; |
|
625 HandleMark hm; |
|
626 reset_thread_local_buffer(); |
|
627 ++flushpoint_id; |
|
628 write_metadata_in_flushpoint = (msgs & MSGBIT(MSG_FLUSHPOINT_METADATA)); |
|
629 FlushFunctor flushpoint(*this); |
|
630 Flush fl(_chunkwriter, flushpoint); |
|
631 invoke_with_flush_event(fl); |
|
632 write_thread_local_buffer(_chunkwriter); |
|
633 _repository.flush_chunk(); |
411 } |
634 } |
412 |
635 |
413 // |
636 // |
414 // pre-safepoint write sequence |
637 // pre-safepoint write sequence |
415 // |
638 // |
416 // lock stream lock -> |
639 // write checkpoint epoch transition list-> |
417 // write non-safepoint dependent types -> |
640 // write stack trace checkpoint -> |
418 // write checkpoint epoch transition list-> |
641 // write string pool checkpoint -> |
419 // write stack trace checkpoint -> |
642 // notify about pending rotation -> |
420 // write string pool checkpoint -> |
643 // write storage |
421 // write storage -> |
|
422 // release stream lock |
|
423 // |
644 // |
424 void JfrRecorderService::pre_safepoint_write() { |
645 void JfrRecorderService::pre_safepoint_write() { |
425 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
|
426 assert(_chunkwriter.is_valid(), "invariant"); |
646 assert(_chunkwriter.is_valid(), "invariant"); |
427 _checkpoint_manager.write_types(); |
|
428 _checkpoint_manager.write_epoch_transition_mspace(); |
647 _checkpoint_manager.write_epoch_transition_mspace(); |
429 write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, false); |
648 flush_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, false); |
430 write_stringpool_checkpoint(_string_pool, _chunkwriter); |
649 if (_string_pool.modified()) { |
|
650 flush_stringpool_checkpoint(_string_pool, _chunkwriter); |
|
651 } |
|
652 _checkpoint_manager.notify_types_on_rotation(); |
431 _storage.write(); |
653 _storage.write(); |
432 } |
654 } |
433 |
655 |
434 void JfrRecorderService::invoke_safepoint_write() { |
656 void JfrRecorderService::invoke_safepoint_write() { |
435 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this); |
657 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this); |
442 } |
664 } |
443 |
665 |
444 // |
666 // |
445 // safepoint write sequence |
667 // safepoint write sequence |
446 // |
668 // |
447 // lock stream lock -> |
669 // write object sample stacktraces -> |
448 // write object sample stacktraces -> |
670 // write stacktrace repository -> |
449 // write stacktrace repository -> |
671 // write string pool -> |
450 // write string pool -> |
672 // write storage -> |
451 // write safepoint dependent types -> |
673 // notify java threads -> |
452 // write storage -> |
674 // shift_epoch -> |
453 // shift_epoch -> |
675 // update time |
454 // update time -> |
|
455 // lock metadata descriptor -> |
|
456 // release stream lock |
|
457 // |
676 // |
458 void JfrRecorderService::safepoint_write() { |
677 void JfrRecorderService::safepoint_write() { |
459 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
678 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
460 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
|
461 write_object_sample_stacktrace(_stack_trace_repository); |
679 write_object_sample_stacktrace(_stack_trace_repository); |
462 write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, true); |
680 flush_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, true); |
463 write_stringpool_checkpoint_safepoint(_string_pool, _chunkwriter); |
681 if (_string_pool.modified()) { |
464 _checkpoint_manager.write_safepoint_types(); |
682 flush_stringpool_checkpoint_safepoint(_string_pool, _chunkwriter); |
|
683 } |
465 _storage.write_at_safepoint(); |
684 _storage.write_at_safepoint(); |
|
685 _checkpoint_manager.notify_threads(); |
466 _checkpoint_manager.shift_epoch(); |
686 _checkpoint_manager.shift_epoch(); |
467 _chunkwriter.time_stamp_chunk_now(); |
687 _chunkwriter.time_stamp_chunk_now(); |
468 JfrMetadataEvent::lock(); |
|
469 } |
|
470 |
|
471 static int64_t write_metadata_event(JfrChunkWriter& chunkwriter) { |
|
472 assert(chunkwriter.is_valid(), "invariant"); |
|
473 const int64_t metadata_offset = chunkwriter.current_offset(); |
|
474 JfrMetadataEvent::write(chunkwriter, metadata_offset); |
|
475 return metadata_offset; |
|
476 } |
688 } |
477 |
689 |
478 // |
690 // |
479 // post-safepoint write sequence |
691 // post-safepoint write sequence |
480 // |
692 // |
481 // lock stream lock -> |
693 // write type set -> |
482 // write type set -> |
694 // write checkpoints -> |
483 // write checkpoints -> |
695 // write metadata event -> |
484 // write metadata event -> |
696 // close chunk |
485 // write chunk header -> |
|
486 // close chunk fd -> |
|
487 // release stream lock |
|
488 // |
697 // |
489 void JfrRecorderService::post_safepoint_write() { |
698 void JfrRecorderService::post_safepoint_write() { |
490 assert(_chunkwriter.is_valid(), "invariant"); |
699 assert(_chunkwriter.is_valid(), "invariant"); |
491 // During the safepoint tasks just completed, the system transitioned to a new epoch. |
700 // 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 |
701 // 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 |
702 // 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. |
703 // 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(); |
704 _checkpoint_manager.write_type_set(); |
496 MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag); |
|
497 // serialize any outstanding checkpoint memory |
705 // serialize any outstanding checkpoint memory |
498 _checkpoint_manager.write(); |
706 _checkpoint_manager.write(); |
499 // serialize the metadata descriptor event and close out the chunk |
707 // serialize the metadata descriptor event and close out the chunk |
500 _repository.close_chunk(write_metadata_event(_chunkwriter)); |
708 flush_metadata_event_checkpoint(_chunkwriter); |
501 assert(!_chunkwriter.is_valid(), "invariant"); |
709 _repository.close_chunk(); |
502 } |
710 } |
503 |
711 |
504 void JfrRecorderService::vm_error_rotation() { |
712 void JfrRecorderService::vm_error_rotation() { |
505 if (_chunkwriter.is_valid()) { |
713 if (_chunkwriter.is_valid()) { |
506 finalize_current_chunk_on_vm_error(); |
714 finalize_current_chunk_on_vm_error(); |