src/share/vm/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp

Mon, 12 Aug 2019 18:30:40 +0300

author
apetushkov
date
Mon, 12 Aug 2019 18:30:40 +0300
changeset 9858
b985cbb00e68
child 9885
8e875c964f41
permissions
-rw-r--r--

8223147: JFR Backport
8199712: Flight Recorder
8203346: JFR: Inconsistent signature of jfr_add_string_constant
8195817: JFR.stop should require name of recording
8195818: JFR.start should increase autogenerated name by one
8195819: Remove recording=x from jcmd JFR.check output
8203921: JFR thread sampling is missing fixes from JDK-8194552
8203929: Limit amount of data for JFR.dump
8203664: JFR start failure after AppCDS archive created with JFR StartFlightRecording
8003209: JFR events for network utilization
8207392: [PPC64] Implement JFR profiling
8202835: jfr/event/os/TestSystemProcess.java fails on missing events
Summary: Backport JFR from JDK11. Initial integration
Reviewed-by: neugens

apetushkov@9858 1 /*
apetushkov@9858 2 * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
apetushkov@9858 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
apetushkov@9858 4 *
apetushkov@9858 5 * This code is free software; you can redistribute it and/or modify it
apetushkov@9858 6 * under the terms of the GNU General Public License version 2 only, as
apetushkov@9858 7 * published by the Free Software Foundation.
apetushkov@9858 8 *
apetushkov@9858 9 * This code is distributed in the hope that it will be useful, but WITHOUT
apetushkov@9858 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
apetushkov@9858 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
apetushkov@9858 12 * version 2 for more details (a copy is included in the LICENSE file that
apetushkov@9858 13 * accompanied this code).
apetushkov@9858 14 *
apetushkov@9858 15 * You should have received a copy of the GNU General Public License version
apetushkov@9858 16 * 2 along with this work; if not, write to the Free Software Foundation,
apetushkov@9858 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
apetushkov@9858 18 *
apetushkov@9858 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
apetushkov@9858 20 * or visit www.oracle.com if you need additional information or have any
apetushkov@9858 21 * questions.
apetushkov@9858 22 *
apetushkov@9858 23 */
apetushkov@9858 24
apetushkov@9858 25 #include "precompiled.hpp"
apetushkov@9858 26 #include "jfrfiles/jfrTypes.hpp"
apetushkov@9858 27 #include "jfr/leakprofiler/chains/edge.hpp"
apetushkov@9858 28 #include "jfr/leakprofiler/chains/edgeStore.hpp"
apetushkov@9858 29 #include "jfr/leakprofiler/chains/edgeUtils.hpp"
apetushkov@9858 30 #include "jfr/leakprofiler/checkpoint/objectSampleDescription.hpp"
apetushkov@9858 31 #include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp"
apetushkov@9858 32 #include "jfr/leakprofiler/checkpoint/rootResolver.hpp"
apetushkov@9858 33 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
apetushkov@9858 34 #include "jfr/leakprofiler/utilities/rootType.hpp"
apetushkov@9858 35 #include "jfr/leakprofiler/utilities/unifiedOop.hpp"
apetushkov@9858 36 #include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp"
apetushkov@9858 37 #include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp"
apetushkov@9858 38 #include "oops/oop.inline.hpp"
apetushkov@9858 39 #include "oops/symbol.hpp"
apetushkov@9858 40 #include "utilities/growableArray.hpp"
apetushkov@9858 41
apetushkov@9858 42 template <typename Data>
apetushkov@9858 43 class ObjectSampleAuxInfo : public ResourceObj {
apetushkov@9858 44 public:
apetushkov@9858 45 Data _data;
apetushkov@9858 46 traceid _id;
apetushkov@9858 47 ObjectSampleAuxInfo() : _data(), _id(0) {}
apetushkov@9858 48 };
apetushkov@9858 49
apetushkov@9858 50 class ObjectSampleArrayData {
apetushkov@9858 51 public:
apetushkov@9858 52 int _array_size;
apetushkov@9858 53 int _array_index;
apetushkov@9858 54 ObjectSampleArrayData() : _array_size(0), _array_index(0) {}
apetushkov@9858 55 };
apetushkov@9858 56
apetushkov@9858 57 class ObjectSampleFieldInfo : public ResourceObj {
apetushkov@9858 58 public:
apetushkov@9858 59 const Symbol* _field_name_symbol;
apetushkov@9858 60 jshort _field_modifiers;
apetushkov@9858 61 ObjectSampleFieldInfo() : _field_name_symbol(NULL), _field_modifiers(0) {}
apetushkov@9858 62 };
apetushkov@9858 63
apetushkov@9858 64 class ObjectSampleRootDescriptionData {
apetushkov@9858 65 public:
apetushkov@9858 66 const Edge* _root_edge;
apetushkov@9858 67 const char* _description;
apetushkov@9858 68 OldObjectRoot::System _system;
apetushkov@9858 69 OldObjectRoot::Type _type;
apetushkov@9858 70 ObjectSampleRootDescriptionData() : _root_edge(NULL),
apetushkov@9858 71 _description(NULL),
apetushkov@9858 72 _system(OldObjectRoot::_system_undetermined),
apetushkov@9858 73 _type(OldObjectRoot::_type_undetermined) {}
apetushkov@9858 74 };
apetushkov@9858 75
apetushkov@9858 76 class OldObjectSampleData {
apetushkov@9858 77 public:
apetushkov@9858 78 oop _object;
apetushkov@9858 79 traceid _reference_id;
apetushkov@9858 80 };
apetushkov@9858 81
apetushkov@9858 82 class ReferenceData {
apetushkov@9858 83 public:
apetushkov@9858 84 traceid _field_info_id;
apetushkov@9858 85 traceid _array_info_id;
apetushkov@9858 86 traceid _old_object_sample_id;
apetushkov@9858 87 size_t _skip;
apetushkov@9858 88 };
apetushkov@9858 89
apetushkov@9858 90 static int initial_storage_size = 16;
apetushkov@9858 91
apetushkov@9858 92 template <typename Data>
apetushkov@9858 93 class SampleSet : public ResourceObj {
apetushkov@9858 94 private:
apetushkov@9858 95 GrowableArray<Data>* _storage;
apetushkov@9858 96 public:
apetushkov@9858 97 SampleSet() : _storage(NULL) {}
apetushkov@9858 98
apetushkov@9858 99 traceid store(Data data) {
apetushkov@9858 100 assert(data != NULL, "invariant");
apetushkov@9858 101 if (_storage == NULL) {
apetushkov@9858 102 _storage = new GrowableArray<Data>(initial_storage_size);
apetushkov@9858 103 }
apetushkov@9858 104 assert(_storage != NULL, "invariant");
apetushkov@9858 105 assert(_storage->find(data) == -1, "invariant");
apetushkov@9858 106 _storage->append(data);
apetushkov@9858 107 return data->_id;
apetushkov@9858 108 }
apetushkov@9858 109
apetushkov@9858 110 size_t size() const {
apetushkov@9858 111 return _storage != NULL ? (size_t)_storage->length() : 0;
apetushkov@9858 112 }
apetushkov@9858 113
apetushkov@9858 114 template <typename Functor>
apetushkov@9858 115 void iterate(Functor& functor) {
apetushkov@9858 116 if (_storage != NULL) {
apetushkov@9858 117 for (int i = 0; i < _storage->length(); ++i) {
apetushkov@9858 118 functor(_storage->at(i));
apetushkov@9858 119 }
apetushkov@9858 120 }
apetushkov@9858 121 }
apetushkov@9858 122
apetushkov@9858 123 const GrowableArray<Data>& storage() const {
apetushkov@9858 124 return *_storage;
apetushkov@9858 125 }
apetushkov@9858 126 };
apetushkov@9858 127
apetushkov@9858 128 typedef ObjectSampleAuxInfo<ObjectSampleArrayData> ObjectSampleArrayInfo;
apetushkov@9858 129 typedef ObjectSampleAuxInfo<ObjectSampleRootDescriptionData> ObjectSampleRootDescriptionInfo;
apetushkov@9858 130 typedef ObjectSampleAuxInfo<OldObjectSampleData> OldObjectSampleInfo;
apetushkov@9858 131 typedef ObjectSampleAuxInfo<ReferenceData> ReferenceInfo;
apetushkov@9858 132
apetushkov@9858 133 class FieldTable : public ResourceObj {
apetushkov@9858 134 template <typename,
apetushkov@9858 135 typename,
apetushkov@9858 136 template<typename, typename> class,
apetushkov@9858 137 typename,
apetushkov@9858 138 size_t>
apetushkov@9858 139 friend class HashTableHost;
apetushkov@9858 140 typedef HashTableHost<const ObjectSampleFieldInfo*, traceid, Entry, FieldTable, 109> FieldInfoTable;
apetushkov@9858 141 public:
apetushkov@9858 142 typedef FieldInfoTable::HashEntry FieldInfoEntry;
apetushkov@9858 143
apetushkov@9858 144 private:
apetushkov@9858 145 static traceid _field_id_counter;
apetushkov@9858 146 FieldInfoTable* _table;
apetushkov@9858 147
apetushkov@9858 148 void assign_id(FieldInfoEntry* entry) {
apetushkov@9858 149 assert(entry != NULL, "invariant");
apetushkov@9858 150 entry->set_id(++_field_id_counter);
apetushkov@9858 151 }
apetushkov@9858 152
apetushkov@9858 153 bool equals(const ObjectSampleFieldInfo* query, uintptr_t hash, const FieldInfoEntry* entry) {
apetushkov@9858 154 assert(hash == entry->hash(), "invariant");
apetushkov@9858 155 assert(query != NULL, "invariant");
apetushkov@9858 156 const ObjectSampleFieldInfo* stored = entry->literal();
apetushkov@9858 157 assert(stored != NULL, "invariant");
apetushkov@9858 158 assert(((Symbol*)stored->_field_name_symbol)->identity_hash() == ((Symbol*)query->_field_name_symbol)->identity_hash(), "invariant");
apetushkov@9858 159 return stored->_field_modifiers == query->_field_modifiers;
apetushkov@9858 160 }
apetushkov@9858 161
apetushkov@9858 162 public:
apetushkov@9858 163 FieldTable() : _table(new FieldInfoTable(this)) {}
apetushkov@9858 164 ~FieldTable() {
apetushkov@9858 165 assert(_table != NULL, "invariant");
apetushkov@9858 166 delete _table;
apetushkov@9858 167 }
apetushkov@9858 168
apetushkov@9858 169 traceid store(const ObjectSampleFieldInfo* field_info) {
apetushkov@9858 170 assert(field_info != NULL, "invariant");
apetushkov@9858 171 const FieldInfoEntry& entry =_table->lookup_put(field_info,
apetushkov@9858 172 ((Symbol*)field_info->_field_name_symbol)->identity_hash());
apetushkov@9858 173 return entry.id();
apetushkov@9858 174 }
apetushkov@9858 175
apetushkov@9858 176 size_t size() const {
apetushkov@9858 177 return _table->cardinality();
apetushkov@9858 178 }
apetushkov@9858 179
apetushkov@9858 180 template <typename T>
apetushkov@9858 181 void iterate(T& functor) const {
apetushkov@9858 182 _table->iterate_entry<T>(functor);
apetushkov@9858 183 }
apetushkov@9858 184 };
apetushkov@9858 185
apetushkov@9858 186 traceid FieldTable::_field_id_counter = 0;
apetushkov@9858 187
apetushkov@9858 188 typedef SampleSet<const OldObjectSampleInfo*> SampleInfo;
apetushkov@9858 189 typedef SampleSet<const ReferenceInfo*> RefInfo;
apetushkov@9858 190 typedef SampleSet<const ObjectSampleArrayInfo*> ArrayInfo;
apetushkov@9858 191 typedef SampleSet<const ObjectSampleRootDescriptionInfo*> RootDescriptionInfo;
apetushkov@9858 192
apetushkov@9858 193 static SampleInfo* sample_infos = NULL;
apetushkov@9858 194 static RefInfo* ref_infos = NULL;
apetushkov@9858 195 static ArrayInfo* array_infos = NULL;
apetushkov@9858 196 static FieldTable* field_infos = NULL;
apetushkov@9858 197 static RootDescriptionInfo* root_infos = NULL;
apetushkov@9858 198
apetushkov@9858 199 int __write_sample_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* si) {
apetushkov@9858 200 assert(writer != NULL, "invariant");
apetushkov@9858 201 assert(si != NULL, "invariant");
apetushkov@9858 202 const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si;
apetushkov@9858 203 oop object = oosi->_data._object;
apetushkov@9858 204 assert(object != NULL, "invariant");
apetushkov@9858 205 writer->write(oosi->_id);
apetushkov@9858 206 writer->write((u8)(const HeapWord*)object);
apetushkov@9858 207 writer->write(const_cast<const Klass*>(object->klass()));
apetushkov@9858 208 ObjectSampleDescription od(object);
apetushkov@9858 209 writer->write(od.description());
apetushkov@9858 210 writer->write(oosi->_data._reference_id);
apetushkov@9858 211 return 1;
apetushkov@9858 212 }
apetushkov@9858 213
apetushkov@9858 214 typedef JfrArtifactWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl;
apetushkov@9858 215 typedef JfrArtifactWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter;
apetushkov@9858 216
apetushkov@9858 217 static void write_sample_infos(JfrCheckpointWriter& writer) {
apetushkov@9858 218 if (sample_infos != NULL) {
apetushkov@9858 219 SampleWriter sw(&writer, NULL, false);
apetushkov@9858 220 sample_infos->iterate(sw);
apetushkov@9858 221 }
apetushkov@9858 222 }
apetushkov@9858 223
apetushkov@9858 224 int __write_reference_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ri) {
apetushkov@9858 225 assert(writer != NULL, "invariant");
apetushkov@9858 226 assert(ri != NULL, "invariant");
apetushkov@9858 227 const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri;
apetushkov@9858 228 writer->write(ref_info->_id);
apetushkov@9858 229 writer->write(ref_info->_data._array_info_id);
apetushkov@9858 230 writer->write(ref_info->_data._field_info_id);
apetushkov@9858 231 writer->write(ref_info->_data._old_object_sample_id);
apetushkov@9858 232 writer->write<s4>((s4)ref_info->_data._skip);
apetushkov@9858 233 return 1;
apetushkov@9858 234 }
apetushkov@9858 235
apetushkov@9858 236 typedef JfrArtifactWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl;
apetushkov@9858 237 typedef JfrArtifactWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter;
apetushkov@9858 238
apetushkov@9858 239 static void write_reference_infos(JfrCheckpointWriter& writer) {
apetushkov@9858 240 if (ref_infos != NULL) {
apetushkov@9858 241 ReferenceWriter rw(&writer, NULL, false);
apetushkov@9858 242 ref_infos->iterate(rw);
apetushkov@9858 243 }
apetushkov@9858 244 }
apetushkov@9858 245
apetushkov@9858 246 int __write_array_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ai) {
apetushkov@9858 247 assert(writer != NULL, "invariant");
apetushkov@9858 248 assert(ai != NULL, "invariant");
apetushkov@9858 249 const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai;
apetushkov@9858 250 writer->write(osai->_id);
apetushkov@9858 251 writer->write(osai->_data._array_size);
apetushkov@9858 252 writer->write(osai->_data._array_index);
apetushkov@9858 253 return 1;
apetushkov@9858 254 }
apetushkov@9858 255
apetushkov@9858 256 static traceid get_array_info_id(const Edge& edge, traceid id) {
apetushkov@9858 257 if (edge.is_root() || !EdgeUtils::is_array_element(edge)) {
apetushkov@9858 258 return 0;
apetushkov@9858 259 }
apetushkov@9858 260 if (array_infos == NULL) {
apetushkov@9858 261 array_infos = new ArrayInfo();
apetushkov@9858 262 }
apetushkov@9858 263 assert(array_infos != NULL, "invariant");
apetushkov@9858 264
apetushkov@9858 265 ObjectSampleArrayInfo* const osai = new ObjectSampleArrayInfo();
apetushkov@9858 266 assert(osai != NULL, "invariant");
apetushkov@9858 267 osai->_id = id;
apetushkov@9858 268 osai->_data._array_size = EdgeUtils::array_size(edge);
apetushkov@9858 269 osai->_data._array_index = EdgeUtils::array_index(edge);
apetushkov@9858 270 return array_infos->store(osai);
apetushkov@9858 271 }
apetushkov@9858 272
apetushkov@9858 273 typedef JfrArtifactWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl;
apetushkov@9858 274 typedef JfrArtifactWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter;
apetushkov@9858 275
apetushkov@9858 276 static void write_array_infos(JfrCheckpointWriter& writer) {
apetushkov@9858 277 if (array_infos != NULL) {
apetushkov@9858 278 ArrayWriter aw(&writer, NULL, false);
apetushkov@9858 279 array_infos->iterate(aw);
apetushkov@9858 280 }
apetushkov@9858 281 }
apetushkov@9858 282
apetushkov@9858 283 int __write_field_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* fi) {
apetushkov@9858 284 assert(writer != NULL, "invariant");
apetushkov@9858 285 assert(fi != NULL, "invariant");
apetushkov@9858 286 const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi;
apetushkov@9858 287 writer->write(field_info_entry->id());
apetushkov@9858 288 const ObjectSampleFieldInfo* const osfi = field_info_entry->literal();
apetushkov@9858 289 writer->write(osfi->_field_name_symbol->as_C_string());
apetushkov@9858 290 writer->write(osfi->_field_modifiers);
apetushkov@9858 291 return 1;
apetushkov@9858 292 }
apetushkov@9858 293
apetushkov@9858 294 static traceid get_field_info_id(const Edge& edge) {
apetushkov@9858 295 if (edge.is_root()) {
apetushkov@9858 296 return 0;
apetushkov@9858 297 }
apetushkov@9858 298
apetushkov@9858 299 assert(!EdgeUtils::is_array_element(edge), "invariant");
apetushkov@9858 300 const Symbol* const field_name_symbol = EdgeUtils::field_name_symbol(edge);
apetushkov@9858 301 if (field_name_symbol == NULL) {
apetushkov@9858 302 return 0;
apetushkov@9858 303 }
apetushkov@9858 304
apetushkov@9858 305 if (field_infos == NULL) {
apetushkov@9858 306 field_infos = new FieldTable();
apetushkov@9858 307 }
apetushkov@9858 308 assert(field_infos != NULL, "invariant");
apetushkov@9858 309
apetushkov@9858 310 ObjectSampleFieldInfo* const osfi = new ObjectSampleFieldInfo();
apetushkov@9858 311 assert(osfi != NULL, "invariant");
apetushkov@9858 312 osfi->_field_name_symbol = field_name_symbol;
apetushkov@9858 313 osfi->_field_modifiers = EdgeUtils::field_modifiers(edge);
apetushkov@9858 314 return field_infos->store(osfi);
apetushkov@9858 315 }
apetushkov@9858 316
apetushkov@9858 317 typedef JfrArtifactWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl;
apetushkov@9858 318 typedef JfrArtifactWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter;
apetushkov@9858 319
apetushkov@9858 320 static void write_field_infos(JfrCheckpointWriter& writer) {
apetushkov@9858 321 if (field_infos != NULL) {
apetushkov@9858 322 FieldWriter fw(&writer, NULL, false);
apetushkov@9858 323 field_infos->iterate(fw);
apetushkov@9858 324 }
apetushkov@9858 325 }
apetushkov@9858 326
apetushkov@9858 327 static const char* description(const ObjectSampleRootDescriptionInfo* osdi) {
apetushkov@9858 328 assert(osdi != NULL, "invariant");
apetushkov@9858 329
apetushkov@9858 330 if (osdi->_data._description == NULL) {
apetushkov@9858 331 return NULL;
apetushkov@9858 332 }
apetushkov@9858 333
apetushkov@9858 334 ObjectDescriptionBuilder description;
apetushkov@9858 335 if (osdi->_data._system == OldObjectRoot::_threads) {
apetushkov@9858 336 description.write_text("Thread Name: ");
apetushkov@9858 337 }
apetushkov@9858 338 description.write_text(osdi->_data._description);
apetushkov@9858 339 return description.description();
apetushkov@9858 340 }
apetushkov@9858 341
apetushkov@9858 342 int __write_root_description_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* di) {
apetushkov@9858 343 assert(writer != NULL, "invariant");
apetushkov@9858 344 assert(di != NULL, "invariant");
apetushkov@9858 345 const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di;
apetushkov@9858 346 writer->write(osdi->_id);
apetushkov@9858 347 writer->write(description(osdi));
apetushkov@9858 348 writer->write<u8>(osdi->_data._system);
apetushkov@9858 349 writer->write<u8>(osdi->_data._type);
apetushkov@9858 350 return 1;
apetushkov@9858 351 }
apetushkov@9858 352
apetushkov@9858 353 static traceid get_root_description_info_id(const Edge& edge, traceid id) {
apetushkov@9858 354 assert(edge.is_root(), "invariant");
apetushkov@9858 355 if (EdgeUtils::is_leak_edge(edge)) {
apetushkov@9858 356 return 0;
apetushkov@9858 357 }
apetushkov@9858 358
apetushkov@9858 359 if (root_infos == NULL) {
apetushkov@9858 360 root_infos = new RootDescriptionInfo();
apetushkov@9858 361 }
apetushkov@9858 362 assert(root_infos != NULL, "invariant");
apetushkov@9858 363 ObjectSampleRootDescriptionInfo* const oodi = new ObjectSampleRootDescriptionInfo();
apetushkov@9858 364 oodi->_id = id;
apetushkov@9858 365 oodi->_data._root_edge = &edge;
apetushkov@9858 366 return root_infos->store(oodi);
apetushkov@9858 367 }
apetushkov@9858 368
apetushkov@9858 369 typedef JfrArtifactWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl;
apetushkov@9858 370 typedef JfrArtifactWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter;
apetushkov@9858 371
apetushkov@9858 372
apetushkov@9858 373 int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) {
apetushkov@9858 374 return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0;
apetushkov@9858 375 }
apetushkov@9858 376
apetushkov@9858 377 int _root_desc_compare_(const ObjectSampleRootDescriptionInfo*const & lhs, const ObjectSampleRootDescriptionInfo* const& rhs) {
apetushkov@9858 378 const uintptr_t lhs_ref = (uintptr_t)lhs->_data._root_edge->reference();
apetushkov@9858 379 const uintptr_t rhs_ref = (uintptr_t)rhs->_data._root_edge->reference();
apetushkov@9858 380 return _edge_reference_compare_(lhs_ref, rhs_ref);
apetushkov@9858 381 }
apetushkov@9858 382
apetushkov@9858 383 static int find_sorted(const RootCallbackInfo& callback_info,
apetushkov@9858 384 const GrowableArray<const ObjectSampleRootDescriptionInfo*>* arr,
apetushkov@9858 385 int length,
apetushkov@9858 386 bool& found) {
apetushkov@9858 387 assert(arr != NULL, "invariant");
apetushkov@9858 388 assert(length >= 0, "invariant");
apetushkov@9858 389 assert(length <= arr->length(), "invariant");
apetushkov@9858 390
apetushkov@9858 391 found = false;
apetushkov@9858 392 int min = 0;
apetushkov@9858 393 int max = length;
apetushkov@9858 394 while (max >= min) {
apetushkov@9858 395 const int mid = (int)(((uint)max + min) / 2);
apetushkov@9858 396 int diff = _edge_reference_compare_((uintptr_t)callback_info._high,
apetushkov@9858 397 (uintptr_t)arr->at(mid)->_data._root_edge->reference());
apetushkov@9858 398 if (diff > 0) {
apetushkov@9858 399 min = mid + 1;
apetushkov@9858 400 } else if (diff < 0) {
apetushkov@9858 401 max = mid - 1;
apetushkov@9858 402 } else {
apetushkov@9858 403 found = true;
apetushkov@9858 404 return mid;
apetushkov@9858 405 }
apetushkov@9858 406 }
apetushkov@9858 407 return min;
apetushkov@9858 408 }
apetushkov@9858 409
apetushkov@9858 410 class RootResolutionSet : public ResourceObj, public RootCallback {
apetushkov@9858 411 private:
apetushkov@9858 412 GrowableArray<const ObjectSampleRootDescriptionInfo*>* _unresolved_roots;
apetushkov@9858 413
apetushkov@9858 414 const uintptr_t high() const {
apetushkov@9858 415 return (uintptr_t)_unresolved_roots->top()->_data._root_edge->reference();
apetushkov@9858 416 }
apetushkov@9858 417
apetushkov@9858 418 const uintptr_t low() const {
apetushkov@9858 419 return (uintptr_t)_unresolved_roots->first()->_data._root_edge->reference();
apetushkov@9858 420 }
apetushkov@9858 421
apetushkov@9858 422 bool in_set_address_range(const RootCallbackInfo& callback_info) const {
apetushkov@9858 423 assert(callback_info._low == NULL, "invariant");
apetushkov@9858 424 const uintptr_t addr = (uintptr_t)callback_info._high;
apetushkov@9858 425 return low() <= addr && high() >= addr;
apetushkov@9858 426 }
apetushkov@9858 427
apetushkov@9858 428 int compare_to_range(const RootCallbackInfo& callback_info) const {
apetushkov@9858 429 assert(callback_info._high != NULL, "invariant");
apetushkov@9858 430 assert(callback_info._low != NULL, "invariant");
apetushkov@9858 431
apetushkov@9858 432 for (int i = 0; i < _unresolved_roots->length(); ++i) {
apetushkov@9858 433 const uintptr_t ref_addr = (uintptr_t)_unresolved_roots->at(i)->_data._root_edge->reference();
apetushkov@9858 434 if ((uintptr_t)callback_info._low <= ref_addr && (uintptr_t)callback_info._high >= ref_addr) {
apetushkov@9858 435 return i;
apetushkov@9858 436 }
apetushkov@9858 437 }
apetushkov@9858 438 return -1;
apetushkov@9858 439 }
apetushkov@9858 440
apetushkov@9858 441 int exact(const RootCallbackInfo& callback_info) const {
apetushkov@9858 442 assert(callback_info._high != NULL, "invariant");
apetushkov@9858 443 assert(in_set_address_range(callback_info), "invariant");
apetushkov@9858 444
apetushkov@9858 445 bool found;
apetushkov@9858 446 const int idx = find_sorted(callback_info, _unresolved_roots, _unresolved_roots->length(), found);
apetushkov@9858 447 return found ? idx : -1;
apetushkov@9858 448 }
apetushkov@9858 449
apetushkov@9858 450 bool resolve_root(const RootCallbackInfo& callback_info, int idx) const {
apetushkov@9858 451 assert(idx >= 0, "invariant");
apetushkov@9858 452 assert(idx < _unresolved_roots->length(), "invariant");
apetushkov@9858 453
apetushkov@9858 454 ObjectSampleRootDescriptionInfo* const desc =
apetushkov@9858 455 const_cast<ObjectSampleRootDescriptionInfo*>(_unresolved_roots->at(idx));
apetushkov@9858 456 assert(desc != NULL, "invariant");
apetushkov@9858 457 assert((uintptr_t)callback_info._high == (uintptr_t)desc->_data._root_edge->reference(), "invariant");
apetushkov@9858 458
apetushkov@9858 459 desc->_data._system = callback_info._system;
apetushkov@9858 460 desc->_data._type = callback_info._type;
apetushkov@9858 461
apetushkov@9858 462 if (callback_info._system == OldObjectRoot::_threads) {
apetushkov@9858 463 const JavaThread* jt = (const JavaThread*)callback_info._context;
apetushkov@9858 464 assert(jt != NULL, "invariant");
apetushkov@9858 465 desc->_data._description = jt->name();
apetushkov@9858 466 }
apetushkov@9858 467
apetushkov@9858 468 _unresolved_roots->remove_at(idx);
apetushkov@9858 469 return _unresolved_roots->is_empty();
apetushkov@9858 470 }
apetushkov@9858 471
apetushkov@9858 472 public:
apetushkov@9858 473 RootResolutionSet(RootDescriptionInfo* info) : _unresolved_roots(NULL) {
apetushkov@9858 474 assert(info != NULL, "invariant");
apetushkov@9858 475 // construct a sorted copy
apetushkov@9858 476 const GrowableArray<const ObjectSampleRootDescriptionInfo*>& info_storage = info->storage();
apetushkov@9858 477 const int length = info_storage.length();
apetushkov@9858 478 _unresolved_roots = new GrowableArray<const ObjectSampleRootDescriptionInfo*>(length);
apetushkov@9858 479 assert(_unresolved_roots != NULL, "invariant");
apetushkov@9858 480
apetushkov@9858 481 for (int i = 0; i < length; ++i) {
apetushkov@9858 482 _unresolved_roots->insert_sorted<_root_desc_compare_>(info_storage.at(i));
apetushkov@9858 483 }
apetushkov@9858 484 }
apetushkov@9858 485
apetushkov@9858 486 bool process(const RootCallbackInfo& callback_info) {
apetushkov@9858 487 if (NULL == callback_info._low) {
apetushkov@9858 488 if (in_set_address_range(callback_info)) {
apetushkov@9858 489 const int idx = exact(callback_info);
apetushkov@9858 490 return idx == -1 ? false : resolve_root(callback_info, idx);
apetushkov@9858 491 }
apetushkov@9858 492 return false;
apetushkov@9858 493 }
apetushkov@9858 494 assert(callback_info._low != NULL, "invariant");
apetushkov@9858 495 const int idx = compare_to_range(callback_info);
apetushkov@9858 496 return idx == -1 ? false : resolve_root(callback_info, idx);
apetushkov@9858 497 }
apetushkov@9858 498
apetushkov@9858 499 int entries() const {
apetushkov@9858 500 return _unresolved_roots->length();
apetushkov@9858 501 }
apetushkov@9858 502
apetushkov@9858 503 const void* at(int idx) const {
apetushkov@9858 504 assert(idx >= 0, "invariant");
apetushkov@9858 505 assert(idx < _unresolved_roots->length(), "invariant");
apetushkov@9858 506 return _unresolved_roots->at(idx)->_data._root_edge->reference();
apetushkov@9858 507 }
apetushkov@9858 508 };
apetushkov@9858 509
apetushkov@9858 510 static void write_root_descriptors(JfrCheckpointWriter& writer) {
apetushkov@9858 511 if (root_infos != NULL) {
apetushkov@9858 512 // resolve roots
apetushkov@9858 513 RootResolutionSet rrs(root_infos);
apetushkov@9858 514 RootResolver::resolve(rrs);
apetushkov@9858 515 // write roots
apetushkov@9858 516 RootDescriptionWriter rw(&writer, NULL, false);
apetushkov@9858 517 root_infos->iterate(rw);
apetushkov@9858 518 }
apetushkov@9858 519 }
apetushkov@9858 520
apetushkov@9858 521 static void add_old_object_sample_info(const Edge* current, traceid id) {
apetushkov@9858 522 assert(current != NULL, "invariant");
apetushkov@9858 523 if (sample_infos == NULL) {
apetushkov@9858 524 sample_infos = new SampleInfo();
apetushkov@9858 525 }
apetushkov@9858 526 assert(sample_infos != NULL, "invariant");
apetushkov@9858 527 OldObjectSampleInfo* const oosi = new OldObjectSampleInfo();
apetushkov@9858 528 assert(oosi != NULL, "invariant");
apetushkov@9858 529 oosi->_id = id;
apetushkov@9858 530 oosi->_data._object = current->pointee();
apetushkov@9858 531 oosi->_data._reference_id = current->is_root() ? (traceid)0 : id;
apetushkov@9858 532 sample_infos->store(oosi);
apetushkov@9858 533 }
apetushkov@9858 534
apetushkov@9858 535 static void add_reference_info(const RoutableEdge* current, traceid id, traceid parent_id) {
apetushkov@9858 536 assert(current != NULL, "invariant");
apetushkov@9858 537 if (ref_infos == NULL) {
apetushkov@9858 538 ref_infos = new RefInfo();
apetushkov@9858 539 }
apetushkov@9858 540
apetushkov@9858 541 assert(ref_infos != NULL, "invariant");
apetushkov@9858 542 ReferenceInfo* const ri = new ReferenceInfo();
apetushkov@9858 543 assert(ri != NULL, "invariant");
apetushkov@9858 544
apetushkov@9858 545 ri->_id = id;
apetushkov@9858 546 ri->_data._array_info_id = !current->is_skip_edge() ? get_array_info_id(*current, id) : 0;
apetushkov@9858 547 ri->_data._field_info_id = ri->_data._array_info_id == 0 && !current->is_skip_edge() ?
apetushkov@9858 548 get_field_info_id(*current) : (traceid)0;
apetushkov@9858 549 ri->_data._old_object_sample_id = parent_id;
apetushkov@9858 550 ri->_data._skip = current->skip_length();
apetushkov@9858 551 ref_infos->store(ri);
apetushkov@9858 552 }
apetushkov@9858 553
apetushkov@9858 554 static traceid add_root_info(const Edge* root, traceid id) {
apetushkov@9858 555 assert(root != NULL, "invariant");
apetushkov@9858 556 assert(root->is_root(), "invariant");
apetushkov@9858 557 return get_root_description_info_id(*root, id);
apetushkov@9858 558 }
apetushkov@9858 559
apetushkov@9858 560 void ObjectSampleWriter::write(const RoutableEdge* edge) {
apetushkov@9858 561 assert(edge != NULL, "invariant");
apetushkov@9858 562 const traceid id = _store->get_id(edge);
apetushkov@9858 563 add_old_object_sample_info(edge, id);
apetushkov@9858 564 const RoutableEdge* parent = edge->logical_parent();
apetushkov@9858 565 if (parent != NULL) {
apetushkov@9858 566 add_reference_info(edge, id, _store->get_id(parent));
apetushkov@9858 567 } else {
apetushkov@9858 568 assert(edge->is_root(), "invariant");
apetushkov@9858 569 add_root_info(edge, id);
apetushkov@9858 570 }
apetushkov@9858 571 }
apetushkov@9858 572
apetushkov@9858 573 ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, const EdgeStore* store) :
apetushkov@9858 574 _writer(writer),
apetushkov@9858 575 _store(store) {
apetushkov@9858 576 assert(store != NULL, "invariant");
apetushkov@9858 577 assert(store->number_of_entries() > 0, "invariant");
apetushkov@9858 578 sample_infos = NULL;
apetushkov@9858 579 ref_infos = NULL;
apetushkov@9858 580 array_infos = NULL;
apetushkov@9858 581 field_infos = NULL;
apetushkov@9858 582 root_infos = NULL;
apetushkov@9858 583 }
apetushkov@9858 584
apetushkov@9858 585 ObjectSampleWriter::~ObjectSampleWriter() {
apetushkov@9858 586 write_sample_infos(_writer);
apetushkov@9858 587 write_reference_infos(_writer);
apetushkov@9858 588 write_array_infos(_writer);
apetushkov@9858 589 write_field_infos(_writer);
apetushkov@9858 590 write_root_descriptors(_writer);
apetushkov@9858 591 }
apetushkov@9858 592
apetushkov@9858 593 void ObjectSampleWriter::write_chain(const RoutableEdge& edge) {
apetushkov@9858 594 assert(EdgeUtils::is_leak_edge(edge), "invariant");
apetushkov@9858 595 if (edge.processed()) {
apetushkov@9858 596 return;
apetushkov@9858 597 }
apetushkov@9858 598 EdgeUtils::collapse_chain(edge);
apetushkov@9858 599 const RoutableEdge* current = &edge;
apetushkov@9858 600 while (current != NULL) {
apetushkov@9858 601 if (current->processed()) {
apetushkov@9858 602 return;
apetushkov@9858 603 }
apetushkov@9858 604 write(current);
apetushkov@9858 605 current->set_processed();
apetushkov@9858 606 current = current->logical_parent();
apetushkov@9858 607 }
apetushkov@9858 608 }
apetushkov@9858 609
apetushkov@9858 610 bool ObjectSampleWriter::operator()(const RoutableEdge& edge) {
apetushkov@9858 611 if (EdgeUtils::is_leak_edge(edge)) {
apetushkov@9858 612 write_chain(edge);
apetushkov@9858 613 }
apetushkov@9858 614 return true;
apetushkov@9858 615 }

mercurial