108 |
108 |
109 static void add_to_unloaded_klass_set(traceid klass_id) { |
109 static void add_to_unloaded_klass_set(traceid klass_id) { |
110 if (unloaded_klass_set == NULL) { |
110 if (unloaded_klass_set == NULL) { |
111 unloaded_klass_set = c_heap_allocate_array<traceid>(); |
111 unloaded_klass_set = c_heap_allocate_array<traceid>(); |
112 } |
112 } |
113 add(unloaded_klass_set, klass_id); |
113 unloaded_klass_set->append(klass_id); |
|
114 } |
|
115 |
|
116 static void sort_unloaded_klass_set() { |
|
117 if (unloaded_klass_set != NULL && unloaded_klass_set->length() > 1) { |
|
118 unloaded_klass_set->sort(sort_traceid); |
|
119 } |
114 } |
120 } |
115 |
121 |
116 void ObjectSampleCheckpoint::on_klass_unload(const Klass* k) { |
122 void ObjectSampleCheckpoint::on_klass_unload(const Klass* k) { |
117 assert(k != NULL, "invariant"); |
123 assert(k != NULL, "invariant"); |
118 add_to_unloaded_klass_set(TRACE_ID(k)); |
124 add_to_unloaded_klass_set(TRACE_ID(k)); |
210 |
216 |
211 inline void BlobCache::unlink(BlobEntry* entry) const { |
217 inline void BlobCache::unlink(BlobEntry* entry) const { |
212 assert(entry != NULL, "invariant"); |
218 assert(entry != NULL, "invariant"); |
213 } |
219 } |
214 |
220 |
|
221 static GrowableArray<traceid>* id_set = NULL; |
|
222 |
|
223 static void prepare_for_resolution() { |
|
224 id_set = new GrowableArray<traceid>(JfrOptionSet::old_object_queue_size()); |
|
225 sort_unloaded_klass_set(); |
|
226 } |
|
227 |
215 static bool stack_trace_precondition(const ObjectSample* sample) { |
228 static bool stack_trace_precondition(const ObjectSample* sample) { |
216 assert(sample != NULL, "invariant"); |
229 assert(sample != NULL, "invariant"); |
217 return sample->has_stack_trace_id() && !sample->is_dead(); |
230 return sample->has_stack_trace_id() && !sample->is_dead(); |
218 } |
231 } |
219 |
232 |
222 const JfrStackTraceRepository& _stack_trace_repo; |
235 const JfrStackTraceRepository& _stack_trace_repo; |
223 BlobCache _cache; |
236 BlobCache _cache; |
224 const JfrStackTrace* resolve(const ObjectSample* sample); |
237 const JfrStackTrace* resolve(const ObjectSample* sample); |
225 void install(ObjectSample* sample); |
238 void install(ObjectSample* sample); |
226 public: |
239 public: |
227 StackTraceBlobInstaller(const JfrStackTraceRepository& stack_trace_repo) : |
240 StackTraceBlobInstaller(const JfrStackTraceRepository& stack_trace_repo); |
228 _stack_trace_repo(stack_trace_repo), |
|
229 _cache(JfrOptionSet::old_object_queue_size()) {} |
|
230 void sample_do(ObjectSample* sample) { |
241 void sample_do(ObjectSample* sample) { |
231 if (stack_trace_precondition(sample)) { |
242 if (stack_trace_precondition(sample)) { |
232 install(sample); |
243 install(sample); |
233 } |
244 } |
234 } |
245 } |
235 }; |
246 }; |
|
247 |
|
248 StackTraceBlobInstaller::StackTraceBlobInstaller(const JfrStackTraceRepository& stack_trace_repo) : |
|
249 _stack_trace_repo(stack_trace_repo), _cache(JfrOptionSet::old_object_queue_size()) { |
|
250 prepare_for_resolution(); |
|
251 } |
236 |
252 |
237 const JfrStackTrace* StackTraceBlobInstaller::resolve(const ObjectSample* sample) { |
253 const JfrStackTrace* StackTraceBlobInstaller::resolve(const ObjectSample* sample) { |
238 return _stack_trace_repo.lookup(sample->stack_trace_hash(), sample->stack_trace_id()); |
254 return _stack_trace_repo.lookup(sample->stack_trace_hash(), sample->stack_trace_id()); |
239 } |
255 } |
240 |
256 |
262 blob = writer.move(); |
278 blob = writer.move(); |
263 _cache.put(sample, blob); |
279 _cache.put(sample, blob); |
264 sample->set_stacktrace(blob); |
280 sample->set_stacktrace(blob); |
265 } |
281 } |
266 |
282 |
267 static GrowableArray<traceid>* id_set = NULL; |
283 static void install_stack_traces(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) { |
268 |
|
269 static void allocate_traceid_working_set() { |
|
270 id_set = new GrowableArray<traceid>(JfrOptionSet::old_object_queue_size()); |
|
271 } |
|
272 |
|
273 static void resolve_stack_traces(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) { |
|
274 assert(sampler != NULL, "invariant"); |
284 assert(sampler != NULL, "invariant"); |
275 const ObjectSample* const last = sampler->last(); |
285 const ObjectSample* const last = sampler->last(); |
276 if (last != sampler->last_resolved()) { |
286 if (last != sampler->last_resolved()) { |
277 allocate_traceid_working_set(); |
|
278 StackTraceBlobInstaller installer(stack_trace_repo); |
287 StackTraceBlobInstaller installer(stack_trace_repo); |
279 iterate_samples(installer); |
288 iterate_samples(installer); |
280 } |
289 } |
281 } |
290 } |
282 |
291 |
283 // caller needs ResourceMark |
292 // caller needs ResourceMark |
284 void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) { |
293 void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) { |
285 assert(sampler != NULL, "invariant"); |
294 assert(sampler != NULL, "invariant"); |
286 assert(LeakProfiler::is_running(), "invariant"); |
295 assert(LeakProfiler::is_running(), "invariant"); |
287 resolve_stack_traces(sampler, stack_trace_repo); |
296 install_stack_traces(sampler, stack_trace_repo); |
288 } |
297 } |
289 |
298 |
290 static traceid get_klass_id(traceid method_id) { |
299 static traceid get_klass_id(traceid method_id) { |
291 assert(method_id != 0, "invariant"); |
300 assert(method_id != 0, "invariant"); |
292 return method_id >> TRACE_ID_SHIFT; |
301 return method_id >> TRACE_ID_SHIFT; |
398 ObjectSampleWriter osw(writer, edge_store); |
407 ObjectSampleWriter osw(writer, edge_store); |
399 edge_store->iterate(osw); |
408 edge_store->iterate(osw); |
400 } |
409 } |
401 } |
410 } |
402 |
411 |
403 class BlobInstaller { |
|
404 private: |
|
405 const JfrBlobHandle& _blob; |
|
406 public: |
|
407 BlobInstaller(const JfrBlobHandle& blob) : _blob(blob) {} |
|
408 void sample_do(ObjectSample* sample) { |
|
409 if (!sample->is_dead()) { |
|
410 sample->set_type_set(_blob); |
|
411 } |
|
412 } |
|
413 }; |
|
414 |
|
415 static void clear_unloaded_klass_set() { |
412 static void clear_unloaded_klass_set() { |
416 if (unloaded_klass_set != NULL && unloaded_klass_set->is_nonempty()) { |
413 if (unloaded_klass_set != NULL && unloaded_klass_set->is_nonempty()) { |
417 unloaded_klass_set->clear(); |
414 unloaded_klass_set->clear(); |
418 } |
415 } |
419 } |
416 } |
420 |
417 |
421 static void install_blob(JfrCheckpointWriter& writer, bool copy = false) { |
418 // A linked list of saved type set blobs for the epoch. |
|
419 // The link consist of a reference counted handle. |
|
420 static JfrBlobHandle saved_type_set_blobs; |
|
421 |
|
422 static void release_state_for_previous_epoch() { |
|
423 // decrements the reference count and the list is reinitialized |
|
424 saved_type_set_blobs = JfrBlobHandle(); |
|
425 clear_unloaded_klass_set(); |
|
426 } |
|
427 |
|
428 class BlobInstaller { |
|
429 public: |
|
430 ~BlobInstaller() { |
|
431 release_state_for_previous_epoch(); |
|
432 } |
|
433 void sample_do(ObjectSample* sample) { |
|
434 if (!sample->is_dead()) { |
|
435 sample->set_type_set(saved_type_set_blobs); |
|
436 } |
|
437 } |
|
438 }; |
|
439 |
|
440 static void install_type_set_blobs() { |
|
441 BlobInstaller installer; |
|
442 iterate_samples(installer); |
|
443 } |
|
444 |
|
445 static void save_type_set_blob(JfrCheckpointWriter& writer, bool copy = false) { |
422 assert(writer.has_data(), "invariant"); |
446 assert(writer.has_data(), "invariant"); |
423 const JfrBlobHandle blob = copy ? writer.copy() : writer.move(); |
447 const JfrBlobHandle blob = copy ? writer.copy() : writer.move(); |
424 BlobInstaller installer(blob); |
448 if (saved_type_set_blobs.valid()) { |
425 iterate_samples(installer); |
449 saved_type_set_blobs->set_next(blob); |
|
450 } else { |
|
451 saved_type_set_blobs = blob; |
|
452 } |
426 } |
453 } |
427 |
454 |
428 void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) { |
455 void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) { |
429 assert(LeakProfiler::is_running(), "invariant"); |
456 assert(LeakProfiler::is_running(), "invariant"); |
430 const ObjectSample* last = ObjectSampler::sampler()->last(); |
457 const ObjectSample* last = ObjectSampler::sampler()->last(); |
431 if (writer.has_data() && last != NULL) { |
458 if (writer.has_data() && last != NULL) { |
432 install_blob(writer); |
459 save_type_set_blob(writer); |
|
460 install_type_set_blobs(); |
433 ObjectSampler::sampler()->set_last_resolved(last); |
461 ObjectSampler::sampler()->set_last_resolved(last); |
434 } |
462 } |
435 // Only happens post chunk rotation and we would not have hit another class unload safepoint. |
|
436 // Therefore it is safe to release the set of unloaded classes tracked during the previous epoch. |
|
437 clear_unloaded_klass_set(); |
|
438 } |
463 } |
439 |
464 |
440 void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) { |
465 void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) { |
441 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
466 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
442 assert(LeakProfiler::is_running(), "invariant"); |
467 assert(LeakProfiler::is_running(), "invariant"); |
443 if (writer.has_data() && ObjectSampler::sampler()->last() != NULL) { |
468 if (writer.has_data() && ObjectSampler::sampler()->last() != NULL) { |
444 install_blob(writer, true); |
469 save_type_set_blob(writer, true); |
445 } |
470 } |
446 } |
471 } |