135 } |
135 } |
136 bool not_acquired() const { return !_acquired; } |
136 bool not_acquired() const { return !_acquired; } |
137 }; |
137 }; |
138 |
138 |
139 template <typename E, typename Instance, size_t(Instance::*func)()> |
139 template <typename E, typename Instance, size_t(Instance::*func)()> |
140 class ServiceFunctor { |
140 class Content { |
141 private: |
141 private: |
142 Instance& _instance; |
142 Instance& _instance; |
143 u4 _elements; |
143 u4 _elements; |
144 public: |
144 public: |
145 typedef E EventType; |
145 typedef E EventType; |
146 ServiceFunctor(Instance& instance) : _instance(instance), _elements(0) {} |
146 Content(Instance& instance) : _instance(instance), _elements(0) {} |
147 bool process() { |
147 bool process() { |
148 _elements = (u4)(_instance.*func)(); |
148 _elements = (u4)(_instance.*func)(); |
149 return true; |
149 return true; |
150 } |
150 } |
151 u4 elements() const { return _elements; } |
151 u4 elements() const { return _elements; } |
152 }; |
152 }; |
153 |
153 |
154 template <typename ContentFunctor> |
154 template <typename Content> |
155 class WriteSubsystem : public StackObj { |
155 class WriteContent : public StackObj { |
156 protected: |
156 protected: |
157 const JfrTicks _start_time; |
157 const JfrTicks _start_time; |
158 JfrTicks _end_time; |
158 JfrTicks _end_time; |
159 JfrChunkWriter& _cw; |
159 JfrChunkWriter& _cw; |
160 ContentFunctor& _content_functor; |
160 Content& _content; |
161 const int64_t _start_offset; |
161 const int64_t _start_offset; |
162 public: |
162 public: |
163 typedef typename ContentFunctor::EventType EventType; |
163 typedef typename Content::EventType EventType; |
164 |
164 |
165 WriteSubsystem(JfrChunkWriter& cw, ContentFunctor& functor) : |
165 WriteContent(JfrChunkWriter& cw, Content& content) : |
166 _start_time(JfrTicks::now()), |
166 _start_time(JfrTicks::now()), |
167 _end_time(), |
167 _end_time(), |
168 _cw(cw), |
168 _cw(cw), |
169 _content_functor(functor), |
169 _content(content), |
170 _start_offset(_cw.current_offset()) { |
170 _start_offset(_cw.current_offset()) { |
171 assert(_cw.is_valid(), "invariant"); |
171 assert(_cw.is_valid(), "invariant"); |
172 } |
172 } |
173 |
173 |
174 bool process() { |
174 bool process() { |
175 // invocation |
175 // invocation |
176 _content_functor.process(); |
176 _content.process(); |
177 _end_time = JfrTicks::now(); |
177 _end_time = JfrTicks::now(); |
178 return 0 != _content_functor.elements(); |
178 return 0 != _content.elements(); |
179 } |
179 } |
180 |
180 |
181 const JfrTicks& start_time() const { |
181 const JfrTicks& start_time() const { |
182 return _start_time; |
182 return _start_time; |
183 } |
183 } |
246 const int64_t number_of_elements_offset = cw.current_offset(); |
245 const int64_t number_of_elements_offset = cw.current_offset(); |
247 cw.reserve(sizeof(u4)); |
246 cw.reserve(sizeof(u4)); |
248 return number_of_elements_offset; |
247 return number_of_elements_offset; |
249 } |
248 } |
250 |
249 |
251 template <typename ContentFunctor> |
250 template <typename Content> |
252 class WriteSubsystemCheckpointEvent : public WriteSubsystem<ContentFunctor> { |
251 class WriteCheckpointEvent : public WriteContent<Content> { |
253 private: |
252 private: |
254 const u8 _type_id; |
253 const u8 _type_id; |
255 public: |
254 public: |
256 WriteSubsystemCheckpointEvent(JfrChunkWriter& cw, ContentFunctor& functor, u8 type_id) : |
255 WriteCheckpointEvent(JfrChunkWriter& cw, Content& content, u8 type_id) : |
257 WriteSubsystem<ContentFunctor>(cw, functor), _type_id(type_id) {} |
256 WriteContent<Content>(cw, content), _type_id(type_id) {} |
258 |
257 |
259 bool process() { |
258 bool process() { |
260 const int64_t num_elements_offset = write_checkpoint_event_prologue(this->_cw, _type_id); |
259 const int64_t num_elements_offset = write_checkpoint_event_prologue(this->_cw, _type_id); |
261 if (!WriteSubsystem<ContentFunctor>::process()) { |
260 if (!WriteContent<Content>::process()) { |
262 // nothing to do, rewind writer to start |
261 // nothing to do, rewind writer to start |
263 this->rewind(); |
262 this->rewind(); |
264 assert(this->current_offset() == this->start_offset(), "invariant"); |
263 assert(this->current_offset() == this->start_offset(), "invariant"); |
265 return false; |
264 return false; |
266 } |
265 } |
285 e.commit(); |
290 e.commit(); |
286 } |
291 } |
287 } |
292 } |
288 |
293 |
289 template <typename Functor> |
294 template <typename Functor> |
290 static u4 invoke(Functor& f) { |
|
291 f.process(); |
|
292 return f.elements(); |
|
293 } |
|
294 |
|
295 template <typename Functor> |
|
296 static u4 invoke_with_flush_event(Functor& f) { |
295 static u4 invoke_with_flush_event(Functor& f) { |
297 const u4 elements = invoke(f); |
296 const u4 elements = invoke(f); |
298 write_flush_event(f); |
297 write_flush_event(f); |
299 return elements; |
298 return elements; |
|
299 } |
|
300 |
|
301 class StackTraceRepository : public StackObj { |
|
302 private: |
|
303 JfrStackTraceRepository& _repo; |
|
304 JfrChunkWriter& _cw; |
|
305 size_t _elements; |
|
306 bool _clear; |
|
307 |
|
308 public: |
|
309 typedef EventFlushStacktrace EventType; |
|
310 StackTraceRepository(JfrStackTraceRepository& repo, JfrChunkWriter& cw, bool clear) : |
|
311 _repo(repo), _cw(cw), _elements(0), _clear(clear) {} |
|
312 bool process() { |
|
313 _elements = _repo.write(_cw, _clear); |
|
314 return true; |
|
315 } |
|
316 size_t elements() const { return _elements; } |
|
317 void reset() { _elements = 0; } |
|
318 }; |
|
319 |
|
320 typedef WriteCheckpointEvent<StackTraceRepository> WriteStackTrace; |
|
321 |
|
322 static u4 flush_stacktrace(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter) { |
|
323 StackTraceRepository str(stack_trace_repo, chunkwriter, false); |
|
324 WriteStackTrace wst(chunkwriter, str, TYPE_STACKTRACE); |
|
325 return invoke_with_flush_event(wst); |
|
326 } |
|
327 |
|
328 static u4 write_stacktrace(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) { |
|
329 StackTraceRepository str(stack_trace_repo, chunkwriter, clear); |
|
330 WriteStackTrace wst(chunkwriter, str, TYPE_STACKTRACE); |
|
331 return invoke(wst); |
|
332 } |
|
333 |
|
334 typedef Content<EventFlushStorage, JfrStorage, &JfrStorage::write> Storage; |
|
335 typedef WriteContent<Storage> WriteStorage; |
|
336 |
|
337 static size_t flush_storage(JfrStorage& storage, JfrChunkWriter& chunkwriter) { |
|
338 assert(chunkwriter.is_valid(), "invariant"); |
|
339 Storage fsf(storage); |
|
340 WriteStorage fs(chunkwriter, fsf); |
|
341 return invoke_with_flush_event(fs); |
|
342 } |
|
343 |
|
344 static size_t write_storage(JfrStorage& storage, JfrChunkWriter& chunkwriter) { |
|
345 assert(chunkwriter.is_valid(), "invariant"); |
|
346 Storage fsf(storage); |
|
347 WriteStorage fs(chunkwriter, fsf); |
|
348 return invoke(fs); |
|
349 } |
|
350 |
|
351 typedef Content<EventFlushStringPool, JfrStringPool, &JfrStringPool::write> StringPool; |
|
352 typedef Content<EventFlushStringPool, JfrStringPool, &JfrStringPool::write_at_safepoint> StringPoolSafepoint; |
|
353 typedef WriteCheckpointEvent<StringPool> WriteStringPool; |
|
354 typedef WriteCheckpointEvent<StringPoolSafepoint> WriteStringPoolSafepoint; |
|
355 |
|
356 static u4 flush_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
|
357 StringPool sp(string_pool); |
|
358 WriteStringPool wsp(chunkwriter, sp, TYPE_STRING); |
|
359 return invoke_with_flush_event(wsp); |
|
360 } |
|
361 |
|
362 static u4 write_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
|
363 StringPool sp(string_pool); |
|
364 WriteStringPool wsp(chunkwriter, sp, TYPE_STRING); |
|
365 return invoke(wsp); |
|
366 } |
|
367 |
|
368 static u4 write_stringpool_safepoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
|
369 StringPoolSafepoint sps(string_pool); |
|
370 WriteStringPoolSafepoint wsps(chunkwriter, sps, TYPE_STRING); |
|
371 return invoke(wsps); |
|
372 } |
|
373 |
|
374 typedef Content<EventFlushTypeSet, JfrCheckpointManager, &JfrCheckpointManager::flush_type_set> FlushTypeSetFunctor; |
|
375 typedef WriteContent<FlushTypeSetFunctor> FlushTypeSet; |
|
376 |
|
377 static u4 flush_typeset(JfrCheckpointManager& checkpoint_manager, JfrChunkWriter& chunkwriter) { |
|
378 FlushTypeSetFunctor flush_type_set(checkpoint_manager); |
|
379 FlushTypeSet fts(chunkwriter, flush_type_set); |
|
380 return invoke_with_flush_event(fts); |
|
381 } |
|
382 |
|
383 class MetadataEvent : public StackObj { |
|
384 private: |
|
385 JfrChunkWriter& _cw; |
|
386 public: |
|
387 typedef EventFlushMetadata EventType; |
|
388 MetadataEvent(JfrChunkWriter& cw) : _cw(cw) {} |
|
389 bool process() { |
|
390 JfrMetadataEvent::write(_cw); |
|
391 return true; |
|
392 } |
|
393 size_t elements() const { return 1; } |
|
394 }; |
|
395 |
|
396 typedef WriteContent<MetadataEvent> WriteMetadata; |
|
397 |
|
398 static u4 flush_metadata(JfrChunkWriter& chunkwriter) { |
|
399 assert(chunkwriter.is_valid(), "invariant"); |
|
400 MetadataEvent me(chunkwriter); |
|
401 WriteMetadata wm(chunkwriter, me); |
|
402 return invoke_with_flush_event(wm); |
|
403 } |
|
404 |
|
405 static u4 write_metadata(JfrChunkWriter& chunkwriter) { |
|
406 assert(chunkwriter.is_valid(), "invariant"); |
|
407 MetadataEvent me(chunkwriter); |
|
408 WriteMetadata wm(chunkwriter, me); |
|
409 return invoke(wm); |
300 } |
410 } |
301 |
411 |
302 template <typename Instance, void(Instance::*func)()> |
412 template <typename Instance, void(Instance::*func)()> |
303 class JfrVMOperation : public VM_Operation { |
413 class JfrVMOperation : public VM_Operation { |
304 private: |
414 private: |
308 void doit() { (_instance.*func)(); } |
418 void doit() { (_instance.*func)(); } |
309 VMOp_Type type() const { return VMOp_JFRCheckpoint; } |
419 VMOp_Type type() const { return VMOp_JFRCheckpoint; } |
310 Mode evaluation_mode() const { return _safepoint; } // default |
420 Mode evaluation_mode() const { return _safepoint; } // default |
311 }; |
421 }; |
312 |
422 |
313 class FlushStackTraceRepository : public StackObj { |
|
314 private: |
|
315 JfrStackTraceRepository& _repo; |
|
316 JfrChunkWriter& _cw; |
|
317 size_t _elements; |
|
318 bool _clear; |
|
319 |
|
320 public: |
|
321 typedef EventFlushStacktrace EventType; |
|
322 FlushStackTraceRepository(JfrStackTraceRepository& repo, JfrChunkWriter& cw, bool clear) : |
|
323 _repo(repo), _cw(cw), _elements(0), _clear(clear) {} |
|
324 bool process() { |
|
325 _elements = _repo.write(_cw, _clear); |
|
326 return true; |
|
327 } |
|
328 size_t elements() const { return _elements; } |
|
329 void reset() { _elements = 0; } |
|
330 }; |
|
331 |
|
332 class FlushMetadataEvent : public StackObj { |
|
333 private: |
|
334 JfrChunkWriter& _cw; |
|
335 public: |
|
336 typedef EventFlushMetadata EventType; |
|
337 FlushMetadataEvent(JfrChunkWriter& cw) : _cw(cw) {} |
|
338 bool process() { |
|
339 JfrMetadataEvent::write(_cw); |
|
340 return true; |
|
341 } |
|
342 size_t elements() const { return 1; } |
|
343 }; |
|
344 |
|
345 static bool recording = false; |
|
346 |
|
347 static void set_recording_state(bool is_recording) { |
|
348 OrderAccess::storestore(); |
|
349 recording = is_recording; |
|
350 } |
|
351 |
|
352 bool JfrRecorderService::is_recording() { |
|
353 return recording; |
|
354 } |
|
355 |
|
356 JfrRecorderService::JfrRecorderService() : |
423 JfrRecorderService::JfrRecorderService() : |
357 _checkpoint_manager(JfrCheckpointManager::instance()), |
424 _checkpoint_manager(JfrCheckpointManager::instance()), |
358 _chunkwriter(JfrRepository::chunkwriter()), |
425 _chunkwriter(JfrRepository::chunkwriter()), |
359 _repository(JfrRepository::instance()), |
426 _repository(JfrRepository::instance()), |
360 _stack_trace_repository(JfrStackTraceRepository::instance()), |
427 _stack_trace_repository(JfrStackTraceRepository::instance()), |
361 _storage(JfrStorage::instance()), |
428 _storage(JfrStorage::instance()), |
362 _string_pool(JfrStringPool::instance()) {} |
429 _string_pool(JfrStringPool::instance()) {} |
363 |
430 |
|
431 static bool recording = false; |
|
432 |
|
433 static void set_recording_state(bool is_recording) { |
|
434 OrderAccess::storestore(); |
|
435 recording = is_recording; |
|
436 } |
|
437 |
|
438 bool JfrRecorderService::is_recording() { |
|
439 return recording; |
|
440 } |
|
441 |
364 void JfrRecorderService::start() { |
442 void JfrRecorderService::start() { |
365 RotationLock rl(Thread::current()); |
443 RotationLock rl(Thread::current()); |
366 if (rl.not_acquired()) { |
444 if (rl.not_acquired()) { |
367 return; |
445 return; |
368 } |
446 } |
414 |
483 |
415 void JfrRecorderService::post_safepoint_clear() { |
484 void JfrRecorderService::post_safepoint_clear() { |
416 _checkpoint_manager.clear(); |
485 _checkpoint_manager.clear(); |
417 } |
486 } |
418 |
487 |
|
488 void JfrRecorderService::open_new_chunk(bool vm_error) { |
|
489 JfrChunkRotation::on_rotation(); |
|
490 const bool valid_chunk = _repository.open_chunk(vm_error); |
|
491 _storage.control().set_to_disk(valid_chunk); |
|
492 if (valid_chunk) { |
|
493 _checkpoint_manager.write_constants(); |
|
494 } |
|
495 } |
|
496 |
419 static void stop() { |
497 static void stop() { |
420 assert(JfrRecorderService::is_recording(), "invariant"); |
498 assert(JfrRecorderService::is_recording(), "invariant"); |
421 log_debug(jfr, system)("Recording STOPPED"); |
499 log_debug(jfr, system)("Recording STOPPED"); |
422 set_recording_state(false); |
500 set_recording_state(false); |
423 assert(!JfrRecorderService::is_recording(), "invariant"); |
501 assert(!JfrRecorderService::is_recording(), "invariant"); |
|
502 } |
|
503 |
|
504 void JfrRecorderService::prepare_for_vm_error_rotation() { |
|
505 if (!_chunkwriter.is_valid()) { |
|
506 open_new_chunk(true); |
|
507 } |
|
508 _checkpoint_manager.register_service_thread(Thread::current()); |
|
509 } |
|
510 |
|
511 void JfrRecorderService::vm_error_rotation() { |
|
512 if (_chunkwriter.is_valid()) { |
|
513 pre_safepoint_write(); |
|
514 // Do not attempt safepoint dependent operations during emergency dump. |
|
515 // Optimistically write tagged artifacts. |
|
516 _checkpoint_manager.shift_epoch(); |
|
517 // update time |
|
518 _chunkwriter.set_time_stamp(); |
|
519 post_safepoint_write(); |
|
520 assert(!_chunkwriter.is_valid(), "invariant"); |
|
521 _repository.on_vm_error(); |
|
522 } |
424 } |
523 } |
425 |
524 |
426 void JfrRecorderService::rotate(int msgs) { |
525 void JfrRecorderService::rotate(int msgs) { |
427 RotationLock rl(Thread::current()); |
526 RotationLock rl(Thread::current()); |
428 if (rl.not_acquired()) { |
527 if (rl.not_acquired()) { |
443 if (msgs & (MSGBIT(MSG_STOP))) { |
542 if (msgs & (MSGBIT(MSG_STOP))) { |
444 stop(); |
543 stop(); |
445 } |
544 } |
446 } |
545 } |
447 |
546 |
448 void JfrRecorderService::prepare_for_vm_error_rotation() { |
|
449 if (!_chunkwriter.is_valid()) { |
|
450 open_new_chunk(true); |
|
451 } |
|
452 _checkpoint_manager.register_service_thread(Thread::current()); |
|
453 } |
|
454 |
|
455 void JfrRecorderService::open_new_chunk(bool vm_error) { |
|
456 JfrChunkRotation::on_rotation(); |
|
457 const bool valid_chunk = _repository.open_chunk(vm_error); |
|
458 _storage.control().set_to_disk(valid_chunk); |
|
459 if (valid_chunk) { |
|
460 _checkpoint_manager.write_constants(); |
|
461 } |
|
462 } |
|
463 |
|
464 void JfrRecorderService::in_memory_rotation() { |
547 void JfrRecorderService::in_memory_rotation() { |
465 // currently running an in-memory recording |
548 // currently running an in-memory recording |
466 assert(!_storage.control().to_disk(), "invariant"); |
549 assert(!_storage.control().to_disk(), "invariant"); |
467 open_new_chunk(); |
550 open_new_chunk(); |
468 if (_chunkwriter.is_valid()) { |
551 if (_chunkwriter.is_valid()) { |
469 // dump all in-memory buffer data to the newly created chunk |
552 // dump all in-memory buffer data to the newly created chunk |
470 serialize_storage_from_in_memory_recording(); |
553 write_storage(_storage, _chunkwriter); |
471 } |
554 } |
472 } |
|
473 |
|
474 void JfrRecorderService::serialize_storage_from_in_memory_recording() { |
|
475 _storage.write(); |
|
476 } |
555 } |
477 |
556 |
478 void JfrRecorderService::chunk_rotation() { |
557 void JfrRecorderService::chunk_rotation() { |
479 finalize_current_chunk(); |
558 finalize_current_chunk(); |
480 open_new_chunk(); |
559 open_new_chunk(); |
491 pre_safepoint_write(); |
570 pre_safepoint_write(); |
492 invoke_safepoint_write(); |
571 invoke_safepoint_write(); |
493 post_safepoint_write(); |
572 post_safepoint_write(); |
494 } |
573 } |
495 |
574 |
496 typedef ServiceFunctor<EventFlushStringPool, JfrStringPool, &JfrStringPool::write> FlushStringPoolFunctor; |
575 void JfrRecorderService::pre_safepoint_write() { |
497 typedef ServiceFunctor<EventFlushStringPool, JfrStringPool, &JfrStringPool::write_at_safepoint> FlushStringPoolSafepointFunctor; |
576 assert(_chunkwriter.is_valid(), "invariant"); |
498 typedef WriteSubsystemCheckpointEvent<FlushStackTraceRepository> FlushStackTraceCheckpoint; |
577 if (_stack_trace_repository.is_modified()) { |
499 typedef WriteSubsystemCheckpointEvent<FlushStringPoolFunctor> FlushStringPoolCheckpoint; |
578 write_stacktrace(_stack_trace_repository, _chunkwriter, false); |
500 typedef WriteSubsystemCheckpointEvent<FlushStringPoolSafepointFunctor> FlushStringPoolCheckpointSafepoint; |
579 } |
501 |
580 if (_string_pool.is_modified()) { |
502 static u4 flush_stacktrace(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) { |
581 write_stringpool(_string_pool, _chunkwriter); |
503 FlushStackTraceRepository flush_stacktrace_repo(stack_trace_repo, chunkwriter, clear); |
582 } |
504 FlushStackTraceCheckpoint flush_stack_trace_checkpoint(chunkwriter, flush_stacktrace_repo, TYPE_STACKTRACE); |
583 if (LeakProfiler::is_running()) { |
505 return invoke_with_flush_event(flush_stack_trace_checkpoint); |
584 // Exclusive access to the object sampler instance. |
506 } |
585 // The sampler is released (unlocked) later in post_safepoint_write. |
507 |
586 ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire(), _stack_trace_repository); |
508 static u4 flush_stacktrace(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter) { |
587 } |
509 return flush_stacktrace(stack_trace_repo, chunkwriter, false); |
588 _checkpoint_manager.notify_types_on_rotation(); |
510 } |
589 write_storage(_storage, _chunkwriter); |
511 |
590 } |
512 static u4 flush_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) { |
591 |
513 FlushStackTraceRepository flush_stacktrace_repo(stack_trace_repo, chunkwriter, clear); |
592 void JfrRecorderService::invoke_safepoint_write() { |
514 FlushStackTraceCheckpoint flush_stack_trace_checkpoint(chunkwriter, flush_stacktrace_repo, TYPE_STACKTRACE); |
593 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this); |
515 return invoke(flush_stack_trace_checkpoint); |
594 VMThread::execute(&safepoint_task); |
516 } |
595 } |
517 |
596 |
518 static u4 flush_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
597 void JfrRecorderService::safepoint_write() { |
519 FlushStringPoolFunctor flush_string_pool(string_pool); |
598 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
520 FlushStringPoolCheckpoint flush_string_pool_checkpoint(chunkwriter, flush_string_pool, TYPE_STRING); |
599 write_stacktrace(_stack_trace_repository, _chunkwriter, true); |
521 return invoke_with_flush_event(flush_string_pool_checkpoint); |
600 if (_string_pool.is_modified()) { |
522 } |
601 write_stringpool_safepoint(_string_pool, _chunkwriter); |
523 |
602 } |
524 static u4 flush_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
603 _storage.write_at_safepoint(); |
525 FlushStringPoolFunctor flush_string_pool(string_pool); |
604 _checkpoint_manager.notify_threads(); |
526 FlushStringPoolCheckpoint flush_string_pool_checkpoint(chunkwriter, flush_string_pool, TYPE_STRING); |
605 _checkpoint_manager.shift_epoch(); |
527 return invoke(flush_string_pool_checkpoint); |
606 _chunkwriter.set_time_stamp(); |
528 } |
607 } |
529 |
608 |
530 static u4 flush_stringpool_checkpoint_safepoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { |
609 void JfrRecorderService::post_safepoint_write() { |
531 FlushStringPoolSafepointFunctor flush_string_pool(string_pool); |
610 assert(_chunkwriter.is_valid(), "invariant"); |
532 FlushStringPoolCheckpointSafepoint flush_string_pool_checkpoint(chunkwriter, flush_string_pool, TYPE_STRING); |
611 // During the safepoint tasks just completed, the system transitioned to a new epoch. |
533 return invoke(flush_string_pool_checkpoint); |
612 // Type tagging is epoch relative which entails we are able to write out the |
534 } |
613 // already tagged artifacts for the previous epoch. We can accomplish this concurrently |
535 |
614 // with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint. |
536 typedef ServiceFunctor<EventFlushTypeSet, JfrCheckpointManager, &JfrCheckpointManager::flush_type_set> FlushTypeSetFunctor; |
615 _checkpoint_manager.write_type_set(); |
537 typedef WriteSubsystem<FlushTypeSetFunctor> FlushTypeSet; |
616 if (LeakProfiler::is_running()) { |
538 |
617 // The object sampler instance was exclusively acquired and locked in pre_safepoint_write. |
539 static u4 flush_typeset(JfrCheckpointManager& checkpoint_manager, JfrChunkWriter& chunkwriter) { |
618 // Note: There is a dependency on write_type_set() above, ensure the release is subsequent. |
540 FlushTypeSetFunctor flush_type_set(checkpoint_manager); |
619 ObjectSampler::release(); |
541 FlushTypeSet fts(chunkwriter, flush_type_set); |
620 } |
542 return invoke_with_flush_event(fts); |
621 // serialize any outstanding checkpoint memory |
543 } |
622 _checkpoint_manager.write(); |
544 |
623 // serialize the metadata descriptor event and close out the chunk |
545 typedef WriteSubsystem<FlushMetadataEvent> FlushMetadata; |
624 write_metadata(_chunkwriter); |
546 |
625 _repository.close_chunk(); |
547 static u4 flush_metadata_event(JfrChunkWriter& chunkwriter) { |
|
548 assert(chunkwriter.is_valid(), "invariant"); |
|
549 FlushMetadataEvent fme(chunkwriter); |
|
550 FlushMetadata fm(chunkwriter, fme); |
|
551 return invoke_with_flush_event(fm); |
|
552 } |
|
553 |
|
554 static u4 flush_metadata_event_checkpoint(JfrChunkWriter& chunkwriter) { |
|
555 assert(chunkwriter.is_valid(), "invariant"); |
|
556 FlushMetadataEvent wme(chunkwriter); |
|
557 FlushMetadata wm(chunkwriter, wme); |
|
558 return invoke(wm); |
|
559 } |
626 } |
560 |
627 |
561 static JfrBuffer* thread_local_buffer() { |
628 static JfrBuffer* thread_local_buffer() { |
562 return Thread::current()->jfr_thread_local()->native_buffer(); |
629 return Thread::current()->jfr_thread_local()->native_buffer(); |
563 } |
630 } |
581 reset_buffer(buffer); |
648 reset_buffer(buffer); |
582 } |
649 } |
583 assert(buffer->empty(), "invariant"); |
650 assert(buffer->empty(), "invariant"); |
584 } |
651 } |
585 |
652 |
586 typedef ServiceFunctor<EventFlushStorage, JfrStorage, &JfrStorage::write> FlushStorageFunctor; |
|
587 typedef WriteSubsystem<FlushStorageFunctor> FlushStorage; |
|
588 |
|
589 static size_t flush_storage(JfrStorage& storage, JfrChunkWriter& chunkwriter) { |
|
590 assert(chunkwriter.is_valid(), "invariant"); |
|
591 FlushStorageFunctor fsf(storage); |
|
592 FlushStorage fs(chunkwriter, fsf); |
|
593 return invoke_with_flush_event(fs); |
|
594 } |
|
595 |
|
596 typedef ServiceFunctor<EventFlush, JfrRecorderService, &JfrRecorderService::flush> FlushFunctor; |
|
597 typedef WriteSubsystem<FlushFunctor> Flush; |
|
598 |
|
599 static bool write_metadata_in_flushpoint = false; |
653 static bool write_metadata_in_flushpoint = false; |
600 |
654 |
601 size_t JfrRecorderService::flush() { |
655 size_t JfrRecorderService::flush() { |
602 size_t total_elements = 0; |
656 size_t total_elements = 0; |
603 if (write_metadata_in_flushpoint) { |
657 if (write_metadata_in_flushpoint) { |
604 total_elements = flush_metadata_event(_chunkwriter); |
658 total_elements = flush_metadata(_chunkwriter); |
605 } |
659 } |
606 const size_t storage_elements = flush_storage(_storage, _chunkwriter); |
660 const size_t storage_elements = flush_storage(_storage, _chunkwriter); |
607 if (0 == storage_elements) { |
661 if (0 == storage_elements) { |
608 return total_elements; |
662 return total_elements; |
609 } |
663 } |
635 invoke_with_flush_event(fl); |
692 invoke_with_flush_event(fl); |
636 write_thread_local_buffer(_chunkwriter); |
693 write_thread_local_buffer(_chunkwriter); |
637 _repository.flush_chunk(); |
694 _repository.flush_chunk(); |
638 } |
695 } |
639 |
696 |
640 // |
|
641 // pre-safepoint write sequence |
|
642 // |
|
643 // write stack trace checkpoint -> |
|
644 // write string pool checkpoint -> |
|
645 // notify about pending rotation -> |
|
646 // write storage |
|
647 // |
|
648 void JfrRecorderService::pre_safepoint_write() { |
|
649 assert(_chunkwriter.is_valid(), "invariant"); |
|
650 if (_stack_trace_repository.is_modified()) { |
|
651 flush_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, false); |
|
652 } |
|
653 if (_string_pool.is_modified()) { |
|
654 flush_stringpool_checkpoint(_string_pool, _chunkwriter); |
|
655 } |
|
656 if (LeakProfiler::is_running()) { |
|
657 // Exclusive access to the object sampler instance. |
|
658 // The sampler is released (unlocked) later in post_safepoint_write. |
|
659 ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire(), _stack_trace_repository); |
|
660 } |
|
661 _checkpoint_manager.notify_types_on_rotation(); |
|
662 _storage.write(); |
|
663 } |
|
664 |
|
665 void JfrRecorderService::invoke_safepoint_write() { |
|
666 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this); |
|
667 VMThread::execute(&safepoint_task); |
|
668 } |
|
669 |
|
670 // |
|
671 // safepoint write sequence |
|
672 // |
|
673 // write object sample stacktraces -> |
|
674 // write stacktrace repository -> |
|
675 // write string pool -> |
|
676 // write storage -> |
|
677 // notify java threads -> |
|
678 // shift_epoch -> |
|
679 // update time |
|
680 // |
|
681 void JfrRecorderService::safepoint_write() { |
|
682 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
|
683 flush_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, true); |
|
684 if (_string_pool.is_modified()) { |
|
685 flush_stringpool_checkpoint_safepoint(_string_pool, _chunkwriter); |
|
686 } |
|
687 _storage.write_at_safepoint(); |
|
688 _checkpoint_manager.notify_threads(); |
|
689 _checkpoint_manager.shift_epoch(); |
|
690 _chunkwriter.set_time_stamp(); |
|
691 } |
|
692 |
|
693 // |
|
694 // post-safepoint write sequence |
|
695 // |
|
696 // write type set -> |
|
697 // write checkpoints -> |
|
698 // write metadata event -> |
|
699 // close chunk |
|
700 // |
|
701 void JfrRecorderService::post_safepoint_write() { |
|
702 assert(_chunkwriter.is_valid(), "invariant"); |
|
703 // During the safepoint tasks just completed, the system transitioned to a new epoch. |
|
704 // Type tagging is epoch relative which entails we are able to write out the |
|
705 // already tagged artifacts for the previous epoch. We can accomplish this concurrently |
|
706 // with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint. |
|
707 _checkpoint_manager.write_type_set(); |
|
708 if (LeakProfiler::is_running()) { |
|
709 // The object sampler instance was exclusively acquired and locked in pre_safepoint_write. |
|
710 // Note: There is a dependency on write_type_set() above, ensure the release is subsequent. |
|
711 ObjectSampler::release(); |
|
712 } |
|
713 // serialize any outstanding checkpoint memory |
|
714 _checkpoint_manager.write(); |
|
715 // serialize the metadata descriptor event and close out the chunk |
|
716 flush_metadata_event_checkpoint(_chunkwriter); |
|
717 _repository.close_chunk(); |
|
718 } |
|
719 |
|
720 void JfrRecorderService::vm_error_rotation() { |
|
721 if (_chunkwriter.is_valid()) { |
|
722 finalize_current_chunk_on_vm_error(); |
|
723 assert(!_chunkwriter.is_valid(), "invariant"); |
|
724 _repository.on_vm_error(); |
|
725 } |
|
726 } |
|
727 |
|
728 void JfrRecorderService::finalize_current_chunk_on_vm_error() { |
|
729 assert(_chunkwriter.is_valid(), "invariant"); |
|
730 pre_safepoint_write(); |
|
731 // Do not attempt safepoint dependent operations during emergency dump. |
|
732 // Optimistically write tagged artifacts. |
|
733 _checkpoint_manager.shift_epoch(); |
|
734 // update time |
|
735 _chunkwriter.set_time_stamp(); |
|
736 post_safepoint_write(); |
|
737 } |
|
738 |
|
739 void JfrRecorderService::process_full_buffers() { |
697 void JfrRecorderService::process_full_buffers() { |
740 if (_chunkwriter.is_valid()) { |
698 if (_chunkwriter.is_valid()) { |
741 _storage.write_full(); |
699 _storage.write_full(); |
742 } |
700 } |
743 } |
701 } |