rev 57156 : imported patch 8234796-v3

   1 /*
   2  * Copyright (c) 2016, 2019, 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 "classfile/javaClasses.inline.hpp"
  27 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
  28 #include "jfr/leakprofiler/leakProfiler.hpp"
  29 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
  30 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
  31 #include "jfr/recorder/checkpoint/types/jfrTypeManager.hpp"
  32 #include "jfr/recorder/checkpoint/types/jfrTypeSet.hpp"
  33 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
  34 #include "jfr/recorder/jfrRecorder.hpp"
  35 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
  36 #include "jfr/recorder/service/jfrOptionSet.hpp"
  37 #include "jfr/recorder/storage/jfrMemorySpace.inline.hpp"
  38 #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
  39 #include "jfr/utilities/jfrBigEndian.hpp"
  40 #include "jfr/utilities/jfrIterator.hpp"
  41 #include "jfr/utilities/jfrThreadIterator.hpp"
  42 #include "jfr/utilities/jfrTypes.hpp"
  43 #include "jfr/writers/jfrJavaEventWriter.hpp"
  44 #include "logging/log.hpp"

  45 #include "memory/resourceArea.hpp"
  46 #include "runtime/handles.inline.hpp"
  47 #include "runtime/mutex.hpp"
  48 #include "runtime/orderAccess.hpp"
  49 #include "runtime/os.inline.hpp"
  50 #include "runtime/safepoint.hpp"
  51 
  52 typedef JfrCheckpointManager::Buffer* BufferPtr;
  53 
  54 static JfrCheckpointManager* _instance = NULL;
  55 
  56 JfrCheckpointManager& JfrCheckpointManager::instance() {
  57   return *_instance;
  58 }
  59 
  60 JfrCheckpointManager* JfrCheckpointManager::create(JfrChunkWriter& cw) {
  61   assert(_instance == NULL, "invariant");
  62   _instance = new JfrCheckpointManager(cw);
  63   return _instance;
  64 }
  65 
  66 void JfrCheckpointManager::destroy() {
  67   assert(_instance != NULL, "invariant");
  68   delete _instance;
  69   _instance = NULL;
  70 }
  71 
  72 JfrCheckpointManager::JfrCheckpointManager(JfrChunkWriter& cw) :
  73   _free_list_mspace(NULL),
  74   _epoch_transition_mspace(NULL),
  75   _lock(NULL),
  76   _service_thread(NULL),
  77   _chunkwriter(cw),
  78   _checkpoint_epoch_state(JfrTraceIdEpoch::epoch()) {}
  79 
  80 JfrCheckpointManager::~JfrCheckpointManager() {
  81   if (_free_list_mspace != NULL) {
  82     delete _free_list_mspace;
  83   }
  84   if (_epoch_transition_mspace != NULL) {
  85     delete _epoch_transition_mspace;
  86   }
  87   if (_lock != NULL) {
  88     delete _lock;
  89   }
  90   JfrTypeManager::destroy();
  91 }
  92 
  93 static const size_t unlimited_mspace_size = 0;
  94 static const size_t checkpoint_buffer_cache_count = 2;
  95 static const size_t checkpoint_buffer_size = 512 * K;
  96 
  97 static JfrCheckpointMspace* allocate_mspace(size_t size, size_t limit, size_t cache_count, JfrCheckpointManager* mgr) {
  98   return create_mspace<JfrCheckpointMspace, JfrCheckpointManager>(size, limit, cache_count, mgr);
  99 }
 100 
 101 bool JfrCheckpointManager::initialize() {
 102   assert(_free_list_mspace == NULL, "invariant");
 103   _free_list_mspace = allocate_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this);
 104   if (_free_list_mspace == NULL) {
 105     return false;
 106   }
 107   assert(_epoch_transition_mspace == NULL, "invariant");
 108   _epoch_transition_mspace = allocate_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this);
 109   if (_epoch_transition_mspace == NULL) {
 110     return false;
 111   }
 112   assert(_lock == NULL, "invariant");
 113   _lock = new Mutex(Monitor::leaf - 1, "Checkpoint mutex", Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never);
 114   if (_lock == NULL) {
 115     return false;
 116   }
 117   return JfrTypeManager::initialize();
 118 }
 119 
 120 void JfrCheckpointManager::register_service_thread(const Thread* thread) {
 121   _service_thread = thread;
 122 }
 123 
 124 void JfrCheckpointManager::register_full(BufferPtr t, Thread* thread) {
 125   // nothing here at the moment
 126   assert(t != NULL, "invariant");
 127   assert(t->acquired_by(thread), "invariant");
 128   assert(t->retired(), "invariant");
 129 }
 130 
 131 void JfrCheckpointManager::lock() {
 132   assert(!_lock->owned_by_self(), "invariant");
 133   _lock->lock_without_safepoint_check();
 134 }
 135 
 136 void JfrCheckpointManager::unlock() {
 137   _lock->unlock();
 138 }
 139 
 140 #ifdef ASSERT
 141 bool JfrCheckpointManager::is_locked() const {
 142   return _lock->owned_by_self();
 143 }
 144 
 145 static void assert_free_lease(const BufferPtr buffer) {
 146   assert(buffer != NULL, "invariant");
 147   assert(buffer->acquired_by_self(), "invariant");
 148   assert(buffer->lease(), "invariant");
 149 }
 150 
 151 static void assert_release(const BufferPtr buffer) {
 152   assert(buffer != NULL, "invariant");
 153   assert(buffer->lease(), "invariant");
 154   assert(buffer->acquired_by_self(), "invariant");
 155 }
 156 #endif // ASSERT
 157 
 158 static BufferPtr lease_free(size_t size, JfrCheckpointMspace* mspace, size_t retry_count, Thread* thread) {
 159   static const size_t max_elem_size = mspace->min_elem_size(); // min is max
 160   BufferPtr buffer;
 161   if (size <= max_elem_size) {
 162     BufferPtr buffer = mspace_get_free_lease_with_retry(size, mspace, retry_count, thread);
 163     if (buffer != NULL) {
 164       DEBUG_ONLY(assert_free_lease(buffer);)
 165       return buffer;
 166     }
 167   }
 168   buffer = mspace_allocate_transient_lease_to_free(size, mspace, thread);
 169   DEBUG_ONLY(assert_free_lease(buffer);)
 170   return buffer;
 171 }
 172 
 173 bool JfrCheckpointManager::use_epoch_transition_mspace(const Thread* thread) const {
 174   return _service_thread != thread && _checkpoint_epoch_state != JfrTraceIdEpoch::epoch();
 175 }
 176 
 177 static const size_t lease_retry = 10;
 178 
 179 BufferPtr JfrCheckpointManager::lease_buffer(Thread* thread, size_t size /* 0 */) {
 180   JfrCheckpointManager& manager = instance();
 181   if (manager.use_epoch_transition_mspace(thread)) {
 182     return lease_free(size, manager._epoch_transition_mspace, lease_retry, thread);
 183   }
 184   return lease_free(size, manager._free_list_mspace, lease_retry, thread);
 185 }
 186 
 187 JfrCheckpointMspace* JfrCheckpointManager::lookup(BufferPtr old) const {
 188   assert(old != NULL, "invariant");
 189   return _free_list_mspace->in_free_list(old) ? _free_list_mspace : _epoch_transition_mspace;
 190 }
 191 
 192 BufferPtr JfrCheckpointManager::lease_buffer(BufferPtr old, Thread* thread, size_t size /* 0 */) {
 193   assert(old != NULL, "invariant");
 194   JfrCheckpointMspace* mspace = instance().lookup(old);
 195   assert(mspace != NULL, "invariant");
 196   return lease_free(size, mspace, lease_retry, thread);
 197 }
 198 
 199 /*
 200  * If the buffer was a lease, release back.
 201  *
 202  * The buffer is effectively invalidated for the thread post-return,
 203  * and the caller should take means to ensure that it is not referenced.
 204  */
 205 static void release(BufferPtr const buffer, Thread* thread) {
 206   DEBUG_ONLY(assert_release(buffer);)
 207   buffer->clear_lease();
 208   buffer->release();
 209 }
 210 
 211 BufferPtr JfrCheckpointManager::flush(BufferPtr old, size_t used, size_t requested, Thread* thread) {
 212   assert(old != NULL, "invariant");
 213   assert(old->lease(), "invariant");
 214   if (0 == requested) {
 215     // indicates a lease is being returned
 216     release(old, thread);
 217     return NULL;
 218   }
 219   // migration of in-flight information
 220   BufferPtr const new_buffer = lease_buffer(old, thread, used + requested);
 221   if (new_buffer != NULL) {
 222     migrate_outstanding_writes(old, new_buffer, used, requested);
 223   }
 224   release(old, thread);
 225   return new_buffer; // might be NULL
 226 }
 227 
 228 // offsets into the JfrCheckpointEntry
 229 static const juint starttime_offset = sizeof(jlong);
 230 static const juint duration_offset = starttime_offset + sizeof(jlong);
 231 static const juint checkpoint_type_offset = duration_offset + sizeof(jlong);
 232 static const juint types_offset = checkpoint_type_offset + sizeof(juint);
 233 static const juint payload_offset = types_offset + sizeof(juint);
 234 
 235 template <typename Return>
 236 static Return read_data(const u1* data) {
 237   return JfrBigEndian::read<Return>(data);
 238 }
 239 
 240 static jlong total_size(const u1* data) {
 241   return read_data<jlong>(data);
 242 }
 243 
 244 static jlong starttime(const u1* data) {
 245   return read_data<jlong>(data + starttime_offset);
 246 }
 247 
 248 static jlong duration(const u1* data) {
 249   return read_data<jlong>(data + duration_offset);
 250 }
 251 
 252 static u1 checkpoint_type(const u1* data) {
 253   return read_data<u1>(data + checkpoint_type_offset);
 254 }
 255 
 256 static juint number_of_types(const u1* data) {
 257   return read_data<juint>(data + types_offset);
 258 }
 259 
 260 static void write_checkpoint_header(JfrChunkWriter& cw, int64_t delta_to_last_checkpoint, const u1* data) {
 261   cw.reserve(sizeof(u4));
 262   cw.write<u8>(EVENT_CHECKPOINT);
 263   cw.write(starttime(data));
 264   cw.write(duration(data));
 265   cw.write(delta_to_last_checkpoint);
 266   cw.write(checkpoint_type(data));
 267   cw.write(number_of_types(data));
 268 }
 269 
 270 static void write_checkpoint_content(JfrChunkWriter& cw, const u1* data, size_t size) {
 271   assert(data != NULL, "invariant");
 272   cw.write_unbuffered(data + payload_offset, size - sizeof(JfrCheckpointEntry));
 273 }
 274 
 275 static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) {
 276   assert(data != NULL, "invariant");
 277   const int64_t event_begin = cw.current_offset();
 278   const int64_t last_checkpoint_event = cw.last_checkpoint_offset();
 279   const int64_t delta_to_last_checkpoint = last_checkpoint_event == 0 ? 0 : last_checkpoint_event - event_begin;
 280   const int64_t checkpoint_size = total_size(data);
 281   write_checkpoint_header(cw, delta_to_last_checkpoint, data);
 282   write_checkpoint_content(cw, data, checkpoint_size);
 283   const int64_t event_size = cw.current_offset() - event_begin;
 284   cw.write_padded_at_offset<u4>(event_size, event_begin);
 285   cw.set_last_checkpoint_offset(event_begin);
 286   return (size_t)checkpoint_size;
 287 }
 288 
 289 static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size) {
 290   assert(cw.is_valid(), "invariant");
 291   assert(data != NULL, "invariant");
 292   assert(size > 0, "invariant");
 293   const u1* const limit = data + size;
 294   const u1* next = data;
 295   size_t processed = 0;
 296   while (next < limit) {
 297     const size_t checkpoint_size = write_checkpoint_event(cw, next);
 298     processed += checkpoint_size;
 299     next += checkpoint_size;
 300   }
 301   assert(next == limit, "invariant");
 302   return processed;
 303 }
 304 
 305 template <typename T>
 306 class CheckpointWriteOp {
 307  private:
 308   JfrChunkWriter& _writer;
 309   size_t _processed;
 310  public:
 311   typedef T Type;
 312   CheckpointWriteOp(JfrChunkWriter& writer) : _writer(writer), _processed(0) {}
 313   bool write(Type* t, const u1* data, size_t size) {
 314     _processed += write_checkpoints(_writer, data, size);
 315     return true;
 316   }
 317   size_t processed() const { return _processed; }
 318 };
 319 
 320 typedef CheckpointWriteOp<JfrCheckpointMspace::Type> WriteOperation;
 321 typedef ReleaseOp<JfrCheckpointMspace> CheckpointReleaseOperation;
 322 
 323 template <template <typename> class WriterHost, template <typename, typename, typename> class CompositeOperation>
 324 static size_t write_mspace(JfrCheckpointMspace* mspace, JfrChunkWriter& chunkwriter) {
 325   assert(mspace != NULL, "invariant");
 326   WriteOperation wo(chunkwriter);
 327   WriterHost<WriteOperation> wh(wo);
 328   CheckpointReleaseOperation cro(mspace, Thread::current(), false);
 329   CompositeOperation<WriterHost<WriteOperation>, CheckpointReleaseOperation, CompositeOperationAnd> co(&wh, &cro);
 330   assert(mspace->is_full_empty(), "invariant");
 331   process_free_list(co, mspace);
 332   return wo.processed();
 333 }
 334 
 335 void JfrCheckpointManager::synchronize_epoch() {
 336   assert(_checkpoint_epoch_state != JfrTraceIdEpoch::epoch(), "invariant");
 337   OrderAccess::storestore();
 338   _checkpoint_epoch_state = JfrTraceIdEpoch::epoch();
 339 }
 340 
 341 size_t JfrCheckpointManager::write() {
 342   const size_t processed = write_mspace<MutexedWriteOp, CompositeOperation>(_free_list_mspace, _chunkwriter);
 343   synchronize_epoch();
 344   return processed;
 345 }
 346 
 347 size_t JfrCheckpointManager::write_epoch_transition_mspace() {
 348   return write_mspace<ExclusiveOp, CompositeOperation>(_epoch_transition_mspace, _chunkwriter);
 349 }
 350 
 351 typedef MutexedWriteOp<WriteOperation> FlushOperation;
 352 
 353 size_t JfrCheckpointManager::flush() {
 354   WriteOperation wo(_chunkwriter);
 355   FlushOperation fo(wo);
 356   assert(_free_list_mspace->is_full_empty(), "invariant");
 357   process_free_list(fo, _free_list_mspace);
 358   return wo.processed();
 359 }
 360 
 361 typedef DiscardOp<DefaultDiscarder<JfrBuffer> > DiscardOperation;
 362 size_t JfrCheckpointManager::clear() {
 363   JfrTypeSet::clear();
 364   DiscardOperation discarder(mutexed); // mutexed discard mode
 365   process_free_list(discarder, _free_list_mspace);
 366   process_free_list(discarder, _epoch_transition_mspace);
 367   synchronize_epoch();
 368   return discarder.elements();
 369 }
 370 
 371 // Optimization for write_static_type_set() and write_threads() is to write
 372 // directly into the epoch transition mspace because we will immediately
 373 // serialize and reset this mspace post-write.
 374 static JfrBuffer* get_epoch_transition_buffer(JfrCheckpointMspace* mspace, Thread* t) {
 375   assert(mspace != NULL, "invariant");
 376   JfrBuffer* const buffer = mspace->free_head();
 377   assert(buffer != NULL, "invariant");
 378   buffer->acquire(t);
 379   buffer->set_lease();
 380   DEBUG_ONLY(assert_free_lease(buffer);)
 381   return buffer;
 382 }
 383 
 384 bool JfrCheckpointManager::is_static_type_set_required() {
 385   return JfrTypeManager::has_new_static_type();
 386 }
 387 
 388 size_t JfrCheckpointManager::write_static_type_set() {
 389   Thread* const t = Thread::current();
 390   ResourceMark rm(t);
 391   HandleMark hm(t);
 392   JfrCheckpointWriter writer(t, get_epoch_transition_buffer(_epoch_transition_mspace, t), STATICS);
 393   JfrTypeManager::write_static_types(writer);
 394   return writer.used_size();
 395 }
 396 
 397 size_t JfrCheckpointManager::write_threads() {
 398   Thread* const t = Thread::current();
 399   ResourceMark rm(t);
 400   HandleMark hm(t);
 401   JfrCheckpointWriter writer(t, get_epoch_transition_buffer(_epoch_transition_mspace, t), THREADS);
 402   JfrTypeManager::write_threads(writer);
 403   return writer.used_size();
 404 }
 405 
 406 size_t JfrCheckpointManager::write_static_type_set_and_threads() {
 407   write_static_type_set();
 408   write_threads();
 409   return write_epoch_transition_mspace();
 410 }
 411 
 412 void JfrCheckpointManager::shift_epoch() {
 413   debug_only(const u1 current_epoch = JfrTraceIdEpoch::current();)
 414   JfrTraceIdEpoch::shift_epoch();
 415   assert(current_epoch != JfrTraceIdEpoch::current(), "invariant");
 416 }
 417 
 418 void JfrCheckpointManager::on_rotation() {
 419   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
 420   JfrTypeManager::on_rotation();
 421   notify_threads();
 422 }
 423 
 424 void JfrCheckpointManager::write_type_set() {
 425   assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
 426   if (LeakProfiler::is_running()) {
 427     Thread* const t = Thread::current();
 428     // can safepoint here
 429     MutexLocker cld_lock(ClassLoaderDataGraph_lock);
 430     MutexLocker module_lock(Module_lock);
 431     JfrCheckpointWriter leakp_writer(t);
 432     JfrCheckpointWriter writer(t);
 433     JfrTypeSet::serialize(&writer, &leakp_writer, false, false);
 434     ObjectSampleCheckpoint::on_type_set(leakp_writer);
 435   } else {
 436     // can safepoint here
 437     MutexLocker cld_lock(ClassLoaderDataGraph_lock);
 438     MutexLocker module_lock(Module_lock);
 439     JfrCheckpointWriter writer(Thread::current());
 440     JfrTypeSet::serialize(&writer, NULL, false, false);
 441   }
 442   write();
 443 }
 444 
 445 void JfrCheckpointManager::write_type_set_for_unloaded_classes() {
 446   assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
 447   JfrCheckpointWriter writer(Thread::current());
 448   const JfrCheckpointContext ctx = writer.context();
 449   JfrTypeSet::serialize(&writer, NULL, true, false);
 450   if (LeakProfiler::is_running()) {
 451     ObjectSampleCheckpoint::on_type_set_unload(writer);
 452   }
 453   if (!JfrRecorder::is_recording()) {
 454     // discard by rewind
 455     writer.set_context(ctx);
 456   }
 457 }
 458 
 459 bool JfrCheckpointManager::is_type_set_required() {
 460   return JfrTraceIdEpoch::has_changed_tag_state();
 461 }
 462 
 463 size_t JfrCheckpointManager::flush_type_set() {
 464   size_t elements = 0;
 465   {
 466     JfrCheckpointWriter writer(Thread::current());
 467     // can safepoint here
 468     MutexLocker cld_lock(ClassLoaderDataGraph_lock);
 469     MutexLocker module_lock(Module_lock);
 470     elements = JfrTypeSet::serialize(&writer, NULL, false, true);
 471   }
 472   flush();
 473   return elements;
 474 }
 475 
 476 void JfrCheckpointManager::flush_static_type_set() {
 477   flush();
 478 }
 479 
 480 void JfrCheckpointManager::create_thread_blob(Thread* t) {
 481   JfrTypeManager::create_thread_blob(t);
 482 }
 483 
 484 void JfrCheckpointManager::write_thread_checkpoint(Thread* t) {
 485   JfrTypeManager::write_thread_checkpoint(t);
 486 }
 487 
 488 class JfrNotifyClosure : public ThreadClosure {
 489  public:
 490   void do_thread(Thread* t) {
 491     assert(t != NULL, "invariant");
 492     assert(t->is_Java_thread(), "invariant");
 493     assert_locked_or_safepoint(Threads_lock);
 494     JfrJavaEventWriter::notify((JavaThread*)t);
 495   }
 496 };
 497 
 498 void JfrCheckpointManager::notify_threads() {
 499   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
 500   JfrNotifyClosure tc;
 501   JfrJavaThreadIterator iter;
 502   while (iter.has_next()) {
 503     tc.do_thread(iter.next());
 504   }
 505 }
--- EOF ---