Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp
38922 views
/*1* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "jfrfiles/jfrTypes.hpp"26#include "jfr/leakprofiler/chains/edge.hpp"27#include "jfr/leakprofiler/chains/edgeStore.hpp"28#include "jfr/leakprofiler/chains/edgeUtils.hpp"29#include "jfr/leakprofiler/checkpoint/objectSampleDescription.hpp"30#include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp"31#include "jfr/leakprofiler/checkpoint/rootResolver.hpp"32#include "jfr/leakprofiler/sampling/objectSampler.hpp"33#include "jfr/leakprofiler/utilities/rootType.hpp"34#include "jfr/leakprofiler/utilities/unifiedOop.hpp"35#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp"36#include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp"37#include "oops/oop.inline.hpp"38#include "oops/symbol.hpp"39#include "utilities/growableArray.hpp"4041template <typename Data>42class ObjectSampleAuxInfo : public ResourceObj {43public:44Data _data;45traceid _id;46ObjectSampleAuxInfo() : _data(), _id(0) {}47};4849class ObjectSampleArrayData {50public:51int _array_size;52int _array_index;53ObjectSampleArrayData() : _array_size(0), _array_index(0) {}54};5556class ObjectSampleFieldInfo : public ResourceObj {57public:58const Symbol* _field_name_symbol;59jshort _field_modifiers;60ObjectSampleFieldInfo() : _field_name_symbol(NULL), _field_modifiers(0) {}61};6263class ObjectSampleRootDescriptionData {64public:65const Edge* _root_edge;66const char* _description;67OldObjectRoot::System _system;68OldObjectRoot::Type _type;69ObjectSampleRootDescriptionData() : _root_edge(NULL),70_description(NULL),71_system(OldObjectRoot::_system_undetermined),72_type(OldObjectRoot::_type_undetermined) {}73};7475class OldObjectSampleData {76public:77oop _object;78traceid _reference_id;79};8081class ReferenceData {82public:83traceid _field_info_id;84traceid _array_info_id;85traceid _old_object_sample_id;86size_t _skip;87};8889static int initial_storage_size = 16;9091template <typename Data>92class SampleSet : public ResourceObj {93private:94GrowableArray<Data>* _storage;95public:96SampleSet() : _storage(NULL) {}9798traceid store(Data data) {99assert(data != NULL, "invariant");100if (_storage == NULL) {101_storage = new GrowableArray<Data>(initial_storage_size);102}103assert(_storage != NULL, "invariant");104assert(_storage->find(data) == -1, "invariant");105_storage->append(data);106return data->_id;107}108109size_t size() const {110return _storage != NULL ? (size_t)_storage->length() : 0;111}112113template <typename Functor>114void iterate(Functor& functor) {115if (_storage != NULL) {116for (int i = 0; i < _storage->length(); ++i) {117functor(_storage->at(i));118}119}120}121122const GrowableArray<Data>& storage() const {123return *_storage;124}125};126127typedef ObjectSampleAuxInfo<ObjectSampleArrayData> ObjectSampleArrayInfo;128typedef ObjectSampleAuxInfo<ObjectSampleRootDescriptionData> ObjectSampleRootDescriptionInfo;129typedef ObjectSampleAuxInfo<OldObjectSampleData> OldObjectSampleInfo;130typedef ObjectSampleAuxInfo<ReferenceData> ReferenceInfo;131132class FieldTable : public ResourceObj {133template <typename,134typename,135template<typename, typename> class,136typename,137size_t>138friend class HashTableHost;139typedef HashTableHost<const ObjectSampleFieldInfo*, traceid, Entry, FieldTable, 109> FieldInfoTable;140public:141typedef FieldInfoTable::HashEntry FieldInfoEntry;142143private:144static traceid _field_id_counter;145FieldInfoTable* _table;146147void assign_id(FieldInfoEntry* entry) {148assert(entry != NULL, "invariant");149entry->set_id(++_field_id_counter);150}151152bool equals(const ObjectSampleFieldInfo* query, uintptr_t hash, const FieldInfoEntry* entry) {153assert(hash == entry->hash(), "invariant");154assert(query != NULL, "invariant");155const ObjectSampleFieldInfo* stored = entry->literal();156assert(stored != NULL, "invariant");157assert(((Symbol*)stored->_field_name_symbol)->identity_hash() == ((Symbol*)query->_field_name_symbol)->identity_hash(), "invariant");158return stored->_field_modifiers == query->_field_modifiers;159}160161public:162FieldTable() : _table(new FieldInfoTable(this)) {}163~FieldTable() {164assert(_table != NULL, "invariant");165delete _table;166}167168traceid store(const ObjectSampleFieldInfo* field_info) {169assert(field_info != NULL, "invariant");170const FieldInfoEntry& entry =_table->lookup_put(field_info,171((Symbol*)field_info->_field_name_symbol)->identity_hash());172return entry.id();173}174175size_t size() const {176return _table->cardinality();177}178179template <typename T>180void iterate(T& functor) const {181_table->iterate_entry<T>(functor);182}183};184185traceid FieldTable::_field_id_counter = 0;186187typedef SampleSet<const OldObjectSampleInfo*> SampleInfo;188typedef SampleSet<const ReferenceInfo*> RefInfo;189typedef SampleSet<const ObjectSampleArrayInfo*> ArrayInfo;190typedef SampleSet<const ObjectSampleRootDescriptionInfo*> RootDescriptionInfo;191192static SampleInfo* sample_infos = NULL;193static RefInfo* ref_infos = NULL;194static ArrayInfo* array_infos = NULL;195static FieldTable* field_infos = NULL;196static RootDescriptionInfo* root_infos = NULL;197198int __write_sample_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* si) {199assert(writer != NULL, "invariant");200assert(si != NULL, "invariant");201const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si;202oop object = oosi->_data._object;203assert(object != NULL, "invariant");204writer->write(oosi->_id);205writer->write((u8)(const HeapWord*)object);206writer->write(const_cast<const Klass*>(object->klass()));207ObjectSampleDescription od(object);208writer->write(od.description());209writer->write(oosi->_data._reference_id);210return 1;211}212213typedef JfrArtifactWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl;214typedef JfrArtifactWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter;215216static void write_sample_infos(JfrCheckpointWriter& writer) {217if (sample_infos != NULL) {218SampleWriter sw(&writer, NULL, false);219sample_infos->iterate(sw);220}221}222223int __write_reference_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ri) {224assert(writer != NULL, "invariant");225assert(ri != NULL, "invariant");226const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri;227writer->write(ref_info->_id);228writer->write(ref_info->_data._array_info_id);229writer->write(ref_info->_data._field_info_id);230writer->write(ref_info->_data._old_object_sample_id);231writer->write<s4>((s4)ref_info->_data._skip);232return 1;233}234235typedef JfrArtifactWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl;236typedef JfrArtifactWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter;237238static void write_reference_infos(JfrCheckpointWriter& writer) {239if (ref_infos != NULL) {240ReferenceWriter rw(&writer, NULL, false);241ref_infos->iterate(rw);242}243}244245int __write_array_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ai) {246assert(writer != NULL, "invariant");247assert(ai != NULL, "invariant");248const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai;249writer->write(osai->_id);250writer->write(osai->_data._array_size);251writer->write(osai->_data._array_index);252return 1;253}254255static traceid get_array_info_id(const Edge& edge, traceid id) {256if (edge.is_root() || !EdgeUtils::is_array_element(edge)) {257return 0;258}259if (array_infos == NULL) {260array_infos = new ArrayInfo();261}262assert(array_infos != NULL, "invariant");263264ObjectSampleArrayInfo* const osai = new ObjectSampleArrayInfo();265assert(osai != NULL, "invariant");266osai->_id = id;267osai->_data._array_size = EdgeUtils::array_size(edge);268osai->_data._array_index = EdgeUtils::array_index(edge);269return array_infos->store(osai);270}271272typedef JfrArtifactWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl;273typedef JfrArtifactWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter;274275static void write_array_infos(JfrCheckpointWriter& writer) {276if (array_infos != NULL) {277ArrayWriter aw(&writer, NULL, false);278array_infos->iterate(aw);279}280}281282int __write_field_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* fi) {283assert(writer != NULL, "invariant");284assert(fi != NULL, "invariant");285const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi;286writer->write(field_info_entry->id());287const ObjectSampleFieldInfo* const osfi = field_info_entry->literal();288writer->write(osfi->_field_name_symbol->as_C_string());289writer->write(osfi->_field_modifiers);290return 1;291}292293static traceid get_field_info_id(const Edge& edge) {294if (edge.is_root()) {295return 0;296}297298assert(!EdgeUtils::is_array_element(edge), "invariant");299const Symbol* const field_name_symbol = EdgeUtils::field_name_symbol(edge);300if (field_name_symbol == NULL) {301return 0;302}303304if (field_infos == NULL) {305field_infos = new FieldTable();306}307assert(field_infos != NULL, "invariant");308309ObjectSampleFieldInfo* const osfi = new ObjectSampleFieldInfo();310assert(osfi != NULL, "invariant");311osfi->_field_name_symbol = field_name_symbol;312osfi->_field_modifiers = EdgeUtils::field_modifiers(edge);313return field_infos->store(osfi);314}315316typedef JfrArtifactWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl;317typedef JfrArtifactWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter;318319static void write_field_infos(JfrCheckpointWriter& writer) {320if (field_infos != NULL) {321FieldWriter fw(&writer, NULL, false);322field_infos->iterate(fw);323}324}325326static const char* description(const ObjectSampleRootDescriptionInfo* osdi) {327assert(osdi != NULL, "invariant");328329if (osdi->_data._description == NULL) {330return NULL;331}332333ObjectDescriptionBuilder description;334if (osdi->_data._system == OldObjectRoot::_threads) {335description.write_text("Thread Name: ");336}337description.write_text(osdi->_data._description);338return description.description();339}340341int __write_root_description_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* di) {342assert(writer != NULL, "invariant");343assert(di != NULL, "invariant");344const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di;345writer->write(osdi->_id);346writer->write(description(osdi));347writer->write<u8>(osdi->_data._system);348writer->write<u8>(osdi->_data._type);349return 1;350}351352static traceid get_gc_root_description_info_id(const Edge& edge, traceid id) {353assert(edge.is_root(), "invariant");354if (EdgeUtils::is_leak_edge(edge)) {355return 0;356}357358if (root_infos == NULL) {359root_infos = new RootDescriptionInfo();360}361assert(root_infos != NULL, "invariant");362ObjectSampleRootDescriptionInfo* const oodi = new ObjectSampleRootDescriptionInfo();363oodi->_id = id;364oodi->_data._root_edge = &edge;365return root_infos->store(oodi);366}367368typedef JfrArtifactWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl;369typedef JfrArtifactWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter;370371372int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) {373return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0;374}375376int _root_desc_compare_(const ObjectSampleRootDescriptionInfo*const & lhs, const ObjectSampleRootDescriptionInfo* const& rhs) {377const uintptr_t lhs_ref = (uintptr_t)lhs->_data._root_edge->reference();378const uintptr_t rhs_ref = (uintptr_t)rhs->_data._root_edge->reference();379return _edge_reference_compare_(lhs_ref, rhs_ref);380}381382static int find_sorted(const RootCallbackInfo& callback_info,383const GrowableArray<const ObjectSampleRootDescriptionInfo*>* arr,384int length,385bool& found) {386assert(arr != NULL, "invariant");387assert(length >= 0, "invariant");388assert(length <= arr->length(), "invariant");389390found = false;391int min = 0;392int max = length;393while (max >= min) {394const int mid = (int)(((uint)max + min) / 2);395int diff = _edge_reference_compare_((uintptr_t)callback_info._high,396(uintptr_t)arr->at(mid)->_data._root_edge->reference());397if (diff > 0) {398min = mid + 1;399} else if (diff < 0) {400max = mid - 1;401} else {402found = true;403return mid;404}405}406return min;407}408409class RootResolutionSet : public ResourceObj, public RootCallback {410private:411GrowableArray<const ObjectSampleRootDescriptionInfo*>* _unresolved_roots;412413const uintptr_t high() const {414return (uintptr_t)_unresolved_roots->top()->_data._root_edge->reference();415}416417const uintptr_t low() const {418return (uintptr_t)_unresolved_roots->first()->_data._root_edge->reference();419}420421bool in_set_address_range(const RootCallbackInfo& callback_info) const {422assert(callback_info._low == NULL, "invariant");423const uintptr_t addr = (uintptr_t)callback_info._high;424return low() <= addr && high() >= addr;425}426427int compare_to_range(const RootCallbackInfo& callback_info) const {428assert(callback_info._high != NULL, "invariant");429assert(callback_info._low != NULL, "invariant");430431for (int i = 0; i < _unresolved_roots->length(); ++i) {432const uintptr_t ref_addr = (uintptr_t)_unresolved_roots->at(i)->_data._root_edge->reference();433if ((uintptr_t)callback_info._low <= ref_addr && (uintptr_t)callback_info._high >= ref_addr) {434return i;435}436}437return -1;438}439440int exact(const RootCallbackInfo& callback_info) const {441assert(callback_info._high != NULL, "invariant");442assert(in_set_address_range(callback_info), "invariant");443444bool found;445const int idx = find_sorted(callback_info, _unresolved_roots, _unresolved_roots->length(), found);446return found ? idx : -1;447}448449bool resolve_root(const RootCallbackInfo& callback_info, int idx) const {450assert(idx >= 0, "invariant");451assert(idx < _unresolved_roots->length(), "invariant");452453ObjectSampleRootDescriptionInfo* const desc =454const_cast<ObjectSampleRootDescriptionInfo*>(_unresolved_roots->at(idx));455assert(desc != NULL, "invariant");456assert((uintptr_t)callback_info._high == (uintptr_t)desc->_data._root_edge->reference(), "invariant");457458desc->_data._system = callback_info._system;459desc->_data._type = callback_info._type;460461if (callback_info._system == OldObjectRoot::_threads) {462const JavaThread* jt = (const JavaThread*)callback_info._context;463assert(jt != NULL, "invariant");464desc->_data._description = jt->name();465}466467_unresolved_roots->remove_at(idx);468return _unresolved_roots->is_empty();469}470471public:472RootResolutionSet(RootDescriptionInfo* info) : _unresolved_roots(NULL) {473assert(info != NULL, "invariant");474// construct a sorted copy475const GrowableArray<const ObjectSampleRootDescriptionInfo*>& info_storage = info->storage();476const int length = info_storage.length();477_unresolved_roots = new GrowableArray<const ObjectSampleRootDescriptionInfo*>(length);478assert(_unresolved_roots != NULL, "invariant");479480for (int i = 0; i < length; ++i) {481_unresolved_roots->insert_sorted<_root_desc_compare_>(info_storage.at(i));482}483}484485bool process(const RootCallbackInfo& callback_info) {486if (NULL == callback_info._low) {487if (in_set_address_range(callback_info)) {488const int idx = exact(callback_info);489return idx == -1 ? false : resolve_root(callback_info, idx);490}491return false;492}493assert(callback_info._low != NULL, "invariant");494const int idx = compare_to_range(callback_info);495return idx == -1 ? false : resolve_root(callback_info, idx);496}497498int entries() const {499return _unresolved_roots->length();500}501502const void* at(int idx) const {503assert(idx >= 0, "invariant");504assert(idx < _unresolved_roots->length(), "invariant");505return _unresolved_roots->at(idx)->_data._root_edge->reference();506}507};508509static void write_root_descriptors(JfrCheckpointWriter& writer) {510if (root_infos != NULL) {511// resolve roots512RootResolutionSet rrs(root_infos);513RootResolver::resolve(rrs);514// write roots515RootDescriptionWriter rw(&writer, NULL, false);516root_infos->iterate(rw);517}518}519520static void add_old_object_sample_info(const StoredEdge* current, traceid id) {521assert(current != NULL, "invariant");522if (sample_infos == NULL) {523sample_infos = new SampleInfo();524}525assert(sample_infos != NULL, "invariant");526OldObjectSampleInfo* const oosi = new OldObjectSampleInfo();527assert(oosi != NULL, "invariant");528oosi->_id = id;529oosi->_data._object = current->pointee();530oosi->_data._reference_id = current->parent() == NULL ? (traceid)0 : id;531sample_infos->store(oosi);532}533534static void add_reference_info(const StoredEdge* current, traceid id, traceid parent_id) {535assert(current != NULL, "invariant");536if (ref_infos == NULL) {537ref_infos = new RefInfo();538}539540assert(ref_infos != NULL, "invariant");541ReferenceInfo* const ri = new ReferenceInfo();542assert(ri != NULL, "invariant");543544ri->_id = id;545ri->_data._array_info_id = !current->is_skip_edge() ? get_array_info_id(*current, id) : 0;546ri->_data._field_info_id = ri->_data._array_info_id == 0 && !current->is_skip_edge() ? get_field_info_id(*current) : (traceid)0;547ri->_data._old_object_sample_id = parent_id;548ri->_data._skip = current->skip_length();549ref_infos->store(ri);550}551552static bool is_gc_root(const StoredEdge* current) {553assert(current != NULL, "invariant");554return current->parent() == NULL && current->gc_root_id() != 0;555}556557static traceid add_gc_root_info(const StoredEdge* root, traceid id) {558assert(root != NULL, "invariant");559assert(is_gc_root(root), "invariant");560return get_gc_root_description_info_id(*root, id);561}562563void ObjectSampleWriter::write(const StoredEdge* edge) {564assert(edge != NULL, "invariant");565const traceid id = _store->get_id(edge);566add_old_object_sample_info(edge, id);567const StoredEdge* const parent = edge->parent();568if (parent != NULL) {569add_reference_info(edge, id, _store->get_id(parent));570} else {571if (is_gc_root(edge)) {572assert(edge->gc_root_id() == id, "invariant");573add_gc_root_info(edge, id);574}575}576}577578ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, EdgeStore* store) :579_writer(writer),580_store(store) {581assert(store != NULL, "invariant");582assert(!store->is_empty(), "invariant");583sample_infos = NULL;584ref_infos = NULL;585array_infos = NULL;586field_infos = NULL;587root_infos = NULL;588}589590ObjectSampleWriter::~ObjectSampleWriter() {591write_sample_infos(_writer);592write_reference_infos(_writer);593write_array_infos(_writer);594write_field_infos(_writer);595write_root_descriptors(_writer);596}597598bool ObjectSampleWriter::operator()(StoredEdge& e) {599write(&e);600return true;601}602603604