85 |
86 |
86 static const size_t unlimited_mspace_size = 0; |
87 static const size_t unlimited_mspace_size = 0; |
87 static const size_t checkpoint_buffer_cache_count = 2; |
88 static const size_t checkpoint_buffer_cache_count = 2; |
88 static const size_t checkpoint_buffer_size = 512 * K; |
89 static const size_t checkpoint_buffer_size = 512 * K; |
89 |
90 |
90 static JfrCheckpointMspace* create_mspace(size_t buffer_size, size_t limit, size_t cache_count, JfrCheckpointManager* system) { |
91 static JfrCheckpointMspace* allocate_mspace(size_t size, size_t limit, size_t cache_count, JfrCheckpointManager* mgr) { |
91 JfrCheckpointMspace* mspace = new JfrCheckpointMspace(buffer_size, limit, cache_count, system); |
92 return create_mspace<JfrCheckpointMspace, JfrCheckpointManager>(size, limit, cache_count, mgr); |
92 if (mspace != NULL) { |
|
93 mspace->initialize(); |
|
94 } |
|
95 return mspace; |
|
96 } |
93 } |
97 |
94 |
98 bool JfrCheckpointManager::initialize() { |
95 bool JfrCheckpointManager::initialize() { |
99 assert(_free_list_mspace == NULL, "invariant"); |
96 assert(_free_list_mspace == NULL, "invariant"); |
100 _free_list_mspace = create_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this); |
97 _free_list_mspace = allocate_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this); |
101 if (_free_list_mspace == NULL) { |
98 if (_free_list_mspace == NULL) { |
102 return false; |
99 return false; |
103 } |
100 } |
104 assert(_epoch_transition_mspace == NULL, "invariant"); |
101 assert(_epoch_transition_mspace == NULL, "invariant"); |
105 _epoch_transition_mspace = create_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this); |
102 _epoch_transition_mspace = allocate_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this); |
106 if (_epoch_transition_mspace == NULL) { |
103 if (_epoch_transition_mspace == NULL) { |
107 return false; |
104 return false; |
108 } |
105 } |
109 assert(_lock == NULL, "invariant"); |
106 assert(_lock == NULL, "invariant"); |
110 _lock = new Mutex(Monitor::leaf - 1, "Checkpoint mutex", Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never); |
107 _lock = new Mutex(Monitor::leaf - 1, "Checkpoint mutex", Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never); |
111 if (_lock == NULL) { |
108 if (_lock == NULL) { |
112 return false; |
109 return false; |
113 } |
110 } |
114 return JfrTypeManager::initialize(); |
111 return JfrTypeManager::initialize(); |
115 } |
|
116 |
|
117 bool JfrCheckpointManager::use_epoch_transition_mspace(const Thread* thread) const { |
|
118 return _service_thread != thread && OrderAccess::load_acquire(&_checkpoint_epoch_state) != JfrTraceIdEpoch::epoch(); |
|
119 } |
|
120 |
|
121 void JfrCheckpointManager::synchronize_epoch() { |
|
122 assert(_checkpoint_epoch_state != JfrTraceIdEpoch::epoch(), "invariant"); |
|
123 OrderAccess::storestore(); |
|
124 _checkpoint_epoch_state = JfrTraceIdEpoch::epoch(); |
|
125 } |
|
126 |
|
127 void JfrCheckpointManager::shift_epoch() { |
|
128 debug_only(const u1 current_epoch = JfrTraceIdEpoch::current();) |
|
129 JfrTraceIdEpoch::shift_epoch(); |
|
130 assert(current_epoch != JfrTraceIdEpoch::current(), "invariant"); |
|
131 } |
112 } |
132 |
113 |
133 void JfrCheckpointManager::register_service_thread(const Thread* thread) { |
114 void JfrCheckpointManager::register_service_thread(const Thread* thread) { |
134 _service_thread = thread; |
115 _service_thread = thread; |
135 } |
116 } |
254 |
237 |
255 static juint number_of_types(const u1* data) { |
238 static juint number_of_types(const u1* data) { |
256 return read_data<juint>(data + types_offset); |
239 return read_data<juint>(data + types_offset); |
257 } |
240 } |
258 |
241 |
259 static void write_checkpoint_header(JfrChunkWriter& cw, intptr_t offset_prev_cp_event, const u1* data) { |
242 static void write_checkpoint_header(JfrChunkWriter& cw, int64_t offset_prev_cp_event, const u1* data) { |
260 cw.reserve(sizeof(u4)); |
243 cw.reserve(sizeof(u4)); |
261 cw.write((u8)EVENT_CHECKPOINT); |
244 cw.write<u8>(EVENT_CHECKPOINT); |
262 cw.write(starttime(data)); |
245 cw.write(starttime(data)); |
263 cw.write(duration(data)); |
246 cw.write(duration(data)); |
264 cw.write((jlong)offset_prev_cp_event); |
247 cw.write(offset_prev_cp_event); |
265 cw.write(is_flushpoint(data)); |
248 cw.write(is_flushpoint(data)); |
266 cw.write(number_of_types(data)); |
249 cw.write(number_of_types(data)); |
267 } |
250 } |
268 |
251 |
269 static void write_checkpoint_content(JfrChunkWriter& cw, const u1* data, size_t size) { |
252 static void write_checkpoint_content(JfrChunkWriter& cw, const u1* data, size_t size) { |
270 assert(data != NULL, "invariant"); |
253 assert(data != NULL, "invariant"); |
271 cw.write_unbuffered(data + payload_offset, size); |
254 cw.write_unbuffered(data + payload_offset, size - sizeof(JfrCheckpointEntry)); |
272 } |
255 } |
273 |
256 |
274 static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) { |
257 static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) { |
275 assert(data != NULL, "invariant"); |
258 assert(data != NULL, "invariant"); |
276 const intptr_t previous_checkpoint_event = cw.previous_checkpoint_offset(); |
259 const int64_t event_begin = cw.current_offset(); |
277 const intptr_t event_begin = cw.current_offset(); |
260 const int64_t last_checkpoint_event = cw.last_checkpoint_offset(); |
278 const intptr_t offset_to_previous_checkpoint_event = 0 == previous_checkpoint_event ? 0 : previous_checkpoint_event - event_begin; |
261 const int64_t delta = last_checkpoint_event == 0 ? 0 : last_checkpoint_event - event_begin; |
279 const jlong total_checkpoint_size = total_size(data); |
262 const int64_t checkpoint_size = total_size(data); |
280 write_checkpoint_header(cw, offset_to_previous_checkpoint_event, data); |
263 write_checkpoint_header(cw, delta, data); |
281 write_checkpoint_content(cw, data, total_checkpoint_size - sizeof(JfrCheckpointEntry)); |
264 write_checkpoint_content(cw, data, checkpoint_size); |
282 const jlong checkpoint_event_size = cw.current_offset() - event_begin; |
265 const int64_t event_size = cw.current_offset() - event_begin; |
283 cw.write_padded_at_offset<u4>(checkpoint_event_size, event_begin); |
266 cw.write_padded_at_offset<u4>(event_size, event_begin); |
284 cw.set_previous_checkpoint_offset(event_begin); |
267 cw.set_last_checkpoint_offset(event_begin); |
285 return (size_t)total_checkpoint_size; |
268 return (size_t)checkpoint_size; |
286 } |
269 } |
287 |
270 |
288 static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size) { |
271 static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size) { |
289 assert(cw.is_valid(), "invariant"); |
272 assert(cw.is_valid(), "invariant"); |
290 assert(data != NULL, "invariant"); |
273 assert(data != NULL, "invariant"); |
291 assert(size > 0, "invariant"); |
274 assert(size > 0, "invariant"); |
292 const u1* const limit = data + size; |
275 const u1* const limit = data + size; |
293 const u1* next_entry = data; |
276 const u1* next = data; |
294 size_t processed = 0; |
277 size_t processed = 0; |
295 while (next_entry < limit) { |
278 while (next < limit) { |
296 const size_t checkpoint_size = write_checkpoint_event(cw, next_entry); |
279 const size_t checkpoint_size = write_checkpoint_event(cw, next); |
297 processed += checkpoint_size; |
280 processed += checkpoint_size; |
298 next_entry += checkpoint_size; |
281 next += checkpoint_size; |
299 } |
282 } |
300 assert(next_entry == limit, "invariant"); |
283 assert(next == limit, "invariant"); |
301 return processed; |
284 return processed; |
302 } |
285 } |
303 |
286 |
304 template <typename T> |
287 template <typename T> |
305 class CheckpointWriteOp { |
288 class CheckpointWriteOp { |
315 } |
298 } |
316 size_t processed() const { return _processed; } |
299 size_t processed() const { return _processed; } |
317 }; |
300 }; |
318 |
301 |
319 typedef CheckpointWriteOp<JfrCheckpointMspace::Type> WriteOperation; |
302 typedef CheckpointWriteOp<JfrCheckpointMspace::Type> WriteOperation; |
320 typedef MutexedWriteOp<WriteOperation> MutexedWriteOperation; |
|
321 typedef ReleaseOp<JfrCheckpointMspace> CheckpointReleaseOperation; |
303 typedef ReleaseOp<JfrCheckpointMspace> CheckpointReleaseOperation; |
322 typedef CompositeOperation<MutexedWriteOperation, CheckpointReleaseOperation> CheckpointWriteOperation; |
304 |
323 |
305 template <template <typename> class WriterHost, template <typename, typename> class CompositeOperation> |
324 static size_t write_mspace_exclusive(JfrCheckpointMspace* mspace, JfrChunkWriter& chunkwriter) { |
306 static size_t write_mspace(JfrCheckpointMspace* mspace, JfrChunkWriter& chunkwriter) { |
325 Thread* const thread = Thread::current(); |
307 assert(mspace != NULL, "invariant"); |
326 WriteOperation wo(chunkwriter); |
308 WriteOperation wo(chunkwriter); |
327 MutexedWriteOperation mwo(wo); |
309 WriterHost<WriteOperation> wh(wo); |
328 CheckpointReleaseOperation cro(mspace, thread, false); |
310 CheckpointReleaseOperation cro(mspace, Thread::current(), false); |
329 CheckpointWriteOperation cpwo(&mwo, &cro); |
311 CompositeOperation<WriterHost<WriteOperation>, CheckpointReleaseOperation> co(&wh, &cro); |
330 assert(mspace->is_full_empty(), "invariant"); |
312 assert(mspace->is_full_empty(), "invariant"); |
331 process_free_list(cpwo, mspace); |
313 process_free_list(co, mspace); |
332 return wo.processed(); |
314 return wo.processed(); |
333 } |
315 } |
334 |
316 |
|
317 void JfrCheckpointManager::synchronize_epoch() { |
|
318 assert(_checkpoint_epoch_state != JfrTraceIdEpoch::epoch(), "invariant"); |
|
319 OrderAccess::storestore(); |
|
320 _checkpoint_epoch_state = JfrTraceIdEpoch::epoch(); |
|
321 } |
|
322 |
335 size_t JfrCheckpointManager::write() { |
323 size_t JfrCheckpointManager::write() { |
336 const size_t processed = write_mspace_exclusive(_free_list_mspace, _chunkwriter); |
324 const size_t processed = write_mspace<MutexedWriteOp, CompositeOperation>(_free_list_mspace, _chunkwriter); |
337 synchronize_epoch(); |
325 synchronize_epoch(); |
338 return processed; |
326 return processed; |
339 } |
327 } |
340 |
328 |
341 size_t JfrCheckpointManager::write_epoch_transition_mspace() { |
329 size_t JfrCheckpointManager::write_epoch_transition_mspace() { |
342 return write_mspace_exclusive(_epoch_transition_mspace, _chunkwriter); |
330 return write_mspace<ExclusiveOp, CompositeOperation>(_epoch_transition_mspace, _chunkwriter); |
343 } |
331 } |
344 |
332 |
345 typedef DiscardOp<DefaultDiscarder<JfrBuffer> > DiscardOperation; |
333 typedef DiscardOp<DefaultDiscarder<JfrBuffer> > DiscardOperation; |
346 size_t JfrCheckpointManager::clear() { |
334 size_t JfrCheckpointManager::clear() { |
347 DiscardOperation discarder(mutexed); // mutexed discard mode |
335 DiscardOperation discarder(mutexed); // mutexed discard mode |
371 void JfrCheckpointManager::write_type_set_for_unloaded_classes() { |
359 void JfrCheckpointManager::write_type_set_for_unloaded_classes() { |
372 assert_locked_or_safepoint(ClassLoaderDataGraph_lock); |
360 assert_locked_or_safepoint(ClassLoaderDataGraph_lock); |
373 JfrTypeManager::write_type_set_for_unloaded_classes(); |
361 JfrTypeManager::write_type_set_for_unloaded_classes(); |
374 } |
362 } |
375 |
363 |
376 void JfrCheckpointManager::create_thread_checkpoint(JavaThread* jt) { |
364 void JfrCheckpointManager::create_thread_blob(JavaThread* jt) { |
377 JfrTypeManager::create_thread_checkpoint(jt); |
365 JfrTypeManager::create_thread_blob(jt); |
378 } |
366 } |
379 |
367 |
380 void JfrCheckpointManager::write_thread_checkpoint(JavaThread* jt) { |
368 void JfrCheckpointManager::write_thread_checkpoint(JavaThread* jt) { |
381 JfrTypeManager::write_thread_checkpoint(jt); |
369 JfrTypeManager::write_thread_checkpoint(jt); |
382 } |
370 } |
|
371 |
|
372 void JfrCheckpointManager::shift_epoch() { |
|
373 debug_only(const u1 current_epoch = JfrTraceIdEpoch::current();) |
|
374 JfrTraceIdEpoch::shift_epoch(); |
|
375 assert(current_epoch != JfrTraceIdEpoch::current(), "invariant"); |
|
376 } |