src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp
changeset 50113 caf115bb98ad
child 50117 fb66b2959eaf
equal deleted inserted replaced
50112:7a2a740815b7 50113:caf115bb98ad
       
     1 /*
       
     2  * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 #include "precompiled.hpp"
       
    26 #include "jfr/jfrEvents.hpp"
       
    27 #include "jfr/jni/jfrJavaSupport.hpp"
       
    28 #include "jfr/recorder/jfrRecorder.hpp"
       
    29 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
       
    30 #include "jfr/recorder/service/jfrOptionSet.hpp"
       
    31 #include "jfr/recorder/service/jfrPostBox.hpp"
       
    32 #include "jfr/recorder/storage/jfrMemorySpace.inline.hpp"
       
    33 #include "jfr/recorder/storage/jfrStorage.hpp"
       
    34 #include "jfr/recorder/storage/jfrStorageControl.hpp"
       
    35 #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
       
    36 #include "jfr/utilities/jfrIterator.hpp"
       
    37 #include "jfr/utilities/jfrTime.hpp"
       
    38 #include "jfr/writers/jfrNativeEventWriter.hpp"
       
    39 #include "logging/log.hpp"
       
    40 #include "runtime/mutexLocker.hpp"
       
    41 #include "runtime/orderAccess.inline.hpp"
       
    42 #include "runtime/safepoint.hpp"
       
    43 #include "runtime/thread.hpp"
       
    44 
       
    45 typedef JfrStorage::Buffer* BufferPtr;
       
    46 
       
    47 static JfrStorage* _instance = NULL;
       
    48 static JfrStorageControl* _control;
       
    49 
       
    50 JfrStorage& JfrStorage::instance() {
       
    51   return *_instance;
       
    52 }
       
    53 
       
    54 JfrStorage* JfrStorage::create(JfrChunkWriter& chunkwriter, JfrPostBox& post_box) {
       
    55   assert(_instance == NULL, "invariant");
       
    56   _instance = new JfrStorage(chunkwriter, post_box);
       
    57   return _instance;
       
    58 }
       
    59 
       
    60 void JfrStorage::destroy() {
       
    61   if (_instance != NULL) {
       
    62     delete _instance;
       
    63     _instance = NULL;
       
    64   }
       
    65 }
       
    66 
       
    67 JfrStorage::JfrStorage(JfrChunkWriter& chunkwriter, JfrPostBox& post_box) :
       
    68   _control(NULL),
       
    69   _global_mspace(NULL),
       
    70   _thread_local_mspace(NULL),
       
    71   _transient_mspace(NULL),
       
    72   _age_mspace(NULL),
       
    73   _chunkwriter(chunkwriter),
       
    74   _post_box(post_box) {}
       
    75 
       
    76 JfrStorage::~JfrStorage() {
       
    77   if (_control != NULL) {
       
    78     delete _control;
       
    79   }
       
    80   if (_global_mspace != NULL) {
       
    81     delete _global_mspace;
       
    82   }
       
    83   if (_thread_local_mspace != NULL) {
       
    84     delete _thread_local_mspace;
       
    85   }
       
    86   if (_transient_mspace != NULL) {
       
    87     delete _transient_mspace;
       
    88   }
       
    89   if (_age_mspace != NULL) {
       
    90     delete _age_mspace;
       
    91   }
       
    92   _instance = NULL;
       
    93 }
       
    94 
       
    95 static const size_t in_memory_discard_threshold_delta = 2; // start to discard data when the only this number of free buffers are left
       
    96 static const size_t unlimited_mspace_size = 0;
       
    97 static const size_t thread_local_cache_count = 8;
       
    98 static const size_t thread_local_scavenge_threshold = thread_local_cache_count / 2;
       
    99 static const size_t transient_buffer_size_multiplier = 8; // against thread local buffer size
       
   100 
       
   101 template <typename Mspace>
       
   102 static Mspace* create_mspace(size_t buffer_size, size_t limit, size_t cache_count, JfrStorage* storage_instance) {
       
   103   Mspace* mspace = new Mspace(buffer_size, limit, cache_count, storage_instance);
       
   104   if (mspace != NULL) {
       
   105     mspace->initialize();
       
   106   }
       
   107   return mspace;
       
   108 }
       
   109 
       
   110 bool JfrStorage::initialize() {
       
   111   assert(_control == NULL, "invariant");
       
   112   assert(_global_mspace == NULL, "invariant");
       
   113   assert(_thread_local_mspace == NULL, "invariant");
       
   114   assert(_transient_mspace == NULL, "invariant");
       
   115   assert(_age_mspace == NULL, "invariant");
       
   116 
       
   117   const size_t num_global_buffers = (size_t)JfrOptionSet::num_global_buffers();
       
   118   assert(num_global_buffers >= in_memory_discard_threshold_delta, "invariant");
       
   119   const size_t memory_size = (size_t)JfrOptionSet::memory_size();
       
   120   const size_t global_buffer_size = (size_t)JfrOptionSet::global_buffer_size();
       
   121   const size_t thread_buffer_size = (size_t)JfrOptionSet::thread_buffer_size();
       
   122 
       
   123   _control = new JfrStorageControl(num_global_buffers, num_global_buffers - in_memory_discard_threshold_delta);
       
   124   if (_control == NULL) {
       
   125     return false;
       
   126   }
       
   127   _global_mspace = create_mspace<JfrStorageMspace>(global_buffer_size, memory_size, num_global_buffers, this);
       
   128   if (_global_mspace == NULL) {
       
   129     return false;
       
   130   }
       
   131   _thread_local_mspace = create_mspace<JfrThreadLocalMspace>(thread_buffer_size, unlimited_mspace_size, thread_local_cache_count, this);
       
   132   if (_thread_local_mspace == NULL) {
       
   133     return false;
       
   134   }
       
   135   _transient_mspace = create_mspace<JfrStorageMspace>(thread_buffer_size * transient_buffer_size_multiplier, unlimited_mspace_size, 0, this);
       
   136   if (_transient_mspace == NULL) {
       
   137     return false;
       
   138   }
       
   139   _age_mspace = create_mspace<JfrStorageAgeMspace>(0 /* no extra size except header */, unlimited_mspace_size, num_global_buffers, this);
       
   140   if (_age_mspace == NULL) {
       
   141     return false;
       
   142   }
       
   143   control().set_scavenge_threshold(thread_local_scavenge_threshold);
       
   144   return true;
       
   145 }
       
   146 
       
   147 JfrStorageControl& JfrStorage::control() {
       
   148   return *instance()._control;
       
   149 }
       
   150 
       
   151 static void log_allocation_failure(const char* msg, size_t size) {
       
   152   log_warning(jfr)("Unable to allocate " SIZE_FORMAT " bytes of %s.", size, msg);
       
   153 }
       
   154 
       
   155 BufferPtr JfrStorage::acquire_thread_local(Thread* thread, size_t size /* 0 */) {
       
   156   BufferPtr buffer = mspace_get_to_full(size, instance()._thread_local_mspace, thread);
       
   157   if (buffer == NULL) {
       
   158     log_allocation_failure("thread local_memory", size);
       
   159     return NULL;
       
   160   }
       
   161   assert(buffer->acquired_by_self(), "invariant");
       
   162   return buffer;
       
   163 }
       
   164 
       
   165 BufferPtr JfrStorage::acquire_transient(size_t size, Thread* thread) {
       
   166   BufferPtr buffer = mspace_allocate_transient_lease_to_full(size, instance()._transient_mspace, thread);
       
   167   if (buffer == NULL) {
       
   168     log_allocation_failure("transient memory", size);
       
   169     return NULL;
       
   170   }
       
   171   assert(buffer->acquired_by_self(), "invariant");
       
   172   assert(buffer->transient(), "invariant");
       
   173   assert(buffer->lease(), "invariant");
       
   174   return buffer;
       
   175 }
       
   176 
       
   177 static BufferPtr get_lease(size_t size, JfrStorageMspace* mspace, JfrStorage& storage_instance, size_t retry_count, Thread* thread) {
       
   178   assert(size <= mspace->min_elem_size(), "invariant");
       
   179   while (true) {
       
   180     BufferPtr t = mspace_get_free_lease_with_retry(size, mspace, retry_count, thread);
       
   181     if (t == NULL && storage_instance.control().should_discard()) {
       
   182       storage_instance.discard_oldest(thread);
       
   183       continue;
       
   184     }
       
   185     return t;
       
   186   }
       
   187 }
       
   188 
       
   189 static BufferPtr get_promotion_buffer(size_t size, JfrStorageMspace* mspace, JfrStorage& storage_instance, size_t retry_count, Thread* thread) {
       
   190   assert(size <= mspace->min_elem_size(), "invariant");
       
   191   while (true) {
       
   192     BufferPtr t = mspace_get_free_with_retry(size, mspace, retry_count, thread);
       
   193     if (t == NULL && storage_instance.control().should_discard()) {
       
   194       storage_instance.discard_oldest(thread);
       
   195       continue;
       
   196     }
       
   197     return t;
       
   198   }
       
   199 }
       
   200 
       
   201 static const size_t lease_retry = 10;
       
   202 
       
   203 BufferPtr JfrStorage::acquire_large(size_t size, Thread* thread) {
       
   204   JfrStorage& storage_instance = instance();
       
   205   const size_t max_elem_size = storage_instance._global_mspace->min_elem_size(); // min is also max
       
   206   // if not too large and capacity is still available, ask for a lease from the global system
       
   207   if (size < max_elem_size && storage_instance.control().is_global_lease_allowed()) {
       
   208     BufferPtr const buffer = get_lease(size, storage_instance._global_mspace, storage_instance, lease_retry, thread);
       
   209     if (buffer != NULL) {
       
   210       assert(buffer->acquired_by_self(), "invariant");
       
   211       assert(!buffer->transient(), "invariant");
       
   212       assert(buffer->lease(), "invariant");
       
   213       storage_instance.control().increment_leased();
       
   214       return buffer;
       
   215     }
       
   216   }
       
   217   return acquire_transient(size, thread);
       
   218 }
       
   219 
       
   220 static void write_data_loss_event(JfrBuffer* buffer, u8 unflushed_size, Thread* thread) {
       
   221   assert(buffer != NULL, "invariant");
       
   222   assert(buffer->empty(), "invariant");
       
   223   const u8 total_data_loss = thread->jfr_thread_local()->add_data_lost(unflushed_size);
       
   224   if (EventDataLoss::is_enabled()) {
       
   225     JfrNativeEventWriter writer(buffer, thread);
       
   226     writer.write<u8>(EventDataLoss::eventId);
       
   227     writer.write(JfrTicks::now());
       
   228     writer.write(unflushed_size);
       
   229     writer.write(total_data_loss);
       
   230   }
       
   231 }
       
   232 
       
   233 static void write_data_loss(BufferPtr buffer, Thread* thread) {
       
   234   assert(buffer != NULL, "invariant");
       
   235   const size_t unflushed_size = buffer->unflushed_size();
       
   236   buffer->concurrent_reinitialization();
       
   237   if (unflushed_size == 0) {
       
   238     return;
       
   239   }
       
   240   write_data_loss_event(buffer, unflushed_size, thread);
       
   241 }
       
   242 
       
   243 static const size_t promotion_retry = 100;
       
   244 
       
   245 bool JfrStorage::flush_regular_buffer(BufferPtr buffer, Thread* thread) {
       
   246   assert(buffer != NULL, "invariant");
       
   247   assert(!buffer->lease(), "invariant");
       
   248   assert(!buffer->transient(), "invariant");
       
   249   const size_t unflushed_size = buffer->unflushed_size();
       
   250   if (unflushed_size == 0) {
       
   251     buffer->concurrent_reinitialization();
       
   252     assert(buffer->empty(), "invariant");
       
   253     return true;
       
   254   }
       
   255   BufferPtr const promotion_buffer = get_promotion_buffer(unflushed_size, _global_mspace, *this, promotion_retry, thread);
       
   256   if (promotion_buffer == NULL) {
       
   257     write_data_loss(buffer, thread);
       
   258     return false;
       
   259   }
       
   260   assert(promotion_buffer->acquired_by_self(), "invariant");
       
   261   assert(promotion_buffer->free_size() >= unflushed_size, "invariant");
       
   262   buffer->concurrent_move_and_reinitialize(promotion_buffer, unflushed_size);
       
   263   assert(buffer->empty(), "invariant");
       
   264   return true;
       
   265 }
       
   266 
       
   267 /*
       
   268 * 1. If the buffer was a "lease" from the global system, release back.
       
   269 * 2. If the buffer is transient (temporal dynamically allocated), retire and register full.
       
   270 *
       
   271 * The buffer is effectively invalidated for the thread post-return,
       
   272 * and the caller should take means to ensure that it is not referenced any longer.
       
   273 */
       
   274 void JfrStorage::release_large(BufferPtr buffer, Thread* thread) {
       
   275   assert(buffer != NULL, "invariant");
       
   276   assert(buffer->lease(), "invariant");
       
   277   assert(buffer->acquired_by_self(), "invariant");
       
   278   buffer->clear_lease();
       
   279   if (buffer->transient()) {
       
   280     buffer->set_retired();
       
   281     register_full(buffer, thread);
       
   282   } else {
       
   283     buffer->release();
       
   284     control().decrement_leased();
       
   285   }
       
   286 }
       
   287 
       
   288 static JfrAgeNode* new_age_node(BufferPtr buffer, JfrStorageAgeMspace* age_mspace, Thread* thread) {
       
   289   assert(buffer != NULL, "invariant");
       
   290   assert(age_mspace != NULL, "invariant");
       
   291   return mspace_allocate_transient(0, age_mspace, thread);
       
   292 }
       
   293 
       
   294 static void log_registration_failure(size_t unflushed_size) {
       
   295   log_warning(jfr)("Unable to register a full buffer of " SIZE_FORMAT " bytes.", unflushed_size);
       
   296   log_debug(jfr, system)("Cleared 1 full buffer of " SIZE_FORMAT " bytes.", unflushed_size);
       
   297 }
       
   298 
       
   299 static void handle_registration_failure(BufferPtr buffer) {
       
   300   assert(buffer != NULL, "invariant");
       
   301   assert(buffer->retired(), "invariant");
       
   302   const size_t unflushed_size = buffer->unflushed_size();
       
   303   buffer->reinitialize();
       
   304   log_registration_failure(unflushed_size);
       
   305 }
       
   306 
       
   307 static JfrAgeNode* get_free_age_node(JfrStorageAgeMspace* age_mspace, Thread* thread) {
       
   308   assert(JfrBuffer_lock->owned_by_self(), "invariant");
       
   309   return mspace_get_free_with_detach(0, age_mspace, thread);
       
   310 }
       
   311 
       
   312 static bool insert_full_age_node(JfrAgeNode* age_node, JfrStorageAgeMspace* age_mspace, Thread* thread) {
       
   313   assert(JfrBuffer_lock->owned_by_self(), "invariant");
       
   314   assert(age_node->retired_buffer()->retired(), "invariant");
       
   315   age_mspace->insert_full_head(age_node);
       
   316   return true;
       
   317 }
       
   318 
       
   319 static bool full_buffer_registration(BufferPtr buffer, JfrStorageAgeMspace* age_mspace, JfrStorageControl& control, Thread* thread) {
       
   320   assert(buffer != NULL, "invariant");
       
   321   assert(buffer->retired(), "invariant");
       
   322   assert(age_mspace != NULL, "invariant");
       
   323   MutexLockerEx lock(JfrBuffer_lock, Mutex::_no_safepoint_check_flag);
       
   324   JfrAgeNode* age_node = get_free_age_node(age_mspace, thread);
       
   325   if (age_node == NULL) {
       
   326     age_node = new_age_node(buffer, age_mspace, thread);
       
   327     if (age_node == NULL) {
       
   328       return false;
       
   329     }
       
   330   }
       
   331   assert(age_node->acquired_by_self(), "invariant");
       
   332   assert(age_node != NULL, "invariant");
       
   333   age_node->set_retired_buffer(buffer);
       
   334   return insert_full_age_node(age_node, age_mspace, thread);
       
   335 }
       
   336 
       
   337 void JfrStorage::register_full(BufferPtr buffer, Thread* thread) {
       
   338   assert(buffer != NULL, "invariant");
       
   339   assert(buffer->retired(), "invariant");
       
   340   if (!full_buffer_registration(buffer, _age_mspace, control(), thread)) {
       
   341     handle_registration_failure(buffer);
       
   342     buffer->release();
       
   343   }
       
   344   if (control().should_post_buffer_full_message()) {
       
   345     _post_box.post(MSG_FULLBUFFER);
       
   346   }
       
   347 }
       
   348 
       
   349 void JfrStorage::lock() {
       
   350   assert(!JfrBuffer_lock->owned_by_self(), "invariant");
       
   351   JfrBuffer_lock->lock_without_safepoint_check();
       
   352 }
       
   353 
       
   354 void JfrStorage::unlock() {
       
   355   assert(JfrBuffer_lock->owned_by_self(), "invariant");
       
   356   JfrBuffer_lock->unlock();
       
   357 }
       
   358 
       
   359 #ifdef ASSERT
       
   360 bool JfrStorage::is_locked() const {
       
   361   return JfrBuffer_lock->owned_by_self();
       
   362 }
       
   363 #endif
       
   364 
       
   365 // don't use buffer on return, it is gone
       
   366 void JfrStorage::release(BufferPtr buffer, Thread* thread) {
       
   367   assert(buffer != NULL, "invariant");
       
   368   assert(!buffer->lease(), "invariant");
       
   369   assert(!buffer->transient(), "invariant");
       
   370   assert(!buffer->retired(), "invariant");
       
   371   if (!buffer->empty()) {
       
   372     if (!flush_regular_buffer(buffer, thread)) {
       
   373       buffer->concurrent_reinitialization();
       
   374     }
       
   375   }
       
   376   assert(buffer->empty(), "invariant");
       
   377   control().increment_dead();
       
   378   buffer->release();
       
   379   buffer->set_retired();
       
   380 }
       
   381 
       
   382 void JfrStorage::release_thread_local(BufferPtr buffer, Thread* thread) {
       
   383   assert(buffer != NULL, "invariant");
       
   384   JfrStorage& storage_instance = instance();
       
   385   storage_instance.release(buffer, thread);
       
   386   if (storage_instance.control().should_scavenge()) {
       
   387     storage_instance._post_box.post(MSG_DEADBUFFER);
       
   388   }
       
   389 }
       
   390 
       
   391 static void log_discard(size_t count, size_t amount, size_t current) {
       
   392   if (log_is_enabled(Debug, jfr, system)) {
       
   393     assert(count > 0, "invariant");
       
   394     log_debug(jfr, system)("Cleared " SIZE_FORMAT " full buffer(s) of " SIZE_FORMAT" bytes.", count, amount);
       
   395     log_debug(jfr, system)("Current number of full buffers " SIZE_FORMAT "", current);
       
   396   }
       
   397 }
       
   398 
       
   399 void JfrStorage::discard_oldest(Thread* thread) {
       
   400   if (JfrBuffer_lock->try_lock()) {
       
   401     if (!control().should_discard()) {
       
   402       // another thread handled it
       
   403       return;
       
   404     }
       
   405     const size_t num_full_pre_discard = control().full_count();
       
   406     size_t num_full_post_discard = 0;
       
   407     size_t discarded_size = 0;
       
   408     while (true) {
       
   409       JfrAgeNode* const oldest_age_node = _age_mspace->full_tail();
       
   410       if (oldest_age_node == NULL) {
       
   411         break;
       
   412       }
       
   413       BufferPtr const buffer = oldest_age_node->retired_buffer();
       
   414       assert(buffer->retired(), "invariant");
       
   415       discarded_size += buffer->unflushed_size();
       
   416       num_full_post_discard = control().decrement_full();
       
   417       if (buffer->transient()) {
       
   418         mspace_release_full(buffer, _transient_mspace);
       
   419         mspace_release_full(oldest_age_node, _age_mspace);
       
   420         continue;
       
   421       } else {
       
   422         mspace_release_full(oldest_age_node, _age_mspace);
       
   423         buffer->reinitialize();
       
   424         buffer->release(); // pusb
       
   425         break;
       
   426       }
       
   427     }
       
   428     JfrBuffer_lock->unlock();
       
   429     const size_t number_of_discards = num_full_pre_discard - num_full_post_discard;
       
   430     if (number_of_discards > 0) {
       
   431       log_discard(number_of_discards, discarded_size, num_full_post_discard);
       
   432     }
       
   433   }
       
   434 }
       
   435 
       
   436 #ifdef ASSERT
       
   437 typedef const BufferPtr ConstBufferPtr;
       
   438 
       
   439 static void assert_flush_precondition(ConstBufferPtr cur, size_t used, bool native, const Thread* t) {
       
   440   assert(t != NULL, "invariant");
       
   441   assert(cur != NULL, "invariant");
       
   442   assert(cur->pos() + used <= cur->end(), "invariant");
       
   443   assert(native ? t->jfr_thread_local()->native_buffer() == cur : t->jfr_thread_local()->java_buffer() == cur, "invariant");
       
   444 }
       
   445 
       
   446 static void assert_flush_regular_precondition(ConstBufferPtr cur, const u1* const cur_pos, size_t used, size_t req, const Thread* t) {
       
   447   assert(t != NULL, "invariant");
       
   448   assert(t->jfr_thread_local()->shelved_buffer() == NULL, "invariant");
       
   449   assert(cur != NULL, "invariant");
       
   450   assert(!cur->lease(), "invariant");
       
   451   assert(cur_pos != NULL, "invariant");
       
   452   assert(req >= used, "invariant");
       
   453 }
       
   454 
       
   455 static void assert_provision_large_precondition(ConstBufferPtr cur, size_t used, size_t req, const Thread* t) {
       
   456   assert(cur != NULL, "invariant");
       
   457   assert(t != NULL, "invariant");
       
   458   assert(t->jfr_thread_local()->shelved_buffer() != NULL, "invariant");
       
   459   assert(req >= used, "invariant");
       
   460 }
       
   461 
       
   462 static void assert_flush_large_precondition(ConstBufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) {
       
   463   assert(t != NULL, "invariant");
       
   464   assert(cur != NULL, "invariant");
       
   465   assert(cur->lease(), "invariant");
       
   466   assert(cur_pos != NULL, "invariant");
       
   467   assert(native ? t->jfr_thread_local()->native_buffer() == cur : t->jfr_thread_local()->java_buffer() == cur, "invariant");
       
   468   assert(t->jfr_thread_local()->shelved_buffer() != NULL, "invariant");
       
   469   assert(req >= used, "invariant");
       
   470   assert(cur != t->jfr_thread_local()->shelved_buffer(), "invariant");
       
   471 }
       
   472 #endif // ASSERT
       
   473 
       
   474 BufferPtr JfrStorage::flush(BufferPtr cur, size_t used, size_t req, bool native, Thread* t) {
       
   475   debug_only(assert_flush_precondition(cur, used, native, t);)
       
   476   const u1* const cur_pos = cur->pos();
       
   477   req += used;
       
   478   // requested size now encompass the outstanding used size
       
   479   return cur->lease() ? instance().flush_large(cur, cur_pos, used, req, native, t) :
       
   480                           instance().flush_regular(cur, cur_pos, used, req, native, t);
       
   481 }
       
   482 
       
   483 BufferPtr JfrStorage::flush_regular(BufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) {
       
   484   debug_only(assert_flush_regular_precondition(cur, cur_pos, used, req, t);)
       
   485   // A flush is needed before memcpy since a non-large buffer is thread stable
       
   486   // (thread local). The flush will not modify memory in addresses above pos()
       
   487   // which is where the "used / uncommitted" data resides. It is therefore both
       
   488   // possible and valid to migrate data after the flush. This is however only
       
   489   // the case for stable thread local buffers; it is not the case for large buffers.
       
   490   if (!cur->empty()) {
       
   491     flush_regular_buffer(cur, t);
       
   492   }
       
   493   assert(t->jfr_thread_local()->shelved_buffer() == NULL, "invariant");
       
   494   if (cur->free_size() >= req) {
       
   495     // simplest case, no switching of buffers
       
   496     if (used > 0) {
       
   497       memcpy(cur->pos(), (void*)cur_pos, used);
       
   498     }
       
   499     assert(native ? t->jfr_thread_local()->native_buffer() == cur : t->jfr_thread_local()->java_buffer() == cur, "invariant");
       
   500     return cur;
       
   501   }
       
   502   // Going for a "larger-than-regular" buffer.
       
   503   // Shelve the current buffer to make room for a temporary lease.
       
   504   t->jfr_thread_local()->shelve_buffer(cur);
       
   505   return provision_large(cur, cur_pos, used, req, native, t);
       
   506 }
       
   507 
       
   508 static BufferPtr store_buffer_to_thread_local(BufferPtr buffer, JfrThreadLocal* jfr_thread_local, bool native) {
       
   509   assert(buffer != NULL, "invariant");
       
   510   if (native) {
       
   511     jfr_thread_local->set_native_buffer(buffer);
       
   512   } else {
       
   513     jfr_thread_local->set_java_buffer(buffer);
       
   514   }
       
   515   return buffer;
       
   516 }
       
   517 
       
   518 static BufferPtr restore_shelved_buffer(bool native, Thread* t) {
       
   519   JfrThreadLocal* const tl = t->jfr_thread_local();
       
   520   BufferPtr shelved = tl->shelved_buffer();
       
   521   assert(shelved != NULL, "invariant");
       
   522   tl->shelve_buffer(NULL);
       
   523   // restore shelved buffer back as primary
       
   524   return store_buffer_to_thread_local(shelved, tl, native);
       
   525 }
       
   526 
       
   527 BufferPtr JfrStorage::flush_large(BufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) {
       
   528   debug_only(assert_flush_large_precondition(cur, cur_pos, used, req, native, t);)
       
   529   // Can the "regular" buffer (now shelved) accommodate the requested size?
       
   530   BufferPtr shelved = t->jfr_thread_local()->shelved_buffer();
       
   531   assert(shelved != NULL, "invariant");
       
   532   if (shelved->free_size() >= req) {
       
   533     if (req > 0) {
       
   534       memcpy(shelved->pos(), (void*)cur_pos, (size_t)used);
       
   535     }
       
   536     // release and invalidate
       
   537     release_large(cur, t);
       
   538     return restore_shelved_buffer(native, t);
       
   539   }
       
   540   // regular too small
       
   541   return provision_large(cur, cur_pos,  used, req, native, t);
       
   542 }
       
   543 
       
   544 static BufferPtr large_fail(BufferPtr cur, bool native, JfrStorage& storage_instance, Thread* t) {
       
   545   assert(cur != NULL, "invariant");
       
   546   assert(t != NULL, "invariant");
       
   547   if (cur->lease()) {
       
   548     storage_instance.release_large(cur, t);
       
   549   }
       
   550   return restore_shelved_buffer(native, t);
       
   551 }
       
   552 
       
   553 // Always returns a non-null buffer.
       
   554 // If accommodating the large request fails, the shelved buffer is returned
       
   555 // even though it might be smaller than the requested size.
       
   556 // Caller needs to ensure if the size was successfully accommodated.
       
   557 BufferPtr JfrStorage::provision_large(BufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) {
       
   558   debug_only(assert_provision_large_precondition(cur, used, req, t);)
       
   559   assert(t->jfr_thread_local()->shelved_buffer() != NULL, "invariant");
       
   560   BufferPtr const buffer = acquire_large(req, t);
       
   561   if (buffer == NULL) {
       
   562     // unable to allocate and serve the request
       
   563     return large_fail(cur, native, *this, t);
       
   564   }
       
   565   // ok managed to acquire a "large" buffer for the requested size
       
   566   assert(buffer->free_size() >= req, "invariant");
       
   567   assert(buffer->lease(), "invariant");
       
   568   // transfer outstanding data
       
   569   memcpy(buffer->pos(), (void*)cur_pos, used);
       
   570   if (cur->lease()) {
       
   571     release_large(cur, t);
       
   572     // don't use current anymore, it is gone
       
   573   }
       
   574   return store_buffer_to_thread_local(buffer, t->jfr_thread_local(), native);
       
   575 }
       
   576 
       
   577 typedef UnBufferedWriteToChunk<JfrBuffer> WriteOperation;
       
   578 typedef MutexedWriteOp<WriteOperation> MutexedWriteOperation;
       
   579 typedef ConcurrentWriteOp<WriteOperation> ConcurrentWriteOperation;
       
   580 typedef ConcurrentWriteOpExcludeRetired<WriteOperation> ThreadLocalConcurrentWriteOperation;
       
   581 
       
   582 size_t JfrStorage::write() {
       
   583   const size_t full_size_processed = write_full();
       
   584   WriteOperation wo(_chunkwriter);
       
   585   ThreadLocalConcurrentWriteOperation tlwo(wo);
       
   586   process_full_list(tlwo, _thread_local_mspace);
       
   587   ConcurrentWriteOperation cwo(wo);
       
   588   process_free_list(cwo, _global_mspace);
       
   589   return full_size_processed + wo.processed();
       
   590 }
       
   591 
       
   592 size_t JfrStorage::write_at_safepoint() {
       
   593   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
       
   594   WriteOperation wo(_chunkwriter);
       
   595   MutexedWriteOperation writer(wo); // mutexed write mode
       
   596   process_full_list(writer, _thread_local_mspace);
       
   597   assert(_transient_mspace->is_free_empty(), "invariant");
       
   598   process_full_list(writer, _transient_mspace);
       
   599   assert(_global_mspace->is_full_empty(), "invariant");
       
   600   process_free_list(writer, _global_mspace);
       
   601   return wo.processed();
       
   602 }
       
   603 
       
   604 typedef DiscardOp<DefaultDiscarder<JfrStorage::Buffer> > DiscardOperation;
       
   605 typedef ReleaseOp<JfrStorageMspace> ReleaseOperation;
       
   606 typedef CompositeOperation<MutexedWriteOperation, ReleaseOperation> FullOperation;
       
   607 
       
   608 size_t JfrStorage::clear() {
       
   609   const size_t full_size_processed = clear_full();
       
   610   DiscardOperation discarder(concurrent); // concurrent discard mode
       
   611   process_full_list(discarder, _thread_local_mspace);
       
   612   assert(_transient_mspace->is_free_empty(), "invariant");
       
   613   process_full_list(discarder, _transient_mspace);
       
   614   assert(_global_mspace->is_full_empty(), "invariant");
       
   615   process_free_list(discarder, _global_mspace);
       
   616   return full_size_processed + discarder.processed();
       
   617 }
       
   618 
       
   619 static void insert_free_age_nodes(JfrStorageAgeMspace* age_mspace, JfrAgeNode* head, JfrAgeNode* tail, size_t count) {
       
   620   if (tail != NULL) {
       
   621     assert(tail->next() == NULL, "invariant");
       
   622     assert(head != NULL, "invariant");
       
   623     assert(head->prev() == NULL, "invariant");
       
   624     MutexLockerEx buffer_lock(JfrBuffer_lock, Mutex::_no_safepoint_check_flag);
       
   625     age_mspace->insert_free_tail(head, tail, count);
       
   626   }
       
   627 }
       
   628 
       
   629 template <typename Processor>
       
   630 static void process_age_list(Processor& processor, JfrStorageAgeMspace* age_mspace, JfrAgeNode* head, size_t count) {
       
   631   assert(age_mspace != NULL, "invariant");
       
   632   assert(head != NULL, "invariant");
       
   633   JfrAgeNode* node = head;
       
   634   JfrAgeNode* last = NULL;
       
   635   while (node != NULL) {
       
   636     last = node;
       
   637     BufferPtr const buffer = node->retired_buffer();
       
   638     assert(buffer != NULL, "invariant");
       
   639     assert(buffer->retired(), "invariant");
       
   640     processor.process(buffer);
       
   641     // at this point, buffer is already live or destroyed
       
   642     node->clear_identity();
       
   643     JfrAgeNode* const next = (JfrAgeNode*)node->next();
       
   644     if (node->transient()) {
       
   645       // detach
       
   646       last = (JfrAgeNode*)last->prev();
       
   647       if (last != NULL) {
       
   648         last->set_next(next);
       
   649       } else {
       
   650         head = next;
       
   651       }
       
   652       if (next != NULL) {
       
   653         next->set_prev(last);
       
   654       }
       
   655       --count;
       
   656       age_mspace->deallocate(node);
       
   657     }
       
   658     node = next;
       
   659   }
       
   660   insert_free_age_nodes(age_mspace, head, last, count);
       
   661 }
       
   662 
       
   663 template <typename Processor>
       
   664 static size_t process_full(Processor& processor, JfrStorageControl& control, JfrStorageAgeMspace* age_mspace) {
       
   665   assert(age_mspace != NULL, "invariant");
       
   666   if (age_mspace->is_full_empty()) {
       
   667     // nothing to do
       
   668     return 0;
       
   669   }
       
   670   size_t count;
       
   671   JfrAgeNode* head;;
       
   672   {
       
   673     // fetch age list
       
   674     MutexLockerEx buffer_lock(JfrBuffer_lock, Mutex::_no_safepoint_check_flag);
       
   675     count = age_mspace->full_count();
       
   676     head = age_mspace->clear_full();
       
   677     control.reset_full();
       
   678   }
       
   679   assert(head != NULL, "invariant");
       
   680   process_age_list(processor, age_mspace, head, count);
       
   681   return count;
       
   682 }
       
   683 
       
   684 static void log(size_t count, size_t amount, bool clear = false) {
       
   685   if (log_is_enabled(Debug, jfr, system)) {
       
   686     if (count > 0) {
       
   687       log_debug(jfr, system)("%s " SIZE_FORMAT " full buffer(s) of " SIZE_FORMAT" B of data%s",
       
   688         clear ? "Discarded" : "Wrote", count, amount, clear ? "." : " to chunk.");
       
   689     }
       
   690   }
       
   691 }
       
   692 
       
   693 // full writer
       
   694 // Assumption is retired only; exclusive access
       
   695 // MutexedWriter -> ReleaseOp
       
   696 //
       
   697 size_t JfrStorage::write_full() {
       
   698   assert(_chunkwriter.is_valid(), "invariant");
       
   699   Thread* const thread = Thread::current();
       
   700   WriteOperation wo(_chunkwriter);
       
   701   MutexedWriteOperation writer(wo); // a retired buffer implies mutexed access
       
   702   ReleaseOperation ro(_transient_mspace, thread);
       
   703   FullOperation cmd(&writer, &ro);
       
   704   const size_t count = process_full(cmd, control(), _age_mspace);
       
   705   log(count, writer.processed());
       
   706   return writer.processed();
       
   707 }
       
   708 
       
   709 size_t JfrStorage::clear_full() {
       
   710   DiscardOperation discarder(mutexed); // a retired buffer implies mutexed access
       
   711   const size_t count = process_full(discarder, control(), _age_mspace);
       
   712   log(count, discarder.processed(), true);
       
   713   return discarder.processed();
       
   714 }
       
   715 
       
   716 static void scavenge_log(size_t count, size_t amount, size_t current) {
       
   717   if (count > 0) {
       
   718     if (log_is_enabled(Debug, jfr, system)) {
       
   719       log_debug(jfr, system)("Released " SIZE_FORMAT " dead buffer(s) of " SIZE_FORMAT" B of data.", count, amount);
       
   720       log_debug(jfr, system)("Current number of dead buffers " SIZE_FORMAT "", current);
       
   721     }
       
   722   }
       
   723 }
       
   724 
       
   725 template <typename Mspace>
       
   726 class Scavenger {
       
   727 private:
       
   728   JfrStorageControl& _control;
       
   729   Mspace* _mspace;
       
   730   size_t _count;
       
   731   size_t _amount;
       
   732 public:
       
   733   typedef typename Mspace::Type Type;
       
   734   Scavenger(JfrStorageControl& control, Mspace* mspace) : _control(control), _mspace(mspace), _count(0), _amount(0) {}
       
   735   bool process(Type* t) {
       
   736     if (t->retired()) {
       
   737       assert(!t->transient(), "invariant");
       
   738       assert(!t->lease(), "invariant");
       
   739       assert(t->empty(), "invariant");
       
   740       assert(t->identity() == NULL, "invariant");
       
   741       ++_count;
       
   742       _amount += t->total_size();
       
   743       t->clear_retired();
       
   744       _control.decrement_dead();
       
   745       mspace_release_full_critical(t, _mspace);
       
   746     }
       
   747     return true;
       
   748   }
       
   749   size_t processed() const { return _count; }
       
   750   size_t amount() const { return _amount; }
       
   751 };
       
   752 
       
   753 size_t JfrStorage::scavenge() {
       
   754   JfrStorageControl& ctrl = control();
       
   755   if (ctrl.dead_count() == 0) {
       
   756     return 0;
       
   757   }
       
   758   Scavenger<JfrThreadLocalMspace> scavenger(ctrl, _thread_local_mspace);
       
   759   process_full_list(scavenger, _thread_local_mspace);
       
   760   scavenge_log(scavenger.processed(), scavenger.amount(), ctrl.dead_count());
       
   761   return scavenger.processed();
       
   762 }