1 /* |
1 /* |
2 * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
31 #include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp" |
31 #include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp" |
32 #include "jfr/leakprofiler/checkpoint/rootResolver.hpp" |
32 #include "jfr/leakprofiler/checkpoint/rootResolver.hpp" |
33 #include "jfr/leakprofiler/sampling/objectSampler.hpp" |
33 #include "jfr/leakprofiler/sampling/objectSampler.hpp" |
34 #include "jfr/leakprofiler/utilities/rootType.hpp" |
34 #include "jfr/leakprofiler/utilities/rootType.hpp" |
35 #include "jfr/leakprofiler/utilities/unifiedOop.hpp" |
35 #include "jfr/leakprofiler/utilities/unifiedOop.hpp" |
36 #include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" |
36 #include "jfr/writers/jfrTypeWriterHost.hpp" |
37 #include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp" |
|
38 #include "oops/oop.inline.hpp" |
37 #include "oops/oop.inline.hpp" |
39 #include "oops/symbol.hpp" |
38 #include "oops/symbol.hpp" |
40 #include "utilities/growableArray.hpp" |
39 #include "utilities/growableArray.hpp" |
41 |
40 |
42 template <typename Data> |
41 template <typename Data> |
157 assert(stored != NULL, "invariant"); |
156 assert(stored != NULL, "invariant"); |
158 assert(stored->_field_name_symbol->identity_hash() == query->_field_name_symbol->identity_hash(), "invariant"); |
157 assert(stored->_field_name_symbol->identity_hash() == query->_field_name_symbol->identity_hash(), "invariant"); |
159 return stored->_field_modifiers == query->_field_modifiers; |
158 return stored->_field_modifiers == query->_field_modifiers; |
160 } |
159 } |
161 |
160 |
|
161 void unlink(FieldInfoEntry* entry) { |
|
162 assert(entry != NULL, "invariant"); |
|
163 // nothing |
|
164 } |
|
165 |
162 public: |
166 public: |
163 FieldTable() : _table(new FieldInfoTable(this)) {} |
167 FieldTable() : _table(new FieldInfoTable(this)) {} |
164 ~FieldTable() { |
168 ~FieldTable() { |
165 assert(_table != NULL, "invariant"); |
169 assert(_table != NULL, "invariant"); |
166 delete _table; |
170 delete _table; |
194 static RefInfo* ref_infos = NULL; |
198 static RefInfo* ref_infos = NULL; |
195 static ArrayInfo* array_infos = NULL; |
199 static ArrayInfo* array_infos = NULL; |
196 static FieldTable* field_infos = NULL; |
200 static FieldTable* field_infos = NULL; |
197 static RootDescriptionInfo* root_infos = NULL; |
201 static RootDescriptionInfo* root_infos = NULL; |
198 |
202 |
199 int __write_sample_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* si) { |
203 int __write_sample_info__(JfrCheckpointWriter* writer, const void* si) { |
200 assert(writer != NULL, "invariant"); |
204 assert(writer != NULL, "invariant"); |
201 assert(si != NULL, "invariant"); |
205 assert(si != NULL, "invariant"); |
202 const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si; |
206 const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si; |
203 oop object = oosi->_data._object; |
207 oop object = oosi->_data._object; |
204 assert(object != NULL, "invariant"); |
208 assert(object != NULL, "invariant"); |
209 writer->write(od.description()); |
213 writer->write(od.description()); |
210 writer->write(oosi->_data._reference_id); |
214 writer->write(oosi->_data._reference_id); |
211 return 1; |
215 return 1; |
212 } |
216 } |
213 |
217 |
214 typedef JfrArtifactWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl; |
218 typedef JfrTypeWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl; |
215 typedef JfrArtifactWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter; |
219 typedef JfrTypeWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter; |
216 |
220 |
217 static void write_sample_infos(JfrCheckpointWriter& writer) { |
221 static void write_sample_infos(JfrCheckpointWriter& writer) { |
218 if (sample_infos != NULL) { |
222 if (sample_infos != NULL) { |
219 SampleWriter sw(&writer, NULL, false); |
223 SampleWriter sw(&writer); |
220 sample_infos->iterate(sw); |
224 sample_infos->iterate(sw); |
221 } |
225 } |
222 } |
226 } |
223 |
227 |
224 int __write_reference_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ri) { |
228 int __write_reference_info__(JfrCheckpointWriter* writer, const void* ri) { |
225 assert(writer != NULL, "invariant"); |
229 assert(writer != NULL, "invariant"); |
226 assert(ri != NULL, "invariant"); |
230 assert(ri != NULL, "invariant"); |
227 const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri; |
231 const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri; |
228 writer->write(ref_info->_id); |
232 writer->write(ref_info->_id); |
229 writer->write(ref_info->_data._array_info_id); |
233 writer->write(ref_info->_data._array_info_id); |
231 writer->write(ref_info->_data._old_object_sample_id); |
235 writer->write(ref_info->_data._old_object_sample_id); |
232 writer->write<s4>((s4)ref_info->_data._skip); |
236 writer->write<s4>((s4)ref_info->_data._skip); |
233 return 1; |
237 return 1; |
234 } |
238 } |
235 |
239 |
236 typedef JfrArtifactWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl; |
240 typedef JfrTypeWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl; |
237 typedef JfrArtifactWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter; |
241 typedef JfrTypeWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter; |
238 |
242 |
239 static void write_reference_infos(JfrCheckpointWriter& writer) { |
243 static void write_reference_infos(JfrCheckpointWriter& writer) { |
240 if (ref_infos != NULL) { |
244 if (ref_infos != NULL) { |
241 ReferenceWriter rw(&writer, NULL, false); |
245 ReferenceWriter rw(&writer); |
242 ref_infos->iterate(rw); |
246 ref_infos->iterate(rw); |
243 } |
247 } |
244 } |
248 } |
245 |
249 |
246 int __write_array_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ai) { |
250 int __write_array_info__(JfrCheckpointWriter* writer, const void* ai) { |
247 assert(writer != NULL, "invariant"); |
251 assert(writer != NULL, "invariant"); |
248 assert(ai != NULL, "invariant"); |
252 assert(ai != NULL, "invariant"); |
249 const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai; |
253 const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai; |
250 writer->write(osai->_id); |
254 writer->write(osai->_id); |
251 writer->write(osai->_data._array_size); |
255 writer->write(osai->_data._array_size); |
268 osai->_data._array_size = EdgeUtils::array_size(edge); |
272 osai->_data._array_size = EdgeUtils::array_size(edge); |
269 osai->_data._array_index = EdgeUtils::array_index(edge); |
273 osai->_data._array_index = EdgeUtils::array_index(edge); |
270 return array_infos->store(osai); |
274 return array_infos->store(osai); |
271 } |
275 } |
272 |
276 |
273 typedef JfrArtifactWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl; |
277 typedef JfrTypeWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl; |
274 typedef JfrArtifactWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter; |
278 typedef JfrTypeWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter; |
275 |
279 |
276 static void write_array_infos(JfrCheckpointWriter& writer) { |
280 static void write_array_infos(JfrCheckpointWriter& writer) { |
277 if (array_infos != NULL) { |
281 if (array_infos != NULL) { |
278 ArrayWriter aw(&writer, NULL, false); |
282 ArrayWriter aw(&writer); |
279 array_infos->iterate(aw); |
283 array_infos->iterate(aw); |
280 } |
284 } |
281 } |
285 } |
282 |
286 |
283 int __write_field_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* fi) { |
287 int __write_field_info__(JfrCheckpointWriter* writer, const void* fi) { |
284 assert(writer != NULL, "invariant"); |
288 assert(writer != NULL, "invariant"); |
285 assert(fi != NULL, "invariant"); |
289 assert(fi != NULL, "invariant"); |
286 const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi; |
290 const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi; |
287 writer->write(field_info_entry->id()); |
291 writer->write(field_info_entry->id()); |
288 const ObjectSampleFieldInfo* const osfi = field_info_entry->literal(); |
292 const ObjectSampleFieldInfo* const osfi = field_info_entry->literal(); |
312 osfi->_field_name_symbol = field_name_symbol; |
316 osfi->_field_name_symbol = field_name_symbol; |
313 osfi->_field_modifiers = EdgeUtils::field_modifiers(edge); |
317 osfi->_field_modifiers = EdgeUtils::field_modifiers(edge); |
314 return field_infos->store(osfi); |
318 return field_infos->store(osfi); |
315 } |
319 } |
316 |
320 |
317 typedef JfrArtifactWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl; |
321 typedef JfrTypeWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl; |
318 typedef JfrArtifactWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter; |
322 typedef JfrTypeWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter; |
319 |
323 |
320 static void write_field_infos(JfrCheckpointWriter& writer) { |
324 static void write_field_infos(JfrCheckpointWriter& writer) { |
321 if (field_infos != NULL) { |
325 if (field_infos != NULL) { |
322 FieldWriter fw(&writer, NULL, false); |
326 FieldWriter fw(&writer); |
323 field_infos->iterate(fw); |
327 field_infos->iterate(fw); |
324 } |
328 } |
325 } |
329 } |
326 |
330 |
327 static const char* description(const ObjectSampleRootDescriptionInfo* osdi) { |
331 static const char* description(const ObjectSampleRootDescriptionInfo* osdi) { |
337 } |
341 } |
338 description.write_text(osdi->_data._description); |
342 description.write_text(osdi->_data._description); |
339 return description.description(); |
343 return description.description(); |
340 } |
344 } |
341 |
345 |
342 int __write_root_description_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* di) { |
346 int __write_root_description_info__(JfrCheckpointWriter* writer, const void* di) { |
343 assert(writer != NULL, "invariant"); |
347 assert(writer != NULL, "invariant"); |
344 assert(di != NULL, "invariant"); |
348 assert(di != NULL, "invariant"); |
345 const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di; |
349 const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di; |
346 writer->write(osdi->_id); |
350 writer->write(osdi->_id); |
347 writer->write(description(osdi)); |
351 writer->write(description(osdi)); |
348 writer->write<u8>(osdi->_data._system); |
352 writer->write<u8>(osdi->_data._system); |
349 writer->write<u8>(osdi->_data._type); |
353 writer->write<u8>(osdi->_data._type); |
350 return 1; |
354 return 1; |
351 } |
355 } |
352 |
356 |
353 static traceid get_root_description_info_id(const Edge& edge, traceid id) { |
357 static traceid get_gc_root_description_info_id(const Edge& edge, traceid id) { |
354 assert(edge.is_root(), "invariant"); |
358 assert(edge.is_root(), "invariant"); |
355 if (EdgeUtils::is_leak_edge(edge)) { |
359 if (EdgeUtils::is_leak_edge(edge)) { |
356 return 0; |
360 return 0; |
357 } |
361 } |
358 |
362 |
364 oodi->_id = id; |
368 oodi->_id = id; |
365 oodi->_data._root_edge = &edge; |
369 oodi->_data._root_edge = &edge; |
366 return root_infos->store(oodi); |
370 return root_infos->store(oodi); |
367 } |
371 } |
368 |
372 |
369 typedef JfrArtifactWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl; |
373 typedef JfrTypeWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl; |
370 typedef JfrArtifactWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter; |
374 typedef JfrTypeWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter; |
371 |
375 |
372 |
376 |
373 int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) { |
377 int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) { |
374 return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; |
378 return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; |
375 } |
379 } |
511 if (root_infos != NULL) { |
515 if (root_infos != NULL) { |
512 // resolve roots |
516 // resolve roots |
513 RootResolutionSet rrs(root_infos); |
517 RootResolutionSet rrs(root_infos); |
514 RootResolver::resolve(rrs); |
518 RootResolver::resolve(rrs); |
515 // write roots |
519 // write roots |
516 RootDescriptionWriter rw(&writer, NULL, false); |
520 RootDescriptionWriter rw(&writer); |
517 root_infos->iterate(rw); |
521 root_infos->iterate(rw); |
518 } |
522 } |
519 } |
523 } |
520 |
524 |
521 static void add_old_object_sample_info(const Edge* current, traceid id) { |
525 static void add_old_object_sample_info(const StoredEdge* current, traceid id) { |
522 assert(current != NULL, "invariant"); |
526 assert(current != NULL, "invariant"); |
523 if (sample_infos == NULL) { |
527 if (sample_infos == NULL) { |
524 sample_infos = new SampleInfo(); |
528 sample_infos = new SampleInfo(); |
525 } |
529 } |
526 assert(sample_infos != NULL, "invariant"); |
530 assert(sample_infos != NULL, "invariant"); |
527 OldObjectSampleInfo* const oosi = new OldObjectSampleInfo(); |
531 OldObjectSampleInfo* const oosi = new OldObjectSampleInfo(); |
528 assert(oosi != NULL, "invariant"); |
532 assert(oosi != NULL, "invariant"); |
529 oosi->_id = id; |
533 oosi->_id = id; |
530 oosi->_data._object = current->pointee(); |
534 oosi->_data._object = current->pointee(); |
531 oosi->_data._reference_id = current->is_root() ? (traceid)0 : id; |
535 oosi->_data._reference_id = current->parent() == NULL ? (traceid)0 : id; |
532 sample_infos->store(oosi); |
536 sample_infos->store(oosi); |
533 } |
537 } |
534 |
538 |
535 static void add_reference_info(const RoutableEdge* current, traceid id, traceid parent_id) { |
539 static void add_reference_info(const StoredEdge* current, traceid id, traceid parent_id) { |
536 assert(current != NULL, "invariant"); |
540 assert(current != NULL, "invariant"); |
537 if (ref_infos == NULL) { |
541 if (ref_infos == NULL) { |
538 ref_infos = new RefInfo(); |
542 ref_infos = new RefInfo(); |
539 } |
543 } |
540 |
544 |
542 ReferenceInfo* const ri = new ReferenceInfo(); |
546 ReferenceInfo* const ri = new ReferenceInfo(); |
543 assert(ri != NULL, "invariant"); |
547 assert(ri != NULL, "invariant"); |
544 |
548 |
545 ri->_id = id; |
549 ri->_id = id; |
546 ri->_data._array_info_id = !current->is_skip_edge() ? get_array_info_id(*current, id) : 0; |
550 ri->_data._array_info_id = !current->is_skip_edge() ? get_array_info_id(*current, id) : 0; |
547 ri->_data._field_info_id = ri->_data._array_info_id == 0 && !current->is_skip_edge() ? |
551 ri->_data._field_info_id = ri->_data._array_info_id == 0 && !current->is_skip_edge() ? get_field_info_id(*current) : (traceid)0; |
548 get_field_info_id(*current) : (traceid)0; |
|
549 ri->_data._old_object_sample_id = parent_id; |
552 ri->_data._old_object_sample_id = parent_id; |
550 ri->_data._skip = current->skip_length(); |
553 ri->_data._skip = current->skip_length(); |
551 ref_infos->store(ri); |
554 ref_infos->store(ri); |
552 } |
555 } |
553 |
556 |
554 static traceid add_root_info(const Edge* root, traceid id) { |
557 static bool is_gc_root(const StoredEdge* current) { |
|
558 assert(current != NULL, "invariant"); |
|
559 return current->parent() == NULL && current->gc_root_id() != 0; |
|
560 } |
|
561 |
|
562 static traceid add_gc_root_info(const StoredEdge* root, traceid id) { |
555 assert(root != NULL, "invariant"); |
563 assert(root != NULL, "invariant"); |
556 assert(root->is_root(), "invariant"); |
564 assert(is_gc_root(root), "invariant"); |
557 return get_root_description_info_id(*root, id); |
565 return get_gc_root_description_info_id(*root, id); |
558 } |
566 } |
559 |
567 |
560 void ObjectSampleWriter::write(const RoutableEdge* edge) { |
568 void ObjectSampleWriter::write(const StoredEdge* edge) { |
561 assert(edge != NULL, "invariant"); |
569 assert(edge != NULL, "invariant"); |
562 const traceid id = _store->get_id(edge); |
570 const traceid id = _store->get_id(edge); |
563 add_old_object_sample_info(edge, id); |
571 add_old_object_sample_info(edge, id); |
564 const RoutableEdge* parent = edge->logical_parent(); |
572 const StoredEdge* const parent = edge->parent(); |
565 if (parent != NULL) { |
573 if (parent != NULL) { |
566 add_reference_info(edge, id, _store->get_id(parent)); |
574 add_reference_info(edge, id, _store->get_id(parent)); |
567 } else { |
575 } else { |
568 assert(edge->is_root(), "invariant"); |
576 if (is_gc_root(edge)) { |
569 add_root_info(edge, id); |
577 assert(edge->gc_root_id() == id, "invariant"); |
570 } |
578 add_gc_root_info(edge, id); |
571 } |
579 } |
572 |
580 } |
573 ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, const EdgeStore* store) : |
581 } |
|
582 |
|
583 ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, EdgeStore* store) : |
574 _writer(writer), |
584 _writer(writer), |
575 _store(store) { |
585 _store(store) { |
576 assert(store != NULL, "invariant"); |
586 assert(store != NULL, "invariant"); |
577 assert(store->number_of_entries() > 0, "invariant"); |
587 assert(!store->is_empty(), "invariant"); |
578 sample_infos = NULL; |
588 sample_infos = NULL; |
579 ref_infos = NULL; |
589 ref_infos = NULL; |
580 array_infos = NULL; |
590 array_infos = NULL; |
581 field_infos = NULL; |
591 field_infos = NULL; |
582 root_infos = NULL; |
592 root_infos = NULL; |
588 write_array_infos(_writer); |
598 write_array_infos(_writer); |
589 write_field_infos(_writer); |
599 write_field_infos(_writer); |
590 write_root_descriptors(_writer); |
600 write_root_descriptors(_writer); |
591 } |
601 } |
592 |
602 |
593 void ObjectSampleWriter::write_chain(const RoutableEdge& edge) { |
603 bool ObjectSampleWriter::operator()(StoredEdge& e) { |
594 assert(EdgeUtils::is_leak_edge(edge), "invariant"); |
604 write(&e); |
595 if (edge.processed()) { |
|
596 return; |
|
597 } |
|
598 EdgeUtils::collapse_chain(edge); |
|
599 const RoutableEdge* current = &edge; |
|
600 while (current != NULL) { |
|
601 if (current->processed()) { |
|
602 return; |
|
603 } |
|
604 write(current); |
|
605 current->set_processed(); |
|
606 current = current->logical_parent(); |
|
607 } |
|
608 } |
|
609 |
|
610 bool ObjectSampleWriter::operator()(const RoutableEdge& edge) { |
|
611 if (EdgeUtils::is_leak_edge(edge)) { |
|
612 write_chain(edge); |
|
613 } |
|
614 return true; |
605 return true; |
615 } |
606 } |