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