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