src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp
branchJEP-349-branch
changeset 58068 22dab580786c
parent 57987 23e3cd901cb6
child 58154 060d9d139109
equal deleted inserted replaced
58049:10ecdb5d3574 58068:22dab580786c
   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   }
   197   int64_t current_offset() const {
   197   int64_t current_offset() const {
   198     return _cw.current_offset();
   198     return _cw.current_offset();
   199   }
   199   }
   200 
   200 
   201   u4 elements() const {
   201   u4 elements() const {
   202     return (u4) _content_functor.elements();
   202     return (u4) _content.elements();
   203   }
   203   }
   204 
   204 
   205   u4 size() const {
   205   u4 size() const {
   206     return (u4)(end_offset() - start_offset());
   206     return (u4)(end_offset() - start_offset());
   207   }
   207   }
   227   }
   227   }
   228 
   228 
   229   void rewind() {
   229   void rewind() {
   230     _cw.seek(start_offset());
   230     _cw.seek(start_offset());
   231   }
   231   }
   232 
       
   233 };
   232 };
   234 
   233 
   235 static int64_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) {
   234 static int64_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) {
   236   const int64_t last_cp_offset = cw.last_checkpoint_offset();
   235   const int64_t last_cp_offset = cw.last_checkpoint_offset();
   237   const int64_t delta_to_last_checkpoint = 0 == last_cp_offset ? 0 : last_cp_offset - cw.current_offset();
   236   const int64_t delta_to_last_checkpoint = 0 == last_cp_offset ? 0 : last_cp_offset - cw.current_offset();
   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     }
   272     return true;
   271     return true;
   273   }
   272   }
   274 };
   273 };
   275 
   274 
   276 template <typename Functor>
   275 template <typename Functor>
       
   276 static u4 invoke(Functor& f) {
       
   277   f.process();
       
   278   return f.elements();
       
   279 }
       
   280 
       
   281 template <typename Functor>
   277 static void write_flush_event(Functor& f) {
   282 static void write_flush_event(Functor& f) {
   278   if (Functor::is_event_enabled()) {
   283   if (Functor::is_event_enabled()) {
   279     typename Functor::EventType e(UNTIMED);
   284     typename Functor::EventType e(UNTIMED);
   280     e.set_starttime(f.start_time());
   285     e.set_starttime(f.start_time());
   281     e.set_endtime(f.end_time());
   286     e.set_endtime(f.end_time());
   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   }
   392 void JfrRecorderService::invoke_safepoint_clear() {
   470 void JfrRecorderService::invoke_safepoint_clear() {
   393   JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_clear> safepoint_task(*this);
   471   JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_clear> safepoint_task(*this);
   394   VMThread::execute(&safepoint_task);
   472   VMThread::execute(&safepoint_task);
   395 }
   473 }
   396 
   474 
   397 //
       
   398 // safepoint clear sequence
       
   399 //
       
   400 //  clear stacktrace repository ->
       
   401 //    clear string pool ->
       
   402 //      clear storage ->
       
   403 //        shift epoch ->
       
   404 //          update time
       
   405 //
       
   406 void JfrRecorderService::safepoint_clear() {
   475 void JfrRecorderService::safepoint_clear() {
   407   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
   476   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
   408   _stack_trace_repository.clear();
   477   _stack_trace_repository.clear();
   409   _string_pool.clear();
   478   _string_pool.clear();
   410   _storage.clear();
   479   _storage.clear();
   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   }
   620     // don't tally this, it is only in order to flush the waiting constants
   674     // don't tally this, it is only in order to flush the waiting constants
   621     _checkpoint_manager.flush_constant_set();
   675     _checkpoint_manager.flush_constant_set();
   622   }
   676   }
   623   return total_elements;
   677   return total_elements;
   624 }
   678 }
       
   679 
       
   680 typedef Content<EventFlush, JfrRecorderService, &JfrRecorderService::flush> FlushFunctor;
       
   681 typedef WriteContent<FlushFunctor> Flush;
   625 
   682 
   626 void JfrRecorderService::flush(int msgs) {
   683 void JfrRecorderService::flush(int msgs) {
   627   assert(_chunkwriter.is_valid(), "invariant");
   684   assert(_chunkwriter.is_valid(), "invariant");
   628   ResourceMark rm;
   685   ResourceMark rm;
   629   HandleMark hm;
   686   HandleMark hm;
   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 }