Path: blob/master/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp
41155 views
/*1* Copyright (c) 2014, 2020, 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/unifiedOopRef.inline.hpp"35#include "jfr/metadata/jfrSerializer.hpp"36#include "jfr/writers/jfrTypeWriterHost.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, JfrHashtableEntry, FieldTable, 109> FieldInfoTable;140public:141typedef FieldInfoTable::HashEntry FieldInfoEntry;142143private:144static traceid _field_id_counter;145FieldInfoTable* _table;146const ObjectSampleFieldInfo* _lookup;147148void on_link(FieldInfoEntry* entry) {149assert(entry != NULL, "invariant");150entry->set_id(++_field_id_counter);151}152153bool on_equals(uintptr_t hash, const FieldInfoEntry* entry) {154assert(hash == entry->hash(), "invariant");155assert(_lookup != NULL, "invariant");156return entry->literal()->_field_modifiers == _lookup->_field_modifiers;157}158159void on_unlink(FieldInfoEntry* entry) {160assert(entry != NULL, "invariant");161// nothing162}163164public:165FieldTable() : _table(new FieldInfoTable(this)), _lookup(NULL) {}166~FieldTable() {167assert(_table != NULL, "invariant");168delete _table;169}170171traceid store(const ObjectSampleFieldInfo* field_info) {172assert(field_info != NULL, "invariant");173_lookup = field_info;174const FieldInfoEntry& entry = _table->lookup_put(field_info->_field_name_symbol->identity_hash(), field_info);175return entry.id();176}177178size_t size() const {179return _table->cardinality();180}181182template <typename T>183void iterate(T& functor) const {184_table->iterate_entry<T>(functor);185}186};187188traceid FieldTable::_field_id_counter = 0;189190typedef SampleSet<const OldObjectSampleInfo*> SampleInfo;191typedef SampleSet<const ReferenceInfo*> RefInfo;192typedef SampleSet<const ObjectSampleArrayInfo*> ArrayInfo;193typedef SampleSet<const ObjectSampleRootDescriptionInfo*> RootDescriptionInfo;194195static SampleInfo* sample_infos = NULL;196static RefInfo* ref_infos = NULL;197static ArrayInfo* array_infos = NULL;198static FieldTable* field_infos = NULL;199static RootDescriptionInfo* root_infos = NULL;200201int __write_sample_info__(JfrCheckpointWriter* writer, const void* si) {202assert(writer != NULL, "invariant");203assert(si != NULL, "invariant");204const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si;205oop object = oosi->_data._object;206assert(object != NULL, "invariant");207writer->write(oosi->_id);208writer->write(cast_from_oop<u8>(object));209writer->write(const_cast<const Klass*>(object->klass()));210ObjectSampleDescription od(object);211writer->write(od.description());212writer->write(oosi->_data._reference_id);213return 1;214}215216typedef JfrTypeWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl;217typedef JfrTypeWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter;218219static void write_sample_infos(JfrCheckpointWriter& writer) {220if (sample_infos != NULL) {221SampleWriter sw(&writer);222sample_infos->iterate(sw);223}224}225226int __write_reference_info__(JfrCheckpointWriter* writer, const void* ri) {227assert(writer != NULL, "invariant");228assert(ri != NULL, "invariant");229const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri;230writer->write(ref_info->_id);231writer->write(ref_info->_data._array_info_id);232writer->write(ref_info->_data._field_info_id);233writer->write(ref_info->_data._old_object_sample_id);234writer->write<s4>((s4)ref_info->_data._skip);235return 1;236}237238typedef JfrTypeWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl;239typedef JfrTypeWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter;240241static void write_reference_infos(JfrCheckpointWriter& writer) {242if (ref_infos != NULL) {243ReferenceWriter rw(&writer);244ref_infos->iterate(rw);245}246}247248int __write_array_info__(JfrCheckpointWriter* writer, const void* ai) {249assert(writer != NULL, "invariant");250assert(ai != NULL, "invariant");251const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai;252writer->write(osai->_id);253writer->write(osai->_data._array_size);254writer->write(osai->_data._array_index);255return 1;256}257258static traceid get_array_info_id(const Edge& edge, traceid id) {259if (edge.is_root() || !EdgeUtils::is_array_element(edge)) {260return 0;261}262if (array_infos == NULL) {263array_infos = new ArrayInfo();264}265assert(array_infos != NULL, "invariant");266267ObjectSampleArrayInfo* const osai = new ObjectSampleArrayInfo();268assert(osai != NULL, "invariant");269osai->_id = id;270osai->_data._array_size = EdgeUtils::array_size(edge);271osai->_data._array_index = EdgeUtils::array_index(edge);272return array_infos->store(osai);273}274275typedef JfrTypeWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl;276typedef JfrTypeWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter;277278static void write_array_infos(JfrCheckpointWriter& writer) {279if (array_infos != NULL) {280ArrayWriter aw(&writer);281array_infos->iterate(aw);282}283}284285int __write_field_info__(JfrCheckpointWriter* writer, const void* fi) {286assert(writer != NULL, "invariant");287assert(fi != NULL, "invariant");288const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi;289writer->write(field_info_entry->id());290const ObjectSampleFieldInfo* const osfi = field_info_entry->literal();291writer->write(osfi->_field_name_symbol->as_C_string());292writer->write(osfi->_field_modifiers);293return 1;294}295296static traceid get_field_info_id(const Edge& edge) {297if (edge.is_root()) {298return 0;299}300assert(!EdgeUtils::is_array_element(edge), "invariant");301jshort field_modifiers;302const Symbol* const field_name_symbol = EdgeUtils::field_name(edge, &field_modifiers);303if (field_name_symbol == NULL) {304return 0;305}306if (field_infos == NULL) {307field_infos = new FieldTable();308}309assert(field_infos != NULL, "invariant");310ObjectSampleFieldInfo* const osfi = new ObjectSampleFieldInfo();311assert(osfi != NULL, "invariant");312osfi->_field_name_symbol = field_name_symbol;313osfi->_field_modifiers = field_modifiers;314return field_infos->store(osfi);315}316317typedef JfrTypeWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl;318typedef JfrTypeWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter;319320static void write_field_infos(JfrCheckpointWriter& writer) {321if (field_infos != NULL) {322FieldWriter fw(&writer);323field_infos->iterate(fw);324}325}326327static const char* description(const ObjectSampleRootDescriptionInfo* osdi) {328assert(osdi != NULL, "invariant");329330if (osdi->_data._description == NULL) {331return NULL;332}333334ObjectDescriptionBuilder description;335if (osdi->_data._system == OldObjectRoot::_threads) {336description.write_text("Thread Name: ");337}338description.write_text(osdi->_data._description);339return description.description();340}341342int __write_root_description_info__(JfrCheckpointWriter* writer, const void* di) {343assert(writer != NULL, "invariant");344assert(di != NULL, "invariant");345const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di;346writer->write(osdi->_id);347writer->write(description(osdi));348writer->write<u8>(osdi->_data._system);349writer->write<u8>(osdi->_data._type);350return 1;351}352353static traceid get_gc_root_description_info_id(const Edge& edge, traceid id) {354assert(edge.is_root(), "invariant");355if (root_infos == NULL) {356root_infos = new RootDescriptionInfo();357}358assert(root_infos != NULL, "invariant");359ObjectSampleRootDescriptionInfo* const oodi = new ObjectSampleRootDescriptionInfo();360oodi->_id = id;361oodi->_data._root_edge = &edge;362return root_infos->store(oodi);363}364365typedef JfrTypeWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl;366typedef JfrTypeWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter;367368369int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) {370return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0;371}372373int _root_desc_compare_(const ObjectSampleRootDescriptionInfo*const & lhs, const ObjectSampleRootDescriptionInfo* const& rhs) {374const uintptr_t lhs_ref = lhs->_data._root_edge->reference().addr<uintptr_t>();375const uintptr_t rhs_ref = rhs->_data._root_edge->reference().addr<uintptr_t>();376return _edge_reference_compare_(lhs_ref, rhs_ref);377}378379static int find_sorted(const RootCallbackInfo& callback_info,380const GrowableArray<const ObjectSampleRootDescriptionInfo*>* arr,381int length,382bool& found) {383assert(arr != NULL, "invariant");384assert(length >= 0, "invariant");385assert(length <= arr->length(), "invariant");386387found = false;388int min = 0;389int max = length;390while (max >= min) {391const int mid = (int)(((uint)max + min) / 2);392int diff = _edge_reference_compare_((uintptr_t)callback_info._high,393arr->at(mid)->_data._root_edge->reference().addr<uintptr_t>());394if (diff > 0) {395min = mid + 1;396} else if (diff < 0) {397max = mid - 1;398} else {399found = true;400return mid;401}402}403return min;404}405406class RootResolutionSet : public ResourceObj, public RootCallback {407private:408GrowableArray<const ObjectSampleRootDescriptionInfo*>* _unresolved_roots;409410const uintptr_t high() const {411return _unresolved_roots->last()->_data._root_edge->reference().addr<uintptr_t>();412}413414const uintptr_t low() const {415return _unresolved_roots->first()->_data._root_edge->reference().addr<uintptr_t>();416}417418bool in_set_address_range(const RootCallbackInfo& callback_info) const {419assert(callback_info._low == NULL, "invariant");420const uintptr_t addr = (uintptr_t)callback_info._high;421return low() <= addr && high() >= addr;422}423424int compare_to_range(const RootCallbackInfo& callback_info) const {425assert(callback_info._high != NULL, "invariant");426assert(callback_info._low != NULL, "invariant");427428for (int i = 0; i < _unresolved_roots->length(); ++i) {429const uintptr_t ref_addr = _unresolved_roots->at(i)->_data._root_edge->reference().addr<uintptr_t>();430if ((uintptr_t)callback_info._low <= ref_addr && (uintptr_t)callback_info._high >= ref_addr) {431return i;432}433}434return -1;435}436437int exact(const RootCallbackInfo& callback_info) const {438assert(callback_info._high != NULL, "invariant");439assert(in_set_address_range(callback_info), "invariant");440441bool found;442const int idx = find_sorted(callback_info, _unresolved_roots, _unresolved_roots->length(), found);443return found ? idx : -1;444}445446bool resolve_root(const RootCallbackInfo& callback_info, int idx) const {447assert(idx >= 0, "invariant");448assert(idx < _unresolved_roots->length(), "invariant");449450ObjectSampleRootDescriptionInfo* const desc =451const_cast<ObjectSampleRootDescriptionInfo*>(_unresolved_roots->at(idx));452assert(desc != NULL, "invariant");453assert((uintptr_t)callback_info._high == desc->_data._root_edge->reference().addr<uintptr_t>(), "invariant");454455desc->_data._system = callback_info._system;456desc->_data._type = callback_info._type;457458if (callback_info._system == OldObjectRoot::_threads) {459const JavaThread* jt = (const JavaThread*)callback_info._context;460assert(jt != NULL, "invariant");461desc->_data._description = jt->name();462}463464_unresolved_roots->remove_at(idx);465return _unresolved_roots->is_empty();466}467468public:469RootResolutionSet(RootDescriptionInfo* info) : _unresolved_roots(NULL) {470assert(info != NULL, "invariant");471// construct a sorted copy472const GrowableArray<const ObjectSampleRootDescriptionInfo*>& info_storage = info->storage();473const int length = info_storage.length();474_unresolved_roots = new GrowableArray<const ObjectSampleRootDescriptionInfo*>(length);475assert(_unresolved_roots != NULL, "invariant");476477for (int i = 0; i < length; ++i) {478_unresolved_roots->insert_sorted<_root_desc_compare_>(info_storage.at(i));479}480}481482bool process(const RootCallbackInfo& callback_info) {483if (NULL == callback_info._low) {484if (in_set_address_range(callback_info)) {485const int idx = exact(callback_info);486return idx == -1 ? false : resolve_root(callback_info, idx);487}488return false;489}490assert(callback_info._low != NULL, "invariant");491const int idx = compare_to_range(callback_info);492return idx == -1 ? false : resolve_root(callback_info, idx);493}494495int entries() const {496return _unresolved_roots->length();497}498499UnifiedOopRef at(int idx) const {500assert(idx >= 0, "invariant");501assert(idx < _unresolved_roots->length(), "invariant");502return _unresolved_roots->at(idx)->_data._root_edge->reference();503}504};505506static void write_root_descriptors(JfrCheckpointWriter& writer) {507if (root_infos != NULL) {508// resolve roots509RootResolutionSet rrs(root_infos);510RootResolver::resolve(rrs);511// write roots512RootDescriptionWriter rw(&writer);513root_infos->iterate(rw);514}515}516517static void add_old_object_sample_info(const StoredEdge* current, traceid id) {518assert(current != NULL, "invariant");519if (sample_infos == NULL) {520sample_infos = new SampleInfo();521}522assert(sample_infos != NULL, "invariant");523OldObjectSampleInfo* const oosi = new OldObjectSampleInfo();524assert(oosi != NULL, "invariant");525oosi->_id = id;526oosi->_data._object = current->pointee();527oosi->_data._reference_id = current->parent() == NULL ? 0 : id;528sample_infos->store(oosi);529}530531static void add_reference_info(const StoredEdge* current, traceid id, traceid parent_id) {532assert(current != NULL, "invariant");533if (ref_infos == NULL) {534ref_infos = new RefInfo();535}536537assert(ref_infos != NULL, "invariant");538ReferenceInfo* const ri = new ReferenceInfo();539assert(ri != NULL, "invariant");540541ri->_id = id;542ri->_data._array_info_id = current->is_skip_edge() ? 0 : get_array_info_id(*current, id);543ri->_data._field_info_id = ri->_data._array_info_id != 0 || current->is_skip_edge() ? 0 : get_field_info_id(*current);544ri->_data._old_object_sample_id = parent_id;545ri->_data._skip = current->skip_length();546ref_infos->store(ri);547}548549static bool is_gc_root(const StoredEdge* current) {550assert(current != NULL, "invariant");551return current->parent() == NULL && current->gc_root_id() != 0;552}553554static traceid add_gc_root_info(const StoredEdge* root, traceid id) {555assert(root != NULL, "invariant");556assert(is_gc_root(root), "invariant");557return get_gc_root_description_info_id(*root, id);558}559560void ObjectSampleWriter::write(const StoredEdge* edge) {561assert(edge != NULL, "invariant");562const traceid id = _store->get_id(edge);563add_old_object_sample_info(edge, id);564const StoredEdge* const parent = edge->parent();565if (parent != NULL) {566add_reference_info(edge, id, _store->get_id(parent));567return;568}569if (is_gc_root(edge)) {570assert(edge->gc_root_id() == id, "invariant");571add_gc_root_info(edge, id);572}573}574575class RootSystemType : public JfrSerializer {576public:577void serialize(JfrCheckpointWriter& writer) {578const u4 nof_root_systems = OldObjectRoot::_number_of_systems;579writer.write_count(nof_root_systems);580for (u4 i = 0; i < nof_root_systems; ++i) {581writer.write_key(i);582writer.write(OldObjectRoot::system_description((OldObjectRoot::System)i));583}584}585};586587class RootType : public JfrSerializer {588public:589void serialize(JfrCheckpointWriter& writer) {590const u4 nof_root_types = OldObjectRoot::_number_of_types;591writer.write_count(nof_root_types);592for (u4 i = 0; i < nof_root_types; ++i) {593writer.write_key(i);594writer.write(OldObjectRoot::type_description((OldObjectRoot::Type)i));595}596}597};598599static void register_serializers() {600static bool is_registered = false;601if (!is_registered) {602JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, true, new RootSystemType());603JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, true, new RootType());604is_registered = true;605}606}607608ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, EdgeStore* store) :609_writer(writer),610_store(store) {611assert(store != NULL, "invariant");612assert(!store->is_empty(), "invariant");613register_serializers();614sample_infos = NULL;615ref_infos = NULL;616array_infos = NULL;617field_infos = NULL;618root_infos = NULL;619}620621ObjectSampleWriter::~ObjectSampleWriter() {622write_sample_infos(_writer);623write_reference_infos(_writer);624write_array_infos(_writer);625write_field_infos(_writer);626write_root_descriptors(_writer);627}628629bool ObjectSampleWriter::operator()(StoredEdge& e) {630write(&e);631return true;632}633634635