38
38
#include " jfr/recorder/storage/jfrStorageUtils.inline.hpp"
39
39
#include " jfr/utilities/jfrBigEndian.hpp"
40
40
#include " jfr/utilities/jfrIterator.hpp"
41
+ #include " jfr/utilities/jfrLinkedList.inline.hpp"
41
42
#include " jfr/utilities/jfrThreadIterator.hpp"
42
43
#include " jfr/utilities/jfrTypes.hpp"
43
44
#include " jfr/writers/jfrJavaEventWriter.hpp"
50
51
#include " runtime/os.inline.hpp"
51
52
#include " runtime/safepoint.hpp"
52
53
53
- typedef JfrCheckpointManager::Buffer* BufferPtr;
54
-
55
- static JfrCheckpointManager* _instance = NULL ;
54
+ typedef JfrCheckpointManager::BufferPtr BufferPtr;
56
55
57
56
static volatile bool constant_pending = false ;
58
57
@@ -70,6 +69,8 @@ static void set_constant_pending() {
70
69
}
71
70
}
72
71
72
+ static JfrCheckpointManager* _instance = NULL ;
73
+
73
74
JfrCheckpointManager& JfrCheckpointManager::instance () {
74
75
return *_instance;
75
76
}
@@ -89,7 +90,6 @@ void JfrCheckpointManager::destroy() {
89
90
JfrCheckpointManager::JfrCheckpointManager (JfrChunkWriter& cw) :
90
91
_free_list_mspace(NULL ),
91
92
_epoch_transition_mspace(NULL ),
92
- _lock(NULL ),
93
93
_service_thread(NULL ),
94
94
_chunkwriter(cw),
95
95
_checkpoint_epoch_state(JfrTraceIdEpoch::epoch()) {}
@@ -101,9 +101,6 @@ JfrCheckpointManager::~JfrCheckpointManager() {
101
101
if (_epoch_transition_mspace != NULL ) {
102
102
delete _epoch_transition_mspace;
103
103
}
104
- if (_lock != NULL ) {
105
- delete _lock;
106
- }
107
104
JfrTypeManager::destroy ();
108
105
}
109
106
@@ -126,40 +123,22 @@ bool JfrCheckpointManager::initialize() {
126
123
if (_epoch_transition_mspace == NULL ) {
127
124
return false ;
128
125
}
129
- assert (_lock == NULL , " invariant" );
130
- _lock = new Mutex (Monitor::leaf - 1 , " Checkpoint mutex" , Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never);
131
- if (_lock == NULL ) {
132
- return false ;
133
- }
134
126
return JfrTypeManager::initialize ();
135
127
}
136
128
137
129
void JfrCheckpointManager::register_service_thread (const Thread* thread) {
138
130
_service_thread = thread;
139
131
}
140
132
141
- void JfrCheckpointManager::register_full (BufferPtr t , Thread* thread) {
133
+ void JfrCheckpointManager::register_full (BufferPtr buffer , Thread* thread) {
142
134
// nothing here at the moment
143
- assert (t != NULL , " invariant" );
144
- assert (t->acquired_by (thread), " invariant" );
145
- assert (t->retired (), " invariant" );
146
- }
147
-
148
- void JfrCheckpointManager::lock () {
149
- assert (!_lock->owned_by_self (), " invariant" );
150
- _lock->lock_without_safepoint_check ();
151
- }
152
-
153
- void JfrCheckpointManager::unlock () {
154
- _lock->unlock ();
135
+ assert (buffer != NULL , " invariant" );
136
+ assert (buffer->acquired_by (thread), " invariant" );
137
+ assert (buffer->retired (), " invariant" );
155
138
}
156
139
157
140
#ifdef ASSERT
158
- bool JfrCheckpointManager::is_locked () const {
159
- return _lock->owned_by_self ();
160
- }
161
-
162
- static void assert_free_lease (const BufferPtr buffer) {
141
+ static void assert_lease (const BufferPtr buffer) {
163
142
assert (buffer != NULL , " invariant" );
164
143
assert (buffer->acquired_by_self (), " invariant" );
165
144
assert (buffer->lease (), " invariant" );
@@ -172,45 +151,46 @@ static void assert_release(const BufferPtr buffer) {
172
151
}
173
152
#endif // ASSERT
174
153
175
- static BufferPtr lease_free (size_t size, JfrCheckpointMspace* mspace, size_t retry_count, Thread* thread) {
154
+ bool JfrCheckpointManager::use_epoch_transition_mspace (const Thread* thread) const {
155
+ return _service_thread != thread && Atomic::load_acquire (&_checkpoint_epoch_state) != JfrTraceIdEpoch::epoch ();
156
+ }
157
+
158
+ static const size_t lease_retry = 10 ;
159
+
160
+ BufferPtr JfrCheckpointManager::lease (JfrCheckpointMspace* mspace, Thread* thread, size_t size /* 0 */ ) {
161
+ assert (mspace != NULL , " invariant" );
176
162
static const size_t max_elem_size = mspace->min_elem_size (); // min is max
177
163
BufferPtr buffer;
178
164
if (size <= max_elem_size) {
179
- BufferPtr buffer = mspace_get_free_lease_with_retry (size, mspace, retry_count , thread);
165
+ buffer = mspace_get_free_lease_with_retry (size, mspace, lease_retry , thread);
180
166
if (buffer != NULL ) {
181
- DEBUG_ONLY (assert_free_lease (buffer);)
167
+ DEBUG_ONLY (assert_lease (buffer);)
182
168
return buffer;
183
169
}
184
170
}
185
- buffer = mspace_allocate_transient_lease_to_free (size, mspace, thread);
186
- DEBUG_ONLY (assert_free_lease (buffer);)
171
+ buffer = mspace_allocate_transient_lease_to_full (size, mspace, thread);
172
+ DEBUG_ONLY (assert_lease (buffer);)
187
173
return buffer;
188
174
}
189
175
190
- bool JfrCheckpointManager::use_epoch_transition_mspace (const Thread* thread) const {
191
- return _service_thread != thread && Atomic::load_acquire (&_checkpoint_epoch_state) != JfrTraceIdEpoch::epoch ();
192
- }
193
-
194
- static const size_t lease_retry = 10 ;
195
-
196
- BufferPtr JfrCheckpointManager::lease_buffer (Thread* thread, size_t size /* 0 */ ) {
176
+ BufferPtr JfrCheckpointManager::lease (Thread* thread, size_t size /* 0 */ ) {
197
177
JfrCheckpointManager& manager = instance ();
198
- if ( manager.use_epoch_transition_mspace (thread)) {
199
- return lease_free (size, manager._epoch_transition_mspace , lease_retry, thread);
200
- }
201
- return lease_free (size, manager. _free_list_mspace , lease_retry, thread );
178
+ JfrCheckpointMspace* const mspace = manager.use_epoch_transition_mspace (thread) ?
179
+ manager._epoch_transition_mspace :
180
+ manager. _free_list_mspace ;
181
+ return lease (mspace, thread, size );
202
182
}
203
183
204
184
JfrCheckpointMspace* JfrCheckpointManager::lookup (BufferPtr old) const {
205
185
assert (old != NULL , " invariant" );
206
- return _free_list_mspace->in_free_list (old) ? _free_list_mspace : _epoch_transition_mspace;
186
+ return _free_list_mspace->in_mspace (old) ? _free_list_mspace : _epoch_transition_mspace;
207
187
}
208
188
209
- BufferPtr JfrCheckpointManager::lease_buffer (BufferPtr old, Thread* thread, size_t size /* 0 */ ) {
189
+ BufferPtr JfrCheckpointManager::lease (BufferPtr old, Thread* thread, size_t size /* 0 */ ) {
210
190
assert (old != NULL , " invariant" );
211
191
JfrCheckpointMspace* mspace = instance ().lookup (old);
212
192
assert (mspace != NULL , " invariant" );
213
- return lease_free (size, mspace, lease_retry, thread );
193
+ return lease ( mspace, thread, size );
214
194
}
215
195
216
196
/*
@@ -219,10 +199,14 @@ BufferPtr JfrCheckpointManager::lease_buffer(BufferPtr old, Thread* thread, size
219
199
* The buffer is effectively invalidated for the thread post-return,
220
200
* and the caller should take means to ensure that it is not referenced.
221
201
*/
222
- static void release (BufferPtr const buffer, Thread* thread) {
202
+ static void release (BufferPtr buffer, Thread* thread) {
223
203
DEBUG_ONLY (assert_release (buffer);)
224
204
buffer->clear_lease ();
225
- buffer->release ();
205
+ if (buffer->transient ()) {
206
+ buffer->set_retired ();
207
+ } else {
208
+ buffer->release ();
209
+ }
226
210
}
227
211
228
212
BufferPtr JfrCheckpointManager::flush (BufferPtr old, size_t used, size_t requested, Thread* thread) {
@@ -235,7 +219,7 @@ BufferPtr JfrCheckpointManager::flush(BufferPtr old, size_t used, size_t request
235
219
return NULL ;
236
220
}
237
221
// migration of in-flight information
238
- BufferPtr const new_buffer = lease_buffer (old, thread, used + requested);
222
+ BufferPtr const new_buffer = lease (old, thread, used + requested);
239
223
if (new_buffer != NULL ) {
240
224
migrate_outstanding_writes (old, new_buffer, used, requested);
241
225
}
@@ -335,18 +319,22 @@ class CheckpointWriteOp {
335
319
size_t processed () const { return _processed; }
336
320
};
337
321
338
- typedef CheckpointWriteOp<JfrCheckpointMspace::Type> WriteOperation;
339
- typedef ReleaseOp<JfrCheckpointMspace> CheckpointReleaseOperation;
322
+ typedef CheckpointWriteOp<JfrCheckpointManager::Buffer> WriteOperation;
323
+ typedef ReleaseOp<JfrCheckpointMspace> CheckpointReleaseFreeOperation;
324
+ typedef ScavengingReleaseOp<JfrCheckpointMspace> CheckpointReleaseFullOperation;
340
325
341
- template <template <typename > class WriterHost , template < typename , typename , typename > class CompositeOperation >
326
+ template <template <typename > class WriterHost >
342
327
static size_t write_mspace (JfrCheckpointMspace* mspace, JfrChunkWriter& chunkwriter) {
343
328
assert (mspace != NULL , " invariant" );
344
329
WriteOperation wo (chunkwriter);
345
330
WriterHost<WriteOperation> wh (wo);
346
- CheckpointReleaseOperation cro (mspace, Thread::current (), false );
347
- CompositeOperation<WriterHost<WriteOperation>, CheckpointReleaseOperation, CompositeOperationAnd> co (&wh, &cro);
348
- assert (mspace->is_full_empty (), " invariant" );
349
- process_free_list (co, mspace);
331
+ CheckpointReleaseFreeOperation free_release_op (mspace);
332
+ CompositeOperation<WriterHost<WriteOperation>, CheckpointReleaseFreeOperation> free_op (&wh, &free_release_op);
333
+ process_free_list (free_op, mspace);
334
+ CheckpointReleaseFullOperation full_release_op (mspace);
335
+ MutexedWriteOp<WriteOperation> full_write_op (wo);
336
+ CompositeOperation<MutexedWriteOp<WriteOperation>, CheckpointReleaseFullOperation> full_op (&full_write_op, &full_release_op);
337
+ process_full_list (full_op, mspace);
350
338
return wo.processed ();
351
339
}
352
340
@@ -369,52 +357,66 @@ void JfrCheckpointManager::synchronize_checkpoint_manager_with_current_epoch() {
369
357
}
370
358
371
359
size_t JfrCheckpointManager::write () {
372
- const size_t processed = write_mspace<MutexedWriteOp, CompositeOperation >(_free_list_mspace, _chunkwriter);
360
+ const size_t processed = write_mspace<MutexedWriteOp>(_free_list_mspace, _chunkwriter);
373
361
synchronize_checkpoint_manager_with_current_epoch ();
374
362
return processed;
375
363
}
376
364
377
365
size_t JfrCheckpointManager::write_epoch_transition_mspace () {
378
- return write_mspace<ExclusiveOp, CompositeOperation >(_epoch_transition_mspace, _chunkwriter);
366
+ return write_mspace<ExclusiveOp>(_epoch_transition_mspace, _chunkwriter);
379
367
}
380
368
381
- typedef DiscardOp<DefaultDiscarder<JfrBuffer> > DiscardOperation;
369
+ typedef DiscardOp<DefaultDiscarder<JfrCheckpointManager::Buffer> > DiscardOperation;
370
+ typedef ExclusiveDiscardOp<DefaultDiscarder<JfrCheckpointManager::Buffer> > DiscardOperationEpochTransitionMspace;
371
+ typedef CompositeOperation<DiscardOperation, CheckpointReleaseFreeOperation> DiscardFreeOperation;
372
+ typedef CompositeOperation<DiscardOperation, CheckpointReleaseFullOperation> DiscardFullOperation;
373
+ typedef CompositeOperation<DiscardOperationEpochTransitionMspace, CheckpointReleaseFreeOperation> DiscardEpochTransMspaceFreeOperation;
374
+ typedef CompositeOperation<DiscardOperationEpochTransitionMspace, CheckpointReleaseFullOperation> DiscardEpochTransMspaceFullOperation;
375
+
382
376
size_t JfrCheckpointManager::clear () {
383
377
clear_type_set ();
384
- DiscardOperation discarder (mutexed); // mutexed discard mode
385
- process_free_list (discarder, _free_list_mspace);
386
- process_free_list (discarder, _epoch_transition_mspace);
378
+ DiscardOperation mutex_discarder (mutexed);
379
+ CheckpointReleaseFreeOperation free_release_op (_free_list_mspace);
380
+ DiscardFreeOperation free_op (&mutex_discarder, &free_release_op);
381
+ process_free_list (free_op, _free_list_mspace);
382
+ CheckpointReleaseFullOperation full_release_op (_free_list_mspace);
383
+ DiscardFullOperation full_op (&mutex_discarder, &full_release_op);
384
+ process_full_list (full_op, _free_list_mspace);
385
+ DiscardOperationEpochTransitionMspace epoch_transition_discarder (mutexed);
386
+ CheckpointReleaseFreeOperation epoch_free_release_op (_epoch_transition_mspace);
387
+ DiscardEpochTransMspaceFreeOperation epoch_free_op (&epoch_transition_discarder, &epoch_free_release_op);
388
+ process_free_list (epoch_free_op, _epoch_transition_mspace);
389
+ CheckpointReleaseFullOperation epoch_full_release_op (_epoch_transition_mspace);
390
+ DiscardEpochTransMspaceFullOperation epoch_full_op (&epoch_transition_discarder, &epoch_full_release_op);
391
+ process_full_list (epoch_full_op, _epoch_transition_mspace);
387
392
synchronize_checkpoint_manager_with_current_epoch ();
388
- return discarder .elements ();
393
+ return mutex_discarder. elements () + epoch_transition_discarder .elements ();
389
394
}
390
395
391
396
// Optimization for write_static_type_set() and write_threads() is to write
392
397
// directly into the epoch transition mspace because we will immediately
393
398
// serialize and reset this mspace post-write.
394
- static JfrBuffer* get_epoch_transition_buffer (JfrCheckpointMspace* mspace, Thread* t) {
395
- assert (mspace != NULL , " invariant" );
396
- JfrBuffer* const buffer = mspace->free_head ();
397
- assert (buffer != NULL , " invariant" );
398
- buffer->acquire (t);
399
- buffer->set_lease ();
400
- DEBUG_ONLY (assert_free_lease (buffer);)
399
+ BufferPtr JfrCheckpointManager::epoch_transition_buffer (Thread* thread) {
400
+ assert (_epoch_transition_mspace->free_list_is_nonempty (), " invariant" );
401
+ BufferPtr const buffer = lease (_epoch_transition_mspace, thread, _epoch_transition_mspace->min_elem_size ());
402
+ DEBUG_ONLY (assert_lease (buffer);)
401
403
return buffer;
402
404
}
403
405
404
406
size_t JfrCheckpointManager::write_static_type_set () {
405
- Thread* const t = Thread::current ();
406
- ResourceMark rm (t );
407
- HandleMark hm (t );
408
- JfrCheckpointWriter writer (t, get_epoch_transition_buffer (_epoch_transition_mspace, t ), STATICS);
407
+ Thread* const thread = Thread::current ();
408
+ ResourceMark rm (thread );
409
+ HandleMark hm (thread );
410
+ JfrCheckpointWriter writer (thread, epoch_transition_buffer (thread ), STATICS);
409
411
JfrTypeManager::write_static_types (writer);
410
412
return writer.used_size ();
411
413
}
412
414
413
415
size_t JfrCheckpointManager::write_threads () {
414
- Thread* const t = Thread::current ();
415
- ResourceMark rm (t );
416
- HandleMark hm (t );
417
- JfrCheckpointWriter writer (t, get_epoch_transition_buffer (_epoch_transition_mspace, t ), THREADS);
416
+ Thread* const thread = Thread::current ();
417
+ ResourceMark rm (thread );
418
+ HandleMark hm (thread );
419
+ JfrCheckpointWriter writer (thread, epoch_transition_buffer (thread ), THREADS);
418
420
JfrTypeManager::write_threads (writer);
419
421
return writer.used_size ();
420
422
}
@@ -442,20 +444,20 @@ void JfrCheckpointManager::clear_type_set() {
442
444
443
445
void JfrCheckpointManager::write_type_set () {
444
446
assert (!SafepointSynchronize::is_at_safepoint (), " invariant" );
447
+ Thread* const thread = Thread::current ();
445
448
if (LeakProfiler::is_running ()) {
446
- Thread* const t = Thread::current ();
447
449
// can safepoint here
448
- MutexLocker cld_lock (t , ClassLoaderDataGraph_lock);
449
- MutexLocker module_lock (t , Module_lock);
450
- JfrCheckpointWriter leakp_writer (t );
451
- JfrCheckpointWriter writer (t );
450
+ MutexLocker cld_lock (thread , ClassLoaderDataGraph_lock);
451
+ MutexLocker module_lock (thread , Module_lock);
452
+ JfrCheckpointWriter leakp_writer (thread );
453
+ JfrCheckpointWriter writer (thread );
452
454
JfrTypeSet::serialize (&writer, &leakp_writer, false , false );
453
455
ObjectSampleCheckpoint::on_type_set (leakp_writer);
454
456
} else {
455
457
// can safepoint here
456
458
MutexLocker cld_lock (ClassLoaderDataGraph_lock);
457
459
MutexLocker module_lock (Module_lock);
458
- JfrCheckpointWriter writer (Thread::current () );
460
+ JfrCheckpointWriter writer (thread );
459
461
JfrTypeSet::serialize (&writer, NULL , false , false );
460
462
}
461
463
write ();
@@ -489,27 +491,27 @@ size_t JfrCheckpointManager::flush_type_set() {
489
491
if (is_constant_pending ()) {
490
492
WriteOperation wo (_chunkwriter);
491
493
FlushOperation fo (wo);
492
- assert (_free_list_mspace->is_full_empty (), " invariant" );
493
494
process_free_list (fo, _free_list_mspace);
495
+ process_full_list (fo, _free_list_mspace);
494
496
}
495
497
return elements;
496
498
}
497
499
498
- void JfrCheckpointManager::create_thread_blob (Thread* t ) {
499
- JfrTypeManager::create_thread_blob (t );
500
+ void JfrCheckpointManager::create_thread_blob (Thread* thread ) {
501
+ JfrTypeManager::create_thread_blob (thread );
500
502
}
501
503
502
- void JfrCheckpointManager::write_thread_checkpoint (Thread* t ) {
503
- JfrTypeManager::write_thread_checkpoint (t );
504
+ void JfrCheckpointManager::write_thread_checkpoint (Thread* thread ) {
505
+ JfrTypeManager::write_thread_checkpoint (thread );
504
506
}
505
507
506
508
class JfrNotifyClosure : public ThreadClosure {
507
509
public:
508
- void do_thread (Thread* t ) {
509
- assert (t != NULL , " invariant" );
510
- assert (t ->is_Java_thread (), " invariant" );
510
+ void do_thread (Thread* thread ) {
511
+ assert (thread != NULL , " invariant" );
512
+ assert (thread ->is_Java_thread (), " invariant" );
511
513
assert_locked_or_safepoint (Threads_lock);
512
- JfrJavaEventWriter::notify ((JavaThread*)t );
514
+ JfrJavaEventWriter::notify ((JavaThread*)thread );
513
515
}
514
516
};
515
517
0 commit comments