src/share/vm/jfr/recorder/service/jfrRecorderService.cpp

Wed, 09 Oct 2019 16:11:58 +0800

author
ddong
date
Wed, 09 Oct 2019 16:11:58 +0800
changeset 9885
8e875c964f41
parent 9875
6388d0d497f7
child 9947
db357034b763
permissions
-rw-r--r--

8214542: JFR: Old Object Sample event slow on a deep heap in debug builds
Reviewed-by: egahlin, rwestberg

apetushkov@9858 1 /*
apetushkov@9858 2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
apetushkov@9858 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
apetushkov@9858 4 *
apetushkov@9858 5 * This code is free software; you can redistribute it and/or modify it
apetushkov@9858 6 * under the terms of the GNU General Public License version 2 only, as
apetushkov@9858 7 * published by the Free Software Foundation.
apetushkov@9858 8 *
apetushkov@9858 9 * This code is distributed in the hope that it will be useful, but WITHOUT
apetushkov@9858 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
apetushkov@9858 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
apetushkov@9858 12 * version 2 for more details (a copy is included in the LICENSE file that
apetushkov@9858 13 * accompanied this code).
apetushkov@9858 14 *
apetushkov@9858 15 * You should have received a copy of the GNU General Public License version
apetushkov@9858 16 * 2 along with this work; if not, write to the Free Software Foundation,
apetushkov@9858 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
apetushkov@9858 18 *
apetushkov@9858 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
apetushkov@9858 20 * or visit www.oracle.com if you need additional information or have any
apetushkov@9858 21 * questions.
apetushkov@9858 22 *
apetushkov@9858 23 */
apetushkov@9858 24
apetushkov@9858 25 #include "precompiled.hpp"
apetushkov@9858 26 #include "jfr/jni/jfrJavaSupport.hpp"
ddong@9885 27 #include "jfr/leakprofiler/leakProfiler.hpp"
apetushkov@9858 28 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
ddong@9885 29 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
apetushkov@9858 30 #include "jfr/recorder/jfrRecorder.hpp"
apetushkov@9858 31 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
apetushkov@9858 32 #include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp"
mgronlun@9875 33 #include "jfr/recorder/repository/jfrChunkRotation.hpp"
apetushkov@9858 34 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
apetushkov@9858 35 #include "jfr/recorder/repository/jfrRepository.hpp"
apetushkov@9858 36 #include "jfr/recorder/service/jfrPostBox.hpp"
apetushkov@9858 37 #include "jfr/recorder/service/jfrRecorderService.hpp"
apetushkov@9858 38 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
apetushkov@9858 39 #include "jfr/recorder/storage/jfrStorage.hpp"
apetushkov@9858 40 #include "jfr/recorder/storage/jfrStorageControl.hpp"
apetushkov@9858 41 #include "jfr/recorder/stringpool/jfrStringPool.hpp"
apetushkov@9858 42 #include "jfr/utilities/jfrAllocation.hpp"
apetushkov@9858 43 #include "jfr/utilities/jfrTime.hpp"
apetushkov@9858 44 #include "jfr/writers/jfrJavaEventWriter.hpp"
apetushkov@9858 45 #include "jfr/utilities/jfrTypes.hpp"
apetushkov@9858 46 #include "memory/resourceArea.hpp"
apetushkov@9858 47 #include "runtime/atomic.hpp"
apetushkov@9858 48 #include "runtime/handles.inline.hpp"
apetushkov@9858 49 #include "runtime/mutexLocker.hpp"
apetushkov@9858 50 #include "runtime/orderAccess.hpp"
apetushkov@9858 51 #include "runtime/os.hpp"
apetushkov@9858 52 #include "runtime/safepoint.hpp"
apetushkov@9858 53 #include "runtime/thread.inline.hpp"
apetushkov@9858 54 #include "runtime/vm_operations.hpp"
apetushkov@9858 55 #include "runtime/vmThread.hpp"
apetushkov@9858 56
apetushkov@9858 57 // set data iff *dest == NULL
apetushkov@9858 58 static bool try_set(void* const data, void** dest, bool clear) {
apetushkov@9858 59 assert(data != NULL, "invariant");
apetushkov@9858 60 void* const current = OrderAccess::load_ptr_acquire(dest);
apetushkov@9858 61 if (current != NULL) {
apetushkov@9858 62 if (current != data) {
apetushkov@9858 63 // already set
apetushkov@9858 64 return false;
apetushkov@9858 65 }
apetushkov@9858 66 assert(current == data, "invariant");
apetushkov@9858 67 if (!clear) {
apetushkov@9858 68 // recursion disallowed
apetushkov@9858 69 return false;
apetushkov@9858 70 }
apetushkov@9858 71 }
apetushkov@9858 72 return Atomic::cmpxchg_ptr(clear ? NULL : data, dest, current) == current;
apetushkov@9858 73 }
apetushkov@9858 74
apetushkov@9858 75 static void* rotation_thread = NULL;
apetushkov@9858 76 static const int rotation_try_limit = 1000;
apetushkov@9858 77 static const int rotation_retry_sleep_millis = 10;
apetushkov@9858 78
apetushkov@9858 79 class RotationLock : public StackObj {
apetushkov@9858 80 private:
apetushkov@9858 81 Thread* const _thread;
apetushkov@9858 82 bool _acquired;
apetushkov@9858 83
apetushkov@9858 84 void log(bool recursion) {
apetushkov@9858 85 assert(!_acquired, "invariant");
apetushkov@9858 86 const char* error_msg = NULL;
apetushkov@9858 87 if (recursion) {
apetushkov@9858 88 error_msg = "Unable to issue rotation due to recursive calls.";
apetushkov@9858 89 }
apetushkov@9858 90 else {
apetushkov@9858 91 error_msg = "Unable to issue rotation due to wait timeout.";
apetushkov@9858 92 }
apetushkov@9858 93 if (LogJFR) tty->print_cr( // For user, should not be "jfr, system"
apetushkov@9858 94 "%s", error_msg);
apetushkov@9858 95 }
apetushkov@9858 96 public:
apetushkov@9858 97 RotationLock(Thread* thread) : _thread(thread), _acquired(false) {
apetushkov@9858 98 assert(_thread != NULL, "invariant");
apetushkov@9858 99 if (_thread == rotation_thread) {
apetushkov@9858 100 // recursion not supported
apetushkov@9858 101 log(true);
apetushkov@9858 102 return;
apetushkov@9858 103 }
apetushkov@9858 104
apetushkov@9858 105 // limited to not spin indefinitely
apetushkov@9858 106 for (int i = 0; i < rotation_try_limit; ++i) {
apetushkov@9858 107 if (try_set(_thread, &rotation_thread, false)) {
apetushkov@9858 108 _acquired = true;
apetushkov@9858 109 assert(_thread == rotation_thread, "invariant");
apetushkov@9858 110 return;
apetushkov@9858 111 }
apetushkov@9858 112 if (_thread->is_Java_thread()) {
apetushkov@9858 113 // in order to allow the system to move to a safepoint
apetushkov@9858 114 MutexLockerEx msg_lock(JfrMsg_lock);
apetushkov@9858 115 JfrMsg_lock->wait(false, rotation_retry_sleep_millis);
apetushkov@9858 116 }
apetushkov@9858 117 else {
apetushkov@9858 118 os::naked_short_sleep(rotation_retry_sleep_millis);
apetushkov@9858 119 }
apetushkov@9858 120 }
apetushkov@9858 121 log(false);
apetushkov@9858 122 }
apetushkov@9858 123
apetushkov@9858 124 ~RotationLock() {
apetushkov@9858 125 assert(_thread != NULL, "invariant");
apetushkov@9858 126 if (_acquired) {
apetushkov@9858 127 assert(_thread == rotation_thread, "invariant");
apetushkov@9858 128 while (!try_set(_thread, &rotation_thread, true));
apetushkov@9858 129 }
apetushkov@9858 130 }
apetushkov@9858 131 bool not_acquired() const { return !_acquired; }
apetushkov@9858 132 };
apetushkov@9858 133
apetushkov@9858 134 static intptr_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) {
apetushkov@9858 135 const intptr_t prev_cp_offset = cw.previous_checkpoint_offset();
apetushkov@9858 136 const intptr_t prev_cp_relative_offset = 0 == prev_cp_offset ? 0 : prev_cp_offset - cw.current_offset();
apetushkov@9858 137 cw.reserve(sizeof(u4));
apetushkov@9858 138 cw.write<u8>(EVENT_CHECKPOINT);
apetushkov@9858 139 cw.write(JfrTicks::now());
apetushkov@9858 140 cw.write<jlong>((jlong)0);
apetushkov@9858 141 cw.write<jlong>((jlong)prev_cp_relative_offset); // write previous checkpoint offset delta
apetushkov@9858 142 cw.write<bool>(false); // flushpoint
apetushkov@9858 143 cw.write<u4>((u4)1); // nof types in this checkpoint
apetushkov@9858 144 cw.write<u8>(type_id);
apetushkov@9858 145 const intptr_t number_of_elements_offset = cw.current_offset();
apetushkov@9858 146 cw.reserve(sizeof(u4));
apetushkov@9858 147 return number_of_elements_offset;
apetushkov@9858 148 }
apetushkov@9858 149
apetushkov@9858 150 template <typename ContentFunctor>
apetushkov@9858 151 class WriteCheckpointEvent : public StackObj {
apetushkov@9858 152 private:
apetushkov@9858 153 JfrChunkWriter& _cw;
apetushkov@9858 154 u8 _type_id;
apetushkov@9858 155 ContentFunctor& _content_functor;
apetushkov@9858 156 public:
apetushkov@9858 157 WriteCheckpointEvent(JfrChunkWriter& cw, u8 type_id, ContentFunctor& functor) :
apetushkov@9858 158 _cw(cw),
apetushkov@9858 159 _type_id(type_id),
apetushkov@9858 160 _content_functor(functor) {
apetushkov@9858 161 assert(_cw.is_valid(), "invariant");
apetushkov@9858 162 }
apetushkov@9858 163 bool process() {
apetushkov@9858 164 // current_cp_offset is also offset for the event size header field
apetushkov@9858 165 const intptr_t current_cp_offset = _cw.current_offset();
apetushkov@9858 166 const intptr_t num_elements_offset = write_checkpoint_event_prologue(_cw, _type_id);
apetushkov@9858 167 // invocation
apetushkov@9858 168 _content_functor.process();
apetushkov@9858 169 const u4 number_of_elements = (u4)_content_functor.processed();
apetushkov@9858 170 if (number_of_elements == 0) {
apetushkov@9858 171 // nothing to do, rewind writer to start
apetushkov@9858 172 _cw.seek(current_cp_offset);
apetushkov@9858 173 return true;
apetushkov@9858 174 }
apetushkov@9858 175 assert(number_of_elements > 0, "invariant");
apetushkov@9858 176 assert(_cw.current_offset() > num_elements_offset, "invariant");
apetushkov@9858 177 _cw.write_padded_at_offset<u4>(number_of_elements, num_elements_offset);
apetushkov@9858 178 _cw.write_padded_at_offset<u4>((u4)_cw.current_offset() - current_cp_offset, current_cp_offset);
apetushkov@9858 179 // update writer with last checkpoint position
apetushkov@9858 180 _cw.set_previous_checkpoint_offset(current_cp_offset);
apetushkov@9858 181 return true;
apetushkov@9858 182 }
apetushkov@9858 183 };
apetushkov@9858 184
apetushkov@9858 185 template <typename Instance, size_t(Instance::*func)()>
apetushkov@9858 186 class ServiceFunctor {
apetushkov@9858 187 private:
apetushkov@9858 188 Instance& _instance;
apetushkov@9858 189 size_t _processed;
apetushkov@9858 190 public:
apetushkov@9858 191 ServiceFunctor(Instance& instance) : _instance(instance), _processed(0) {}
apetushkov@9858 192 bool process() {
apetushkov@9858 193 _processed = (_instance.*func)();
apetushkov@9858 194 return true;
apetushkov@9858 195 }
apetushkov@9858 196 size_t processed() const { return _processed; }
apetushkov@9858 197 };
apetushkov@9858 198
apetushkov@9858 199 template <typename Instance, void(Instance::*func)()>
apetushkov@9858 200 class JfrVMOperation : public VM_Operation {
apetushkov@9858 201 private:
apetushkov@9858 202 Instance& _instance;
apetushkov@9858 203 public:
apetushkov@9858 204 JfrVMOperation(Instance& instance) : _instance(instance) {}
apetushkov@9858 205 void doit() { (_instance.*func)(); }
apetushkov@9858 206 VMOp_Type type() const { return VMOp_JFRCheckpoint; }
apetushkov@9858 207 Mode evaluation_mode() const { return _safepoint; } // default
apetushkov@9858 208 };
apetushkov@9858 209
apetushkov@9858 210 class WriteStackTraceRepository : public StackObj {
apetushkov@9858 211 private:
apetushkov@9858 212 JfrStackTraceRepository& _repo;
apetushkov@9858 213 JfrChunkWriter& _cw;
apetushkov@9858 214 size_t _elements_processed;
apetushkov@9858 215 bool _clear;
apetushkov@9858 216
apetushkov@9858 217 public:
apetushkov@9858 218 WriteStackTraceRepository(JfrStackTraceRepository& repo, JfrChunkWriter& cw, bool clear) :
apetushkov@9858 219 _repo(repo), _cw(cw), _elements_processed(0), _clear(clear) {}
apetushkov@9858 220 bool process() {
apetushkov@9858 221 _elements_processed = _repo.write(_cw, _clear);
apetushkov@9858 222 return true;
apetushkov@9858 223 }
apetushkov@9858 224 size_t processed() const { return _elements_processed; }
apetushkov@9858 225 void reset() { _elements_processed = 0; }
apetushkov@9858 226 };
apetushkov@9858 227
apetushkov@9858 228 static bool recording = false;
apetushkov@9858 229
apetushkov@9858 230 static void set_recording_state(bool is_recording) {
apetushkov@9858 231 OrderAccess::storestore();
apetushkov@9858 232 recording = is_recording;
apetushkov@9858 233 }
apetushkov@9858 234
apetushkov@9858 235 bool JfrRecorderService::is_recording() {
apetushkov@9858 236 return recording;
apetushkov@9858 237 }
apetushkov@9858 238
apetushkov@9858 239 JfrRecorderService::JfrRecorderService() :
apetushkov@9858 240 _checkpoint_manager(JfrCheckpointManager::instance()),
apetushkov@9858 241 _chunkwriter(JfrRepository::chunkwriter()),
apetushkov@9858 242 _repository(JfrRepository::instance()),
apetushkov@9858 243 _storage(JfrStorage::instance()),
apetushkov@9858 244 _stack_trace_repository(JfrStackTraceRepository::instance()),
apetushkov@9858 245 _string_pool(JfrStringPool::instance()) {}
apetushkov@9858 246
apetushkov@9858 247 void JfrRecorderService::start() {
apetushkov@9858 248 RotationLock rl(Thread::current());
apetushkov@9858 249 if (rl.not_acquired()) {
apetushkov@9858 250 return;
apetushkov@9858 251 }
apetushkov@9858 252 if (LogJFR) tty->print_cr("Request to START recording");
apetushkov@9858 253 assert(!is_recording(), "invariant");
apetushkov@9858 254 clear();
apetushkov@9858 255 set_recording_state(true);
apetushkov@9858 256 assert(is_recording(), "invariant");
apetushkov@9858 257 open_new_chunk();
apetushkov@9858 258 if (LogJFR) tty->print_cr("Recording STARTED");
apetushkov@9858 259 }
apetushkov@9858 260
apetushkov@9858 261 void JfrRecorderService::clear() {
apetushkov@9858 262 ResourceMark rm;
apetushkov@9858 263 HandleMark hm;
apetushkov@9858 264 pre_safepoint_clear();
apetushkov@9858 265 invoke_safepoint_clear();
apetushkov@9858 266 post_safepoint_clear();
apetushkov@9858 267 }
apetushkov@9858 268
apetushkov@9858 269 void JfrRecorderService::pre_safepoint_clear() {
apetushkov@9858 270 _stack_trace_repository.clear();
apetushkov@9858 271 _string_pool.clear();
apetushkov@9858 272 _storage.clear();
apetushkov@9858 273 }
apetushkov@9858 274
apetushkov@9858 275 void JfrRecorderService::invoke_safepoint_clear() {
apetushkov@9858 276 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_clear> safepoint_task(*this);
apetushkov@9858 277 VMThread::execute(&safepoint_task);
apetushkov@9858 278 }
apetushkov@9858 279
apetushkov@9858 280 //
apetushkov@9858 281 // safepoint clear sequence
apetushkov@9858 282 //
apetushkov@9858 283 // clear stacktrace repository ->
apetushkov@9858 284 // clear string pool ->
apetushkov@9858 285 // clear storage ->
apetushkov@9858 286 // shift epoch ->
apetushkov@9858 287 // update time
apetushkov@9858 288 //
apetushkov@9858 289 void JfrRecorderService::safepoint_clear() {
apetushkov@9858 290 assert(SafepointSynchronize::is_at_safepoint(), "invariant");
apetushkov@9858 291 _stack_trace_repository.clear();
apetushkov@9858 292 _string_pool.clear();
apetushkov@9858 293 _storage.clear();
apetushkov@9858 294 _checkpoint_manager.shift_epoch();
apetushkov@9858 295 _chunkwriter.time_stamp_chunk_now();
apetushkov@9858 296 }
apetushkov@9858 297
apetushkov@9858 298 void JfrRecorderService::post_safepoint_clear() {
apetushkov@9858 299 _checkpoint_manager.clear();
apetushkov@9858 300 }
apetushkov@9858 301
apetushkov@9858 302 static void stop() {
apetushkov@9858 303 assert(JfrRecorderService::is_recording(), "invariant");
apetushkov@9858 304 if (LogJFR) tty->print_cr("Recording STOPPED");
apetushkov@9858 305 set_recording_state(false);
apetushkov@9858 306 assert(!JfrRecorderService::is_recording(), "invariant");
apetushkov@9858 307 }
apetushkov@9858 308
apetushkov@9858 309 void JfrRecorderService::rotate(int msgs) {
apetushkov@9858 310 RotationLock rl(Thread::current());
apetushkov@9858 311 if (rl.not_acquired()) {
apetushkov@9858 312 return;
apetushkov@9858 313 }
apetushkov@9858 314 static bool vm_error = false;
apetushkov@9858 315 if (msgs & MSGBIT(MSG_VM_ERROR)) {
apetushkov@9858 316 vm_error = true;
apetushkov@9858 317 prepare_for_vm_error_rotation();
apetushkov@9858 318 }
apetushkov@9858 319 if (msgs & (MSGBIT(MSG_STOP))) {
apetushkov@9858 320 stop();
apetushkov@9858 321 }
apetushkov@9858 322 // action determined by chunkwriter state
apetushkov@9858 323 if (!_chunkwriter.is_valid()) {
apetushkov@9858 324 in_memory_rotation();
apetushkov@9858 325 return;
apetushkov@9858 326 }
apetushkov@9858 327 if (vm_error) {
apetushkov@9858 328 vm_error_rotation();
apetushkov@9858 329 return;
apetushkov@9858 330 }
apetushkov@9858 331 chunk_rotation();
apetushkov@9858 332 }
apetushkov@9858 333
apetushkov@9858 334 void JfrRecorderService::prepare_for_vm_error_rotation() {
apetushkov@9858 335 if (!_chunkwriter.is_valid()) {
apetushkov@9858 336 open_new_chunk(true);
apetushkov@9858 337 }
apetushkov@9858 338 _checkpoint_manager.register_service_thread(Thread::current());
ddong@9885 339 JfrMetadataEvent::lock();
apetushkov@9858 340 }
apetushkov@9858 341
apetushkov@9858 342 void JfrRecorderService::open_new_chunk(bool vm_error) {
apetushkov@9858 343 assert(!_chunkwriter.is_valid(), "invariant");
apetushkov@9858 344 assert(!JfrStream_lock->owned_by_self(), "invariant");
mgronlun@9875 345 JfrChunkRotation::on_rotation();
apetushkov@9858 346 MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
apetushkov@9858 347 if (!_repository.open_chunk(vm_error)) {
apetushkov@9858 348 assert(!_chunkwriter.is_valid(), "invariant");
apetushkov@9858 349 _storage.control().set_to_disk(false);
apetushkov@9858 350 return;
apetushkov@9858 351 }
apetushkov@9858 352 assert(_chunkwriter.is_valid(), "invariant");
apetushkov@9858 353 _storage.control().set_to_disk(true);
apetushkov@9858 354 }
apetushkov@9858 355
apetushkov@9858 356 void JfrRecorderService::in_memory_rotation() {
apetushkov@9858 357 assert(!_chunkwriter.is_valid(), "invariant");
apetushkov@9858 358 // currently running an in-memory recording
apetushkov@9858 359 open_new_chunk();
apetushkov@9858 360 if (_chunkwriter.is_valid()) {
apetushkov@9858 361 // dump all in-memory buffer data to the newly created chunk
apetushkov@9858 362 serialize_storage_from_in_memory_recording();
apetushkov@9858 363 }
apetushkov@9858 364 }
apetushkov@9858 365
apetushkov@9858 366 void JfrRecorderService::serialize_storage_from_in_memory_recording() {
apetushkov@9858 367 assert(!JfrStream_lock->owned_by_self(), "not holding stream lock!");
apetushkov@9858 368 MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
apetushkov@9858 369 _storage.write();
apetushkov@9858 370 }
apetushkov@9858 371
apetushkov@9858 372 void JfrRecorderService::chunk_rotation() {
apetushkov@9858 373 finalize_current_chunk();
apetushkov@9858 374 open_new_chunk();
apetushkov@9858 375 }
apetushkov@9858 376
apetushkov@9858 377 void JfrRecorderService::finalize_current_chunk() {
apetushkov@9858 378 assert(_chunkwriter.is_valid(), "invariant");
apetushkov@9858 379 write();
apetushkov@9858 380 assert(!_chunkwriter.is_valid(), "invariant");
apetushkov@9858 381 }
apetushkov@9858 382
apetushkov@9858 383 void JfrRecorderService::write() {
apetushkov@9858 384 ResourceMark rm;
apetushkov@9858 385 HandleMark hm;
apetushkov@9858 386 pre_safepoint_write();
apetushkov@9858 387 invoke_safepoint_write();
apetushkov@9858 388 post_safepoint_write();
apetushkov@9858 389 }
apetushkov@9858 390
apetushkov@9858 391 typedef ServiceFunctor<JfrStringPool, &JfrStringPool::write> WriteStringPool;
apetushkov@9858 392 typedef ServiceFunctor<JfrStringPool, &JfrStringPool::write_at_safepoint> WriteStringPoolSafepoint;
apetushkov@9858 393 typedef WriteCheckpointEvent<WriteStackTraceRepository> WriteStackTraceCheckpoint;
apetushkov@9858 394 typedef WriteCheckpointEvent<WriteStringPool> WriteStringPoolCheckpoint;
apetushkov@9858 395 typedef WriteCheckpointEvent<WriteStringPoolSafepoint> WriteStringPoolCheckpointSafepoint;
apetushkov@9858 396
apetushkov@9858 397 static void write_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) {
apetushkov@9858 398 WriteStackTraceRepository write_stacktrace_repo(stack_trace_repo, chunkwriter, clear);
apetushkov@9858 399 WriteStackTraceCheckpoint write_stack_trace_checkpoint(chunkwriter, TYPE_STACKTRACE, write_stacktrace_repo);
apetushkov@9858 400 write_stack_trace_checkpoint.process();
apetushkov@9858 401 }
apetushkov@9858 402
ddong@9885 403 static void write_object_sample_stacktrace(ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repository) {
ddong@9885 404 WriteObjectSampleStacktrace object_sample_stacktrace(sampler, stack_trace_repository);
ddong@9885 405 object_sample_stacktrace.process();
ddong@9885 406 }
ddong@9885 407
apetushkov@9858 408 static void write_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
apetushkov@9858 409 WriteStringPool write_string_pool(string_pool);
apetushkov@9858 410 WriteStringPoolCheckpoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool);
apetushkov@9858 411 write_string_pool_checkpoint.process();
apetushkov@9858 412 }
apetushkov@9858 413
apetushkov@9858 414 static void write_stringpool_checkpoint_safepoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
apetushkov@9858 415 WriteStringPoolSafepoint write_string_pool(string_pool);
apetushkov@9858 416 WriteStringPoolCheckpointSafepoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool);
apetushkov@9858 417 write_string_pool_checkpoint.process();
apetushkov@9858 418 }
apetushkov@9858 419
apetushkov@9858 420 //
apetushkov@9858 421 // pre-safepoint write sequence
apetushkov@9858 422 //
apetushkov@9858 423 // lock stream lock ->
apetushkov@9858 424 // write non-safepoint dependent types ->
apetushkov@9858 425 // write checkpoint epoch transition list->
apetushkov@9858 426 // write stack trace checkpoint ->
apetushkov@9858 427 // write string pool checkpoint ->
ddong@9885 428 // write object sample stacktraces ->
ddong@9885 429 // write storage ->
ddong@9885 430 // release stream lock
apetushkov@9858 431 //
apetushkov@9858 432 void JfrRecorderService::pre_safepoint_write() {
apetushkov@9858 433 MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
apetushkov@9858 434 assert(_chunkwriter.is_valid(), "invariant");
apetushkov@9858 435 _checkpoint_manager.write_types();
apetushkov@9858 436 _checkpoint_manager.write_epoch_transition_mspace();
apetushkov@9858 437 write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, false);
apetushkov@9858 438 write_stringpool_checkpoint(_string_pool, _chunkwriter);
ddong@9885 439 if (LeakProfiler::is_running()) {
ddong@9885 440 // Exclusive access to the object sampler instance.
ddong@9885 441 // The sampler is released (unlocked) later in post_safepoint_write.
ddong@9885 442 ObjectSampler* const sampler = ObjectSampler::acquire();
ddong@9885 443 assert(sampler != NULL, "invariant");
ddong@9885 444 write_object_sample_stacktrace(sampler, _stack_trace_repository);
ddong@9885 445 }
apetushkov@9858 446 _storage.write();
apetushkov@9858 447 }
apetushkov@9858 448
apetushkov@9858 449 void JfrRecorderService::invoke_safepoint_write() {
apetushkov@9858 450 JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this);
apetushkov@9858 451 VMThread::execute(&safepoint_task);
apetushkov@9858 452 }
apetushkov@9858 453
apetushkov@9858 454 //
apetushkov@9858 455 // safepoint write sequence
apetushkov@9858 456 //
apetushkov@9858 457 // lock stream lock ->
apetushkov@9858 458 // write stacktrace repository ->
apetushkov@9858 459 // write string pool ->
apetushkov@9858 460 // write safepoint dependent types ->
apetushkov@9858 461 // write storage ->
apetushkov@9858 462 // shift_epoch ->
apetushkov@9858 463 // update time ->
apetushkov@9858 464 // lock metadata descriptor ->
apetushkov@9858 465 // release stream lock
apetushkov@9858 466 //
apetushkov@9858 467 void JfrRecorderService::safepoint_write() {
apetushkov@9858 468 assert(SafepointSynchronize::is_at_safepoint(), "invariant");
apetushkov@9858 469 MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
apetushkov@9858 470 write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, true);
apetushkov@9858 471 write_stringpool_checkpoint_safepoint(_string_pool, _chunkwriter);
apetushkov@9858 472 _checkpoint_manager.write_safepoint_types();
apetushkov@9858 473 _storage.write_at_safepoint();
apetushkov@9858 474 _checkpoint_manager.shift_epoch();
apetushkov@9858 475 _chunkwriter.time_stamp_chunk_now();
apetushkov@9858 476 JfrMetadataEvent::lock();
apetushkov@9858 477 }
apetushkov@9858 478
apetushkov@9858 479 static jlong write_metadata_event(JfrChunkWriter& chunkwriter) {
apetushkov@9858 480 assert(chunkwriter.is_valid(), "invariant");
apetushkov@9858 481 const jlong metadata_offset = chunkwriter.current_offset();
apetushkov@9858 482 JfrMetadataEvent::write(chunkwriter, metadata_offset);
apetushkov@9858 483 return metadata_offset;
apetushkov@9858 484 }
apetushkov@9858 485
apetushkov@9858 486 //
apetushkov@9858 487 // post-safepoint write sequence
apetushkov@9858 488 //
ddong@9885 489 // write type set ->
ddong@9885 490 // release object sampler ->
ddong@9885 491 // lock stream lock ->
ddong@9885 492 // write checkpoints ->
ddong@9885 493 // write metadata event ->
ddong@9885 494 // write chunk header ->
ddong@9885 495 // close chunk fd ->
ddong@9885 496 // release stream lock
apetushkov@9858 497 //
apetushkov@9858 498 void JfrRecorderService::post_safepoint_write() {
apetushkov@9858 499 assert(_chunkwriter.is_valid(), "invariant");
apetushkov@9858 500 // During the safepoint tasks just completed, the system transitioned to a new epoch.
apetushkov@9858 501 // Type tagging is epoch relative which entails we are able to write out the
apetushkov@9858 502 // already tagged artifacts for the previous epoch. We can accomplish this concurrently
apetushkov@9858 503 // with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint.
apetushkov@9858 504 _checkpoint_manager.write_type_set();
ddong@9885 505 if (LeakProfiler::is_running()) {
ddong@9885 506 // The object sampler instance was exclusively acquired and locked in pre_safepoint_write.
ddong@9885 507 // Note: There is a dependency on write_type_set() above, ensure the release is subsequent.
ddong@9885 508 ObjectSampler::release();
ddong@9885 509 } MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
apetushkov@9858 510 // serialize any outstanding checkpoint memory
apetushkov@9858 511 _checkpoint_manager.write();
apetushkov@9858 512 // serialize the metadata descriptor event and close out the chunk
apetushkov@9858 513 _repository.close_chunk(write_metadata_event(_chunkwriter));
apetushkov@9858 514 assert(!_chunkwriter.is_valid(), "invariant");
apetushkov@9858 515 }
apetushkov@9858 516
apetushkov@9858 517 void JfrRecorderService::vm_error_rotation() {
apetushkov@9858 518 if (_chunkwriter.is_valid()) {
apetushkov@9858 519 finalize_current_chunk_on_vm_error();
apetushkov@9858 520 assert(!_chunkwriter.is_valid(), "invariant");
apetushkov@9858 521 _repository.on_vm_error();
apetushkov@9858 522 }
apetushkov@9858 523 }
apetushkov@9858 524
apetushkov@9858 525 void JfrRecorderService::finalize_current_chunk_on_vm_error() {
apetushkov@9858 526 assert(_chunkwriter.is_valid(), "invariant");
apetushkov@9858 527 pre_safepoint_write();
apetushkov@9858 528 // Do not attempt safepoint dependent operations during emergency dump.
apetushkov@9858 529 // Optimistically write tagged artifacts.
apetushkov@9858 530 _checkpoint_manager.shift_epoch();
apetushkov@9858 531 // update time
apetushkov@9858 532 _chunkwriter.time_stamp_chunk_now();
apetushkov@9858 533 post_safepoint_write();
apetushkov@9858 534 assert(!_chunkwriter.is_valid(), "invariant");
apetushkov@9858 535 }
apetushkov@9858 536
apetushkov@9858 537 void JfrRecorderService::process_full_buffers() {
apetushkov@9858 538 if (_chunkwriter.is_valid()) {
apetushkov@9858 539 assert(!JfrStream_lock->owned_by_self(), "invariant");
apetushkov@9858 540 MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
apetushkov@9858 541 _storage.write_full();
apetushkov@9858 542 }
apetushkov@9858 543 }
apetushkov@9858 544
apetushkov@9858 545 void JfrRecorderService::scavenge() {
apetushkov@9858 546 _storage.scavenge();
apetushkov@9858 547 }
apetushkov@9858 548
apetushkov@9858 549 void JfrRecorderService::evaluate_chunk_size_for_rotation() {
mgronlun@9875 550 JfrChunkRotation::evaluate(_chunkwriter);
apetushkov@9858 551 }

mercurial